Spring Boot-11-Spring Aware解析

上文中,介绍了几种 Spring Boot 中的属性配置方式,那么配置完成之后,要在系统里面怎么获取,下面来介绍一种通过 Spring Aware 获取属性的方式

获取属性

这里利用之前学过的启动加载器去打印要获取的属性, 这里还是创建一个类 EnvironmentApplicationRunner 然后去实现 ApplicationRunner ,然后再去实现一个 EnvironmentAware 用来获取 Environment 对象,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Component
@Slf4j
public class EnvironmentApplicationRunner implements ApplicationRunner, EnvironmentAware {

private Environment environment;

@Override
public void run(ApplicationArguments args) throws Exception {
log.info(environment.getProperty("environment.test"));
}

@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}

之后运行,日志打印

1
2020-02-14 15:15:44.427  INFO 32056 --- [           main] c.z.s.e.s.EnvironmentApplicationRunner   : 30

这里已经成功获取到系统配置的属性了

Spring Aware

在 Spring 框架中,Bean 是感知不到容器的存在的,当我们需要使用 Spring 容器的一些功能或者资源的时候,就需要用到 Spring Aware 来实现, 比如我们上面用的 EnvironmentAware 就可以用来获取 Environment 对象

常用的 Spring Aware

Spirng 提供了一些常用的 Aware, 如下:

类名 作用
BeanNameAware 获取容器中的Bean名称
BeanClassLoaderAware 获得类加载器
BeanFactoryAware 获得BeanFactory
EnvironmentAware 获取环境变量
EmbeddedValueResolverAware 获取容器加载的 properties 文件属性值
ResourceLoaderAware 获取资源加载器
ApplicationEventPublisherAware 获取系统广播器
MessageSourceAware 获得文本信息
ApplicationContextAware 获得当前应用上下文

原理解析

为什么被Spring管理的类,只要实现了Aware接口,Spring就会自动把对应的对象注入进来,带着这个问题,我们来看一下源码.

首先,从我们熟悉的 refresh() 方法入手, 这里面的 prepareBeanFactory() 方法,这个方法具体的作用我们之前有写,这里就只看关于 Aware 的一些代码,如下:

image

对于 BeanPostProcessor 我们已经很熟悉了,然后我们进入这个类,看一下他里面的方法

image

然后再看一下这里调用的 invokeAwareInterface() 这个方法

image

这个类中,会处理一部分的 Aware ,那么这个方法是什么时机被调用的,在 doCreateBean() 这个方法后面会调用 initializeBean() 这个方法,进入看一下:

image

这里有先是一个 Aware 相关的方法 invokeAwareMethods() ,进去看一下

image

这个方法中,会处理一部分的 Aware , 然后就是 applyBeanPostProcessorsBeforeInitialization() 这个方法,进入看一下

image

这里就会执行 prepareBeanFactory() 方法中添加的那个 ApplicationContextAwareProcessor ,处理其他的 Aware

Spring Aware 的加载流程大概就是这样

自定义Spring Aware

了解了 Spring Aware 的实现原理,之后,我们可以自定义一个 Spring Aware, 首先仿照上面用到的 EnvironmentAware ,新建一个 MySpringAware继承 Aware 接口, 代码如下:

1
2
3
4
5
public interface MySpringAware extends Aware {

void setAwareModel(AwareModel awareModel);

}

然后这里用到的 AwareModel 代码如下:

1
2
3
4
5
6
7
@Component
@Data
public class AwareModel {

private String name = "defaultName";

}

然后我们需要一个 BeanPostProcessor 对应源码中的 ApplicationContextAwareProcessor,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class MyAwareProcessor implements BeanPostProcessor {

private final ConfigurableApplicationContext applicationContext;

public MyAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MySpringAware) {
((MySpringAware) bean).setAwareModel((AwareModel) applicationContext.getBean("awareModel"));
}
return bean;
}

}

最后在我们开始的那个启动加载器里,实现我们自定义的 Aware 来测试一下是否生效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Component
@Slf4j
public class EnvironmentApplicationRunner implements ApplicationRunner, EnvironmentAware, MySpringAware {

private Environment environment;

private AwareModel awareModel;

@Override
public void run(ApplicationArguments args) throws Exception {
log.info(environment.getProperty("environment.test"));
log.info(awareModel.getName());
}

@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}

@Override
public void setAwareModel(AwareModel awareModel) {
this.awareModel = awareModel;
}
}

启动,日志输出如下:

1
2
2020-02-14 17:17:38.894  INFO 22756 --- [           main] c.z.s.e.s.EnvironmentApplicationRunner   : 34
2020-02-14 17:17:38.894 INFO 22756 --- [ main] c.z.s.e.s.EnvironmentApplicationRunner : defaultName

总结

了解Spring Aware的用法,还有一些常用的 Spring Aware, 以及他们的工作原理,源码部分也比较简单

Aware加载流程图如下:
image

自定义Aware流程图如下:
image