Home [Spring] 1.12.3. Using the @Bean Annotation
Post
Cancel

[Spring] 1.12.3. Using the @Bean Annotation

1.12.3. Using the @Bean Annotation

@Bean is a method-level annotation and a direct analog of the XML <bean/> element. The annotation supports some of the attributes offered by <bean/>, such as: _ init-method _ destroy-method _ autowiring _ name.

  • @Bean은 method-level annotation이며 XML <bean/> 요소의 direct analog다.
  • Annotation은 _ init-method _ delete-method _ autowiring _ name 와 같은 <bean/>에서 제공하는 속성 중 일부를 지원한다.

You can use the @Bean annotation in a @Configuration-annotated or in a @Component-annotated class.

  • @Bean 주석은 @Configuration-annotated 또는 @Component-annotated 클래스에서 사용할 수 있다.

Declaring a Bean

To declare a bean, you can annotate a method with the @Bean annotation. You use this method to register a bean definition within an ApplicationContext of the type specified as the method’s return value. By default, the bean name is the same as the method name. The following example shows a @Bean method declaration:

  • Bean을 선언하려면 @Bean 어노테이션으로 메서드에 annotation을 달 수 있다.
  • 메서드의 반환 값으로 지정된 유형의 ApplicationContext 내에 bean definition를 등록하려면 이 방법을 사용하면 된다.
  • 기본적으로 bean 이름은 메서드 이름과 동일하다.
  • 다음 예제는 @Bean 메서드 선언을 보여준다.
1
2
3
4
5
6
@Configuration
class AppConfig {

    @Bean
    fun transferService() = TransferServiceImpl()
}
  • Spring XML 에서는 다음과 같다.
1
2
3
<beans>
    <bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>

Both declarations make a bean named transferService available in the ApplicationContext, bound to an object instance of type TransferServiceImpl, as the following text image shows:

  • 다음 텍스트 이미지가 보여주듯이, 두 선언 모두 TransferServiceImpl 유형의 개체 인스턴스에 바인딩된 transferService라는 이름의 bean을 ApplicationContext에서 사용할 수 있도록 한다.

transferService -> com.acme.TransferServiceImpl

You can also declare your @Bean method with an interface (or base class) return type, as the following example shows:

  • 다음 예에서 알 수 있듯이 인터페이스(또는 기본 클래스) return type을 사용하여 @Bean method을 선언할 수도 있다.
1
2
3
4
5
6
7
8
@Configuration
class AppConfig {

    @Bean
    fun transferService(): TransferService {
        return TransferServiceImpl()
    }
}

However, this limits the visibility for advance type prediction to the specified interface type (TransferService). Then, with the full type (TransferServiceImpl) known to the container only once, the affected singleton bean has been instantiated. Non-lazy singleton beans get instantiated according to their declaration order, so you may see different type matching results depending on when another component tries to match by a non-declared type (such as @Autowired TransferServiceImpl, which resolves only once the transferService bean has been instantiated).

  • 단, 이는 advance type prediction을 위한 가시성(visibility)을 지정된 인터페이스 유형(TransferService)으로 제한한다.
  • 그 후, full type (TransferServiceImpl)을 container에 단 한 번만 알린 상태에서, 영향을 받은 singleton bean이 인스턴스화되었다.
  • Non-lazy singleton beans은 선언 순서(declaration order)에 따라 인스턴스화되므로 다른 성분이 선언되지 않은 유형(non-declared type) (예: transferService bean이 인스턴스화되면 resolve되는 @Autowired TransferServiceImpl)에 따라 다른 유형의 일치 결과를 볼 수 있다.

If you consistently refer to your types by a declared service interface, your @Bean return types may safely join that design decision. However, for components that implement several interfaces or for components potentially referred to by their implementation type, it is safer to declare the most specific return type possible (at least as specific as required by the injection points that refer to your bean).

  • 만약 당신이 declared service interface로 당신의 types을 일관되게 참조한다면, 당신의 @Bean return types은 안전하게 설계 결정(design decision)에 참여할 수 있다.
  • 단, 여러 인터페이스를 구현하는 components 또는 구현 유형(implementation type)에 의해 잠재적으로 언급되는 components의 경우 가능한 가장 specific return type(최소한 bean을 참조하는 주입 지점(injection points)에서 요구하는 만큼 구체적)을 선언하는 것이 안전하다.

