@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:
You can use the @Bean
annotation in a @Configuration
-annotated or in a
@Component
-annotated class.
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:
- Java
-
@Configuration public class AppConfig { @Bean public TransferServiceImpl transferService() { return new TransferServiceImpl(); } }
- Kotlin
-
@Configuration class AppConfig { @Bean fun transferService() = TransferServiceImpl() }
The preceding configuration is exactly equivalent to the following Spring XML:
<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:
transferService -> com.acme.TransferServiceImpl
You can also use default methods to define beans. This allows composition of bean configurations by implementing interfaces with bean definitions on default methods.
- Java
-
public interface BaseConfig { @Bean default TransferServiceImpl transferService() { return new TransferServiceImpl(); } } @Configuration public class AppConfig implements BaseConfig { }
You can also declare your @Bean
method with an interface (or base class)
return type, as the following example shows:
- Java
-
@Configuration public class AppConfig { @Bean public TransferService transferService() { return new TransferServiceImpl(); } }
- Kotlin
-
@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).
Tip
|
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).
|
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:
- Java
-
@Configuration public class AppConfig { @Bean public TransferService transferService(AccountRepository accountRepository) { return new TransferServiceImpl(accountRepository); } }
- Kotlin
-
@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.
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.
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.
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:
- Java
-
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(); } }
- Kotlin
-
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() }
Note
|
By default, beans defined with Java configuration that have a public 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 The following example shows how to prevent an automatic destruction callback for a
Also, with |
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:
- Java
-
@Configuration public class AppConfig { @Bean public BeanOne beanOne() { BeanOne beanOne = new BeanOne(); beanOne.init(); return beanOne; } // ... }
- Kotlin
-
@Configuration class AppConfig { @Bean fun beanOne() = BeanOne().apply { init() } // ... }
Tip
|
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. |
Spring includes the @Scope
annotation so that you can specify the scope of a bean.
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.
The default scope is singleton
, but you can override this with the @Scope
annotation,
as the following example shows:
- Java
-
@Configuration public class MyConfiguration { @Bean @Scope("prototype") public Encryptor encryptor() { // ... } }
- Kotlin
-
@Configuration class MyConfiguration { @Bean @Scope("prototype") fun encryptor(): Encryptor { // ... } }
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 ScopedProxyMode.DEFAULT
, which
typically indicates that no scoped proxy should be created unless a different default
has been configured at the component-scan instruction level. You can specify
ScopedProxyMode.TARGET_CLASS
, ScopedProxyMode.INTERFACES
or ScopedProxyMode.NO
.
If you port the scoped proxy example from the XML reference documentation (see
scoped proxies) to our @Bean
using Java,
it resembles the following:
- Java
-
// 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; }
- Kotlin
-
// 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()) } }
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:
- Java
-
@Configuration public class AppConfig { @Bean("myThing") public Thing thing() { return new Thing(); } }
- Kotlin
-
@Configuration class AppConfig { @Bean("myThing") fun thing() = Thing() }
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:
- Java
-
@Configuration public class AppConfig { @Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"}) public DataSource dataSource() { // instantiate, configure and return DataSource bean... } }
- Kotlin
-
@Configuration class AppConfig { @Bean("dataSource", "subsystemA-dataSource", "subsystemB-dataSource") fun dataSource(): DataSource { // instantiate, configure and return DataSource bean... } }
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.
To add a description to a @Bean
, you can use the
{api-spring-framework}/context/annotation/Description.html[@Description
]
annotation, as the following example shows:
- Java
-
@Configuration public class AppConfig { @Bean @Description("Provides a basic example of a bean") public Thing thing() { return new Thing(); } }
- Kotlin
-
@Configuration class AppConfig { @Bean @Description("Provides a basic example of a bean") fun thing() = Thing() }