preface

  • This article summarizes how Spring dependency injection static properties fail and can be resolved by adding a set method

I. Test items

  • AppConfig.java
    @Configuration
    @ComponentScan("com.eugene.sumarry.csdn.autowiredstatic")
    public class AppConfig {}Copy the code
  • UserDao.java
    @Repository
    public class UserDao {}Copy the code
  • UserService.java
    @Service
    public class UserService {
    
    	@Autowired
    	private UserDao userDao;
    
    
    	@Override
    	public String toString(a) {
    		return "UserService{" +
    				"userDao=" + userDao +
    				'} '; }}Copy the code
  • Entry.java
    public class Entry {
    
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext context = newAnnotationConfigApplicationContext(AppConfig.class); System.out.println(context.getBean(UserService.class)); }}Copy the code

Problem recurrence and solution

  • Java dependency injection UserDao static variables and run results (Static variable injection failed) :

  • Java dependency injection UserDao instance instance variable and run result (instance variable injection successfully):
  • Add a set method to complete dependency injection of static variables (Static variable injection succeeded) :

Note: Injection can also be done using constructors, but using constructors to inject is not what the @AutoWired annotation does, because you will find that you can inject with or without the @Autowired annotation.At this point, dependency injection is done through constructors (you can debug it yourself after reading the principles section below, if you don't believe me). This article explains the @AutoWired annotation, so dependency injection of constructors is not considered

Third, the principle of

  • Some background: There are many different methods of dependency injection in Spring, and the following four are common to Spring
    Common dependency injection types note
    AbstractBeanDefinition.AUTOWIRE_NO The automatic assembly function is disabled
    AbstractBeanDefinition.AUTOWIRE_BY_NAME Auto-assemble by variable name
    AbstractBeanDefinition.AUTOWIRE_BY_TYPE Automatic assembly according to type
    AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR Automatic assembly according to construction method
    Dependency injection for the @AutoWired annotation will eventually passAutowiredAnnotationBeanPostProcessorPost-processor to process, for the purposes of this blog, is itsThe role of MergedBeanDefinitionPostProcessor identityCheck out my previous blog post on what the afterprocessor can do:Spring 5.0.x source code learning series 8: Instantiating beans using constructors to create beans, autowiring, and loop dependenciesChapter 3:The post-processor and execution sequence involved in the instantiation of spring beans. Finally, throughAutowiredAnnotationBeanPostProcessorThe post-processor processing will place all of the supported autowiring properties of the current class withInjectionMetadataType object save, which attributes are supported by autowiring? Read on.

3.1 How does Spring select variables identified by the @Autowired annotation for dependency injection

  • Please read the comments and source code explanation in the figure below

  • Org. Springframework. Beans. Factory. The annotation. AutowiredAnnotationBeanPostProcessor# buildAutowiringMetadata source analysis

    private InjectionMetadata buildAutowiringMetadata(finalClass<? > clazz) {
    	// Store the current class including the @autowired annotation fields and methods of the parent class
        List<InjectionMetadata.InjectedElement> elements = newArrayList<>(); Class<? > targetClass = clazz;do {
        	// store all @autowired annotated fields and methods in targetClass
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
    
            ReflectionUtils.doWithLocalFields(targetClass, field -> {
            	// new JDK1.8 feature, passing in a method, inside the method is to get all the fields of the current class (excluding the parent class).
                // include your own private variables), and loop through the passed method,
                // The current method
    
                // Determine if the current field has an @autowired annotation
                AnnotationAttributes ann = findAutowiredAnnotation(field);
                if(ann ! =null) {
                	// Check whether the current field is static modifier ===> static variable, if so, only return
                    if (Modifier.isStatic(field.getModifiers())) {
                        if (logger.isWarnEnabled()) {
                            logger.warn("Autowired annotation is not supported on static fields: " + field);
                        }
                        return;
                    }
                    boolean required = determineRequiredStatus(ann);
                    // Wrap the fields as AutowiredFieldElement objects and store them in the list you created initially
                    currElements.add(newAutowiredFieldElement(field, required)); }}); ReflectionUtils.doWithLocalMethods(targetClass, method -> {// This method is the parent of the current class
                //), and executes the currently passed methods one by one
    
                // Check whether the traversal method is a bridge method
                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                if(! BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;
                }
    
                // Get the @autowired annotation for the current method and check to get the real method (because it is possible that the current class is a proxy object, interface, etc.)
                AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
                if(ann ! =null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                	// Check whether the current method is static
                    if (Modifier.isStatic(method.getModifiers())) {
                        if (logger.isWarnEnabled()) {
                            logger.warn("Autowired annotation is not supported on static methods: " + method);
                        }
                        return;
                    }
                    if (method.getParameterCount() == 0) {
                        if (logger.isWarnEnabled()) {
                            logger.warn("Autowired annotation should only be used on methods with parameters: "+ method); }}boolean required = determineRequiredStatus(ann);
    
                    // Find the parameter descriptor in the current method
                    PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                    // Wrap the set method and descriptor for the attribute to be passed in as an AutowiredMethodElement class and add it to the list collection created initially
                    currElements.add(newAutowiredMethodElement(method, required, pd)); }}); elements.addAll(0, currElements);
            // Get the class of the parent class, filter the attributes and methods of the parent class
            targetClass = targetClass.getSuperclass();
        }
        while(targetClass ! =null&& targetClass ! = Object.class);// Finally returns an InjectionMetadata Object containing all bands of the current class and its parent (excluding the Object class)
        // @autowired annotated methods and bullets
        return new InjectionMetadata(clazz, elements);
    }	
    Copy the code
  • In conclusion, AutowiredAnnotationBeanPostProcessor post processor MergedBeanDefinitionPostProcessors post processor’s role is to the current class and its parent class (does not contain Object class) all contain @ Autowire The non-static fields and non-static parameter methods of the d annotation are stored as InjectionMetadata objectsinjectionMetadataCacheProperties of the

3.2 Spring logic for dependency injection

  • When you do dependency injection, it’s definitely donepopulateBeanMethod, the specific results are shown in the figure below:

So far, Spring has targeted dependency injection functionalityThe preparatory workIt’s almost done. Why is it preparation? Because then you have to do the real thinginjectThe property method is injected, and the dependent object is finally assigned via Spring’s beanFacotry or directly from the cache. At this point, the processing of the Spring @Autowired annotation is complete.

Four,

  • To sum up, in view of the main core of the @autowired annotation processing AutowiredAnnotationBeanPostProcessor post processor MergedBeanDefinitionPostProcessor identity, It will filter out all non-static fields and non-static methods annotated with @AutoWired as candidates, and finally fetch the dependent objects through Spring’s bean factory, using reflection techniques to complete the injection
  • I am a slow walker, but I never walk backwards.