Loading...
Spring Framework Reference Documentation 7.0.2의 Using the @Bean Annotation의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
@Bean Annotation@Bean은 메서드 수준의 어노테이션이며 XML <bean/> element와 직접적으로 동일한 역할을 합니다.
이 어노테이션은 다음과 같이 <bean/>이 제공하는 attribute 일부를 지원합니다:
@Bean 어노테이션은 @Configuration이 부여된 클래스나 @Component가 부여된 클래스에서 사용할 수 있습니다.
bean을 선언하려면 메서드에 @Bean 어노테이션을 붙이면 됩니다. 이 메서드를 사용하여
메서드의 반환 값 타입으로 지정된 ApplicationContext 내에 bean definition을 등록합니다.
기본적으로 bean name은 메서드 name과 동일합니다. 다음 예제는 @Bean 메서드 선언을 보여 줍니다:
1@Configuration 2public class AppConfig { 3 4 @Bean 5 public TransferServiceImpl transferService() { 6 return new TransferServiceImpl(); 7 } 8}
1@Configuration 2class AppConfig { 3 4 @Bean 5 fun transferService() = TransferServiceImpl() 6}
앞의 설정은 다음 Spring XML과 정확히 동일합니다:
1<beans> 2 <bean id="transferService" class="com.acme.TransferServiceImpl"/> 3</beans>
두 선언 모두 transferService라는 이름의 bean을 ApplicationContext에서 사용할 수 있도록 만들며,
TransferServiceImpl 타입의 객체 인스턴스에 바인딩합니다. 다음 텍스트 이미지에서 볼 수 있습니다:
transferService -> com.acme.TransferServiceImpl
default 메서드를 사용하여 bean을 정의할 수도 있습니다. 이렇게 하면 default 메서드에 bean definition을 가지고 있는 인터페이스를 구현함으로써 bean 설정을 구성할 수 있습니다.
1public interface BaseConfig { 2 3 @Bean 4 default TransferServiceImpl transferService() { 5 return new TransferServiceImpl(); 6 } 7} 8 9@Configuration 10public class AppConfig implements BaseConfig { 11 12}
또한 @Bean 메서드를 인터페이스(또는 base 클래스) 반환 타입으로 선언할 수도 있습니다. 다음 예제와 같습니다:
1@Configuration 2public class AppConfig { 3 4 @Bean 5 public TransferService transferService() { 6 return new TransferServiceImpl(); 7 } 8}
1@Configuration 2class AppConfig { 3 4 @Bean 5 fun transferService(): TransferService { 6 return TransferServiceImpl() 7 } 8}
그러나 이렇게 하면 advance 타입 prediction에 대한 visibility가 지정된 인터페이스 타입(TransferService)으로
제한됩니다. 그런 다음, 영향을 받는 singleton bean이 인스턴스화된 이후에야 컨테이너에서 전체 타입
(TransferServiceImpl)을 알 수 있게 됩니다.
non-lazy singleton bean은 선언 순서에 따라 인스턴스화되므로,
다른 컴포넌트가 선언되지 않은 타입(예: @Autowired TransferServiceImpl처럼
transferService bean이 인스턴스화된 이후에만 resolve되는 경우)에 의해 matching을 시도하는 시점에 따라
서로 다른 타입 matching 결과를 볼 수 있습니다.
타입을 선언된 service 인터페이스로 일관되게 참조한다면,
@Bean반환 타입 역시 해당 설계 결정에 안전하게 따라갈 수 있습니다. 그러나 여러 인터페이스를 구현하는 컴포넌트나 구현 타입으로 참조될 수 있는 컴포넌트의 경우, bean을 참조하는 injection point에 필요한 최소한의 구체적인 타입(가능한 한 가장 구체적인 반환 타입)을 선언하는 것이 더 안전합니다.
@Bean이 부여된 메서드는 해당 bean을 생성하는 데 필요한 의존성을 기술하는 임의의 개수의 파라미터를
가질 수 있습니다. 예를 들어, TransferService가 AccountRepository를 필요로 한다면, 다음 예제와 같이
메서드 파라미터로 해당 의존성을 구체화할 수 있습니다:
1@Configuration 2public class AppConfig { 3 4 @Bean 5 public TransferService transferService(AccountRepository accountRepository) { 6 return new TransferServiceImpl(accountRepository); 7 } 8}
1@Configuration 2class AppConfig { 3 4 @Bean 5 fun transferService(accountRepository: AccountRepository): TransferService { 6 return TransferServiceImpl(accountRepository) 7 } 8}
resolution mechanism은 생성자 기반 의존성 주입과 거의 동일합니다. 자세한 내용은 the relevant section을 참조하십시오.
@Bean 어노테이션으로 정의된 클래스는 일반적인 lifecycle callback을 지원하며
JSR-250의 @PostConstruct 및 @PreDestroy 어노테이션을 사용할 수 있습니다.
자세한 내용은
JSR-250 annotations을 참조하십시오.
일반적인 Spring lifecycle callback도 완전히 지원됩니다.
bean이 InitializingBean, DisposableBean, 또는 Lifecycle을 구현하는 경우,
컨테이너는 각 인터페이스의 메서드를 호출합니다.
표준 *Aware 인터페이스 집합(예: BeanFactoryAware,
BeanNameAware,
MessageSourceAware,
ApplicationContextAware 등)도 완전히 지원됩니다.
@Bean 어노테이션은 Spring XML의 bean element에서 init-method 및 destroy-method
attribute와 마찬가지로 임의의 initialization 및 destruction callback 메서드를 지정하는 것을
지원합니다. 다음 예제와 같습니다:
1public class BeanOne { 2 3 public void init() { 4 // initialization logic 5 } 6} 7 8public class BeanTwo { 9 10 public void cleanup() { 11 // destruction logic 12 } 13} 14 15@Configuration 16public class AppConfig { 17 18 @Bean(initMethod = "init") 19 public BeanOne beanOne() { 20 return new BeanOne(); 21 } 22 23 @Bean(destroyMethod = "cleanup") 24 public BeanTwo beanTwo() { 25 return new BeanTwo(); 26 } 27}
1class BeanOne { 2 3 fun init() { 4 // initialization logic 5 } 6} 7 8class BeanTwo { 9 10 fun cleanup() { 11 // destruction logic 12 } 13} 14 15@Configuration 16class AppConfig { 17 18 @Bean(initMethod = "init") 19 fun beanOne() = BeanOne() 20 21 @Bean(destroyMethod = "cleanup") 22 fun beanTwo() = BeanTwo() 23}
기본적으로, Java 설정으로 정의된 bean 중 public
close또는shutdown메서드를 가진 bean은 자동으로 destruction callback에 등록됩니다. publicclose또는shutdown메서드가 있고 컨테이너가 종료될 때 해당 메서드가 호출되기를 원치 않는다면, bean definition에@Bean(destroyMethod = "")를 추가하여 기본(inferred)mode를 비활성화할 수 있습니다. JNDI로 획득한 resource의 경우, lifecycle이 애플리케이션 외부에서 관리되므로 기본적으로 그렇게 하고 싶을 수 있습니다. 특히DataSource의 경우 Jakarta EE 애플리케이션 서버에서 문제가 있는 것으로 알려져 있으므로 항상 그렇게 해야 합니다. 다음 예제는DataSource에 대한 자동 destruction callback을 방지하는 방법을 보여 줍니다:
- Java
- Kotlin
1@Bean(destroyMethod = "") 2public DataSource dataSource() throws NamingException { 3 return (DataSource) jndiTemplate.lookup("MyDS"); 4}1@Bean(destroyMethod = "") 2fun dataSource(): DataSource { 3 return jndiTemplate.lookup("MyDS") as DataSource 4}또한,
@Bean메서드에서는 일반적으로 Spring의JndiTemplate또는JndiLocatorDelegatehelper나 직접적인 JNDIInitialContext사용을 통해 programmatic JNDI lookup을 사용하지만,JndiObjectFactoryBeanvariant는 사용하지 않습니다(FactoryBean타입을 반환 타입으로 선언해야 하므로, 여기서 제공된 resource를 참조하려는 다른@Bean메서드에서 cross-reference 호출에 사용하기가 더 어려워집니다).
위 예제에서 BeanOne의 경우, 다음 예제와 같이 construction 중에 init() 메서드를 직접 호출해도
동일하게 유효합니다:
1@Configuration 2public class AppConfig { 3 4 @Bean 5 public BeanOne beanOne() { 6 BeanOne beanOne = new BeanOne(); 7 beanOne.init(); 8 return beanOne; 9 } 10 11 // ... 12}
1@Configuration 2class AppConfig { 3 4 @Bean 5 fun beanOne() = BeanOne().apply { 6 init() 7 } 8 9 // ... 10}
Java에서 직접 작업할 때는 객체로 원하는 작업을 모두 수행할 수 있으며, 항상 컨테이너 lifecycle에 의존할 필요는 없습니다.
Spring은 bean의 scope를 지정할 수 있도록 @Scope 어노테이션을 포함하고 있습니다.
@Scope Annotation@Bean 어노테이션으로 정의된 bean에 대해 특정 scope를 지정할 수 있습니다.
Bean Scopes 섹션에 지정된 표준 scope를
모두 사용할 수 있습니다.
기본 scope는 singleton이지만, 다음 예제와 같이 @Scope 어노테이션으로 이를 override할 수 있습니다:
1@Configuration 2public class MyConfiguration { 3 4 @Bean 5 @Scope("prototype") 6 public Encryptor encryptor() { 7 // ... 8 } 9}
1@Configuration 2class MyConfiguration { 3 4 @Bean 5 @Scope("prototype") 6 fun encryptor(): Encryptor { 7 // ... 8 } 9}
@Scope and scoped-proxySpring은 scoped proxies를 통해
scoped 의존성을 다루는 편리한 방법을 제공합니다. XML 설정을 사용할 때
이러한 프록시를 생성하는 가장 쉬운 방법은 <aop:scoped-proxy/> element입니다.
Java에서 @Scope 어노테이션으로 bean을 설정할 때는 proxyMode attribute를 사용하여
동일한 지원을 제공합니다. 기본값은 ScopedProxyMode.DEFAULT이며, 일반적으로 component-scan
instruction 수준에서 다른 기본값이 설정되지 않는 한 scoped proxy를 생성하지 않음을 의미합니다.
ScopedProxyMode.TARGET_CLASS, ScopedProxyMode.INTERFACES 또는 ScopedProxyMode.NO를
지정할 수 있습니다.
XML reference documentation의 scoped proxy 예제를 Java를 사용하는 @Bean으로 옮기면
다음과 같습니다(자세한 내용은
scoped proxies 참조):
1// an HTTP Session-scoped bean exposed as a proxy 2@Bean 3@SessionScope 4public UserPreferences userPreferences() { 5 return new UserPreferences(); 6} 7 8@Bean 9public Service userService() { 10 UserService service = new SimpleUserService(); 11 // a reference to the proxied userPreferences bean 12 service.setUserPreferences(userPreferences()); 13 return service; 14}
1// an HTTP Session-scoped bean exposed as a proxy 2@Bean 3@SessionScope 4fun userPreferences() = UserPreferences() 5 6@Bean 7fun userService(): Service { 8 return SimpleUserService().apply { 9 // a reference to the proxied userPreferences bean 10 setUserPreferences(userPreferences()) 11 } 12}
기본적으로 설정 클래스는 @Bean 메서드의 name을 결과 bean의 name으로 사용합니다.
그러나 다음 예제와 같이 name attribute로 이 기능을 override할 수 있습니다:
1@Configuration 2public class AppConfig { 3 4 @Bean("myThing") 5 public Thing thing() { 6 return new Thing(); 7 } 8}
1@Configuration 2class AppConfig { 3 4 @Bean("myThing") 5 fun thing() = Thing() 6}
Naming Beans에서 논의한 것처럼,
하나의 bean에 여러 name을 부여(즉, bean aliasing)해야 할 때가 있습니다.
@Bean 어노테이션의 name attribute는 이러한 목적을 위해 String array를 허용합니다.
다음 예제는 bean에 여러 alias를 설정하는 방법을 보여 줍니다:
1@Configuration 2public class AppConfig { 3 4 @Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"}) 5 public DataSource dataSource() { 6 // instantiate, configure and return DataSource bean... 7 } 8}
1@Configuration 2class AppConfig { 3 4 @Bean("dataSource", "subsystemA-dataSource", "subsystemB-dataSource") 5 fun dataSource(): DataSource { 6 // instantiate, configure and return DataSource bean... 7 } 8}
때때로 bean에 대해 보다 자세한 텍스트 description을 제공하는 것이 도움이 됩니다. 이는 bean이 monitoring 목적으로 (예를 들어 JMX를 통해) 노출될 때 특히 유용할 수 있습니다.
@Bean에 description을 추가하려면 다음 예제와 같이
@Description
어노테이션을 사용하면 됩니다:
1@Configuration 2public class AppConfig { 3 4 @Bean 5 @Description("Provides a basic example of a bean") 6 public Thing thing() { 7 return new Thing(); 8 } 9}
1@Configuration 2class AppConfig { 3 4 @Bean 5 @Description("Provides a basic example of a bean") 6 fun thing() = Thing() 7}
Instantiating the Spring Container by Using AnnotationConfigApplicationContext
Using the @Configuration annotation