Details the use of annotations in Java's Spring framework

  • 2020-04-01 04:24:57
  • OfStack

Use Spring annotations to inject properties

1.1. How did we inject properties before using annotations
Class implementation:


class UserManagerImpl implements UserManager { 
  private UserDao userDao; 
  public void setUserDao(UserDao userDao) { 
    this.userDao = userDao; 
  } 
  ... 
}

Profile:


<bean id="userManagerImpl" class="com.kedacom.spring.annotation.service.UserManagerImpl"> 
  <property name="userDao" ref="userDao" /> 
</bean> 
<bean id="userDao" class="com.kedacom.spring.annotation.persistence.UserDaoImpl"> 
  <property name="sessionFactory" ref="mySessionFactory" /> 
</bean>

1.2. Introduction of @autowired annotation (not recommended, @resource is recommended)
Class implementation (annotating member variables)


public class UserManagerImpl implements UserManager { 
  @Autowired 
  private UserDao userDao; 
  ... 
}

Or (annotate the method)


UserManagerImpl implements UserManager { 
  private UserDao userDao; 
  @Autowired 
  public void setUserDao(UserDao userDao) { 
    this.userDao = userDao; 
  } 
  ... 
}

The configuration file


<bean id="userManagerImpl" class="com.kedacom.spring.annotation.service.UserManagerImpl" /> 
<bean id="userDao" class="com.kedacom.spring.annotation.persistence.UserDaoImpl"> 
  <property name="sessionFactory" ref="mySessionFactory" /> 
</bean>

@autowired enables annotation of member variables, methods, and constructors to accomplish Autowired. In the above two different implementations, the annotation location of @autowired is different, and both of them will automatically assemble the property of userDao when Spring initializes the bean of userManagerImpl. The difference is that: in the first implementation, Spring will directly assign the unique bean of userDao type to the member variable of userDao. In the second implementation, Spring invokes the setUserDao method to assemble the unique bean of the UserDao type into the UserDao property.

1.3. Make @autowired work
For @autowired to work, you also need to add the following code to the configuration file


class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />

1.4. @ the Qualifier
@autowired is automatically assembled by type. In the above example, a BeanCreationException is thrown if there is more than one bean of UserDao type in the Spring context; A BeanCreationException is also thrown if a bean of the UserDao type does not exist in the Spring context. We can solve these problems by using @qualifier with @autowired.
1. There may be multiple UserDao instances


@Autowired 
public void setUserDao(@Qualifier("userDao") UserDao userDao) { 
  this.userDao = userDao; 
}

In this way, Spring finds the bean with the id userDao to assemble.
2. There may be no UserDao instance


@Autowired(required = false) 
public void setUserDao(UserDao userDao) { 
  this.userDao = userDao; 
} 

