DI 는 의존을 처리하는 방식이다.
의존에 대한 설계 패턴으로, 의존성 주입이라는 단어로 번역되어 사용된다.
스프링은 기본적으로 DI를 기반으로 동작하기 때문에, 스프링을 잘 이해하려면 DI에 대한 이해가 필수이다.
public class A {
private B b = new B();
}
// 위의 코드보다 느슨한 의존성을 가짐
// 필요할 때만 b를 넣어서 사용 가능.
public class A {
private B b;
public A(B b) {
this.b = b;
}
}
위 의 코드의 경우 A클래스가 B클래스에 의존한다 라고 표현한다.
이렇게 두 클래스 간에 의존성이 있다면 몇 가지 단점이 있다.
- B 클래스를 상속 받은 하위 클래스 C로 변경하려고 할 때 A 클래스의 코드를 수정해 주어야 한다. B 클래스를 사용하는 클래스가 많을 수록, 수정해야 하는 코드의 양이 많아진다.
- 개발 단계에서 B 클래스가 완성되지 않았을 경우, A 클래스를 테스트 할 수 없게 된다.
이처럼 의존하는 객체를 직접 생산하는 방식은 개발 효율을 낮추고, 개발 생산성이 전반적으로 낮아지는 상황이 발생한다.
이러한 단점은 코드를 아래와 같은 구조로 변경하였을 때 해결 가능하다.
// 위의 코드보다 느슨한 의존성을 가짐
// 필요할 때만 b를 넣어서 사용 가능.
public class A {
private B b;
public A(B b)
this.b = b;
}
}
이와 같이 A 클래스 내부에서 B객체를 직접 생성하지 않고 누군가가 의존하는 객체(의존성)를 외부에서 넣어준다(주입)는 의미로 DI라고 부른다. (= 객체를 연결(wire)한다는 표현을 쓰기도 한다.)
- B 클래스를 상속 받은 하위 객체로 변경하고 싶을 때 변경되어야 하는 부분은 객체를 생성하고 연결해주는 조립기로 제한된다. 객체를 필요로 하는 코드는 변경되지 않는다. (= 스프링이 이 조립기에 해당)
- B 클래스의 구현이 완성되어 있지 않더라도 테스트를 할 수 있다. A 클래스를 테스트 할 때 B클래스의 가짜 객체를 생성해서 테스트가 가능하기 때문에 A 클래스와 B 클래스를 동시에 구현 할 수 있다. ⇒ 개발 효율을 향상시킬 수 있다.
간단하게 가짜 구현 객체를 만들어 주는 다양한 테스트 프레임워크가 있다.
ex) Mockito 등
예제 ) Bean 을 이용한 DI구현
@Component, @RestController 어노테이션이 클래스에 붙어있으면 bean 에 저장되어 있다.
@Component 의 target 범위가 type이고, @Bean target 범위가 메소드 이기 때문에 @Bean 은 클래스에 사용하지 못한다.
- new 로 객체를 생성해서 사용하지 않고 getBean으로 저장된 객체를 불러와서 사용한다. (DI)
- Bean scope 가 싱글톤으로 객체를 하나만 생성해서 저장하고 계속 불러와서 사용하기 때문에 여러번 호출해도 같은 주소 값을 가진다.
- scope 옵션을 Prototype으로 변경하여 호출할때마다 객체 생성하도록 변경 가능하다.
config/ApplicationContextProvider.java
package kr.re.kitri.security.web.edu.config;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
}
model/TestBean.java
package kr.re.kitri.security.web.edu.model;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TestBean {
String test1;
public TestBean() {
}
public TestBean(String test1) {
this.test1 = test1;
}
public String getHello() {
return "hello";
}
}
EduApplication.java > ApplicationContext 를 이용하여 getBean를 이용해 Bean 가져오기
package kr.re.kitri.security.web.edu;
import kr.re.kitri.security.web.edu.config.ApplicationContextProvider;
import kr.re.kitri.security.web.edu.model.TestBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
public class EduApplication {
public static void main(String[] args) {
SpringApplication.run(EduApplication.class, args);
ApplicationContext ac = ApplicationContextProvider.getApplicationContext();
TestBean testBean2 = ac.getBean("testBean1", TestBean.class);
TestBean testBean = ac.getBean("testbe", TestBean.class);
TestBean testBeanTest = ac.getBean("testbe", TestBean.class);
// 같은 객체이기 때문에 같은 주소값을 가진다.
System.out.println("testBean의 객체값:" + testBean);
System.out.println("testBeanTest의 객체값:" + testBeanTest);
System.out.println("testBean의 객체값 hello:" + testBean != null ? testBean.getHello() : "null");
}
}
@Configuration
class AppConfig {
// 디폴트는 싱글톤 패턴이고 변경하고 싶을 때는
// @Scrope() 어노테이션으로 변경 가능하다.
@Bean()
public TestBean testBean1() {
return new TestBean();
}
@Bean()
public TestBean testBean2() {
return new TestBean("hello");
}
}
intellij에서 View>Tool Window>Spring 에 들어가면 Beans 에서 testBean이 저장되어 있는 것을 확인할 수 있다.
'Study > Spring' 카테고리의 다른 글
springboot 에서 어노테이션기반 MyBatis 적용하기 (xml 사용하지 않고) (0) | 2023.12.16 |
---|---|
[Spring]Builder (0) | 2023.10.06 |
[Spring] AOP 예제 (0) | 2023.09.25 |
[Spring] 3. AOP (0) | 2023.09.24 |
[Spring] Spring 시작하기 (0) | 2023.09.24 |