Spring assembles beans based on annotations

Spring assembles beans based on annotations

preface

​ In Spring, although XML configuration files can be used to assemble beans, if there are a large number of beans in the application, the XML configuration files will be too bloated, which will bring some difficulties to maintenance and upgrade.

​ Since JDK 5.0, Java has provided Annotation function. Spring 2.5 also provides comprehensive support for Annotation technology. We can use annotations to configure dependency injection.

​ Spring does not use annotations to assemble beans by default, so you need to add < context: annotation config / > in the configuration file to enable annotations.

  • Annotation: it is a class, using @ annotation name
  • In development: use annotations instead of xml configuration files.

What is annotation

​ Annotation is a new feature introduced in Java 5. Its Chinese name is annotation.

​ It provides a secure annotation like mechanism to associate any information or metadata with program elements (classes, methods, member variables, etc.). Add more intuitive and clear descriptions to the elements (classes, methods, member variables) of the program. These descriptions are independent of the business logic of the program and are used by the specified tools or frameworks. Like a modifier, annotation is applied to the declaration statements of packages, types, constructors, methods, member variables, parameters and local variables.
Java annotation is some meta information attached to the code, which is used for parsing and using some tools during compilation and runtime, and plays the function of description and configuration. Annotations do not and cannot affect the actual logic of the code, but only play an auxiliary role. Included in the java.lang.annotation package.

Use of annotations:

1. Generate documents. This is the most common and the earliest annotation provided by java. Commonly used are @ param @return, etc
2. Track code dependencies and implement alternative configuration file functions. For example, Dagger 2 dependency injection, which is very useful for java development in the future, will configure a large number of annotations;
3. Format check at compile time. If @ override is placed in front of the method, if your method does not override the superclass method, it can be checked during compilation.

For more annotation information, click here - basic principle of JAVA annotation - Single_Yam - blog Park (cnblogs.com)

Why use annotations to assemble beans

The traditional approach of Spring is to use. xml files to inject bean s or configure AOPs and things. This has two disadvantages:

  1. If all the contents are configured in an. xml file, the. xml file will be very large; If. xml files are separated according to requirements, there will be many. xml files. In short, this will lead to low readability and maintainability of configuration files.
  2. It is troublesome to constantly switch between. java files and. xml files in development. At the same time, this incoherence in thinking will also reduce the efficiency of development.

In order to solve these two problems, Spring introduces annotations. Through the "@ XXX" method, annotations are closely combined with Java beans, greatly reducing the volume of configuration files and increasing the readability and cohesion of Java beans.

Using Spring annotations

0. Enable component scanning

1) Scan using XML

<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.xsd
       					   http://www.springframework.org/schema/context
       					   http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- Component scanning, scanning classes with annotations -->
    <context:component-scan base-package="com.spring.learn2" />
</beans>

Configuration attribute < context: component scan base package = "com. Spring. Learn2" / >