Bean Dependencies

A @Bean-annotated method can have an arbitrary number of parameters that describe the dependencies required to build that bean. For instance, if our TransferService requires an AccountRepository, we can materialize that dependency with a method parameter, as the following example shows:

  • @Bean-annotated 메서드는 그 bean을 만드는 데 필요한 의존성을 설명하는 임의의 수의 파라미터를 가질 수 있다.
  • 예를 들어, TransferServiceAccountRepository가 필요한 경우, 다음 예에서 알 수 있듯이, 우리는 method parameter를 사용하여 이러한 종속성(dependency)을 실현할 수 있다(materialize).
1
2
3
4
5
6
7
8
@Configuration
class AppConfig {

    @Bean
    fun transferService(accountRepository: AccountRepository): TransferService {
        return TransferServiceImpl(accountRepository)
    }
}

The resolution mechanism is pretty much identical to constructor-based dependency injection. See the relevant section for more details.

  • resolution mechanism은 생성자 기반(constructor-based) 종속성 주입(dependency injection)과 거의 동일하다.
  • 자세한 내용은 관련 섹션을 참조하십시오.

Receiving Lifecycle Callbacks

Any classes defined with the @Bean annotation support the regular lifecycle callbacks and can use the @PostConstruct and @PreDestroy annotations from JSR-250. See JSR-250 annotations for further details.

  • @Bean 주석으로 정의된 클래스는 정기적인 라이프사이클 콜백을 지원하며, JSR-250의 @PostConstruction@PreDestroy 주석을 사용할 수 있다.
  • 자세한 내용은 JSR-250 annotations을 참조하십시오.

The regular Spring lifecycle callbacks are fully supported as well. If a bean implements InitializingBean, DisposableBean, or Lifecycle, their respective methods are called by the container.

  • 정기적인 스프링 lifecycle 콜백도 완전히 지원된다.
  • bean이 InitializingBean, DisposableBean 또는 Lifecycle을 구현하는 경우, bean의 각각의 방법은 컨테이너에 의해 호출된다.

The standard set of *Aware interfaces (such as BeanFactoryAware, BeanNameAware, MessageSourceAware, ApplicationContextAware, and so on) are also fully supported.

The @Bean annotation supports specifying arbitrary initialization and destruction callback methods, much like Spring XML’s init-method and destroy-method attributes on the bean element, as the following example shows:

  • @Bean annotation은 다음 예에서 알 수 있듯이 Bean 요소에 대한 Spring XML의 init-methoddestroy-method 속성과 마찬가지로 임의 초기화 및 destroy 콜백 방법을 지정하는 것을 지원한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class BeanOne {

    fun init() {
        // initialization logic
    }
}

class BeanTwo {

    fun cleanup() {
        // destruction logic
    }
}

@Configuration
class AppConfig {

    @Bean(initMethod = "init")
    fun beanOne() = BeanOne()

    @Bean(destroyMethod = "cleanup")
    fun beanTwo() = BeanTwo()
}

By default, beans defined with Java configuration that have a public close or shutdown method are automatically enlisted with a destruction callback. If you have a public close or shutdown method and you do not wish for it to be called when the container shuts down, you can add @Bean(destroyMethod="") to your bean definition to disable the default (inferred) mode.

You may want to do that by default for a resource that you acquire with JNDI, as its lifecycle is managed outside the application. In particular, make sure to always do it for a DataSource, as it is known to be problematic on Java EE application servers.

