springboot源码解析-管中窥豹系列之aware(六)

丰极 2021-01-14 16:38:22
SpringBoot 源码 解析 系列 管中窥豹


一、前言

  • Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去。
  • 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot源码管中窥豹系列。

 简介

二、ApplicationContextAware

  • 假设我们想使用某个bean, 如果是在@Component类下面,直接用@Autowired引用就行了
  • 假设我们想在某个静态方法里面用,就不能用上面的方法了
  • 你可能想用new Bean()的方式,new一个,但是这个bean里面的@Autowired引用用不了
  • 如果有一个静态的全局ApplicationContext就好了,用spring的能力获取bean: ApplicationContext.getBean(clazz)
  • ApplicationContextAware就是这个用处
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
public interface Aware {
}

我们写一个实现类:


import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
private static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
}
}
  • 通过setApplicationContext,把applicationContext赋值到本地静态变量
  • 通过ApplicationContext的getBean就可以在静态方法中使用任何bean的能力了

三、源码分析

我们进入SpringApplication的run方法:

public ConfigurableApplicationContext run(String... args) {
...
try {
...
refreshContext(context);
...
}
catch (Throwable ex) {
...
}
...
return context;
}

我们进入refreshContext(context)内部:

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
}
}
}

这个refresh是spring的核心方法,以后会多次用到,内容太多,我们这次只关注一个方法:

  • prepareBeanFactory(beanFactory);
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
...
}
}

我们先看prepareBeanFactory(beanFactory):

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
...
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
...
}

我们看一下这个addBeanPostProcessor方法


private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
// Remove from old position, if any
this.beanPostProcessors.remove(beanPostProcessor);
// Track whether it is instantiation/destruction aware
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
// Add to end of list
this.beanPostProcessors.add(beanPostProcessor);
}
  • 先remove,再add
  • beanPostProcessors是一个线程安全的list: CopyOnWriteArrayList
  • 我们往下看看new ApplicationContextAwareProcessor(this),注意:this是ApplicationContext
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
/**
* Create a new ApplicationContextAwareProcessor for the given context.
*/
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
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);
}
}
}
  • 构造方法,把applicationContext设到本地变量上
  • 实现接口的方法:postProcessBeforeInitialization,回调的时候会用,主要是校验权限
  • 最下面的invokeAwareInterfaces是个私有的核心回调方法,根据不同类型,有不同回调

我们看到除了ApplicationContextAware,还有其它的aware, 总共6个

  • EnvironmentAware:环境变量
  • EmbeddedValueResolverAware:值解析器
  • ResourceLoaderAware:资源加载器
  • ApplicationEventPublisherAware:事件发布器
  • MessageSourceAware:信息处理器
  • ApplicationContextAware:spring容器

比如我们想用全局的环境变量,就有EnvironmentAware,想用spring的事件就用ApplicationEventPublisherAware,等等

  • 来源找到了,ApplicationContextAwareProcessor什么时候执行的呢?
  • 这个比较麻烦,我们后面单开一节再详细的去看。

 丰极

欢迎关注微信公众号:丰极,更多技术学习分享。

版权声明
本文为[丰极]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/zhangbin1989/p/14278018.html

  1. Rocketmq CPP client visual studio 2019 compilation
  2. Usage of data custom attribute in jquery
  3. Common decompression in Linux
  4. Upload large files in Java
  5. Sentry (v20.12.1) k8s cloud native architecture exploration, sentry for JavaScript manual capture event basic usage
  6. Sentry (v20.12.1) k8s cloud native architecture exploration, sentry for JavaScript manual capture event basic usage
  7. Docker + MySQL Cluster + read / write separation + MYCAT Management + vertical sub database + load balancing
  8. Docker + MySQL Cluster + read / write separation + MYCAT Management + vertical sub database + load balancing
  9. Java use interceptor infinite forwarding / redirection infinite loop / redirection times too many error (stack overflow error) solution
  10. Java use interceptor infinite forwarding / redirection infinite loop / redirection times too many error (stack overflow error) solution
  11. 010_ MySQL
  12. 010_ MySQL
  13. Fast integration of imsdk and Huawei offline push
  14. 消息队列之RabbitMQ
  15. Rabbitmq of message queue
  16. 初学java进制转换方面补充学习
  17. Learn java base conversion supplementary learning
  18. 了解一下RPC,为何诞生RPC,和HTTP有什么不同?
  19. 了解一下RPC,为何诞生RPC,和HTTP有什么不同?
  20. 初学java进制转换方面补充学习
  21. Learn about RPC, why RPC was born, and what's the difference between RPC and HTTP?
  22. Learn about RPC, why RPC was born, and what's the difference between RPC and HTTP?
  23. Learn java base conversion supplementary learning
  24. JDBC测试连接数据库
  25. JDBC test connection database
  26. 大厂面试官竟然这么爱问Kafka,一连八个Kafka问题把我问蒙了?
  27. The interviewers of big factories love to ask Kafka so much. I'm blinded by eight Kafka questions in a row?
  28. 安卓开发和java开发有什么区别!2021年BATJ30套大厂Android经典高频面试题,面试必问
  29. Spring Security OAuth2.0認證授權四:分散式系統認證授權
  30. What's the difference between Android development and java development! 2021 batj30 Android classic high frequency interview questions
  31. Spring security oauth2.0 authentication and authorization 4: distributed system authentication and authorization
  32. Java微服务 vs Go微服务,究竟谁更强!?
  33. 大厂面试官竟然这么爱问Kafka,一连八个Kafka问题把我问蒙了?
  34. Who is stronger, Java microservice vs go microservice!?
  35. Java微服务 vs Go微服务,究竟谁更强!?
  36. The interviewers of big factories love to ask Kafka so much. I'm blinded by eight Kafka questions in a row?
  37. Who is stronger, Java microservice vs go microservice!?
  38. springboot异常处理之404
  39. Spring boot exception handling 404
  40. Spring Boot Security 国际化 多语言 i18n 趟过巨坑
  41. springboot异常处理之404
  42. Spring boot security international multilingual I18N
  43. Spring boot exception handling 404
  44. Netty系列化之Google Protobuf编解码
  45. Netty之编解码
  46. Java编解码
  47. Netty解码器
  48. Netty与TCP粘包拆包
  49. Netty开发入门
  50. Java集合遍历时遇到的坑
  51. Spring IOC 源码解析(下)
  52. Spring IoC源码解析(上)
  53. Google protobuf codec of netty serialization
  54. Encoding and decoding of netty
  55. Java codec
  56. Netty decoder
  57. Netty and TCP packet sticking and unpacking
  58. Introduction to netty development
  59. Problems encountered in Java collection traversal
  60. Spring IOC source code analysis (2)