Where ` base package

2) The @ componentscan annotation enables component scanning

package com.spring.learn2.config;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan
public class BeanConfig {}
package com;

import com.spring.learn2.config.BeanConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(BeanConfig.class);

        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanName : beanDefinitionNames) {
            System.out.println("beanName: " + beanName);
        }
    }
}

Operation effect

beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: beanConfig

In addition to some beans registered by spring itself, you can see that the last line has registered the class bean config into the container.

Create a configuration class and add @ ComponentScan annotation on the configuration class. This annotation will scan all configuration classes under the package where this class is located by default, which is equivalent to the previous < context: component scan >.

The class bean config defines Spring's assembly rules through Java code. The observation shows that the bean Config class does not explicitly declare any beans, but it uses the @ ComponentScan annotation, which can enable component scanning in Spring

If there is no other configuration, @ ComponentScan will scan the same package as the configuration class by default. Because the Bean Config class is located in the com.spring.learn2.config package, Spring will scan the package and all sub packages under the package to find classes with @ Component annotation. In this way, you can find the classes that use annotations, and automatically create a Bean for them in Spring

3) Specify the packages to scan

(configured using the value attribute of @ ComponentScan)

@ComponentScan(value = "com.spring.learn2")
public class BeanConfig {

}
Use of excludeFilters and includeFilters
Use excludeFilters to exclude scans of certain packages according to rules.
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@ComponentScan(value = "com.spring.learn2",
        excludeFilters = {@Filter(type = FilterType.ANNOTATION,
        value = {Controller.class})})
public class BeanConfig {

}

​ The parameter of excludeFilters is a Filter [] array, and then specify the type of FilterType as ANNOTATION, that is, filtering through ANNOTATION, and the last value is the Controller ANNOTATION class.

​ After configuration, all classes marked by @ Controller annotation under com.spring.learn2 package will be skipped during spring scanning.

Use includeFilters to scan that contains only certain packages according to rules.
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@ComponentScan(value = "com.spring.learn2", includeFilters = {@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})})
public class BeanConfig {

}

By default, spring will automatically discover the classes marked by @ Component, @ Repository, @ Service and @ Controller and register them in the container. To achieve the scanning effect of only containing some packages, you must disable this default behavior (just set useDefaultFilters to false in @ ComponentScan).

@useDefaultFilters property of ComponentScan. The default value of this property is true.

1. Definitions Bean@Component

The @ Component annotation needs to be used on the class. The value attribute of the annotation is used to specify the id value of the bean.

@Component(value = "role")
public class Role {
    private Long id;
    private String roleName;
    private String note;
}

2. Scope of bean @ scope

The annotation @ Scope needs to be used on the class, and its value attribute is used to specify the Scope. The default is singleton.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Scope("prototype")
@Component("RoleService")
public class RoleServiceImpl implements RoleService {
    ...
}

3. Basic type attribute injection @ Value

The @ value annotation needs to be used on the attribute. The value attribute of the annotation is used to specify the value to be injected.
When using this annotation to complete attribute injection, there is no need for setters in the class. Of course, if the property has a setter, it can also be added to the setter.

package com.spring.learn2;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value = "role")
public class Role {
    @Value("1")
    private Long id;
    @Value("role_name_1")
    private String roleName;
    @Value("role_note_1")
    private String note;
}

4. Inject the domain attribute @ Autowired by type

@Autowired is an annotation for spring

You need to use the annotation @ Autowired on the domain attribute. By default, the annotation uses the method of automatically assembling beans by type.
When using this annotation to complete attribute injection, there is no need for setters in the class. Of course, if the property has a setter, it can also be added to the setter.

package com.spring.learn2;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Scope("prototype")
@Component("RoleService")
public class RoleServiceImpl implements RoleService {
    @Autowired
    private Role role;

    /**** setter and getter ****/
    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }
}

5. Inject domain attributes @ Autowired and @ Qualifier by name

The annotation @ Autowired and @ Qualifier need to be used together on the domain attribute.

@The value attribute of Qualifier is used to specify the id value of the Bean to match. Similarly, a setter is not required in a class and can also be added to a setter.

package com.spring.learn2;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Scope("prototype")
@Component("RoleService")
public class RoleServiceImpl implements RoleService {
    @Autowired(required =false)
 	@Qualifier("role")
    private Role role;

    /**** setter and getter ****/
    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }
}

@Autowired also has an attribute required, and the default value is true, which means that the program will be terminated after matching fails. If the value is set to false, the matching fails, will be ignored, and the unmatched property value is null.

6. Domain attribute annotation @ Resource

@Resource is java's own annotation

Spring provides support for the @ resource standard annotation defined in the JSR-250 specification@ Resource annotations can match beans by name or type. Using this annotation requires that the JDK must be version 6 or above.

1. Inject domain attributes by type

@If the Resource annotation does not take any parameters, Bean matching injection will be performed according to the type.

import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component("RoleService")
public class RoleServiceImpl implements RoleService {
    @Resource
    private Role role;

    /**** setter and getter ****/
    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }
}

2. Inject domain attributes by name

@If the Resource annotation specifies its name attribute, the value of name is the id of the Bean matched by name.

package com.spring.learn2;


import org.springframework.stereotype.Component;
import javax.annotation.Resource;


@Component("RoleService")
public class RoleServiceImpl implements RoleService {
    @Resource(name="role")
    private Role role;

    /**** setter and getter ****/
    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }
}

7. Bean's life history @ PostConstruct and @ PreDestroy

Use @ PostConstruct on the method, which is equivalent to the original init method. Use @ PreDestroy on the method, which is equivalent to destroy method.

package com.spring.learn2;


import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;


@Component("RoleService")
public class RoleServiceImpl implements RoleService {
    @Resource(name="role")
    private Role role;

    @PostConstruct
    public void init(){
        System.out.println("Bean Execute after initialization");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("Bean Execute before destruction");
    }

    /**** setter and getter ****/
    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }
}

Annotations commonly used in Spring

@Component replaces < bean class = "" >.

@Component("id") replaces < bean id = "" class = "" >

For web development, three @ Component annotations and derived annotations (with the same function) are provided to replace < bean class = "" >

@Repository: dao layer.

@Service: service layer.

@Controller: web layer.

@Component

This annotation can be used to describe beans in Spring, but it is a generalized concept that represents only one component (Bean) and can act at any level. When using, you only need to mark the annotation on the corresponding class.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value = "role")
public class Role {
    @Value("1")
    private Long id;
    @Value("role_name_1")
    private String roleName;
    @Value("role_note_1")
    private String note;
}
  • The annotation @ Component represents Spring IoC. The class will be scanned to generate Bean instances, and the value attribute represents the id of the class in Spring, which is equivalent to the id of the Bean defined in XML. It can also be abbreviated as @ Component("role") or even directly written as @ Component. For those not written, the Spring IoC container defaults to the class name, but takes the initial lowercase form as the id, Generate objects for them and configure them into containers.
  • The @ Value annotation represents Value injection. Here are just some values simply injected. The id is a long type, and Spring will convert it to type during injection.

@Repository

The class used to identify the data access layer (DAO layer) as a Bean in Spring has the same function as @ Component.

@Service

It usually acts on the business layer (Service layer) to identify the class of the business layer as a Bean in Spring, and its function is the same as @ Component.

@Controller

It usually acts on the control layer (such as the Action of struts 2 and the Controller of Spring MVC). It is used to identify the class of the control layer as a Bean in Spring, and its function is the same as @ Component.

@Autowired

Automatic assembly.

​ By studying the Spring IoC container, we know that Spring first completes the definition and generation of beans, and then looks for the resources to be injected. That is, after Spring generates all beans, if it finds this annotation, it will find the corresponding type in the Bean and inject it, so as to complete dependency injection.

​ The so-called automatic assembly technology is a way for Spring to find the corresponding Bean and automatically complete the assembly work. It will be applied to a very common annotation @ Autowired. At this time, Spring will find the defined Bean according to the type and inject it. Here, we need to pay attention to the Role.

​ It can be applied to Bean's attribute variables, attribute setter methods, non setter methods and constructors, and cooperate with the corresponding annotation processor to complete the automatic configuration of Bean. By default, it is assembled according to the type of Bean.

  • Example

    role

    package com.spring.learn2;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component(value = "role")
    public class Role {
        @Value("1")
        private Long id;
        @Value("role_name_1")
        private String roleName;
        @Value("role_note_1")
        private String note;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getRoleName() {
            return roleName;
        }
    
        public void setRoleName(String roleName) {
            this.roleName = roleName;
        }
    
        public String getNote() {
            return note;
        }
    
        public void setNote(String note) {
            this.note = note;
        }
    }
    

    RoleService

    package com.spring.learn2;
            
    public interface RoleService {
        public void printRoleInfo();
    }
    
    package com.spring.learn2;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component("RoleService")
    public class RoleServiceImpl implements RoleService {
      @Autowired
      private Role role;
    
      @Override
      public void printRoleInfo() {
          System.out.println("id =" + role.getId());
          System.out.println("roleName =" + role.getRoleName());
          System.out.println("note =" + role.getNote());
      }
    
      /**** setter and getter ****/
      public Role getRole() {
          return role;
      }
    
      public void setRole(Role role) {
          this.role = role;
      }
    }
    
    

    MainApp

    package com;
    
    
    import com.spring.learn2.RoleService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainApp {
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("Beans.xml");
            RoleService uc = (RoleService) ctx.getBean("RoleService");
            uc.printRoleInfo();
        }
    }
    
    

    Beans.xml

    Scan classes with annotations

    <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.xsd
           					   http://www.springframework.org/schema/context
           					   http://www.springframework.org/schema/context/spring-context.xsd">
    
        <!-- Component scanning, scanning classes with annotations -->
        <context:component-scan base-package="com.spring.learn2" />
    </beans>
    

    ​ The @ Autowired annotation here indicates that after Spring IoC locates all beans, this field needs to be injected by type, so that the IoC container will find resources and inject them.. For example, if the two beans of code Role and code RoleServiceImpl are defined, the Spring IoC container will generate corresponding instances for them, and then find the defined instances by type according to the @ Autowired annotation and inject them.

    The IoC container sometimes fails to search. By default, it will throw an exception. That is, by default, the Spring IoC container thinks that it must find the corresponding Bean to inject this field. Sometimes this is not a real need, such as logging. Sometimes we think it is dispensable, At this time, you can change @ Autowired through its configuration item required, such as @ Autowired(required=false).

    ​ As mentioned earlier, successful injection is required by default, so the default value of required here is true. When the configuration is changed to false, tell the Spring IoC container that if the corresponding type cannot be found in the defined Bean, no injection is allowed, so there will be no exception thrown. Only in this way, this field may be empty. The reader should verify it by himself to avoid null pointer exceptions. In most cases, this modification is not required.
    ​ @ In addition to the properties, Autowired also allows method configuration. Common Bean setter methods can also use it to complete injection.

@Resource

​ The function is the same as that of Autowired, except that @ Autowired is assembled according to the Bean type by default, while @ Resource is assembled according to the Bean instance name by default.

​ @ There are two important attributes in a Resource: name and type.

Spring resolves the name attribute to the instance name of the Bean, and the type attribute to the instance type of the Bean. If the name attribute is specified, the assembly is performed by the instance name; If the type attribute is specified, the assembly is performed by Bean type. If none is specified, assemble according to the Bean instance name first. If it cannot match, assemble according to the Bean type again; If none of them can match, a NoSuchBeanDefinitionException is thrown.

​ In addition, note that @ Resource is an annotation provided by java, not in Spring@ The complete package path of the Resource annotation is

import  javax.annotation.Resource;

Example

@Resource(name = "userServiceImpl")
private UserService userService;

@Qualifier

When used with @ Autowired annotation, the default assembly by Bean type will be modified to assembly by Bean instance name, which is specified by the parameter of @ Qualifier annotation.

 @Autowired
 @Qualifier("userServiceImp")
 private UserSerevice userService;

@Service, @ Controller these annotations should be placed on the implementation class of the interface, not on the interface.

@Autowired and @ Resource are used to modify fields, constructors, or set methods and inject.

While @ Service, @ Controller, @ Repository, @ Component are used to decorate classes and mark the bean s to be generated by these classes.

Before using annotations, add namespaces and let spring scan classes with annotations

Example

Beans.xml

<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.xsd
       					   http://www.springframework.org/schema/context
       					   http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- Component scanning, scanning classes with annotations -->
    <context:component-scan base-package="com.spring.learn1" />
</beans>

UserDao

package com.spring.learn1;

public interface UserDao {
    /**
     * Output method
     */
    public void outContent();
}

UserDaoImpl

package com.spring.learn1;

import org.springframework.stereotype.Repository;
@Repository("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void outContent() {
        System.out.println("dao method");
    }
}
package com.spring.learn1;

public interface UserService {
    /**
     * Output method
     */
    public void outContent();
}

UserServiceImpl

package com.spring.learn1;

import javax.annotation.Resource;
import org.springframework.stereotype.Service;
@Service("userService")
public class UserServiceImpl implements UserService{

    @Resource(name="userDao")
    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    @Override
    public void outContent() {
        userDao.outContent();
        System.out.println("service");
    }
}

UserController

package com.spring.learn1;

import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
@Controller("userController")
public class UserController {
    @Resource(name = "userService")
    private UserService userService;
    public UserService getUserService() {
        return userService;
    }
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    public void outContent() {
        userService.outContent();
        System.out.println("content");
    }
}

MainApp

package com;


import com.spring.learn1.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("Beans.xml");
        UserController uc = (UserController) ctx.getBean("userController");
        uc.outContent();
    }
}

The following error occurred at runtime

org.springframework.context.support.AbstractApplicationContext refresh

warning: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController' defined in file [. . . ]: Post-processing of merged bean definition failed; nested exception is java.lang.NoSuchMethodError: javax.annotation.Resource.lookup()Ljava/lang/String;
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController' defined in file [. . . ]: Post-processing of merged bean definition failed; nested exception is java.lang.NoSuchMethodError: javax.annotation.Resource.lookup()Ljava/lang/String;
. . . . 
Caused by: java.lang.NoSuchMethodError: javax.annotation.Resource.lookup()Ljava/lang/String;

Check that the package javax.annotation does not exist

Import in pom.xml file

<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.1</version>
</dependency>

The operation is as follows

dao method
service
content

@Resource vs @Autowired

@The assembly sequence of resources is as follows:

  1. @There is nothing behind the Resource. By default, the bean is matched through the name attribute. If it cannot be found, it is matched by type;
  2. If name or type is specified, the bean will be matched according to the specified type;
  3. If name and type are specified, bean s will be matched according to the specified name and type. Any mismatch will result in an error.

Then, distinguish between @ Autowired and @ Resource annotations:

  1. @Autowired matches beans in byType mode by default, and @ Resource matches beans in byName mode by default
  2. @Autowired is the annotation of Spring and @ Resource is the annotation of J2EE. When you look at the imported annotation, the package names of the two annotations will be clear

Spring belongs to a third party, and J2EE is Java's own thing. Therefore, it is recommended to use @ Resource annotation to reduce the coupling between code and spring.

To sum up:

@According to name and type, Resource is name before type, and @ Autowired is type. In general, we'd better use @ Resource.

​ This article explains the usage of @ Service, @ Autowired, @ Resource and @ Qualifier in detail, and focuses on the differences between @ Autowired and @ Resource. The three annotations @ Component, @ Repository and @ Controller are mentioned at the beginning of the article. These three annotations actually have the same meaning as @ Service, but we will layer them when writing code, such as DAO layer, Service layer The Action layer can be represented by @ Repository, @ Service and @ Controller respectively. In fact, the literal meaning is different, and the effect is the same. Then @ Component can act on any level. So it seems that there are seven annotations, but in fact, you can understand that there are only four.

Keywords: Java

Added by enchance on Fri, 03 Dec 2021 13:06:45 +0200