The following example shows how to prevent an automatic destruction callback for a DataSource:

  • 기본적으로 public close 또는 shutdown 방법이 있는 Java configuration으로 정의된 bean은 destruction callback과 함께 자동으로 등록된다(enlisted).
  • public close 또는 shutdown method가 있으며 container가 종료될 때 호출되지 않도록 하려면 bean definition에 @Bean(destroyMethod=")을 추가하여 default (inferred) 모드를 비활성화하십시오.

  • JNDI를 사용하여 취득한 리소스의 라이프사이클은 애플리케이션 외부에서 관리되므로 기본적으로 이 작업을 수행하기를 원할 수 있다.
    • JNDI (Java Naming and Directory Interface): 디렉터리 서비스에서 제공하는 데이터 및 객체를 발견(discover)하고 참고(lookup)하기 위한 자바 API
  • 특히, DataSource 는 Java EE 애플리케이션 서버에서 문제가 있는 것으로 알려져 있으므로 항상 DataSource에 대해 이 작업을 수행하십시오.

  • 다음 예는 DataSource에 대한 자동 파괴 콜백(automatic destruction callback)을 방지하는 방법을 보여준다.
1
2
3
4
@Bean(destroyMethod = "")
fun dataSource(): DataSource {
    return jndiTemplate.lookup("MyDS") as DataSource
}

Also, with @Bean methods, you typically use programmatic JNDI lookups, either by using Spring’s JndiTemplate or JndiLocatorDelegate helpers or straight JNDI InitialContext usage but not the JndiObjectFactoryBean variant (which would force you to declare the return type as the FactoryBean type instead of the actual target type, making it harder to use for cross-reference calls in other @Bean methods that intend to refer to the provided resource here).

  • 또한 @Bean 방법을 사용할 경우 (여기서 제공된 리소스를 참조하려는 다른 @Bean methods에서의 cross-reference calls을 사용하기가 더 어려워지는 실제 target type 대신에 FactoryBean type을 return type으로 선언하도록 만드는)JndiObjectFactoryBean variant을 사용하는게 아닌, 일반적으로 스프링의 JndiTemplate 또는 JndiLocatorDelegate helpers를 사용하거나 JNDI InitialContext를 곧바로 사용함으로써 프로그래밍 방식의 JNDI lookups을 사용하십시오.

In the case of BeanOne from the example above the preceding note, it would be equally valid to call the init() method directly during construction, as the following example shows:

  • 앞의 노트의 예에서 BeanOne의 경우, 다음 예에서 알 수 있듯이, construction 중에 직접 init() method를 호출하는 것이 동등하게 유효(equally valid)할 것이다.
1
2
3
4
5
6
7
8
9
10
@Configuration
class AppConfig {

    @Bean
    fun beanOne() = BeanOne().apply {
        init()
    }

    // ...
}

When you work directly in Java, you can do anything you like with your objects and do not always need to rely on the container lifecycle.

  • Java에서 직접 작업할 때, 당신은 당신의 객체로 당신이 원하는 모든 것을 할 수 있고 컨테이너 수명 주기에 항상 의존할 필요는 없다.

Specifying Bean Scope

Spring includes the @Scope annotation so that you can specify the scope of a bean.

  • Spring에는 @Scope annotation이 포함되어 있어 bean의 범위를 지정할 수 있다.

Using the @Scope Annotation

You can specify that your beans defined with the @Bean annotation should have a specific scope. You can use any of the standard scopes specified in the Bean Scopes section.

  • @Bean annotation으로 정의된 bean에 specific scope를 지정하도록 지정할 수 있다.
  • Bean Scopes 섹션에 지정된 standard scopes를 사용할 수 있다.

The default scope is singleton, but you can override this with the @Scope annotation, as the following example shows:

  • 기본 범위는 singleton이지만, 다음 예에서 볼 수 있듯이 @Scope annotation으로 재정의(override)할 수 있다.
1
2
3
4
5
6
7
8
9
@Configuration
class MyConfiguration {

    @Bean
    @Scope("prototype")
    fun encryptor(): Encryptor {
        // ...
    }
}

@Scope and scoped-proxy

Spring offers a convenient way of working with scoped dependencies through scoped proxies. The easiest way to create such a proxy when using the XML configuration is the <aop:scoped-proxy/> element. Configuring your beans in Java with a @Scope annotation offers equivalent support with the proxyMode attribute. The default is no proxy (ScopedProxyMode.NO), but you can specify ScopedProxyMode.TARGET_CLASS or ScopedProxyMode.INTERFACES.

  • 스프링은 scoped proxies를 통해 범위 의존성(scoped dependencies)을 가지고 작업할 수 있는 편리한 방법을 제공한다.
  • XML 구성을 사용할 때 이러한 프록시를 만드는 가장 쉬운 방법은 <aop:scoped-proxy/> 요소다.
  • @Scope annotation을 사용하여 Java에서 beans을 구성하면 proxyMode 속성으로 동등한 지원을 받을 수 있다.
  • 기본값은 프록시 없음(ScopedProxyMode.NO), 그러나 ScopedProxyMode.TARGET_CLASS 또는 ScopedProxyMode.INTERFACES를 지정할 수 있다.

If you port the scoped proxy example from the XML reference documentation (see scoped proxies) to our @Bean using Java, it resembles the following:

  • XML 참조 문서(scoped proxies 참조)의 범위 프록시 예를 Java를 사용하여 @Bean으로 포팅하는 경우 다음과 유사하다.
1
2
3
4
5
6
7
8
9
10
11
12
// an HTTP Session-scoped bean exposed as a proxy
@Bean
@SessionScope
fun userPreferences() = UserPreferences()

@Bean
fun userService(): Service {
    return SimpleUserService().apply {
        // a reference to the proxied userPreferences bean
        setUserPreferences(userPreferences()
    }
}

Customizing Bean Naming

By default, configuration classes use a @Bean method’s name as the name of the resulting bean. This functionality can be overridden, however, with the name attribute, as the following example shows:

  • 기본적으로 구성 클래스(configuration classes)는 resulting bean의 이름으로 @Bean 메서드의 이름을 사용한다.
  • 그러나 다음 예에서 알 수 있듯이 name 속성으로 이 기능을 재정의할 수 있다.
1
2
3
4
5
6
@Configuration
class AppConfig {

    @Bean("myThing")
    fun thing() = Thing()
}

Bean Aliasing

As discussed in Naming Beans, it is sometimes desirable to give a single bean multiple names, otherwise known as bean aliasing. The name attribute of the @Bean annotation accepts a String array for this purpose. The following example shows how to set a number of aliases for a bean:

  • Naming Beans에서 논의한 바와 같이, bean aliasing으로 알려진, single bean에 여러 개의 이름을 붙이는 것이 바람직할 때도 있다.
  • @Bean annotation의 name 속성은 이러한 목적으로 String 배열을 허용한다.
  • 다음 예제는 bean에 대해 여러 개의 별칭을 설정하는 방법을 보여준다.
1
2
3
4
5
6
7
8
@Configuration
class AppConfig {

    @Bean("dataSource", "subsystemA-dataSource", "subsystemB-dataSource")
    fun dataSource(): DataSource {
        // instantiate, configure and return DataSource bean...
    }
}

Bean Description

Sometimes, it is helpful to provide a more detailed textual description of a bean. This can be particularly useful when beans are exposed (perhaps through JMX) for monitoring purposes.

  • 때로는 bean에 대한 보다 상세한 텍스트 설명을 제공하는 것이 도움이 된다.
  • 특히 beans이 모니터링 목적으로 (아마도 JMX를 통해) 노출되었을 때 유용할 수 있다.

To add a description to a @Bean, you can use the @Description annotation, as the following example shows:

  • @Bean에 설명을 추가하려면 다음 예제에서와 같이 @Description 주석을 사용하십시오.
1
2
3
4
5
6
7
@Configuration
class AppConfig {

    @Bean
    @Description("Provides a basic example of a bean")
    fun thing() = Thing()
}

References

This post is licensed under CC BY 4.0 by the author.

[Spring] 1.12.2. Instantiating the Spring Container by Using AnnotationConfigApplicationContext

[Spring] 1.12.4. Using the @Configuration annotation