文章目录
前言
在通常情况下,Spring容器的中的Bean对象是无法直接获取容器的相关属性的,我们都知道这么做是为了解耦。但在某些特殊情况下,我们为了某些特殊功能,可能要求bean持有一些容器属性,于是Spring就给我们提供了Aware接口,它允许实现它的bean获取容器的相关属性。
使用Aware的优缺点:
- 优点:使Bean能感知到Spring容器,可以调用Spring容器的资源。
- 缺点:增加了Bean和Spring容器之间的耦合性。
SpringBoot Version:2.1.7
Aware接口介绍
先来看看Spring自带的几种Aware接口:
再解释下这些Aware接口的含义:
Aware接口 | 作用 |
---|---|
BeanNameAware | 获取bean在容器中的beanName |
BeanClassLoaderAware | 获取类加载器 |
BeanFactory | 获取创建bean的工厂 |
EnvironmentAware | 获取环境变量 |
EmbeddedValueResolverAware | 获取Spring容器加载的properties文件属性值 |
ResourceLoaderAware | 获取资源加载器 |
ApplicationEventPublisherAware | 获取事件发布(广播)器 |
MessageSourceAware | 获取消息处理器 |
ApplicationContextAware | 获取上下文 |
实验代码
两个Bean:
TestBean.java
import lombok.Data;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component("testBean")
@Data
public class TestBean implements BeanNameAware, EnvironmentAware, MyAware {
private String beanName;
private Environment environment;
private TestBean2 testBean2;
@Override
public void setBeanName(String name) {
this.beanName = name;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setTestBean2(TestBean2 testBean2) {
this.testBean2 = testBean2;
}
}
TestBean2.java
import lombok.Data;
import org.springframework.stereotype.Component;
@Component("testBean2")
@Data
public class TestBean2 {
// 自定义划水bean
}
再写一个启动加载器,方便启动后控制台能看到效果:
ResultCommandLineRunner.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class ResultCommandLineRunner implements CommandLineRunner {
@Autowired
private TestBean testBean;
@Override
public void run(String... args) throws Exception {
System.out.println(testBean.toString());
}
}
自定义Aware接口:
MyAware.java
import org.springframework.beans.factory.Aware;
public interface MyAware extends Aware {
void setTestBean2(TestBean2 testBean2);
}
最后的最后还需要一个后置处理器,用于处理我们自定义的Aware:
MyAwareProcessor.java
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class MyAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext configurableApplicationContext;
public MyAwareProcessor(ConfigurableApplicationContext configurableApplicationContext) {
this.configurableApplicationContext = configurableApplicationContext;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Aware) {
if (bean instanceof MyAware) {
((MyAware) bean).setTestBean2((TestBean2) configurableApplicationContext.getBean("testBean2"));
}
}
return bean;
}
}
- 你可能疑惑为什么自定义的Aware需要BeanPostProcessor实现
看看控制台输出,Aware确实都生效了:
TestBean(beanName=testBean, environment=StandardServletEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[MapPropertySource {name='server.ports'}, ConfigurationPropertySourcesPropertySource {name='configurationProperties'}, StubPropertySource {name='servletConfigInitParams'}, ServletContextPropertySource {name='servletContextInitParams'}, PropertiesPropertySource {name='systemProperties'}, OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}, RandomValuePropertySource {name='random'}, OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.properties]'}]}, testBean2=TestBean2())
跟进源码
这次跟进源码的顺序跟之前可能有些不一样,因为几个关键的回调函数都藏得太深了,所以这次反过来,从回调函数往回跟。
当然,如果你真的非常想知道整个流程(SpringApplication#run -> Aware回调),那么你可跟着栈帧信息追,比如下面这个样子,本篇博客只记录一些关键流程:
在启动应用前,我打了几个断点,方便调试:
之后启动程序,就能进入setBeanName函数处的断点了:
返回上一层,来到invokeAwareMethods:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
- 就是判断实现关系,然后回调对应覆写的实现方法,因为我们只实现了BeanNameAware,所以这段代码中只回调了setBeanName方法。
继续返回上一层:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 刚刚从这里出来
// BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 后置处理器回调
// 其中ApplicationContextAwareProcessor就回调了如下Aware的实现:
// EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware
// ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
跟进applyBeanPostProcessorsBeforeInitialization方法:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
- 看到这里遍历BeanPostProcessor了吗,这就是为什么我们实验代码需要后置处理器。
看看我们当前有哪些后置处理器(getBeanPostProcessors返回):
- 在这里,我们只需关注ApplicationContextAwareProcessor、MyAwareProcessor。
我们先跟进ApplicationContextAwareProcessor的postProcessBeforeInitialization实现:
org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization
@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
// 来到这里
invokeAwareInterfaces(bean);
}
return bean;
}
跟进invokeAwareInterfaces方法,发现就是回调剩余SpringBoot自带Aware:
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
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);
}
}
}
当上面applyBeanPostProcessorsBeforeInitialization
方法的for循环轮到MyAwareProcessor且bean为testBean
时,就会进入:
可以发现相关源码都是回调,没什么好说的,看了这个源码,也只是有助于我们了解它的回调机制、顺序罢了,日常开发看文档应该也知道各个Aware是个什么用法。
那我为什么还要来特地看看呢?因为后面看SpringBoot源码的时候遇到了,想了解下它的回调机制、如何自定义Aware,于是就写下了这篇博客。
一个可能会踩的坑
虽说Aware可以获取Spring容器中的其它属性/组件,但并不是所有属性/组件都需要通过实现Aware获取,就比如实验代码TestBean
中的·Environment·,要让TestBean
持有Environment
bean,我们可以改成如下代码,控制台输出不变:
@Component("testBean")
@Data
public class TestBean implements BeanNameAware, EnvironmentAware, MyAware {
private String beanName;
@Autowired
private Environment environment;
private TestBean2 testBean2;
@Override
public void setBeanName(String name) {
this.beanName = name;
}
// @Override
// public void setEnvironment(Environment environment) {
// this.environment = environment;
// }
@Override
public void setTestBean2(TestBean2 testBean2) {
this.testBean2 = testBean2;
}
}