一、前言

  • 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什么时候执行的呢?
  • 这个比较麻烦,我们后面单开一节再详细的去看。

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

springboot源码解析-管中窥豹系列之aware(六)的更多相关文章

  1. springboot源码解析-管中窥豹系列

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

  2. springboot源码解析-管中窥豹系列之自动装配(九)

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

  3. springboot源码解析-管中窥豹系列之BeanDefine如何加载(十三)

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

  4. springboot源码解析-管中窥豹系列之BeanPostProcessor(十二)

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

  5. springboot源码解析-管中窥豹系列之bean如何生成?(十四)

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

  6. springboot源码解析-管中窥豹系列之web服务器(七)

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

  7. springboot源码解析-管中窥豹系列之BeanDefinition(八)

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

  8. springboot源码解析-管中窥豹系列之EnableXXX(十)

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

  9. springboot源码解析-管中窥豹系列之BeanFactoryPostProcessor(十一)

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

随机推荐

  1. 如何实现 token 加密(来自github每日一题)

    需要一个secret(随机数) 后端利用secret和加密算法(如:HMAC-SHA256)对payload(如账号密码)生成一个字符串(token),返回前端 前端每次request在header中 ...

  2. 从 0 开始的min_max容斥证明

    二项式反演 \[f_n=\sum\limits_{i=0}^nC^i_ng_i \Leftrightarrow g_n=\sum\limits_{i=0}^n{(-1)}^{n-i}f_i \] 证明 ...

  3. Python轻松入门到项目实战-实用教程

    本课程完全基于Python3讲解,针对广大的Python爱好者与同学录制.通过本课程的学习,可以让同学们在学习Python的过程中少走弯路.整个课程以实例教学为核心,通过对大量丰富的经典实例的讲解.让 ...

  4. Day5 - 03 函数的参数-位置参数和默认参数

    位置参数    调用函数时,传入函数的参数,按照位置顺序依次赋值给函数的参数.#计算乘方的函数                def power(x, n):            s = 1     ...

  5. SQL盲注、SQL注入 - SpringBoot配置SQL注入过滤器

    1. SQL盲注.SQL注入   风险:可能会查看.修改或删除数据库条目和表.   原因:未对用户输入正确执行危险字符清理.   固定值:查看危险字符注入的可能解决方案. 2. pom.xml添加依赖 ...

  6. Java_day_01

    一.方法的定义 方法的定义在Java中可以使用多种方式,如果在定义的方法名前面加上 public static 关键字,即可直接在主方法(main)中调用 public class Method{ p ...

  7. PPT技术干货1(上)——设计审美

    序言 PPT直接反映了一个人的能力和态度,PPT能直接反映出老板最看重的4个关键能力: 逻辑思维:全局思考,洞察关键 数据思维:数据分析,指导决策 设计思维:美观大方,彰显专业 工作效率:效率高,出活 ...

  8. 2.Redis info命令详解

    命令 127.0.0.1:6379> info [server|clients|memory|stats|...] # Server redis_version:5.0.4 #redis版本 r ...

  9. AOP的姿势之 简化 MemoryCache 使用方式

    0. 前言 之前写了几篇文章介绍了一些AOP的知识, 但是还没有亮出来AOP的姿势, 也许姿势漂亮一点, 大家会对AOP有点兴趣 内容大致会分为如下几篇:(毕竟人懒,一下子写完太累了,没有动力) AO ...

  10. Abp小试牛刀之 图片上传

    图片上传是很常见的功能,里面有些固定的操作也可以沉淀下来. 本文记录使用Abp vNext做图片上传的姿势. 本文的技术核心与Abp无关,Abp只是手段! 目标 上传图片----->预览图片-- ...