In-depth analysis of Spring Aware principles

1. What is Spring Aware

In Spring learning, dependency injection is the biggest highlight. Beans owned by users are not aware of the existence of the Spring container, which can reduce the coupling between Beans. However, in the development, it is inevitable to use the functions
of the Spring container itself. and resources. At this time, the Bean needs to be aware of the existence of the Spring container in order to use the resources provided by Spring, which is the so-called Spring Aware.

Spring Aware is designed by Spring for the internal use of the framework. If Spring Aware is used, then the Bean will be coupled with the Spring framework.

2. The purpose of designing Spring Aware

The purpose of designing Spring Aware is to allow Bean to obtain the built-in components of the Spring container.
For example, if a custom component wants to use some components at the bottom of the Spring container (such as: ApplicationContext, BeanFactory, etc.), at this time, it is only necessary to let the custom component implement the XxxAware interface. At this time, when Spring creates an object, it will call the method (setXxx() method) defined by the XxxAware interface to inject related components.

Commonly used Aware:

class name effect
ApplicationContextAware Get the current application context
BeanNameAware Get the bean name in the container
BeanClassLoaderAware get class loader
BeanFactoryAware Get the bean factory
EnviromentAware get environment variables
EnvironmentValueResolverAware Get the properties file attribute value loaded by the spring container
ResourceLoaderAware get resource loader
ApplicationEventPublisherAware get application publisher
MessageSourceAware get text message

3. Overview of XxxAware interface

The custom component implements the XxxAware interface:

@Component
public class Employee implements ApplicationContextAware {
    
    
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        this.applicationContext = applicationContext;
    }
}

From the source code of the Employee class, it can be seen that if the ApplicationContextAware interface is implemented, the setApplicationContext() method needs to be implemented. When the IOC container starts and creates the Employee object, Spring will call the setApplicationContext() method and pass the ApplicationContext object into the setApplicationContext() method. We only need to define a member variable of the ApplicationContext type in the Employee class to receive the setApplicationContext( ) method parameters, you can use the ApplicationContext object.

In fact, in Spring, there are many designs similar to the ApplicationContextAware interface. In essence, the XxxAware interface in Spring inherits the Aware interface. Let's look at the source code of the Aware interface, as follows:

package org.springframework.beans.factory;
/**
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 */
public interface Aware {
    
    

}

It can be seen that the Aware interface is an interface introduced in Spring 3.1, and no method is defined in the Aware interface.
Next, let's see which interfaces inherit the Aware interface, as follows:

insert image description here

Four, XxxAware interface case

The ApplicationContextAware interface is used a lot. Let’s talk about this interface first. The IOC container can be obtained through the ApplicationContextAware interface.

First, create a Blue class and implement the ApplicationContextAware interface, and output the ApplicationContext in the implemented setApplicationContext(), as shown below:

package io.mykit.spring.plugins.register.bean;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * @description 测试ApplicationContextAware接口
 */
public class Blue implements ApplicationContextAware {
    
    
    private ApplicationContext applicationContext
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        System.out.println("传入的ioc:" + applicationContext);
        this.applicationContext = applicationContext;
    }
}

We can also implement several XxxAware interfaces for the Blue class at the same time. For example, if the Blue class implements a BeanNameAware interface, we can obtain the name of the current bean in the Spring container through the BeanNameAware interface, as shown below:

/**
 * @description 测试ApplicationContextAware接口
 */
public class Blue implements ApplicationContextAware, BeanNameAware {
    
    
    private ApplicationContext applicationContext
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        System.out.println("传入的ioc:" + applicationContext);
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanName(String name) {
    
    
        System.out.println("当前bean的名字");
    }

}

Next, we implement another EmbeddedValueResolverAware interface, and we can obtain the StringValue parser through the EmbeddedValueResolverAware interface. As follows:

/**
 * @description 测试ApplicationContextAware接口
 */
public class Blue implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
    
    
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        System.out.println("传入的ioc:" + applicationContext);
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanName(String name) {
    
    
        System.out.println("当前bean的名字");
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
    
    
        String resolveStringValue = resolver.resolveStringValue("你好${os.name} 年龄:#{20*18}");
        System.out.println("解析后的字符串为:" + resolveStringValue);
    }
}

Next, we need to mark the @Component annotation on the Blue class to add the Blue class to the IOC container, as follows:

@Component
public class Blue implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
    
    }

The output result information is as follows:

当前bean的名字:blue
解析后的字符串为:你好Windows 10 年龄:360
传入的ioc:org.springframework.context.annotation.AnnotationConfigApplicationContext@5ecddf8f

Five, XxxAware principle

The underlying principle of XxxAware is implemented by the XxxAwareProcessor class. For example, here we take the ApplicationContextAware interface as an example. The underlying principle of the ApplicationContextAware interface is implemented by the ApplicationContextAwareProcessor class. It can be seen from the source code of the ApplicationContextAwareProcessor class that it implements the BeanPostProcessor interface, which is essentially a post-processor.

class ApplicationContextAwareProcessor implements BeanPostProcessor

Next, let's take the principle of analyzing the ApplicationContextAware interface as an example to see how Spring injects the ApplicationContext object into the Blue class.
We put a breakpoint on the setApplicationContext() method of the Blue class, as follows:

insert image description here

Next, we run in debug mode

insert image description here

Here, we can see that the ApplicationContext object has actually been injected into the setApplicationContext() method in the Blue class. We select the postProcessBeforeInitialization() method in IDEA's method call stack, as follows:

insert image description here

We double-click the call stack of the postProcessBeforeInitialization() method in IDEA, and it will automatically locate the postProcessBeforeInitialization() method in IDEA, as shown below:

insert image description here

In fact, the class where the postProcessBeforeInitialization() method is located is ApplicationContextAwareProcessor.

Let's take a look at the invokeAwareInterfaces() method called in the postProcessBeforeInitialization() method, as follows:

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
  
  。。。
  invokeAwareInterfaces(bean);
  return bean;
  。。。
  
  private void invokeAwareInterfaces(Object bean) {
    
    
      if (bean instanceof EnvironmentAware) {
    
    
          ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
      }
      if (bean instanceof EmbeddedValueResolverAware) {
    
    
          ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
      }
      if (bean instanceof ResourceLoaderAware) {
    
    
          ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
      }
      if (bean instanceof ApplicationEventPublisherAware) {
    
    
          ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
      }
      if (bean instanceof MessageSourceAware) {
    
    
          ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
      }
      if (bean instanceof ApplicationContextAware) {
    
    
          ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
      }
}

Summarize:

The principle of XxxAware (based on the bean post-processor to execute the callback method injection component in XxxAware)
customize the bean that implements the XxxAware interface. Before being initialized, the BeanPostProcessor.postProcessBeforeInitialization() method will be executed, and the SetXxx method in the XxxAware interface will be called back. Xxx Inject into a custom bean.

Aware mechanism source code analysis:
When the Spring container is initialized, the third method prepareBeanFactory() in refresh() will be executed, which will register the ApplicationContextAwareProcessor post-processor in the container, and each bean in Spring will call BeanPostProcessor before initialization The .postProcessBeforeInitialization() method, the class that implements the XxxAware interface, can be injected into the instance of the Xxx object.

prepareBeanFactory部分源码:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    
    
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 添加实现Aware机制的后置处理器
   // 忽略下面这些接口的依赖注入分析
   // spring是通过让bean实现xxxAware接口获取相应的对象的实例的,也就没有必要再通过依赖注入的方式获取xxxAware实例对象了
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
}

Guess you like

Origin blog.csdn.net/qq_36602071/article/details/129741747