一、前言

  • 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. react路由初探(1)

    import React from 'react'; import logo from './logo.svg'; import './App.css'; class About extends Re ...

  2. CF500G / T148321 走廊巡逻

    题目链接 这题是 Codeforces Goodbye 2014 的最后一题 CF500G,只是去掉了 \(u \not= x, v \not = v\) 的条件. 官方题解感觉有很多东西说的迷迷瞪瞪 ...

  3. Java集合源码分析(三)——LinkedList

    简介 LinkedList是一个链表结构的列表,也可以被作为堆栈.队列或双端队列使用.它继承于AbstractSequentialList双向链表,实现了List.Deque.Cloneable.ja ...

  4. Servlet中获取请求参数问题

    1.GET方法,可以通过getParamter方法反复获取同一个变量的数据: 2.POST方法,需要注意请求类型(content-Type)是否是application/x-www-form-urle ...

  5. 女朋友突然问我DNS是个啥....

    女朋友突然问我DNS是个啥.... 今天晚上我正在床上躺着刷手机,然后我女朋友突然说她的电脑坏了.说连着WIFi上不了网,让我给她看一下.(这就是有个程序员男朋友的好处) 然后我拿到电脑看了一下发现访 ...

  6. md5 的基本使用

    import hashlib def make_password(password): md5=hashlib.md5() # 实例化 md5.update(password.encode(encod ...

  7. mysql主从双机keepalived配置

    1.关闭selinux SELINUX=disabled 2.yum安装keepalived yum install -y keepalived 3.修改配置文件 主库配置文件: ! Configur ...

  8. jsp+servlet实现美妆店铺开发

    一般的商城都有用户端和商城端两个部分,用户端就是给普通用户使用的,像我们在淘宝购物,我们就是使用的用户端:然而淘宝还分了很多个店铺,每个店铺的商品都是店老板安排人员去管理,那店老板管理自己的店铺用到的 ...

  9. 使用collectd+influxdb+grafna监控进程的健康状态

    一,前言 本文将介绍如何使用collectd+influxdb+grafna进行进程的监控,监控项为:进程健康状态. 思路为:使用collectd的processes插件进行程序进程的监控,储存到in ...

  10. jmeter接口测试笔记

    1.接口测试基础 API:Application Programming Interface,即调用应用程序的通道. 接口测试遵循点 接口的功能性实现:检查接口返回的数据与预期结果的一致性. 测试接口 ...