1.5. @resource (jsr-250 standard annotation, which is recommended to replace Spring's proprietary @autowired annotation)
Spring supports not only its own @autowired annotations, but also several annotations defined by the jsr-250 specification: @resource, @postconstruct, and @predestroy.
The @resource function is equivalent to @autowired, except that @autowired is automatically injected by byType, while @resource is automatically injected by byName by default. It is important that @resource has two attributes, name and type. Spring resolves the name attribute of the @resource annotation to the name of the bean, and the type attribute to the type of the bean. So if you use the name attribute, you use the byName auto-injection policy, and if you use the type attribute, you use the byType auto-injection policy. If you do not specify either the name or the type attribute, the byName auto-injection policy is used through the reflection mechanism.
@resource assembly sequence

If both name and type are specified, a unique matching bean is found from the Spring context for assembly, and an exception is thrown if it is not found
If name is specified, the bean whose name (id) matches is looked up from the context for assembly, and an exception is thrown if it is not found
If type is specified, a unique bean with a type matching is found from the context for assembly, and an exception is thrown if more than one is found
If neither name nor type is specified, the assembly is automatically byName (see 2). If there is no match, a primitive type (UserDao) is returned to match, and if there is a match, automatic assembly is performed.
1.6. @postconstruct (jsr-250)
Add the annotation @postconstruct to the method, and the method is executed by the Spring container after the Bean is initialized (note: Bean initialization involves instantiating the Bean and assembling the Bean's properties (dependency injection)).
A typical scenario is when you need to inject a property defined in its parent class into the Bean, and you cannot copy the property of the parent class or setter method of the property, such as: & PI;


public class UserDaoImpl extends HibernateDaoSupport implements UserDao { 
  private SessionFactory mySessionFacotry; 
  @Resource 
  public void setMySessionFacotry(SessionFactory sessionFacotry) { 
    this.mySessionFacotry = sessionFacotry; 
  } 
  @PostConstruct 
  public void injectSessionFactory() { 
    super.setSessionFactory(mySessionFacotry); 
  } 
  ... 
}

Here we inject our own sessionFactory with @postconstruct, a private property of sessionFactory defined in the parent class of UserDaoImpl (the setSessionFactory method of the parent class is final, not replicable), and then we can access the property by calling super.getsessionfactory ().


1.7. @predestroy (jsr-250)
Annotate the method with @predestroy, and the method will be executed by the Spring container after the Bean is initialized. Since we don't currently have a scenario where we need to use it, I'm not going to demonstrate it here. It is used like @postconstruct.

1.8. Use < Context: the annotation - config / > Simplify the configuration
Spring2.1 adds a new context Schema namespace that provides convenient configuration for annotation-driven, property file introduction, load time weaving, and more. We know that annotations don't do anything by themselves; they just provide metadata information. For metadata information to be truly useful, the processor responsible for processing this metadata must be put to work.
AutowiredAnnotationBeanPostProcessor and CommonAnnotationBeanPostProcessor is deal with the metadata of the processor. But defining these beans directly in a Spring configuration file can be cumbersome. Spring gives us a convenient way to register these beanpostprocessors. Context: the annotation - config / > :


<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-2.5.xsd"> 
  <context:annotation-config /> 
</beans>

< Context: annotationconfig / > The implicitly registered AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor, as well as with the Spring container RequiredAnnotationBeanPostProcessor these four BeanPostProcessor.

2. Complete the definition of the Bean using Spring annotations
While we described the ability to automatically inject beans using @autowired or @resource, we'll show you how to annotate beans to completely remove the beandefined configuration from the XML configuration file.

2.1. @component (not recommended), @repository, @service, and @controller
Just add an @component annotation to the corresponding class to define it as a Bean:


@Component 
public class UserDaoImpl extends HibernateDaoSupport implements UserDao { 
  ... 
}

The default name (id) for a Bean defined using the @component annotation is an unqualified class name with a lowercase beginning. For example, the Bean name defined here is userDaoImpl. You can also specify the name of the Bean:
@ Component (" userDao)"
@component is the generic form of all spring-managed components, and Spring provides more refined forms of annotations: @repository, @service, and @controller, which correspond to storage-layer beans, business-layer beans, and show-layer beans, respectively. In the current version (2.5), these annotations have the same semantics as @component and are completely generic, and may be appended with more semantics in later versions of Spring. Therefore, we recommend using @repository, @service, and @controller instead of @component.

2.2. Use < Context: the component - scan / > Let the Bean definition annotations work


<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-2.5.xsd"> 
  <context:component-scan base-package="com.kedacom.ksoa" /> 
</beans>

Here, all through < Bean> The configuration content of the element definition Bean has been removed, only one line needs to be added < Context: the component - scan / > Configuration solves all the problems -- the Spring XML configuration file is extremely simplified (although configuration metadata is still required, but in the form of annotations). < Context: the component - scan / > The base-package attribute of the class package to be scanned, and all classes in the class package and its recursive subpackage are processed.
< Context: the component - scan / > It also allows you to define filters to include or exclude certain classes under the base package. Spring supports four types of filtering:

Filter type expression example
Annotations org. Example. SomeAnnotation will filter out all use SomeAnnotation comment to the class
The class name specifies org.example.someclass filters the specified class
Regular expression com\. Kedacom \. Spring \. Annotation \. Web \.. * filters some classes through regular expressions
AspectJ expression org.example.. *Service+ filters some classes through AspectJ expressions

Taking regular expressions as an example, I will cite an application example:


<context:component-scan base-package="com.casheen.spring.annotation"> 
  <context:exclude-filter type="regex" expression="com.casheen.spring.annotation.web..*" /> 
</context:component-scan>

Of note is < Context: the component - scan / > Configuration items not only enabled the class package to implement scanning annotation driven Bean definition of function, at the same time also enabled comments drive the function of the automatic injection (i.e., also implicitly registered in internal AutowiredAnnotationBeanPostProcessor and CommonAnnotationBeanPostProcessor), so when using < Context: the component - scan / > After, you can put < Context: the annotation - config / > Removed.

2.3. Use @scope to define the Scope of the Bean
When defining beans using XML, we might also need to define the scope of a Bean through its scope attribute, which we can also do with the @scope annotation:


@Scope("session") 
@Component() 
public class UserSessionBean implements Serializable { 
  ... 
}

3. Define the relationship between the three beans before using the annotation like this


package com.baobaotao;
public class Office {
  private String officeNo = " 001 " ;
 
  //Omit the get/setter
 
  @Override
  public String toString() {
    return "officeNo:" + officeNo;
  }
}

ackage com.baobaotao;
 
public class Car {
  private String brand;
  private double price;
 
  // Omit the get/setter
 
  @Override
  public String toString() {
    return "brand:" + brand + "," + "price:" + price;
  }
}

package com.baobaotao;
 
public class Boss {
  private Car car;
  private Office office;
 
  // Omit the get/setter
 
  @Override
  public String toString() {
    return "car:" + car + "n" + "office:" + office;
  }
}

The configuration file is as follows:


<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  <bean id="boss" class="com.baobaotao.Boss">
    <property name="car" ref="car"/>
    <property name="office" ref="office" />
  </bean>
  <bean id="office" class="com.baobaotao.Office">
    <property name="officeNo" value="002"/>
  </bean>
  <bean id="car" class="com.baobaotao.Car" scope="singleton">
    <property name="brand" value="  The red flag  CA72"/>
    <property name="price" value="2000"/>
  </bean>
</beans>

The test file is as follows:


import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnoIoCTest {
 
  public static void main(String[] args) {
    String[] locations = {"beans.xml"};
    ApplicationContext ctx = 
      new ClassPathXmlApplicationContext(locations);
    Boss boss = (Boss) ctx.getBean("boss");
    System.out.println(boss);
  }
}

 
4. We can then use autowired for the annotation , he can carry on the standard to the member variable, the method and the constructor, completes the automatic assembly work.

Autoware to annotate the use of member variables


package com.baobaotao;
import org.springframework.beans.factory.annotation.Autowired;
 
public class Boss {
 
  @Autowired
  private Car car;
 
  @Autowired
  private Office office;
 
   ... 
}

The corresponding configuration file is as follows:


<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
  <!--  the  BeanPostProcessor  Will automatically work on the annotation  @Autowired  the  Bean  Automatic injection  -->
  <bean class="org.springframework.beans.factory.annotation.
    AutowiredAnnotationBeanPostProcessor"/>
 
  <!--  remove  boss Bean  Property to inject configuration information  -->
  <bean id="boss" class="com.baobaotao.Boss"/>
 
  <bean id="office" class="com.baobaotao.Office">
    <property name="officeNo" value="001"/>
  </bean>
  <bean id="car" class="com.baobaotao.Car" scope="singleton">
    <property name="brand" value="  The red flag  CA72"/>
    <property name="price" value="2000"/>
  </bean>
</beans>

Autoware can also be used on setter methods and constructors


package com.baobaotao;
 
public class Boss {
  private Car car;
  private Office office;
 
   @Autowired
  public void setCar(Car car) {
    this.car = car;
  }
 
  @Autowired
  public void setOffice(Office office) {
    this.office = office;
  }
   ... 
}

package com.baobaotao;
 
public class Boss {
  private Car car;
  private Office office;
 
  @Autowired
  public Boss(Car car ,Office office){
    this.car = car;
    this.office = office ;
  }
 
   ... 
}

When the number of candidate beans is 0, we can use @autowired (required = false) to prevent spring from missing the bean times.

When there are multiple candidate beans, we can specify the name of the injected bean through the @qualifier annotation.

When used in combination with @autowired and @qualifier, the auto-injected policy changes from byType to byName. @autowired comments member variables, methods, and constructors, while the annotation objects for @qualifier are member variables, method arguments, and constructor arguments. It is because of the difference in annotation objects that Spring does not unify @autowired and @qualifier into one annotation class.

5.@resorce reflects by name , it has two parameters, name and type. Name is used to map according to byname, and type is used to map according to bytype.


package com.baobaotao;
 
import javax.annotation.Resource;
 
public class Boss {
  //Automatically inject beans of type Car
  @Resource
  private Car car;
 
  //The bean with the bean name office is automatically injected
  @Resource(name = "office")
  private Office office;
}
@postconstructor and preDestory Is used to annotate methods after class initialization and before class destruction.  


package com.baobaotao;
 
import javax.annotation.Resource;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
 
public class Boss {
  @Resource
  private Car car;
 
  @Resource(name = "office")
  private Office office;
 
  @PostConstruct
  public void postConstruct1(){
    System.out.println("postConstruct1");
  }
 
  @PreDestroy
  public void preDestroy1(){
    System.out.println("preDestroy1"); 
  }
   ... 
}

6.@compent can define beans directly This eliminates the need to configure beans in the XML configuration file


package com.baobaotao;
 
import org.springframework.stereotype.Component;
 
@Component
public class Car {
   ... 
}

package com.baobaotao;
 
import org.springframework.stereotype.Component;
 
@Component
public class Office {
  private String officeNo = "001";
   ... 
}

package com.baobaotao;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
 
@Component("boss")
public class Boss {
  @Autowired
  private Car car;
 
  @Autowired
  private Office office;
   ... 
}

@component has an optional argument that specifies the name of the Bean, and in Boss, we define the Bean name as "Boss." In general, beans are singletons, and where beans need to be injected they can be injected automatically by simply passing the byType policy, so you don't need to specify the name of the Bean.


<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 http://www.springframework.org/schema/context 
 http://www.springframework.org/schema/context/spring-context-2.5.xsd">
  <context:component-scan base-package="com.baobaotao"/>
</beans>

7.@scope can be used to specify its target


package com.baobaotao;
import org.springframework.context.annotation.Scope;
 ... 
@Scope("prototype")
@Component("boss")
public class Boss {


In addition to the @component annotation, Spring 2.5 defines several annotations with special semantics: @repository, @service, and @controller. In the current Spring version, the three annotations are equivalent to @component, but it's easy to see from the naming of the annotation class that they correspond to the persistence layer, the business layer, and the control layer (the Web layer), respectively. While the three annotations are nothing new to @component right now, Spring will add special functionality to them in a future release. So, if a Web application USES the classic three-tier hierarchy, it is best to annotate the classes in the persistence layer, the business layer, and the control layer with @repository, @service, and @controller, and the more neutral classes with @component.


Related articles: