postProcessBeanFactory方法源码跟踪
看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead
代码过宽,可以shift + 鼠标滚轮 左右滑动查看
AbstractApplicationContext类refresh()方法中的第四个调用方法postProcessBeanFactory()的跟踪。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...
try {
// Allows post-processing of the bean factory in context subclasses.
// 允许在上下文的子类中对bean factory进行后处理
postProcessBeanFactory(beanFactory);
···
}
断点进入跟踪。
postProcessBeanFactory(零)
此方法的实现在AbstractRefreshableWebApplicationContext类中,它是XmlWebApplicationContext的父类。进入方法查看:
/**
* Register request/session scopes, a {@link ServletContextAwareProcessor}, etc.
*
* 注册request/session scopes,一个ServletContextAwareProcessor处理器等。
*/
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//ServletContextAwareProcessor中拿到应用上下文持有的servletContext引用和servletConfig引用
//1.添加ServletContextAwareProcessor处理器
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
//在自动注入时忽略指定的依赖接口
//通常被应用上下文用来注册以其他方式解析的依赖项
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
//2.注册web应用的scopes
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
//3.注册和环境有关的beans
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
postProcessBeanFactory方法的接口声明在AbstractApplicationContext类中:
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for registering special
* BeanPostProcessors etc in certain ApplicationContext implementations.
*
* 在应用上下文的内部bean factory初始化之后修改bean factory。
* 所有的bean definitions已经被加载,但是还没有bean被实例化。
* 在明确的ApplicationContext实现中允许指定BeanPostProcessors等的注册
*/
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
1.addBeanPostProcessor
跟踪标记为1的方法
此方法的实现在AbstractBeanFactory类中
这里要注册的处理器ServletContextAwareProcessor带有Aware单词,这个单词是“有意识、能意识到”的意思,个人理解就是能意识到ServletContext的存在,也就是能拿到ServletContext的引用,或者能对其进行设置。
//1.添加ServletContextAwareProcessor处理器
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
/**
* Add a new BeanPostProcessor that will get applied to beans created
* by this factory. To be invoked during factory configuration.
* <p>Note: Post-processors submitted here will be applied in the order of
* registration; any ordering semantics expressed through implementing the
* {@link org.springframework.core.Ordered} interface will be ignored. Note
* that autodetected post-processors(e.g. as beans in an ApplicationContext)
* will always be applied after programmatically registered ones.
*
* 添加一个新的BeanPostProcessor,在工厂创建bean的时候会应用得到。
* 在工厂配置时被调用。
* 注意:Post-processors是按照注册的顺序被提交的
* 任何通过实现Ordered接口的排序表达式都将被忽略。
* 注意,自动检测的post-processors(作为一个在ApplicationContext的bean)总是在编程方式注册后才会被使用。
*/
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
//beanPostProcessors是一个ArrayList,持有在创建bean时被应用的BeanPostProcessors
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
//InstantiationAwareBeanPostProcessor这个接口有两个方法
//一个在实例化之前被调用
//一个在实例化之后,初始化之前被调用,可以用来做一些特殊用途,比如代理
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
//DestructionAwareBeanPostProcessor这个接口只有一个方法,在被销毁前调用
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
}
2.registerWebApplicationScopes
跟踪标记为2的方法
此方法的实现在WebApplicationContextUtils类中
//2.注册web应用的scopes
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
/**
* Register web-specific scopes ("request", "session", "globalSession", "application")
* with the given BeanFactory, as used by the WebApplicationContext.
*
* 注册web特有的scopes("request", "session", "globalSession", "application")到指定的bean工厂
* 被WebApplicationContext使用
*/
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, ServletContext sc) {
//2.1注册request Scope
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
//注册session Scope
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false));
//注册global session Scope
beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true));
if (sc != null) {
ServletContextScope appScope = new ServletContextScope(sc);
//注册application Scope
beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
// Register as ServletContext attribute, for ContextCleanupListener to detect it.
// 为了能让ContextCleanupListener监听器检测到,
// 将application Scope作为ServletContext的属性进行注册
sc.setAttribute(ServletContextScope.class.getName(), appScope);
}
//ServletRequest.class为key,对象为value放入到了beanFactory的resolvableDependencies属性中
//resolvableDependencies是一个ConcurrentHashMap,映射依赖类型和对应的被注入的value
//value要是依赖类型的实例,要不value就应该是个ObjectFactory
//ObjectFactory和FactoryBean的区别可以看下文参考
beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
//是否存在jsf
if (jsfPresent) {
FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
}
}
2.1 registerScope
跟踪标记为2.1的方法
此方法的实现在AbstractBeanFactory类中
//2.1注册request Scope
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
@Override
public void registerScope(String scopeName, Scope scope) {
Assert.notNull(scopeName, "Scope identifier must not be null");
Assert.notNull(scope, "Scope must not be null");
//singleton和prototype在这个方法中不进行注册
if (SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)) {
//不能替换已存在的 singleton scope和 prototype scope
throw new IllegalArgumentException("Cannot replace existing scopes 'singleton' and 'prototype'");
}
//scopes是AbstractBeanFactory的LinkedHashMap属性
Scope previous = this.scopes.put(scopeName, scope);
//打印日志
if (previous != null && previous != scope) {
//对已经注册过的scope进行替换
if (logger.isInfoEnabled()) {
logger.info("Replacing scope '" + scopeName + "' from [" + previous + "] to [" + scope + "]");
}
}
else {
//没注册过的和同一个实例注册两次的scope都打印日志记录下
if (logger.isDebugEnabled()) {
logger.debug("Registering scope '" + scopeName + "' with implementation [" + scope + "]");
}
}
}
3.registerEnvironmentBeans
跟踪标记为3的方法
此方法的实现在WebApplicationContextUtils类中
//3.注册和环境有关的beans
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
/**
* Register web-specific environment beans ("contextParameters", "contextAttributes")
* with the given BeanFactory, as used by the WebApplicationContext.
*
* 注册web特有的environment beans ("contextParameters", "contextAttributes")到指定工厂中
* 被WebApplicationContext所使用
*/
public static void registerEnvironmentBeans(
ConfigurableListableBeanFactory bf, ServletContext servletContext, ServletConfig servletConfig) {
//单例或者beanDefinition中不包含servletContext进入条件
if (servletContext != null && !bf.containsBean(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME)) {
//3.1注册servletContext单例,注册方法跟踪过一次,这里再跟踪一次加深印象
bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);
}
//单例或者beanDefinition中不包含servletConfig进入条件
if (servletConfig != null && !bf.containsBean(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME)) {
//注册servletConfig单例
bf.registerSingleton(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME, servletConfig);
}
//单例或者beanDefinition中不包含contextParameters进入条件
if (!bf.containsBean(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME)) {
Map<String, String> parameterMap = new HashMap<String, String>();
if (servletContext != null) {
Enumeration<?> paramNameEnum = servletContext.getInitParameterNames();
while (paramNameEnum.hasMoreElements()) {
String paramName = (String) paramNameEnum.nextElement();
//将servletContext参数配置放入集合中
//也就是web.xml中context-param标签里的param-name和param-value
parameterMap.put(paramName, servletContext.getInitParameter(paramName));
}
}
if (servletConfig != null) {
Enumeration<?> paramNameEnum = servletConfig.getInitParameterNames();
while (paramNameEnum.hasMoreElements()) {
String paramName = (String) paramNameEnum.nextElement();
//将servletConfig中的参数配置放入集合
parameterMap.put(paramName, servletConfig.getInitParameter(paramName));
}
}
//以contextParameters作为name,集合转换成不可修改状态,作为value,进行注册
bf.registerSingleton(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME,
Collections.unmodifiableMap(parameterMap));
}
//单例或者beanDefinition中不包含contextAttributes进入条件
if (!bf.containsBean(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME)) {
Map<String, Object> attributeMap = new HashMap<String, Object>();
if (servletContext != null) {
Enumeration<?> attrNameEnum = servletContext.getAttributeNames();
while (attrNameEnum.hasMoreElements()) {
String attrName = (String) attrNameEnum.nextElement();
//将servletContext中设置的Attribute放入集合
attributeMap.put(attrName, servletContext.getAttribute(attrName));
}
}
//以contextAttributes作为name,集合转换成不可修改状态,作为value,进行注册
bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME,
Collections.unmodifiableMap(attributeMap));
}
}
3.1 registerSingleton
跟踪标记为3.1的方法
此方法的实现在DefaultListableBeanFactory类中
//3.1注册servletContext单例
bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
//3.1.1调用父类方法,注册单例
super.registerSingleton(beanName, singletonObject);
//AbstractBeanFactory类中有个集合属性alreadyCreated
//里面保存在至少被创建过一次的beanName
//如果这个集合中存在beanName,那么说明已经进入了bean创建阶段
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
// 无法再修改启动时集合元素(为了稳定迭代)
synchronized (this.beanDefinitionMap) {
//beanName不在beanDefinitionMap中,说明是手动注册
if (!this.beanDefinitionMap.containsKey(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames.size() + 1);
updatedSingletons.addAll(this.manualSingletonNames);
updatedSingletons.add(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
// 仍然处于启动注册阶段
if (!this.beanDefinitionMap.containsKey(beanName)) {
//属于手动注册情况
this.manualSingletonNames.add(beanName);
}
}
//进入这个方法查看
clearByTypeCache();
}
/**
* Remove any assumptions about by-type mappings.
*
* 删除按照类型映射有关的任何假设
*/
private void clearByTypeCache() {
//allBeanNamesByType是单例和非单例beanName的映射,key是依赖类型
this.allBeanNamesByType.clear();
//仅单例beanName的映射,key是依赖类型
this.singletonBeanNamesByType.clear();
}
3.1.1 registerSingleton
跟踪标记为3.1.1的方法
此方法的实现在DefaultSingletonBeanRegistry类中
//2.1调用父类方法,注册单例
super.registerSingleton(beanName, singletonObject);
/**
* Register the given existing object as singleton in the bean registry,
* under the given bean name.
* <p>The given instance is supposed to be fully initialized; the registry
* will not perform any initialization callbacks (in particular, it won't
* call InitializingBean's {@code afterPropertiesSet} method).
* The given instance will not receive any destruction callbacks
* (like DisposableBean's {@code destroy} method) either.
* <p>When running within a full BeanFactory: <b>Register a bean definition
* instead of an existing instance if your bean is supposed to receive
* initialization and/or destruction callbacks.</b>
* <p>Typically invoked during registry configuration, but can also be used
* for runtime registration of singletons. As a consequence, a registry
* implementation should synchronize singleton access; it will have to do
* this anyway if it supports a BeanFactory's lazy initialization of singletons.
*
* 在给定的bean name下,将存在的对象作为单例注册在工厂中
* 给定的实例应该是完全初始化;工厂不执行任何初始化回调(特别是,他不会调用InitializingBean的
* afterPropertiesSet方法)
* 给定的实例也不接收任何销毁回调(像DisposableBean的destroy方法)
* 当在完整的BeanFactory运行时:
* 如果你的bean需要接收初始化或者销毁的回调,注册一个bean definition替代一个存在的实例
* 通常此方法在工厂配置时被调用,也能在运行时单例注册时被调用。
* 作为结果,工厂的实现应该同步单例的访问;如果支持BeanFactory的单例的延迟初始化就不得不这样做
*/
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
Object oldObject = this.singletonObjects.get(beanName);
//不能注册两次
if (oldObject != null) {
throw new IllegalStateException("Could not register object [" + singletonObject +
"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
}
//进入这个方法
addSingleton(beanName, singletonObject);
}
}
/**
* Add the given singleton object to the singleton cache of this factory.
* <p>To be called for eager registration of singletons.
*
* 添加给定单例对象到工厂的单例缓存中
* 用来被提早注册的单例调用
*/
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//singletonObjects是一个ConcurrentHashMap
//用来缓存单例对象
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
//singletonFactories是一个HashMap
//里面缓存着单例工厂
this.singletonFactories.remove(beanName);
//早期单例对象
//earlySingletonObjects是一个HashMap
this.earlySingletonObjects.remove(beanName);
//registeredSingletons是一个LinkedHashSet
//被注册单例的集合,以注册的顺序包含着bean name
this.registeredSingletons.add(beanName);
}
}
postProcessBeanFactory方法也跟踪完了。
未完···
参考
FactoryBean与ObjectFactory区别:
https://blog.csdn.net/m0_38043362/article/details/80284577
总结
- 添加后处理器、忽略依赖接口
- 2.注册web应用的scopes
- 3.注册和环境有关的beans
——————————————————————————————————
- 2
- 在工厂中注册
request
session
globalSession
Scope - 如果 ServletContext 不为null,用Scope实现类包裹后注册到工厂,注册为
application
。同时在ServletContext 的属性中保存一份。 - 在工厂中注册各种可解析依赖
——————————————————————————————————
- 3
- 当 servletContext 不为null时,工厂以及其父工厂中没有对应单例或者BeanDefinition,那么就在工厂中注册单例,并标记为手动注册的单例
- 同上注册 servletConfig
- 拿到 servletContext 和 servletConfig 中的初始参数,都放入到map中,然后注册到工厂,name为 contextParameters ,最后标记为手动注册
- 拿到 servletContext 中的属性,都放入到map中,然后注册到工厂,name为 contextAttributes,最后标记为手动注册
postProcessBeanFactory方法源码跟踪的更多相关文章
- prepareBeanFactory方法源码跟踪
看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...
- loadBeanDefinitions方法源码跟踪(一)
看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractBeanDe ...
- prepareRefresh方法源码跟踪
看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...
- loadBeanDefinitions方法源码跟踪(三)
因为字数超过了限制,所以分成了三篇,承接上篇: https://www.jianshu.com/p/46e27afd7d96 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 4.parseCus ...
- obtainFreshBeanFactory方法源码跟踪
看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...
- loadBeanDefinitions方法源码跟踪(二)
因为字数超过了限制,所以分成了三篇,承接上篇: https://www.jianshu.com/p/a0cfaedf3fc5 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 3.parseDef ...
- erlang下lists模块sort(排序)方法源码解析(一)
排序算法一直是各种语言最简单也是最复杂的算法,例如十大经典排序算法(动图演示)里面讲的那样 第一次看lists的sort方法的时候,蒙了,几百行的代码,我心想要这么复杂么(因为C语言的冒泡排序我记得不 ...
- Java源码跟踪阅读技巧
转:https://www.jianshu.com/p/ab865109070c 本文基于Eclipse IDE 1.Quick Type Hierarchy 快速查看类继承体系. 快捷键:Ctrl ...
- Thread.interrupt()源码跟踪
1 JDK源码跟踪 // java.lang.Thread public void interrupt() { if (this != Thread.currentThread()) checkAcc ...
随机推荐
- SpringBoot集成Freemarker前端模板
1.在pom.xml中引入freemarker的jar包 <dependency> <groupId>org.springframework.boot</groupId& ...
- Tensorflow机器学习入门——ModuleNotFoundError: No module named 'tensorflow.keras'
这个bug的解决办法: # from tensorflow.keras import datasets, layers, models from tensorflow.python.keras imp ...
- 变量的注释(python3.6以后的功能)
有时候导入模块,然后使用这个变量的时候,却没点出后面的智能提示.用以下方法可以解决:https://www.cnblogs.com/xieqiankun/p/type_hints_in_python3 ...
- 如何用一个servlet处理多个请求
一个servlet处理多个请求,原理:利用反射机制获取在selvlet类中的其他方法1.前端页面<%@ page language="java" contentType=&q ...
- Linux引导过程!(重点)
1.开机自检:服务器开机后,将根据主板BIOS (基本输入系统),中的设置对CPU .内存.显卡.键盘等设备进行初步检测,并初始化部分硬件. 2.MBR 引导:当从本机硬盘中启动系统时,首先根据硬盘中 ...
- myBatis mapper接口方法重载问题
在mybatis框架中,写dao层的mapper接口时,是不可以进行方法的重载的,下面是截图证明: 当mapper接口中有方法的重载时,会出现异常, 这是mapper接口中定义的两个方法,进行 ...
- Java入门程序“hello,world!”
1.程序开发步骤说明 开发环境已经搭建完毕,可以开发我们第一个Java程序了. Java程序开发三步骤:编写.编译.运行.(图片介绍) 2.编写Java程序 新建一个普通的记事本,给其命名为Hel ...
- 《React后台管理系统实战 :二》antd左导航:cmd批量创建子/目录、用antd进行页面布局、分离左导航为单独组件、子路由、动态写左导航、css样式相对陷阱
一.admin页面布局及路由创建 0)cmd批量创建目录及子目录 //创建各个目录,及charts和子目录bar md home category product role user charts\b ...
- CNN反向传播算法过程
主模块 规格数据输入(加载,调格式,归一化) 定义网络结构 设置训练参数 调用初始化模块 调用训练模块 调用测试模块 画图 初始化模块 设置初始化参数(输入通道,输入尺寸) 遍历层(计算尺寸,输入输出 ...
- Adroid ViewPage+GridView实现每页6个元素,三页滑动切换
//}//public class MainActivity extends Activity {// private static final float APP_PAGE_SIZE = 16.0f ...