1.12. Java-based configuration container
1.12.1. The basic concept: @Bean and @Configuration
@Bean
Examples of the method for indicating annotation, to configure and initialize the new object to be managed by the Spring IoC container. For those familiar with Spring's <beans/>
man of the XML configuration, the role of @ Bean and comments
@Component
use @Bean annotated. However, they are most commonly associated with
@Configuration
use with bean.
@Configuration expressed annotate the class whose main purpose is defined as Bean source. Further, @ Configuration class allows to define dependencies between @Bean Bean by another method call in the same class.
Complete @Configuration and "Lite" @Bean mode?
If not used @Configuration annotated @Bean method declared in the class, they are referred to as processing the "thin" mode. In a @Component Bean or even a common method declared in class is considered to be "thin", the main purpose of which contains different classes, and methods @Bean there is an additional bonus. For example, the service management component can be disclosed to the container by an additional view @Bean method applied on each component class. In this case, @ Bean factory method is a common method of mechanism.
@Configuration different with a complete, streamlined @Bean method can not declare dependencies between Bean. Instead, they operate on its internal state comprising components, and may also operate in accordance with parameters which may be stated. Therefore, such a method should not be called @Bean @Bean other methods. Indeed, each of these methods is merely a method for specific plant bean references, without any special runtime semantics. Positive impact here is, having to apply at runtime CGLIB subclass, so there is no restriction in the class design (that is, contains the class may be final, and so on).
, @ Bean method will be declared in the case of common @Configuration class in order to ensure that you always use the "full" mode, so cross-reference method will be redirected to the life cycle management of the container. This can be prevented by regular Java method calls invoke the same @Bean unexpectedly, thus helping to reduce subtle errors in "Lite" mode untraceable runtime.
1.12.2. Examples of use of the Spring container AnnotationConfigApplicationContext
AnnotationConfigApplicationContext
Achieved not only acceptable @Configuration
type as input may receive a general @Component
class and using the JSR-330
metadata annotation category.
When providing @Configuration class as input, @ Configuration class itself will be registered as Bean definition, and the class is declared in all @Bean method will also be registered as Bean definition.
When provided @Component and JSR-330 type, which are registered as bean definitions, and it is assumed that metadata DI these classes when necessary, for example, @Autowired
or @Inject
.
// 基本用法
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
// 手动注册配置类
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
// 以编程方式启用扫描功能
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.acme");
ctx.refresh();
By AnnotationConfigWebApplicationContext support Web applications
<web-app>
<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<!-- Configuration locations must consist of one or more comma- or space-delimited
fully-qualified @Configuration classes. Fully-qualified packages may also be
specified for component-scanning -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.AppConfig</param-value>
</context-param>
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Declare a Spring MVC DispatcherServlet as usual -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
instead of the default XmlWebApplicationContext -->
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!-- Again, config locations must consist of one or more comma- or space-delimited
and fully-qualified @Configuration classes -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.web.MvcConfig</param-value>
</init-param>
</servlet>
<!-- map all requests for /app/* to the dispatcher servlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
1.12.3. Use @Bean comments
You can be @Configuration
annotated classes or @Component
use annotation class @Bean
notes.
Declaring a Bean
By default, the same name as the bean method names.
Can @Bean
return type declaration of your way to use the interface (or base class).
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
Non-inert according to a single embodiment thereof bean instantiation declaration order, so you may see different types of matching results, depending on when the other component according to the type attempted match undeclared (e.g. @Autowired TransferServiceImpl, only in the example only after resolving of transferService bean).
If you reference the type consistently through the service interface declaration, the @Bean return type can be safely added to the design decisions. However, achieve multiple interfaces or components to achieve its potential component type references, the most specific statement might return type (at least with reference to the specific type of the required injection point your bean like) more secure.
Bean dependence
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
Analytical constructor dependency injection mechanism based on almost the same
Receiving lifecycle callbacks
Any class support with the definition of notation @Bean conventional lifecycle callbacks, and you can use the JSR-250 @PostConstruct
and @PreDestroy
comments.
Spring also fully supports regular lifecycle callbacks. If the bean implements InitializingBean
, DisposableBean
or Lifecycle
, the container will call their respective methods.
Also fully supports the standard *Aware
set of interfaces (e.g. BeanFactoryAware
, BeanNameAware
, MessageSourceAware
, ApplicationContextAware
etc.).
@Bean annotation support specify any initialization and destruction callback methods, like the Spring XML init-method
and destroy-method
bean element attributes, as shown in the following example:
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();
}
}
By default, using the Java configuration having a common definition close
or shutdown
bean method is automatically registered by a callback destruction. If you have a public close or shutdown method, and do not want to call it when the container is closed, you can add @Bean(destroyMethod="")
to the bean definition to disable the default ( inferred
) mode.
By default, you might want to do this to get through JNDI resources, because their life cycle is managed in an external application. In particular, make sure to always operate DataSource, because on the Java EE application server is problematic.
The following example shows how to prevent the destruction of DataSource automatic callback:
@Bean(destroyMethod="")
public DataSource dataSource() throws NamingException {
return (DataSource) jndiTemplate.lookup("MyDS");
}
In addition, for @Bean method, commonly used programming JNDI lookup method is to use Spring JndiTemplate
or JndiLocatorDelegate
helper, or directly using JNDI InitialContext
, but do not use JndiObjectFactoryBean
variant (which will force you to return type is declared as FactoryBean
type, rather than the actual target type this makes it difficult to cross-reference calls) in other @Bean methods intended to refer to resources provided herein.
For example BeanOne foregoing comments, called directly during the construction init()
methods are equally effective, as shown in the following example:
@Bean
public BeanOne beanOne() {
BeanOne beanOne = new BeanOne();
beanOne.init();
return beanOne;
}
When you work directly with Java, you can perform any operations on objects without having to always rely on the container life cycle.
Bean scope specified
The default range is singleton
, but you can use @Scope
annotations to cover it, as in the following example:
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
Spring provides a convenient way by the scope scope proxy process dependent. The easiest way to create such a proxy configuration is the use of XML <aop:scoped-proxy/>
elements. Use @Scope
annotations in Java bean configuration can proxyMode
provide the same support properties. The default value is agentless ( ScopedProxyMode.NO
), but you can specify ScopedProxyMode.TARGET_CLASS
or ScopedProxyMode.INTERFACES
.
If a reference from an XML document scopes proxy example transplanted into our Java @Bean, then it is similar to the following:
// 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;
}
Custom Bean name
By default, configured to use the class @Bean
name as the name of the method result of the bean. However, you can use the name
attribute overrides this function, as shown in the following example:
@Bean(name = "myThing")
public Thing thing() {
return new Thing();
}
Bean alias
It is sometimes desirable to provide multiple names for a single Bean, Bean called aliases. For this purpose @Bean
a comment name
accepts a String array property. The following example shows how to set a plurality of aliases bean:
@Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})
public DataSource dataSource() {
// instantiate, configure and return DataSource bean...
}
Bean Description
In some cases, provide a more detailed text description would be helpful about the bean. When exposing bean (possibly through JMX) to be monitored, it is particularly useful.
To add a description to @Bean
be used @Description
annotations, as shown in the following example:
@Bean
@Description("Provides a basic example of a bean")
public Thing thing() {
return new Thing();
}
1.12.4. Use @Configuration comments
@Configuration
It is a class-level annotation indicating that the object is defined by the source Bean. @Configuration bean class method declarations by public @Bean comment. The method calls for @Bean @Configuration class may also be used to define dependencies between Bean.
Inject dependencies between bean
When the bean interdependence, represents a dependency relationship is like to make a call to another bean method relies as simple, as in the following example:
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
return new BeanOne(beanTwo());
}
@Bean
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
Only when the declaration method @Bean @Configuration class, this declaration bean inter dependency method works. You can not use the dependencies between ordinary @Component class declaration bean.
Find Method Injection
As mentioned earlier, look for the injection method is an advanced feature, you should rarely use. In the single embodiment has scoped bean dependent prototype scope bean, this is useful. Java for this type of arrangement provides a natural way to achieve this pattern. The following example shows how to use the Find method injection:
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();
}
By using Java configuration, you can create a cover abstract createCommand()
method of CommandManager
subclass, which will find a new (prototype) command object in some way. The following example shows how to do this:
@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 createCommand()
// overridden to return a new prototype Command object
return new CommandManager() {
protected Command createCommand() {
return asyncCommand();
}
}
}
For more information about Java-based configuration of how to work within the
Consider the following example, this example shows a method annotated with @Bean is 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();
}
}
Since a new instance of clientDao () method creates ClientDaoImpl and return it, it is often desirable to have two instances (each service a). It is definitely a problem: In Spring, instantiated bean has a singleton scope by default. This is a magical place: all classes at startup @Configuration use CGLIB subclass. In the sub-category, sub-method before calling the method and create a new instance of the parent, first check whether there are any cache (scope) of the bean container.
According to the scope of the bean, the behavior may be different. We are here talking about a single case.
Starting Spring 3.2, CGLIB no longer need to add to your class path, because CGLIB the class has been repackaged org.springframework.cglib
under and directly included in the spring-core
JAR.
Because CGLIB dynamically add functionality at startup, so there are some limitations. In particular, the class can not be disposed final
of. However, since version 4.3, allowing the use of any configuration based on constructors, including the use of single or @Autowired declared non-default constructor for the default injection.
If you want to avoid any restrictions imposed CGLIB, please consider @Bean declare your method on non-@Configuration class (for example, declared on the common @Component class). Then @Bean method does not cross between the intercept method calls, so you have to rely exclusively on where the constructor or method level of dependency injection.
1.12.5. The composition of Java-based configuration
Spring Java-based configuration function lets you write annotations, which can reduce the complexity of configuration.
Use @Import comments
As used in the Spring XML file <import/>
elements to help the same modular configuration, @Import
annotation allows @Bean definitions, as another example of the configuration loaded from the class shown:
@Configuration
public class ConfigA {
@Bean
public A a() {
return new A();
}
}
@Configuration
@Import(ConfigA.class)
public class ConfigB {
@Bean
public B b() {
return new B();
}
}
Starting Spring Framework 4.2, @ Import also supports the reference to the conventional component class, similar to AnnotationConfigApplicationContext.register
the method. If you want to explicitly define all components as an entry point by using some type configuration, so as to avoid scanning assembly, this feature is particularly useful.
Injection dependence on imported defined @Bean
@Configuration
public class ServiceConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
@Bean
public AccountRepository accountRepository(DataSource dataSource) {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
There is another way to achieve the same result. Remember, remember, @Configuration
the class ultimately just another bean container: this means that they can use @Autowired
to @Value
inject the same functions other bean.
In this manner, the dependency injection is the simplest one. During the context initialization process @Configuration early class, and in this way forced to inject dependencies may cause unexpected early initialization. As illustrated, the injection parameters based possible.
In addition, please pay special attention BeanPostProcessor
and BeanFactoryPostProcessor
@Bean defined. It should normally be those declared static @Bean
method, without triggering instance of the class which contains configuration. Otherwise, @ Autowired and @Value not like the configuration work because it is too early to be created as a bean instance.
@Configuration
public class ServiceConfig {
@Autowired
private AccountRepository accountRepository;
@Bean
public TransferService transferService() {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
private final DataSource dataSource;
public RepositoryConfig(DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
From the Spring Framework 4.3 supports only start @Configuration class constructor injection. Also note that if the target bean only defines a constructor without specifying @Autowired.
@Configuration class or conditionally @Bean method comprising
Based on some arbitrary system state, conditionally enable or disable complete even a single @Bean @Configuration class method is often useful. A common example is used only enabled when a specific profile in Spring Environment in @Profile
comments activate Bean.
@Profile comment is called by the use of a more flexible @Conditional
annotation actual implementation.
Condition
Implementation of the interface provides a matches(..)
method returns true or false.
Combination of Java and XML configuration
Spring's support @Configuration class is not intended to completely replace 100% Spring XML. Some tools (for example Spring XML namespaces) remains the ideal way to container configuration. In easy to use XML or necessary under the circumstances, you can select: Use ClassPathXmlApplicationContext
the "XML-centric" approach to instantiate the container, or AnnotationConfigApplicationContext
by way of "Java-centric" instantiation container. @ImportResource
Annotations can import XML as needed.
XML-centric use of @Configuration class
The @Configuration
class declaration is pure Spring <bean/>
elements
<beans>
<context:annotation-config/>
<bean class="com.acme.AppConfig"/>
</beans>
Use <context:component-scan />
pickup @Configuration
class
In this case, we do not need to explicitly declare <context:annotation-config/>
, because <context:component-scan/>
the same functionality is enabled.
<context:component-scan base-package="com.acme"/>
To @Configuration class-centric XML and @ImportResource
@ImportResource("classpath:/com/acme/properties-config.xml")
properties-config.xml
<beans>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
</beans>
By @PropertySource
introducing a properties file