https://sundaland.tistory.com/479
▶ Using the @Bean Annotation
@Bean은 메서드 레벨 어노테이션이며 XML <bean/> 엘리먼트와 직접적으로 대응된다. 이 어노테이션은 <bean/>에서 제공하는 다음과 같은 일부 속성을 지원한다.
- init-method
- destroy-method
- autowiring
- name
@Bean 애노테이션은 @Configuration 어노테이션이 붙은 클래스나 @Component 어노테이션이 붙은 클래스에서 사용할 수 있다.
▷ Declaring a Bean
빈을 선언하려면 @Bean 어노테이션으로 메서드에 어노테이션을 달 수 있다. 이 메서드를 사용하여 메서드의 리턴 값으로 지정된 타입의 ApplicationContext 내에 빈 정의를 등록한다. 기본적으로 빈 이름은 메서드 이름과 동일하다.
▼ @Bean 메서드 선언 예시
@Configuration
public class AppConfig {
@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
위 선언은 다음 텍스트 이미지에서 볼 수 있듯이 TransferServiceImpl 타입의 객체 인스턴스에 바인딩된 transferService라는 이름의 빈을 ApplicationContext에서 사용할 수 있게 한다.
transferService -> com.acme.TransferServiceImpl
디폴트 메서드를 사용하여 빈을 정의할 수도 있다. 이를 통해 디폴트 메서드에서 빈 정의가 있는 인터페이스를 구현하여 빈 구성을 구성할 수 있다.
public interface BaseConfig {
@Bean
default TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
@Configuration
public class AppConfig implements BaseConfig {
}
▼ 인터페이스(또는 베이스 클래스) 리턴 유형으로 @Bean 메서드를 선언
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
그러나, 이는 고급 타입 예측의 가시성을 지정된 인터페이스 타입(TransferService)으로 제한한다. 전체 타입(TransferServiceImpl)은 해당 싱글톤 빈이 인스턴스화된 후에야 컨테이너에 알려진다. 비지연(non-lazy) 싱글톤 빈들은 선언된 순서에 따라 인스턴스화되기 때문에, 다른 컴포넌트가 선언되지 않은 타입(@Autowired TransferServiceImpl)을 기준으로 매칭을 시도할 때, 이 빈이 인스턴스화된 시점에 따라 다른 타입 매칭 결과가 나타날 수 있다.
선언된 서비스 인터페이스로 타입을 일관되게 참조하는 경우 @Bean 리턴 타입이 해당 디자인 결정에 안전하게 결합될 수 있다. 그러나 여러 인터페이스를 구현하는 컴포넌트나 구현 타입으로 잠재적으로 참조되는 컴포넌트의 경우 가능한 가장 구체적인 리턴 타입을 선언하는 것이 더 안전라다. (적어도 빈을 참조하는 주입 지점에서 요구하는 만큼 구체적이다)
▷ Bean Dependencies
@Bean 어노테이션이 붙은 메서드는 해당 빈을 빌드하는 데 필요한 종속성을 설명하는 임의의 수의 파라미터를 가질 수 있다. 예를 들어, TransferService에 AccountRepository가 필요한 경우 다음 예제와 같이 메서드 파라미터로 해당 종속성을 구체화할 수 있다.
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
▷ Receiving Lifecycle Callbacks
@Bean 어노테이션으로 정의된 모든 클래스는 일반 라이프사이클 콜백을 지원하고 JSR-250의 @PostConstruct 및 @PreDestroy 주석을 사용할 수 있다.
일반적인 Spring 라이프사이클 콜백도 완벽하게 지원된다. 빈이 InitializingBean, DisposableBean 또는 Lifecycle을 구현하는 경우 해당 메서드는 컨테이너에서 호출된다.
BeanFactoryAware, BeanNameAware, MessageSourceAware, ApplicationContextAware 등과 같은 표준 *Aware 인터페이스 세트도 완벽하게 지원된다.
@Bean 어노테이션은 다음 예제에서 볼 수 있듯이 빈 요소에 Spring XML의 init-method 및 destroy-method 속성과 매우 유사하게 임의의 init 및 destroy 콜백 메서드를 지정하는 것을 지원한다.
public class BeanOne {
public void init() {
// initialization logic
}
}
public class BeanTwo {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public BeanOne beanOne() {
return new BeanOne();
}
@Bean(destroyMethod = "cleanup")
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
기본적으로 Java 구성으로 정의된 빈은 public close 또는 shutdown 메서드가 있고 자동으로 destroy 콜백에 등록된다. public close 또는 shutdown 메서드가 있고 컨테이너가 종료될 때 호출되지 않도록 하려면 빈 정의에 @Bean(destroyMethod = "")을 추가하여 디폴트(추론된) 모드를 비활성화할 수 있다.
JNDI로 획득한 리소스의 경우 기본적으로 이를 수행할 수 있다. 해당 리소스의 수명 주기는 애플리케이션 외부에서 관리되기 때문이다. 특히 Jakarta EE 애플리케이션 서버에서 문제가 되는 것으로 알려져 있으므로 DataSource의 경우 항상 이를 수행해야 한다.
▼ DataSource에 대한 자동 destruction 콜백을 방지
@Bean(destroyMethod = "")
public DataSource dataSource() throws NamingException {
return (DataSource) jndiTemplate.lookup("MyDS");
}
또한 @Bean 메서드에서는 일반적으로 Spring의 JndiTemplate 또는 JndiLocatorDelegate 헬퍼를 사용하거나 직접 JNDI InitialContext를 사용하지만 JndiObjectFactoryBean 변형은 사용하지 않는 프로그램적 JNDI 조회를 사용한다 (이 경우 실제 대상 유형 대신 FactoryBean 유형으로 반환 유형을 선언해야 하므로 여기에 제공된 리소스를 참조하려는 다른 @Bean 메서드에서 교차 참조 호출에 사용하기 어렵다).
위의 예에서 BeanOne의 경우, 다음 예와 같이 생성 중에 init() 메서드를 직접 호출하는 것도 마찬가지로 유효하다.
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
BeanOne beanOne = new BeanOne();
beanOne.init();
return beanOne;
}
// ...
}
Java에서 직접 작업하는 경우 객체를 원하는 대로 조작할 수 있으며 항상 컨테이너 수명 주기에 의존할 필요가 없다.
▷ Specifying Bean Scope
Spring에는 @Scope 어노테이션이 포함되어 있어 빈의 범위를 지정할 수 있다.
◎ Using the @Scope Annotation
@Bean 어노테이션으로 정의된 빈이 특정 scope를 가져야 한다고 지정할 수 있다. Bean Scopes 섹션에 지정된 표준 범위를 사용할 수 있다.
디폴트 스코프는 싱글톤이지만 다음 예제와 같이 @Scope 어노테이션으로 이를 재정의할 수 있다.
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
}
◎ @Scope and scoped-proxy
Spring은 스코프가 지정된 프록시를 통해 스코프가 지정된 종속성을 처리하는 편리한 방법을 제공한다. XML 구성을 사용할 때 이러한 프록시를 만드는 가장 쉬운 방법은 <aop:scoped-proxy/> 엘리먼트다. @Scope 어노테이션으로 Java에서 빈을 구성하면 proxyMode 특성으로 동일한 지원을 제공한다. 기본값은 ScopedProxyMode.DEFAULT이며, 일반적으로 컴포넌트 스캔 지시 레벨에서 다른 디폴트 값이 구성되지 않는 한 스코프가 지정된 프록시를 만들지 않아야 함을 나타낸다. ScopedProxyMode.TARGET_CLASS, ScopedProxyMode.INTERFACES 또는 ScopedProxyMode.NO를 지정할 수 있다.
// an HTTP Session-scoped bean exposed as a proxy
@Bean
@SessionScope
public UserPreferences userPreferences() {
return new UserPreferences();
}
@Bean
public Service userService() {
UserService service = new SimpleUserService();
// a reference to the proxied userPreferences bean
service.setUserPreferences(userPreferences());
return service;
}
▷ Customizing Bean Naming
기본적으로 구성 클래스는 @Bean 메서드의 이름을 결과 빈의 이름으로 사용한다. 그러나 이 기능은 다음 예제에서 보여지는 것처럼 name 속성을 사용하여 재정의할 수 있다.
@Configuration
public class AppConfig {
@Bean("myThing")
public Thing thing() {
return new Thing();
}
}
▷Bean Aliasing
Naming Beans에서 논의했듯이, 때로는 단일 빈에 여러 이름을 부여하는 것이 바람직한데, 이를 빈 별칭이라고도 한다. @Bean 어노테이션의 name 속성은 이 목적을 위해 문자열 배열을 허용한다. 다음 예는 빈에 대한 여러 별칭을 설정하는 방법을 보여준다.
@Configuration
public class AppConfig {
@Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})
public DataSource dataSource() {
// instantiate, configure and return DataSource bean...
}
}
▷ Bean Description
때로는 빈에 대한 보다 자세한 텍스트 설명을 제공하는 것이 도움이 된다. 이는 모니터링 목적으로 빈이 노출될 때(아마도 JMX를 통해) 특히 유용할 수 있다.
@Bean에 설명을 추가하려면 다음 예와 같이 @Description 어노테이션을 사용할 수 있다.
@Configuration
public class AppConfig {
@Bean
@Description("Provides a basic example of a bean")
public Thing thing() {
return new Thing();
}
}
'스프링 프레임워크 > IoC (Inversion of Control)' 카테고리의 다른 글
Composing Java-based Configurations (0) | 2024.11.19 |
---|---|
Using the @Configuration annotation (0) | 2024.11.19 |
Instantiating the Spring Container by Using AnnotationConfigApplicationContext (0) | 2024.11.19 |
Fine-tuning Annotation-based Autowiring with Qualifiers (0) | 2024.11.19 |
Annotation-based Container Configuration (0) | 2024.11.19 |