Java-based container configuration
- Basic concepts: @Configuration and
- @Bean
+ Basic concepts: @Bean and @Configuration
- 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 to be
- managed by the Spring IoC container.
+
+ Full @Configuration vs 'lite' @Beans mode?
+ When @Bean methods are declared within
+ classes that are not annotated with
+ @Configuration they are referred to as being
+ processed in a 'lite' mode. For example, bean methods declared in a
+ @Component or even in a plain old
+ class will be considered 'lite'.
+ Unlike full @Configuration, lite
+ @Bean methods cannot easily declare inter-bean
+ dependencies. Usually one @Bean method should not
+ invoke another @Bean method when operating in
+ 'lite' mode.
+ Only using @Bean methods within
+ @Configuration classes is a recommended approach
+ of ensuring that 'full' mode is always used. This will prevent the same
+ @Bean method from accidentally being invoked
+ multiple times and helps to reduce subtle bugs that can be hard to track down
+ when operating in 'lite' mode.
+
- 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:
+ The central artifacts in Spring's new Java-configuration support are
+ @Configuration-annotated classes and
+ @Bean-annotated methods.
+ The @Bean annotation is used to indicate that a
+ method instantiates, configures and initializes a new object to be managed by
+ the Spring IoC container. For those familiar with Spring's
+ <beans/> XML configuration the @Bean
+ annotation plays the same role as the <bean/>
+ element. You can use @Bean annotated methods with
+ any Spring @Component, however, they are most
+ often used with @Configuration beans.
+ Annotating a class with @Configuration
+ indicates that its primary purpose is as a source of bean definitions. Furthermore,
+ @Configuration classes allow inter-bean
+ dependencies to be defined by simply calling other @Bean
+ methods in the same class. The simplest possible
+ @Configuration class would read as follows:
@Configuration
public class AppConfig {
@Bean
@@ -33,16 +58,15 @@ public class AppConfig {
}
}
- For those more familiar with Spring <beans/>
- XML, the AppConfig class above would be equivalent to:
+ The AppConfig class above would be equivalent to the
+ following Spring <beans/> XML:
<beans>
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>
- As you can see, the @Bean annotation plays the same
- role as the <bean/> element. The
- @Bean annotation will be discussed in depth in the
- sections below. First, however, we'll cover the various ways of creating a
- spring container using Java-based configuration.
+ The @Bean and @Configuration
+ annotations will be discussed in depth in the sections below. First, however, we'll
+ cover the various ways of creating a spring container using Java-based
+ configuration.
@@ -218,6 +242,387 @@ public class AppConfig {
+
+ 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 and
+ name.
+
+ You can use the @Bean annotation in a
+ @Configuration-annotated or in a
+ @Component-annotated class.
+
+
+ Declaring a bean
+
+ 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. 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 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:
+
+transferService -> com.acme.TransferServiceImpl
+
+
+
+
+ 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.
+
+ 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:
+ 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;
+ }
+
+ // ...
+}
+
+
+ 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!
+
+
+
+
+ Specifying bean scope
+
+
+ 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.
+
+ The default scope is singleton, but you can
+ override this with the @Scope
+ annotation:
+ @Configuration
+public class MyConfiguration {
+ @Bean
+ @Scope("prototype")
+ public 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.
+
+ 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.setUserPreferences(userPreferences());
+ return service;
+}
+
+
+
+
+ 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.
+ @Configuration
+public class AppConfig {
+
+ @Bean(name = "myFoo")
+ public Foo foo() {
+ return new Foo();
+ }
+
+}
+
+
+
+ Bean aliasing
+
+ As discussed in , 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.
+ @Configuration
+public class AppConfig {
+
+ @Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })
+ public DataSource dataSource() {
+ // instantiate, configure and return DataSource bean...
+ }
+
+}
+
+
+
+
+ Using the @Configuration annotation
+ @Configuration is a class-level annotation
+ indicating that an object is a source of bean definitions.
+ @Configuration classes declare beans via
+ public @Bean annotated methods. Calls to
+ @Bean methods on
+ @Configuration classes can also be used to
+ define inter-bean dependencies. See for
+ a general introduction.
+
+
+ Injecting inter-bean dependencies
+
+ When @Beans 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.
+
+
+ This method of declaring inter-bean dependencies only works when
+ the @Bean method is declared within a
+ @Configuration class. You cannot declare
+ inter-bean dependencies using plain @Component
+ classes.
+
+
+
+
+ Lookup method injection
+
+ 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 createCommand() {
+ return asyncCommand();
+ }
+ }
+}
+
+
+
+ Further information about how Java-based configuration works
+ internally
+
+ The following example shows a @Bean annotated
+ method being called twice:
+
+
+@Configuration
+public class AppConfig {
+
+ @Bean
+ public ClientService clientService1() {
+ ClientServiceImpl clientService = new ClientServiceImpl();
+ clientService.setClientDao(clientDao());
+ return clientService;
+ }
+ @Bean
+ public ClientService clientService2() {
+ ClientServiceImpl clientService = new ClientServiceImpl();
+ clientService.setClientDao(clientDao());
+ return clientService;
+ }
+
+ @Bean
+ public ClientDao clientDao() {
+ return new ClientDaoImpl();
+ }
+}
+
+ clientDao() has been called once in
+ clientService1() and once in
+ clientService2(). Since this method creates a new
+ instance of ClientDaoImpl and returns it, you would
+ normally expect having 2 instances (one for each service). That definitely
+ would be problematic: in Spring, instantiated beans have a
+ singleton scope by default. This is where the magic
+ comes in: All @Configuration classes are subclassed at
+ startup-time with CGLIB. In the subclass, the child
+ method checks the container first for any cached (scoped) beans before it
+ calls the parent method and creates a new instance. Note that as of Spring
+ 3.2, it is no longer necessary to add CGLIB to your classpath because
+ CGLIB classes have been repackaged under org.springframework and included
+ directly within the spring-core JAR.
+
+ The behavior could be different according to the scope of your
+ bean. We are talking about singletons here.
+
+
+ There are a few restrictions due to the fact that CGLIB dynamically
+ adds features at startup-time:
+
+ Configuration classes should not be final
+
+
+ They should have a constructor with no arguments
+
+
+
+
+
+
+
+
+
Composing Java-based configurations
@@ -547,366 +952,4 @@ jdbc.password=
-
-
- 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 and
- name.
-
- You can use the @Bean annotation in a
- @Configuration-annotated or in a
- @Component-annotated class.
-
-
- Declaring a bean
-
- 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. 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 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:
-
-transferService -> com.acme.TransferServiceImpl
-
-
-
-
- Injecting dependencies
-
- When @Beans 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.
-
-
-
- Receiving lifecycle callbacks
-
- Beans declared in a
- @Configuration-annotated class support
- 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 on 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;
- }
-
- // ...
-}
-
-
- 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!
-
-
-
-
- Specifying bean scope
-
-
- 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.
-
- The default scope is singleton, but you can
- override this with the @Scope
- annotation:
- @Configuration
-public class MyConfiguration {
- @Bean
- @Scope("prototype")
- public 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.
-
- 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.setUserPreferences(userPreferences());
- return service;
-}
-
-
-
- Lookup method injection
-
- 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 createCommand() {
- return asyncCommand();
- }
- }
-}
-
-
-
-
- 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.
- @Configuration
-public class AppConfig {
-
- @Bean(name = "myFoo")
- public Foo foo() {
- return new Foo();
- }
-
-}
-
-
-
-
-
-
- Bean aliasing
-
- As discussed in , 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.
- @Configuration
-public class AppConfig {
-
- @Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })
- public DataSource dataSource() {
- // instantiate, configure and return DataSource bean...
- }
-
-}
-
-
-
-
- Further information about how Java-based configuration works
- internally
-
- The following example shows a @Bean annotated
- method being called twice:
-
-
-@Configuration
-public class AppConfig {
-
- @Bean
- public ClientService clientService1() {
- ClientServiceImpl clientService = new ClientServiceImpl();
- clientService.setClientDao(clientDao());
- return clientService;
- }
- @Bean
- public ClientService clientService2() {
- ClientServiceImpl clientService = new ClientServiceImpl();
- clientService.setClientDao(clientDao());
- return clientService;
- }
-
- @Bean
- public ClientDao clientDao() {
- return new ClientDaoImpl();
- }
-}
-
- clientDao() has been called once in
- clientService1() and once in
- clientService2(). Since this method creates a new
- instance of ClientDaoImpl and returns it, you would
- normally expect having 2 instances (one for each service). That definitely
- would be problematic: in Spring, instantiated beans have a
- singleton scope by default. This is where the magic
- comes in: All @Configuration classes are subclassed at
- startup-time with CGLIB. In the subclass, the child
- method checks the container first for any cached (scoped) beans before it
- calls the parent method and creates a new instance. Note that as of Spring
- 3.2, it is no longer necessary to add CGLIB to your classpath because
- CGLIB classes have been repackaged under org.springframework and included
- directly within the spring-core JAR.
-
- The behavior could be different according to the scope of your
- bean. We are talking about singletons here.
-
-
- There are a few restrictions due to the fact that CGLIB dynamically
- adds features at startup-time:
-
- Configuration classes should not be final
-
-
- They should have a constructor with no arguments
-
-
-
-