Spring의 의존성 주입 (Dependency Injection, DI) - 1
- Spring의 의존성 주입 컨테이너의 핵심은 BeanFactory 인터페이스 이다.
- BeanFactory는 컴포넌트의 라이프사이클과 의존성을 관리한다.
- Spring은 XML 파일 또는 Properties 파일을 이용하여 bean 구성을 관리할 수 있다.
- 아주 작은 애플리케이션이 아니라면 XML로 관리하는 것이 유리하다.
- ApplicationContext는 BeanFactory를 상속한 인터페이스로 DI 서비스, 트랜잭션 서비스, AOP 서비스, 국제화를 위한 메시지 소스, 애플리케이션 이벤트 처리 등의 서비스를 제공한다.
- 웹 컨테이너 환경에서는 ContextLoaderListner를 이용하여 구동한다(web.xml에 구성).
애플리케이션 컨텍스트 구성하기
- ApplicationContext를 구성하는 방법은 XML 파일을 이용하는 방법 애노테이션을 이용하는 방법 자바 로 구성하는 방법 등이 있다.
- XML 구성으로 경우 ApplicationContext 구성을 위한 context, AOP 구성을 위한 aop, 트랜잭션 지원을 위한 tx 등의 네임스페이스를 제공한다.
<context:component-scan>
태그는 bas-package에 지정한 패키지의 하위에 있는 모든 클래스 내에@Autowired
,@Inject
,@Resource
,@Component
,@Controller
,@Repository
,@Service
등이 애노테이션이 선언되어 의존선 주입이 가능한 빈의 코드를 스캔하도록 스프링에 지시한다.
<?xml version=“1.0” encoding=“UTF-8”>
<beans ...>
<context:component-scan base-package=“스캔할_패키지" />
</beans>
- 또한 base-package에 지정한 패키지 하위에 있으나 스캔에서 제외할 클래스나 인터페이스를 별도로 지정할 수 있다.
<?xml version=“1.0” encoding=“UTF-8”>
<beans …>
<context:component-scan base-package=“스캔할_패키지”>
<context:exclude=filter type="assignable" expression="제외할 클래스 경로" />
<!-- type의 값으로는 annotation, regex, assignable, AspectJ, custom 등이 올 수 있다. -->
</context:component-scan>
</beans>
- XML로 구성하기 : 의존성 주입을 위한 bean 구성. p 속성을 이용하여 주입될 의존성을 지정해준다.
<?xml version=“1.0” encoding=“UTF-8”>
<beans …>
<bean id="renderer
class="com.apress...StandardOutMessageRenderer"
p:messageProvider-reg="provider" />
<bean id="provider"
class="com.apress...HelloWorldMessageProvider" />
</beans>
- Annotation으로 구성하기 : bean 클래스에 적절한 스테레오 타입 애노테이션이 적용되어야 하며 의존성 주입에 사용될 메서드나 생성자에 @Autowired를 적용한다.
스테레오 타입 애노테이션 : 빈을 정의하는 데 사용되는 모든 애노테이션. Org.springframework.stereotype 패키지의 일부이다.
...
@Component(“provider”)
public class HelloWorldMessageProvider implements MessageProvider {
...
}
...
@Service(“renderer”)
public class StandardOutMessageRenderer implements MessageRenderer {
private MessageProvider messageProvider;
…
@Override
@Autowired
public void setMessageProvider(MessageProvider provider) {
this.messageProvider = provider;
}
...
}
<?xml version=“1.0” encoding=“UTF-8”>
<beans …>
<context:component-scan base-package=“스캔할_패키지" />
</beans>
- 두 방법 중 어느 방법이더라도 ApplicationContext에서 bean을 얻는 방법은 동일하다.
...
public static void main(String… args) {
GenericXmlApplicationContext cox = new GenericXmlApplicationContext();
ctx.load(“classpath:spring/app-context-xml.xml”);
ctx.refresh();
MessageRenderer messageRenderer = ctx.getBean(“renderer”, MessageRenderer.class);;
messageRenderer.render();
ctx.close();
}
...
- 자바로 구성하기 : @Configuration 애노테이션을 적용한 클래스 내에 @Bean 애노테이션이 적용된 메서드를 구현하여 구성한다.
...
@Configuration
public class HelloWorldConfiguration {
@Bean
public MessageProvider provider() {
return new HelloWorldMessageProvider();
}
@Bean
public MessageRenderer renderer() {
MessageRenderer renderer = new StandardMessageRenderer();
renderer.setMessageProvider(provider());
return renderer;
}
}
- 자바 구성의 경우 ApplicationContext 구현체를 바꾸어야 한다.
...
public static void main(String… args) {
ApplicationContext cox = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);
MessageRenderer mr = ctx.getBean(“renderer”, MessageRenderer.class);
mr.render();
}
...
- 자바 구성 클래스에 @ComponentScan 애노테이션을 사용하면 @Bean 애노테이션이 적용된 메서드를 생략해도 된다.
...
@ComponentScan(basePackages = {"스캔할_패키지"})
@Configuration
public class HelloWorldConfiguration {
}
- 자바 구성에서 @ImportResource 애노테이션을 이용하여 기존의 xml 구성을 가져와 사용할 수도 있다.
...
@ImportResource(location = {"classpath:spring/app-context-xml.xml"})
@Configuration
public class HelloWorldConfiguration {
}