[To] http://www.oschina.net/bbs/thread/8692
Introduction:The Spring dependency configuration method is loosely coupled with the Spring framework kernel. However, until Spring 3.0, using XML for dependency configuration is almost the only choice. The emergence of Spring 3.0 has changed this situation. It provides a series of annotations for dependency injection, which makes Spring IoC an alternative to XML files. This article describes in detail how to use these annotations to manage dependency configurations.
Use @ Repository, @ Service, @ Controller, and @ Component to identify the class as Bean
Since version 2.0, some annotations have been introduced to simplify Spring development. @ Repository annotation is the first batch introduced. It is used to identify the classes of the data access layer (DAO layer) as Spring Bean. You only need to mark the Annotation on the DAO class. In addition, to enable Spring to scan the classes in the class path and identify the @ Repository annotation, you must enable the Bean automatic scanning function in the XML configuration file. You can use the <context: component-scan/>. As follows:
// Use @ Repository to declare the DAO class as Bean Package bookstore. dao; @ Repository Public class UserDaoImpl implements UserDao {...... }
// Second, enable Spring's automatic scanning function in the XML configuration file <Beans... > ...... <Context: component-scan base-package = "bookstore. dao"/> ...... </Beans> |
In this case, you do not need to explicitly use <bean/> for Bean configuration in XML. Spring will automatically scan all class files in the package specified by the base-package and its sub-packages during container initialization. All classes marked with @ Repository will be registered as Spring Bean.
Why can only @ Repository be labeled on the DAO class? This is because the annotation not only recognizes classes as beans, but also encapsulates the data access exceptions thrown in the labeled classes as Spring Data Access exceptions. Spring itself provides a rich data access exception structure unrelated to specific data access technologies. It is used to encapsulate exceptions thrown by different persistence layer frameworks, this makes exceptions independent from the underlying framework.
Spring 2.5 adds three additional annotations with similar functions on the basis of @ Repository: @ Component, @ Service, and @ Constroller, which are used for different layers of the software system:
- @ Component is a general concept. It only represents a Component (Bean) and can act at any level.
- @ Service is usually used at the business layer, but currently this function is the same as @ Component.
- @ Constroller is usually used in the control layer, but currently this function is the same as @ Component.
By using the @ Repository, @ Component, @ Service, and @ Constroller annotations on the class, Spring will automatically create the corresponding BeanDefinition object and register it in ApplicationContext. These classes become Spring managed components. In addition to the classes at different software levels, these three annotations are used in exactly the same way as @ Repository.
In addition to the preceding four annotations, you can create custom annotations and add @ Component to the annotations, this custom annotation has the same functions as @ Component. However, this function is not commonly used.
When a Bean is automatically detected, its bean name is generated based on the BeanNameGenerator policy of the scanner. By default, for @ Component, @ Repository, @ Service, and @ Controller that contain the name attribute, the name value is used as the Bean name. If this annotation does not contain the name value or other components found by the custom filter, the default Bean name will be a non-qualified class name starting with lowercase. If you do not want to use the default bean naming policy, you can provide a custom naming policy. First, implement the BeanNameGenerator interface and confirm that a default non-parameter constructor is included. Then, a fully qualified class name is provided when the scanner is configured, as shown below:
<beans ...> <context:component-scan base-package="a.b" name-generator="a.SimpleNameGenerator"/> </beans> |
Similar to Spring beans configured through XML, the default scope of beans identified by the preceding annotation is "singleton". To work with these four annotations, when Bean annotation can be used to specify the Bean Scope, Spring 2.5 introduces the @ Scope annotation. You only need to provide the scope name when using this annotation, as shown below:
@Scope("prototype") @Repository public class Demo { … } |
If you want to provide a custom scope resolution policy without using annotation-based methods, you only need to implement the ScopeMetadataResolver interface and confirm that it contains a default constructor without parameters. Then, a fully qualified class name is provided when the scanner is configured:
<context:component-scan base-package="a.b"
scope-resolver="footmark.SimpleScopeResolver" />
Use @ PostConstruct and @ PreDestroy to specify the lifecycle callback Method
Spring Bean is managed by the Spring IoC container and initialized and destroyed by the container (the prototype type is not managed by the container after the container initialization ), generally, we do not need to pay attention to the initialization and destruction operations of Bean by containers. The Bean created by Spring through the constructor or factory method has been initialized and immediately available. However, in some cases, we may need to perform some additional initialization or destruction operations manually, which is usually for obtaining and releasing some resources. Spring 1.x provides two methods to implement lifecycle callback.
The first method is to implement two interfaces provided by Spring: InitializingBean and DisposableBean. If you want to perform some custom operations after Bean Initialization is complete, you can enable the Bean to implement the InitializingBean interface, which contains an afterPropertiesSet () method. After the container sets attributes for the Bean, this method is automatically called. If the Bean implements the DisposableBean interface, the container will call the destroy () method of this interface before destroying the Bean. The disadvantage of this method is that the Bean class can implement the interfaces provided by Spring, which increases the coupling between code and Spring framework. Therefore, this method is not recommended.
The second method is to use the init-method and destroy-method attributes of <bean> in the XML file to specify the callback method after initialization and before destruction. The Code does not need to implement any interfaces. The values of these two attributes are the initialization and destruction methods in the corresponding Bean class. The method name is arbitrary, but the method cannot have parameters. Example:
<bean id=”userService” class=”bookstore.service.UserService” init-method=”init” destroy-method=”destroy”> … </bean> |
Spring 2.5 provides support for JSR-250 on the basis of retaining the above two methods. The JSR-250 Specification defines two annotations used to specify the declarative periodic method: @ PostConstruct and @ PreDestroy. The two annotations are very simple to use. You only need to mark them on the callback method executed after initialization or the callback method executed before destruction. Because annotations are used, you need to configure the corresponding Bean post-processor, that is, add the following line in XML:
<context:annotation-config /> |
Compared with the above three methods for specifying the lifecycle callback, the first method is not recommended. It is not only not as flexible as the last two methods, but also increases the coupling between code and framework. Developers can choose one of the following two methods based on their usage habits, but it is best not to use them together to avoid increasing the maintenance difficulty.
Use @ Required to check Bean Dependencies
The purpose of the review is to determine whether the corresponding Setter methods of the given Bean are called during instantiation. Instead of determining whether a field already has a value. When Spring checks dependencies, it only determines whether the property uses Setter injection. If a property does not use Setter injection, even if the constructor has already injected a value for the property, Spring still considers that it has not executed the injection and throws an exception. In addition, Spring only executes the injection through Setter, but has no requirements on the injection value. Even if the injected <null/>, Spring considers the injection as a dependency injection.
<Bean> the label provides the dependency-check attribute for dependency check. This attribute has the following values:
- None -- the dependency check is not performed by default. You can use the default-dependency-check attribute on the <beans> label to change the default value.
- Simple -- checks the original basic type and set type.
- Objects -- checks complex types (except for types checked by simple ).
- All -- check all types.
The earlier version uses dependency-check to set in the configuration file. The disadvantage is that the granularity is coarse. The @ Required annotation provided by Spring2.0 provides more fine-grained control. @ Required annotation can only be annotated on the Setter method. Because the essence of dependency injection is to check whether the Setter method is called, rather than checking whether the attribute is assigned a value or what value is assigned. If the annotation is marked in a non-setXxxx () method, it is ignored.
To enable Spring to process the annotation, it is necessary to activate the corresponding Bean post-processor. To activate the post-processor, you only need to add the following line in XML.
<context:annotation-config/> |
When a Setter method labeled @ Required is not called, Spring will throw an exception during parsing to remind developers to set the corresponding attributes.
Use @ Resource, @ Autowired, and @ Qualifier to specify automatic Bean Assembly policies
Automatic Assembly means that Spring injects the Bean of the type to be referenced by a Bean according to the specified Automatic Assembly rules during Bean assembly. The <bean> element provides an autowire attribute that specifies the automatic assembly type, which has the following options:
- No -- explicitly specify that automatic assembly is not used.
- ByName -- if a Bean with the same name as the current attribute exists, use this Bean for injection. If the name matches but the type does not match, an exception is thrown. If there is no matching type, nothing will be done.
- ByType -- if there is a Bean of the same type (same type or sub-type) as the current property type, use this Bean for injection. ByType can identify factory methods, that is, the return type of factory-method can be identified. If multiple beans of the same type exist, an exception is thrown. If there is no matching type, nothing will be done.
- Constructor -- similar to byType, but it is for constructor injection. If no Bean matches the constructor's parameter type, an exception is thrown. When this Assembly mode is used, constructors with the most parameters are preferentially matched.
- Autodetect-determines whether to use byType or constructor for automatic assembly based on Bean introspection mechanism. If Bean provides the default constructor, byType is used; otherwise, constructor is used for automatic assembly.
When byType or constructor type is used for automatic assembly, automatic assembly also supports referencing arrays of types or using a generic set, spring checks all types of beans in the container to form a collection or array and then executes the injection. For a Map type that uses the generic type, if the key is of the String type, Spring will automatically execute the Assembly and use the Bean of all types as the value and the Bean name as the key.
We can add the default-autowire attribute to <beans> and set the default automatic encapsulation policy. The default value is "no ". If the property or constructor-arg tag is specified when automatic assembly is used, the value explicitly specified will overwrite the value of automatic assembly. Currently, automatic encapsulation does not support simple types, such as basic types, String, Class, and their array types.
When matching by type (may be byType, constructor, or autodetect), multiple beans may exist in the same type. If the injected attribute is an array, set, or Map, this may be okay, but if it is just a simple reference type, an exception will be thrown. There are several solutions:
- Remove the automatic assembly feature of the Bean and use explicit injection. We may not want a Bean to be treated as a candidate object when other beans perform automatic encapsulation. We can add autowire-candidate = "false" to the <Bean> ". (The autowire-candidate attribute and autowire attribute are independent of each other. A Bean can set autowire-candidate to false and use the autowire feature .) In addition, you can set the default-autowire-candidates attribute of <beans> to specify the matching mode that can be used to automatically assemble candidate beans, for example, default-autowire-candidates = "* serv, * dao" indicates that all beans whose names end with serv or dao are listed as candidates, while others are ignored, it is equivalent to other beans that are specified as autowire-candidate = "false". In this case, you can explicitly specify autowire-candidate = "true" for <Bean> ". The setting specified on <bean> overwrites the setting specified on <beans>.
- If multiple beans of the same type have the preferred Bean, you can set the primary attribute of the <Bean> to "true ", in this way, the Bean is first used for Assembly during automatic assembly. In this case, autowire-candidate cannot be set to false.
- If you are using a Java 5 or later version, you can use annotations for more fine-grained control.
Run automatic assembly with @ Autowired and @ Qualifier annotations
Use the @ Autowired annotation for assembly. Only matching is performed based on the type. @ Autowired annotation can be used for Setter methods, constructors, fields, and even common methods, provided that the method must have at least one parameter. @ Autowired can be used for arrays and generic set types. Then Spring injects all beans of the same type in the container. @ Autowired: When the annotation is applied to the Map type, if the Map key is of the String type, Spring will add beans of all types in the container that match the Map value, use the Bean id or name as the Map key.
@ Autowired: When the annotation acts on a common method, this method is called when the container initializes the Bean instance. Of course, the premise is that automatic assembly is executed. This method will not be executed if the assembly conditions are not met.
When @ Autowired is marked, an exception is thrown if automatic injection fails. We can add a required = false attribute to @ Autowired annotation to change this behavior. In addition, each class can only have one @ Autowired. required () attribute of the constructor to be true. Otherwise, a problem occurs. If @ Autowired is used to mark multiple constructors at the same time, Spring uses the greedy algorithm to match the constructor (the longest constructor ).
@ Autowired has another function: If you label it on the BeanFactory type, ApplicationContext type, ResourceLoader type, ApplicationEventPublisher type, and MessageSource type, Spring will automatically inject instances of these Implementation classes, no additional operations are required.
When the types of multiple beans in the container are the same as those to be injected, the injection cannot be executed. we can add a candidate value to @ Autowired, the method is to add a @ Qualifier annotation after @ Autowired to provide a String type value as the name of the candidate Bean. Example:
@Autowired(required=false) @Qualifier("ppp") public void setPerson(person p){} |
@ Qualifier can even act on the parameters of a method (if the method has only one parameter, we can place the @ Qualifer Annotation on the method declaration, but we recommend placing it before the parameter). The example is as follows:
@Autowired(required=false) public void sayHello(@Qualifier("ppp")Person p,String name){} |
You can specify the qualifier name of a Bean in the configuration file as follows:
<bean id="person" class="footmark.spring.Person"> <qualifier value="ppp"/> </bean> |
If the qualifier name of the Bean is not explicitly specified, the default name is the Bean name. Generally, qualifier should have business meanings, such as "domain" and "persistent", rather than "person.
We can also mark @ Qualifier on the set type, so all beans with the same qualifier name and specified value will be injected.
You must specify the attribute values of each custom annotation in the configuration file. You can use the <meta> label instead of the <qualifier/> label. If both the <meta> label and the <qualifier/> label appear, the <qualifier> label is preferred. If there is no <qualifier> label, the <qualifier> label is encapsulated using the key-Value Pair provided by <meta>. Example:
<bean class="footmark.HelloWorld"> <qualifier type="MovieQualifier"> <attribute key="format" value="VHS"/> <attribute key="genre" value="Comedy"/> </qualifier> </bean> <bean class="footmark.HelloWorld"> <meta key="format" value="DVD"/> <meta key="genre" value="Action"/> </bean> |
@ Autowired: the post-processing registration corresponding to the annotation is similar to the previous one. You only need to add the following line to the configuration file:
<context:annotation-config/> |
If @ Autowired injects system types such as BeanFactory, ApplicationContext, and ResourceLoader, @ Qualifier is not required. Even if @ Qualifier annotation is provided, it will be ignored; for automatic assembly of custom types, if the @ Qualifier annotation is used and the Bean with no matching name is used, the automatic assembly fails.
Use the @ Resource and @ Qualifier annotations in the JSR-250
If you want to perform automatic assembly based on name, you should use the @ Resource annotation provided by the JSR-250 instead of using a combination of @ Autowired and @ Qualifier.
@ Resource uses byName to perform automatic encapsulation. @ Resource annotation can be applied to Setter methods and fields with a parameter, as well as common methods with a parameter. @ Resource annotation has a name attribute used to specify the Bean name in the configuration file. If the name attribute is not specified, the default value is the name of the field or attribute. Although the cooperation between @ Resource and @ Qualifier is still true, @ Qualifier is almost equivalent to the name attribute for @ Resource.
If @ Resource does not specify the name attribute, after the byName match fails, it will return and use byType to continue the match. If the match fails again, an exception is thrown. If the name attribute is not explicitly specified for the @ Resource annotation, if it is marked on the BeanFactory type, ApplicationContext type, ResourceLoader type, ApplicationEventPublisher type, and MessageSource type, spring will automatically inject instances of these Implementation classes without additional operations. In this case, you do not need to specify the name attribute (or specify it as ""); otherwise, the injection fails. If @ Qualifier is used, the annotation will be ignored. For user-defined injection, @ Qualifier and name are equivalent and are not ignored.
The primary and autowire-candidate attributes of <bean> are still valid for @ Resource and @ Autowired.
Use @ Configuration and @ Bean for Bean Declaration
Although Spring has provided more than a dozen annotations since the release of Version 2.0, the annotations are provided only to simplify the XML configuration in some cases, rather than replacing the XML configuration method. From the initialization class of Spring IoC container, we can see that the most common implementation classes of ApplicationContext interfaces are ClassPathXmlApplicationContext and FileSystemXmlApplicationContext, as well as XmlPortletApplicationContext for Portlet and XmlWebApplicationContext for web, they are all XML-oriented. Spring 3.0 adds two implementation classes: AnnotationConfigApplicationContext and AnnotationConfigWebApplicationContext. From the name, we can see that they are generated for annotations and directly rely on annotations as container configuration information to initialize the IoC container class. Because AnnotationConfigWebApplicationContext is a web version of AnnotationConfigApplicationContext, its usage is almost the same as that of the latter. Therefore, this article will take AnnotationConfigApplicationContext as an example to explain.
AnnotationConfigApplicationContext works with @ Configuration and @ Bean annotations. Since then, the XML Configuration method is no longer the only Configuration method for Spring IoC containers. There is a competitive relationship between the two within a certain range, but they are still in a cooperative relationship in most cases. The combination of the two makes the configuration of Spring IoC containers simpler and more powerful.
Previously, we concentrated the configuration information in XML. Now, with annotations, the vector of the configuration information is transferred from the XML file to the Java class. We usually end the class name used to store configuration information with "Config", such as AppDaoConfig. java and AppServiceConfig. java. We need to add the @ Configuration annotation to the class used to specify the Configuration information to explicitly indicate that this class is the source of Bean Configuration information. Spring has the following requirements for the Configuration class:
- The configuration class cannot be final;
- Configuration classes cannot be localized, that is, they cannot be defined within the methods of other classes;
- The configuration class must have a no-argument constructor.
AnnotationConfigApplicationContext identifies the return value of the @ Bean method in the configuration class as Spring Bean and registers it to the container, which is managed by the IoC container. @ Bean is equivalent to the <bean/> label in XML configuration. Example:
@Configuration public class BookStoreDaoConfig{ @Bean public UserDao userDao(){ return new UserDaoImpl();} @Bean public BookDao bookDao(){return new BookDaoImpl();} } |
When parsing the above files, Spring will identify all the methods marked with @ Bean, execute them, and register the return values of the methods (UserDaoImpl and BookDaoImpl objects) into the IoC container. By default, the Bean name is the method name. Therefore, the XML configuration equivalent to the preceding configuration is as follows:
<bean id=”userDao” class=”bookstore.dao.UserDaoImpl”/> <bean id=”bookDao” class=”bookstore.dao.BookDaoImpl”/> |
@ Bean has the following four attributes:
- Name -- specifies the name of one or more beans. This is equivalent to the name attribute of <bean> In XML configuration.
- InitMethod -- after the container initializes the Bean, it will call the method specified by this attribute. This is equivalent to the init-method attribute of <bean> In XML configuration.
- DestroyMethod -- this attribute is similar to the initMethod function. The method specified by this attribute is called before the container destroys the Bean. This is equivalent to the destroy-method attribute of <bean> In XML configuration.
- Autowire -- specifies the automatic assembly policy for Bean attributes. The value is three static attributes of the Autowire type. Autowire. BY_NAME, Autowire. BY_TYPE, Autowire. NO. Compared with the value of the autowire attribute in XML configuration, constructor is missing because constructor has no meaning here.
@ Bean does not directly provide the attribute of the specified Scope. You can use @ Scope to implement this function. The usage of @ Scope is listed above.
The following describes the annotation-based container initialization. AnnotationConfigApplicationContext provides three constructors for initializing containers.
- AnnotationConfigApplicationContext (): This constructor initializes an empty container that does not contain any Bean information. You need to register the configuration class by calling its register () method later and call refresh () method to refresh the container.
- AnnotationConfigApplicationContext (Class <?>... AnnotatedClasses): This is the most common constructor. By passing the involved configuration class to this constructor, the Bean in the corresponding configuration class is automatically registered to the container.
- AnnotationConfigApplicationContext (String... basePackages): This constructor automatically scans all classes in a given package and its sub-packages, automatically recognizes all Spring beans, and registers them to the container. It not only recognizes the Configuration classes marked with @ Configuration, but also recognizes the classes marked with @ Repository, @ Service, @ Controller, and @ Component.
In addition to using the third type of constructor to enable containers to automatically scan Bean configuration information, AnnotationConfigApplicationContext also provides the scan () method, which is similar to the preceding method, this method is mainly used to dynamically add beans to the container after container initialization. After this method is called, you must call refresh () to refresh the container immediately.
Note that AnnotationConfigApplicationContext registers the Configuration class as a Bean when parsing the Configuration class, because @ Configuration annotation is marked by @ Component during its definition. Therefore, one @ Configuration is also one @ Component. In most cases, developers cannot use this Bean, and ideally, this Bean should be transparent to developers. @ Configuration is defined as follows:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration { String value() default ""; } |
In a general project, to ensure a clear structure, multiple XML configuration files are usually defined based on the software module or structure, and then a configuration file for the entry is defined, this file uses <import/> to organize other configuration files. Finally, you only need to pass the file to the ClassPathXmlApplicationContext constructor. Spring also provides similar functions for annotation-based configuration. You only need to define an entry configuration class and use the @ Import Annotation on the class to introduce other configuration classes, finally, you only need to pass the entry class to AnnotationConfigApplicationContext. Example:
@Configuration
@Import({BookStoreServiceConfig.class,BookStoreDaoConfig.class})
public class BookStoreConfig{ … }
Bean configuration using XML and annotation in combination
The original intention of designing @ Configuration and @ Bean is not to completely replace XML, but to provide a feasible option other than XML. Since Spring was released, the Spring development team has been constantly simplifying XML configuration, making the XML configuration method very mature. In addition, Spring 2.0 has provided a series of namespaces, this makes the XML configuration method a simple and powerful Bean definition method. In addition, some advanced functions of XML configuration are not directly supported by related annotations. Therefore, in most current projects, Bean configuration is either performed using pure XML configuration methods, or Bean configuration using annotation-based and XML-supplemented configuration methods.
There are three main reasons for the coexistence of the two: First, most of the projects developed using Spring are mostly based on XML configuration, spring must ensure that the annotation can coexist harmoniously with XML while introducing annotations. This is the premise. Second, because the annotation is introduced late, the function has not been developed for many years. Therefore, for complex configurations, annotations are still difficult to stand alone. In a period of time, XML is still needed to solve the problem. In addition, the Spring Bean configuration method is decoupled from the Spring core module. Therefore, changing the configuration method is transparent to the Spring framework itself. Spring can easily add annotation support by using BeanPostProcessor. This is very easy to implement technically.
To use the mixed configuration method, you must first determine which configuration method is the main one. Different answers to this question will directly affect the implementation method. However, you don't have to worry about it, because the configuration method is simple and easy to understand whether it is mainly XML or annotation. There is no wrong decision here, because only the performance is different. First, let's assume that the XML configuration is the most important.
For a large project that already exists, Bean configuration may be performed in XML at the beginning, and annotation support will be added gradually in the future, in this case, you only need to define the class marked by @ Configuration as a common <bean> In the XML Configuration file, and register the Bean post-processor that processes the annotation. Example:
// Assume the following @ Configuration class exists: Package bookstore. config; Import bookstore. dao .*; @ Configuration Public class MyConfig { @ Bean Public UserDao userDao (){ Return new UserDaoImpl (); } } In this case, you only need to make the following declaration in XML: <Beans... > ...... <Context: annotation-config/> <Bean class = "demo. config. MyConfig"/> </Beans> |
The annotation-oriented Bean post-processor is enabled. Therefore, when ApplicationContext is parsed to the MyConfig class, it is found that the class is labeled with the @ Configuration annotation, and then the @ Bean annotation method in the class is processed, register the return values of these methods as the total Bean of the container.
For the above method, if there are multiple classes labeled @ Configuration, You need to list them one by one in the XML file. Another method is to use the automatic scanning function mentioned above. The configuration is as follows:
<context:component-scan base-package=”bookstore.config” /> |
If so, Spring will scan all the demos. the config package and its sub-packages identify all classes marked with @ Component, @ Controller, @ Service, and @ Repository annotations. Because the @ Configuration annotation itself is also marked with @ Component, spring will be able to identify the @ Configuration annotation class and parse it correctly.
For annotation-centered configuration, you only need to use the @ ImportResource annotation to introduce the existing XML, as shown below:
@ Configuration
@ ImportResource ("classpath:/bookstore/config/spring-beans.xml ")
Public class MyConfig {
......
}
// The initialization process of the container is consistent with the configuration-centric method:
AnnotationConfigApplicationContext ctx =
New AnnotationConfigApplicationContext (MyConfig. class );
......
Conclusion
Starting from version 2.0, each update of Spring will provide more new annotations for developers. This satisfies the appetite of annotation lovers. However, as mentioned above, Spring does not provide more annotations to replace the XML configuration method one day, but to provide developers with more choices. The two Bean declaration methods have their own characteristics. The XML method is more flexible and mature. This configuration method is familiar to most Spring developers. The annotation method is very simple to use, but it is still in the development stage. It is hard to say that the two configuration methods are superior or inferior, but if they can be flexibly combined, the development efficiency will be further improved.