Article directory
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:
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:
Next, we run in debug mode
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:
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:
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);
}