[학습 목표]
Spring Container와 Bean의 의미를 이해할 수 있다
Bean Scope의 의미를 이해할 수 있다
Java 기반 Container 설정에 대해 이해할 수 있다
Spring DI(Dependency Injection)의 의미를 이해할 수 있다
Component 스캔에 대해 이해할 수 있다
스프링 컨테이너는 스프링 프레임워크의 핵심 컴포넌트. 내부에 존재하는 애플리케이션 빈의 생명주기를 관리. 인터페이스로 구현 (다형성 적용)
Bean들의 생명 주기 관리
관리하기 위해 IoC 사용
애너테이션 기반 컨테이너 구성
BeanFactory, ApplicationContext 두 개의 컨테이너로 DI가 이루어진 빈들을 제어하고 관리
// Spring Container 생성
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
[Spring Container 종류]
- BeanFactory : 스프링 설정 파일에 등록된 Bean 객체를 생성하고 관리하는 컨테이너. getBean()으로 빈 인스턴스화. @Bean 메서드명을 사용해 빈 등록
- ApplicationContext : BeanFactory를 상속하여 Bean 객체 관리. 트랜잭션 관리, 메세지 기반의 다국어 처리 등 (부가 기능 : MessageSource, EnvironmentCapable, ApplicationEventPublisher, ResourceLoader 등)
컨테이너 인스턴스화
// Annotation
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
[new와 생성자 주입 코드 차이점]
// new 사용하여 직접 객체 생성
public class OrderServiceImpl implements OrderService {
private final UserRepository userRepository = new UserRepositoryImpl();
private final DiscountInfo discountInfo = new RateDiscountInfo();
@Override
public Order createOrder(Long userId, String itemName, int itemPrice) {
User user = userRepository.findByUserId(userId);
int discountPrice = discountInfo.discount(user, itemPrice);
return new Order(userId, itemName, itemPrice, discountPrice);
}
}
// 생성자 주입
public class OrderServiceImpl implements OrderService {
private final UserRepository userRepository;
private final DiscountInfo discountInfo;
public OrderServiceImpl(UserRepository userRepository, DiscountInfo discountInfo) {
this.userRepository = userRepository;
this. discountInfo = discountInfo;
}
@Override
public Order createOrder(Long userId, String itemName, int itemPrice) {
User user = userRepository.findByUserId(userId);
int discountPrice = discountInfo.discount(user, itemPrice);
return new Order(userId, itemName, itemPrice, discountPrice);
}
}
new 사용 : 직접 객체 생성
생성자 주입 : 의존 객체 주입. 느슨한 의존 관계
Bean : 애플리케이션에서 사용하는 인스턴스화된 객체. 설정 정보와 함께 스프링 컨테이너에 등록, 관리되는 재사용 소프트웨어 컴포넌트. 클래스의 정보, 게터/세터 메서드 포함
Bean 접근 방법
// Create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("service.xml", "daos.xml");
// retrieve configure instance
PetStoreService service = context.getBean("cmarket", cmarketService.class);
// use configure instance
List<String> userList = service.getUsernameList();
Java Bean vs Spring Bean
Java Bean : 클래스에서 getter/setter만 가지고 있는 클래스
[Bean Definition]
Bean 설정 메타정보
Spring Container은 BeanDefinition 이라는 추상화를 통해 Spring Bean을 생성
BeanClassName : 생성할 빈의 클래스명
factoryBeanName : 팩토리 역할의 빈을 사용할 경우 이름 (ex. appConfig)
factoryMethodName : 빈을 생성할 팩토리 메서드 지정 (ex. userService)
Scope : 싱글톤
lazyInit : 실제 빈을 사용할 때 까지 최대한 빈 생성을 지연 처리하는지 여부
InitMethodName : 빈을 생성하고 의존관계를 적용한 뒤에 호출되는 초기화 메서드 명
DestroyMethodName : 빈의 생명주기가 끝나서 제거하기 전에 호출되는 메서드 명
Constructor arguments, Properties : 의존관계 주입에서 사용.
static AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
/*
AppConfig.class를 파라미터로 ac(ApplicationContext) 생성시 AppConfig.class 바탕으로 BeanDefinition 객체 만듬.
스프링은 이것을 바탕으로 빈을 생성
AnnotiationConfigApplicationContext에 AppConfig.class 넘겨줄 때
BeanDefinition의 구현체인 AnnotationGenericBeanDefinition 만듬
해당 객체에서 Bean 메타정보 가지고 Spring Contatiner에서 Bean 생성
*/
[애너테이션]
@Configuration
@Bean
@ComponetScan
@Component
@Configuration // @Bean 애너테이션 메서드에 추가하여 Bean 선언
public class AppConfig {
@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
public interface BaseConfig {
@Bean
default TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
@Configuration
public class AppConfig implements BaseConfig {
}
// Bean 정의 있는 인터페이스 구현하여 Bean configuration 설정
다양한 의존관계 주입 방법
생성자 주입
수정자 주입(setter 주입)
필드 주입
일반 메서드 주입
[생성자 주입]
생성자 통해 의존관계 주입
생성자 호출 시접에 1번만 호출
불변과 필수 의존 관계에 사용
생성자
이후 수정 예정