스프링 빈
스프링 컨테이너에 의해 관리되는 POJO 자바 객체
스프링 컨테이너
스프링 빈의 생명 주기를 관리하며, 생성된 스프링 빈에게 추가 기능을 제공한다.
IoC와 DI 원리가 여기에 적용된다.
개발자는 객체를 생성할 때 new 연산자, 팩토리 메서드 호출 등을 사용하지만, 스프링 컨테이너를 사용하면 해당 역할을 대신해준다.
즉 제어의 흐름을 외부에서 관리한다.
또한, 객체들의 의존 관계를 스프링 컨테이너가 런타임 과정에서 알아서 만들어 준다.
스프링 빈 등록
컴포넌트 스캔
@Component 어노테이션이 붙은 클래스를 스캔해서 빈으로 등록한다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {}
@Target(ElementType.TYPE)이기 때문에 클래스나 인터페이스만 붙일 수 있다.
그 외에도 자주 사용하는 @Service @Repository @Controller 어노테이션도 내부에 @Component 어노테이션의 상속을 받고 있다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
... //스프링의 MVC 컨트롤러로 인식된다.
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
... //개발자들이 서비스임을 인식할 수 있게 한다. (특별한 용도는 없다)
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
... //데이터 접근 계층으로 인식하고, 모든 예외를 DataAccessException으로 변환해준다.
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
... //설정 정보로 인식하고 스프링 빈이 싱글톤으로 유지되도록 추가 처리를 한다.
}
@Bean으로 등록하기
@Bean 어노테이션을 사용해서 수동으로 스프링 빈을 등록할 수 있다.
@Configuration
public class AppConfig {
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
}
빈을 등록하기 위해 인스턴스를 생성하는 메서드에 @Bean을 명시한다.
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
...
}
@Bean 어노테이션은 메서드나 어노테이션 위에만 붙일 수 있으며, 클래스에는 붙일 수 없다.
수동 등록
ApplicationContext를 호출해서 수동으로 스프링 빈을 등록할 수 있다.
public class Main {
public static void main(String[] args) {
final ApplicationContext beanFactory = new AnnotationConfigApplicationContext(AppConfig.class);
final AppConfig bean = beanFactory.getBean("appConfig", AppConfig.class);
}
}
@Bean vs @Configuration
- @Bean
- 개발자가 컨트롤이 불가능한 외부 라이브러리를 빈으로 등록하고 싶을때 사용한다.
- 메소드 또는 어노테이션 위에 붙인다.
- @Component
- 개발자가 직접 컨트롤이 가능한 클래스에 붙인다.
- 클래스 또는 인터페이스 단위에 붙인다.
@Configuration과 싱글톤
@Configuration은 @Bean에 추가 설정을 주어 싱글톤으로 만들지 않는 이상 무조건 빈에 대해 싱글톤을 보장한다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
MemberService, OrderService를 생성할 때 인자로 memberRepository()를 호출하기 때문에 인스턴스가 두개 생성된다고 생각할 수 있다. 즉 싱글톤이 보장 안될 것이라고 생각이 든다.
그러나 @Configuration은 CGLIB를 사용해서 싱글톤을 보장한다.
CGLIB은 프록시 객체의 일종으로 AppConfig가 빈으로 등록될 때, AppConfig 대신 AppConfig$CGLIB 형태로 프록시 객체가 등록된다.
그리고 @Bean이 등록된 메서드마다 이미 스프링 빈이 존재하면 존재하는 빈을 반환하고, 없을 경우 생성해서 스프링 빈으로 등록하고 반환하는 코드가 동적으로 만들어지기 때문에 싱글톤이 보장된다.
Bean Lite Mode
CGLIB를 사용해서 바이트 코드 조작을 하지 않는 방식을 의미한다. 즉, 싱글톤을 보장하지 않는다.
AppConfig에 @Configuration 대신 @Component로 변경한다.
@Component
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
이렇게 하면 objectMapperLiteBean() 메서드를 lite mode로 작동하여 매번 다른 객체를 반환해 줄 수 있다.
만약 ApplicationContext를 호출해서 빈을 수동으로 등록할 경우, @Component 없이도 Bean Lite Mode로 동작한다.
'🍃Spring' 카테고리의 다른 글
[Spring] IoC와 DI (1/2) (0) | 2023.05.27 |
---|---|
[Spring] 스프링 빈 스코프 (2/2) (0) | 2023.05.27 |
[Spring] 테스트 클렌징시 deleteAll()을 사용할 때의 주의점 (0) | 2023.05.13 |
[Spring] WebMvcTest에서 발생하는 SpringSecurity 의존성 문제 해결하기 (0) | 2023.04.19 |
[Redis] Redis 캐시를 사용한 JWT 리프레시 토큰 관리하기 (0) | 2023.04.10 |