The central artifact in Spring's new Java-configuration support is
the @Configuration
-annotated class. These
classes consist principally of
@Bean
-annotated methods that define
instantiation, configuration, and initialization logic for objects that
are managed by the Spring IoC container.
Annotating a class with the
@Configuration
indicates that the class
can be used by the Spring IoC container as a source of bean definitions.
The simplest possible @Configuration
class would read as follows:
@Configuration public class AppConfig { }
An application may use one
@Configuration
-annotated class, or many.
@Configuration
is meta-annotated as a
@Component
. Therefore,
@Configuration
-annotated classes are
candidates for component-scanning and can also take advantage of
@Autowired
annotations at the field and
method levels, but not at the constructor level.
@Configuration
-annotated classes must
also have a default constructor. You can wire externalized values into
@Configuration
-annotated classes with the
@Value
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
and name
.
You can use the @Bean
annotation in
a @Configuration
-annotated or in a
@Component
-annotated class.
To declare a bean, simply 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 will be the same as the method
name. (See bean naming for details
on how to customize this behavior.) The following is a simple example
of a @Bean
method declaration:
@Configuration public class AppConfig { @Bean public TransferService transferService() { return new TransferServiceImpl(); } }
The preceding configuration is exactly equivalent to the following Spring XML:
<beans> <bean name="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
:
transferService -> com.acme.TransferServiceImpl
When @Bean
s have dependencies on
one another, expressing that dependency is as simple as having one
bean method call another:
@Configuration public class AppConfig { @Bean public Foo foo() { return new Foo(bar()); } @Bean public Bar bar() { return new Bar(); } }
In the example above, the foo
bean receives a
reference to bar
via constructor injection.
Beans created in a
@Configuration
-annotated class supports
the regular lifecycle callbacks. Any classes defined with the @Bean
annotation 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 to the bean
element:
public class Foo { public void init() { // initialization logic } } public class Bar { public void cleanup() { // destruction logic } } @Configuration public class AppConfig { @Bean(initMethod = "init") public Foo foo() { return new Foo(); } @Bean(destroyMethod = "cleanup") public Bar bar() { return new Bar(); } }
Of course, in the case of Foo
above, it would be
equally as valid to call the init()
method directly
during construction:
@Configuration public class AppConfig { @Bean public Foo foo() { Foo foo = new Foo(); foo.init(); return foo; } // ... }
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! |
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:
@Configuration public class MyConfiguration { @Bean @Scope("prototype") public 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 no proxy (ScopedProxyMode.NO
), but you can
specify ScopedProxyMode.TARGET_CLASS
or
ScopedProxyMode.INTERFACES
.
If you port the scoped proxy example from the XML reference
documentation (see preceding link) to our
@Bean
using Java, it would look like
the following:
// an HTTP Session-scoped bean exposed as a proxy @Bean @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) public UserPreferences userPreferences() { return new UserPreferences(); } @Bean public Service userService() { UserService service = new SimpleUserService(); // a reference to the proxied userPreferences bean service.seUserPreferences(userPreferences()); return service; }
As noted earlier, lookup method injection is an advanced feature that you should use rarely. It is useful in cases where a singleton-scoped bean has a dependency on a prototype-scoped bean. Using Java for this type of configuration provides a natural means for implementing this pattern.
public abstract class CommandManager { public Object process(Object commandState) { // grab a new instance of the appropriate Command interface Command command = createCommand(); // set the state on the (hopefully brand new) Command instance command.setState(commandState); return command.execute(); } // okay... but where is the implementation of this method? protected abstract Command createCommand(); }
Using Java-configuration support , you can create a subclass
of CommandManager
where the abstract
createCommand()
method is overridden in such a way that
it looks up a new (prototype) command object:
@Bean @Scope("prototype") public AsyncCommand asyncCommand() { AsyncCommand command = new AsyncCommand(); // inject dependencies here as required return command; } @Bean public CommandManager commandManager() { // return new anonymous implementation of CommandManager with command() overridden // to return a new prototype Command object return new CommandManager() { protected Command command() { return asyncCommand(); } } }
By default, Configuration-classes use a
@Bean
methods name as the name of the
resulting bean. This functionality can be overridden, however, with
the name
attribute.
@Configuration public class AppConfig { @Bean(name = "myFoo") public Foo foo() { return new Foo(); } }