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,最后标记为手动注册
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258

推荐阅读更多精彩内容