1.5 스프링 3.1의 IoC 컨테이너와 DI
- 스프링 3.1에 새롭게 도입된 IoC/DI 기술은 두가지
- 강화된 자바 코드 빈 설정
- 런타임 환경 추상화
- 가장 큰 특징은 자바 코드를 이용한 설정 메타정보 작성이 쉽다는 점
- XML을 사용하지 않거나 최소화한 채로 스프링 애플리케이션 개발이 가능
- XML 설정을 사용하면 애플리케이션을 운영, 유지보수하는 여러면에서 유리
- 반대로 자동인식과 관례를 최대한 활용해서 명시적인 설정정보의 양을 최소화하고 툴의 지원을 통해 편리하고 안전하게 개발할 수 있는 자바 코드 방식이 선호되기도 함
1.5.1 빈의 역할과 구분
빈의 종류
애플리케이션 로직 빈
- 스프링에서 말하는 빈은 IoC/DI 컨테이너에 의해 생성되고 관리되는 오브젝트
- 일반적으로 애플리케이션의 로직을 담고 있는 주요 클래스의 오브젝트가 빈으로 지정
- 비즈니스 로직과 기반 서비스를 다루는 서비스 오브젝트, 웹 로직을 다루는 컨트롤러 오브젝트 등이 대표적
애플리케이션 인프라 빈
- DAO가 사용하는 DataSource 오브젝트
- 트랜잭션 추상화에 사용되는 DataSourceTransactionManager
- 빈으로 등록돼서 IoC/DI 컨테이너에 의해 만들어지고 다른 빈과 관계를 맺고 동작
- 애플리케이션 로직을 직접 담당하지 않고, 애플리케이션의 로직 빈을 지원
- 애플리케이션이 동작하는데 직접 참여하므로 애플리케이션 빈의 일종
컨테이너 인프라 빈
- AOP를 설명하면서 소개했던 DefaultAdvisorAutoProxyCreator
- DefaultAdvisorAutoProxyCreator는 Advisor 타입 빈의 포인트컷 정보를 이용해서 타깃 빈을 설정하고, 선정된 빈을 프록시로 바꿔주는 기능을 담당
- 로직을 담고 있지 않고, 다른 애플리케이션 로직을 담은 빈과 관계를 맺고 외부 서비스를 사용하는데 도움을 주지도 않음
- 스프링 컨테이너의 기능에 관여하며 빈을 생성할 때 프록시 생성 같은 특별한 작업 지원
- 스프링 컨테이너 빈으로 등록되서 사용되며, 스프링 IoC/DI 컨테이너의 기능을 확장하는 방법은 확장 기능을 가진 오브젝트를 스프링의 빈으로 등록하는 것
- 스프링 컨테이너는
BeanPostProcessor
나BeanFactoryPostProcessor
같은 확장 포인트를 제공, 이런 인터페이스를 구현한 클래스가 빈으로 되어 있으면 스프링 컨테이너는 스스로 확장하는데 사용
컨테이너 인프라 빈과 전용 태그
- 컨테이너 인프라 빈은 DefaultAdvisorAutoProxyCreator처럼 <bean> 태그를 이용해 직접 빈 등록이 가능
- 하지만 전용 태그를 사용하는 방법이 더 많이 사용
- 자동인식을 이용한 빈 등록을 사용하려면 XML에
<context:component-scan>
태그가 필요 대표적으로 사용되는 전용 태그
<context:component-scan>
태그로 어떤 빈이 등록되는지 예시- 간단한 클래스에
@Component
를 붙이면 빈 스캐너를 통해 빈으로 등록
@Configuration
은 자신이 빈으로 등록되면서 동시에 @Bean이 붙은 메소드의 리턴 오브젝트도 빈으로 등록
SimpleConfig
빈이 등록되면 추가로 Hello 클래스도 빈으로 등록 되고, Hello 클래스에는@PostConstruct
가 있으니 빈 오브젝트가 만들어진 뒤에init()
이 실행
SimpleConfig
에는@Autowired
로 지정된 hello 필드가 있어 컨테이너가 Hello 타입의 빈을 찾아서 자동으로 주입
@Configuration public class SimpleConfig { @Autowired Hello hello; @Bean Hello hello() { return new Hello(); } } public class Hello { @PostConstruct public void init() { System.out.println("Init"); } public void sayHello() {...} }
- 간단한 클래스에
- XML에 bean을 등록하고 자바에서 사용하면 NullPointException이 발생
<beans ...> <bean class="springbook.learingtest.spring31.ioc.SimpleConfig /> </beans> ApplicationContext context = new GenericXmlApplicationContext(BeanRoleText.class, "beanrole.xml"); SimpleConfig sc = context.getBean(SimpleConfig.class); sc.hello.sayHello(); //NullPointException 발생
- NullPointException이 발생한 이유는 스프링 IoC/DI 컨테이너에는 @Configuration/@Bean을 이용해 새로운 빈을 등록해주는 기능이 없기 떄문
- 코드가 바르게 동작하게 하려면 XML에 다음 한줄을 추가
<context:annotation-config />
<context:annotation-confg>
태그는 context 네임스페이스의 태그를 처리하는 핸드러를 통해 특정 빈이 등록되게 해줌 (@Configuration/@Bean 등)
- 이 과정에서 등록되는 빈이 스프링 컨테이너를 확장해서 빈의 등록과 관계 설정, 후처리 등에 새로운 기능을 부여하는 컨테이너 인프라 빈
<context:annotation-confg>
태그를 추가하면 스프링 3.1에서는 6개의 빈이 추가로 등록ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor
ConfigurationClassPostProcessor
@Configuration
과@Bean
을 이용해 새로운 빈을 등록하는 역할
AutowiredAnnotationBeanPostProcessor
- @Autowired가 붙은 필드를 찾아서 빈 의존관계를 설정
RequiredAnnotationBeanPostProcessor
PersistenceAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcesoor
- @PostConstruct가 붙은 메소드를 빈이 초기화 된 뒤에 호출해주는 기능을 제공
- 컨테이너 인프라 빈은 개발자가 직접 개발해서 추가할 일이 거의 없고, 일정한 설정 패턴이 있기 때문에 전용 태그로 등록하고 애트리뷰트를 통해 필요한 속성만 부여하는게 일반적
- 전용 태그가 처음 등장한 스프링 2.0 이전에는 인프라 빈들을 모두
<bean>
로 등록해서 사용
- 전용태그가 많아지면 전용 태그에 의해 등록된 빈을 확인하고 빈의 속성이 어떻게 설정됐는지 살펴볼 필요가 있음 (중복적으로 빈을 사용할 수 있기 때문)
public class BeanDefinitionUtils { public static void printBeanDefinitions(GenericApplicationContext gac) { List<List<String>> roleBeanInfos = new ArrayList<List<String>>(); roleBeanInfos.add(new ArrayList<String>()); roleBeanInfos.add(new ArrayList<String>()); roleBeanInfos.add(new ArrayList<String>()); for(String name : gac.getBeanDefinitionNames()) { int role = gac.getBeanDefinition(name).getRole(); List<String> beanInfos = roleBeanInfos.get(role); beanInfos.add(role + "\t" + name + "\t" + gac.getBean(name).getClass().getName(); } for(List<String> beanInfos : roleBeanInfos) { for(String beanInfo : beanInfos) { System.out.println(beanInfo); } } } }
- 테스트 코드나 main() 에서 애플리케이션 컨텍스트를 생성 후
printBeanDefinitions()
를 호출하면 등록된 빈의 역할과 빈 이름이 출력
- 테스트 코드나 main() 에서 애플리케이션 컨텍스트를 생성 후
빈의 역할
- 스프링을 이용해 대부분 JavaEE 환경에서 동작하는 웹 애플리케이션을 만듬
- web.xml의 설정에 따라 루트 애플리케이션 컨텍스트나 서블릿 컨텍스트 형태로 만듬
- 스프링의 빈을 역할에 따라 구분한다면 세가지로 구분이 가능
- 2000년대 초반에는 자바 5이상에서 사용가능한 enum이 없어서 상수로 정의
int ROLE_APPLICATION = 0; int ROLE_SUPPORT = 1; int ROLE_INFRATRUCTURE = 2;
ROLE_APPLICATION
은 애플리케이션 로직 빈과 애플리케이션 인프라 빈처럼 애플리케이션이 동작하는 중에 사용되는 빈을 의미 (애플리케이션을 구성하는 빈)
ROLE_SUPPORT
는 복합 구조의 빈을 정의할 때 보조적으로 사용되는 빈의 역할을 지정하려고 정의 (실제로는 거의 사용되지 않음, 무시해도 괜찮음)
ROLE_INFRASTRUCTURE
은<context:annotation-config>
같은 전용 태그의 의해 등록되는 컨테이너 인프라 빈들을 의미
- 개발자가 빈을 정의할 때 이 역할 값을 직접 지정할 수 있도록
@Role
애노테이션을 도입
'개발서적 > 토비 스프링 3.1-Vol.2' 카테고리의 다른 글
[토비의 스프링 - Vol.2] 1장 - 1.5.3 웹 애플리케이션의 새로운 IoC 컨테이너 구성 (0) | 2022.01.17 |
---|---|
[토비의 스프링 - Vol.2] 1장 - 1.5.2 컨테이너 인프라 빈을 위한 자바 코드 메타정보 (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 1장 - 1.4 기타 빈 설정 메타정보 (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 1장 - 1.3 프로토타입과 스코프 (0) | 2022.01.17 |
[토비의 스프링 - Vol.2] 1장 - 1.2.5 컨테이너가 자동등록하는 빈 (0) | 2022.01.17 |