• Spring源码学习笔记(六、Spring启动流程解析:BeanFactory后置处理)


    目录:

    • 后置处理器的作用
    • WebApplicationContextUtils
    • Scope是什么,如何自定义Scope

    后置处理器的作用

    本次来说说BeanFactory的后置处理器,从源码来看它是位于refresh函数的第四步,为了方便你查阅我把refresh贴出来。

     1 @Override
     2 public void refresh() throws BeansException, IllegalStateException {
     3     // 方法加锁避免多线程同时刷新Spring上下文
     4     synchronized (this.startupShutdownMonitor) {
     5         // 准备上下文刷新
     6         prepareRefresh();
     7 
     8         // 告诉子类刷新内部的beanFactory返回新的BeanFactory
     9         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    10 
    11         // 在当前上下文中准备要beanFactory
    12         prepareBeanFactory(beanFactory);
    13 
    14         try {
    15             // 允许在上下文子类中对beanFactory进行后置处理
    16             postProcessBeanFactory(beanFactory);
    17 
    18             // 在上下文中将BeanFactory处理器注册为Bean
    19             invokeBeanFactoryPostProcessors(beanFactory);
    20 
    21             // 注册Bean处理器用于拦截Bean的创建
    22             registerBeanPostProcessors(beanFactory);
    23 
    24             // 在上下文中初始化国际化信息
    25             initMessageSource();
    26 
    27             // 在上下文中初始化event multicaster(事件多播器)
    28             initApplicationEventMulticaster();
    29 
    30             // 在指定的上下文子类中初始化其他指定的beans
    31             onRefresh();
    32 
    33             // 检查并注册事件监听
    34             registerListeners();
    35 
    36             // 实例化所有剩余的(非延迟初始化)单例
    37             finishBeanFactoryInitialization(beanFactory);
    38 
    39             // 最后一步:发布相应的事件
    40             finishRefresh();
    41         }
    42 
    43         catch (BeansException ex) {
    44             if (logger.isWarnEnabled()) {
    45                 logger.warn("Exception encountered during context initialization - " +
    46                         "cancelling refresh attempt: " + ex);
    47             }
    48 
    49             // 如果出现异常则销毁已创建的单例
    50             destroyBeans();
    51 
    52             // 重置活动标志
    53             cancelRefresh(ex);
    54 
    55             // 将异常传递给调用者
    56             throw ex;
    57         }
    58 
    59         finally {
    60             // Reset common introspection caches in Spring's core, since we
    61             // might not ever need metadata for singleton beans anymore...
    62             resetCommonCaches();
    63         }
    64     }
    65 }

    postProcessBeanFactory(),顾名思义,它就是创建BeanFactory之后的一些操作。从源码上看,它是一个空函数,主要是为了给子类提供可扩展点的,是一个可选项

    1 protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    2 }

    像我们直接通过ClassPathXmlApplicationContext初始化的话,是不会有任何扩展点的。但如果是Web程序的话便会初始化一些Web程序需要的东西。

    综上所述:postProcessBeanFactory(),主要是为了给子类提供可扩展点的,是一个可选项

    WebApplicationContextUtils

    由上面我们可以来看下Web的一些扩展点(org.springframework.web.context.support.AbstractRefreshableWebApplicationContext#postProcessBeanFactory)。

    1 @Override
    2 protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    3     beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
    4     beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    5     beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
    6 
    7     WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    8     WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
    9 }

    上面的代码大同小异,先是添加了bean的后置处理器,然后忽略了一些Aware。

    我看主要看下web扩展点的关键代码,也就是WebApplicationContextUtils

    ———————————————————————————————————————————————————————

    registerWebApplicationScopes:

     1 public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, ServletContext sc) {
     2     beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
     3     beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false));
     4     beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true));
     5     if (sc != null) {
     6         ServletContextScope appScope = new ServletContextScope(sc);
     7         beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
     8         // Register as ServletContext attribute, for ContextCleanupListener to detect it.
     9         sc.setAttribute(ServletContextScope.class.getName(), appScope);
    10     }
    11 
    12     beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
    13     beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
    14     beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
    15     beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
    16     if (jsfPresent) {
    17         FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
    18     }
    19 }

    2-10行代码主要是注册了web的scope,如request、session、globalSession、application这些scope。以及后面的注册特殊的依赖类型等等,这不是我们的重点,不做赘述。

    这里我们需要知道,在Spring容器中默认只注册了singleton、prototype,向上面的四种都是需要手动注册的,这也就是为什么还需要调用2-10行代码的原因了。

    ———————————————————————————————————————————————————————

    registerEnvironmentBeans:注册和Environment有关的beans。

    Scope是什么,如何自定义Scope

    Scope是什么:

    • Scope也称作用域,在Spring容器中是指改Bean对象对其它Bean对象的请求可见范围
    • 如WebApplicationContext之类的ApplicationContext可以注册标准之外(singleton、prototype)的特殊Scope。如request、session、globalSession、application
    • 当然Bean的Scope同样是可以扩展的,及可以定义自己的可见范围,甚至可以重定义现有的范围,如web的四大scope,但不能覆盖内置的singleton和prototype

    ———————————————————————————————————————————————————————

    自定义Scope:

    我们首先来下web的定制scope是如何实现的,同样是基于接口Scope,只不过封装了一层AbstractRequestAttributesScope。

    所以如果要自定义一个scope的话,只需要实现以下Scope接口。这里我们直接用Spring封装好的SimpleThreadScope作为demo。

    1、使用代码的方式注册一个新的scope:

     1 public class TestSpring {
     2 
     3     public static void main(String[] args) {
     4         Properties properties = System.getProperties();
     5         properties.setProperty("config", "beans");
     6 
     7         ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("${config}.xml");
     8         TestBean testBean = ctx.getBean(TestBean.class);
     9         testBean.run();
    10 
    11         ctx.getBeanFactory().registerScope("thread", new SimpleThreadScope());
    12     }
    13 }

    2、使用配置方式:

     1 <!-- 自定义scope map -->
     2 <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
     3     <property name="scopes">
     4         <map>
     5             <entry key="myScope" value="com.jdr.spring.scope.MyScope"/>
     6         </map>
     7     </property>
     8 </bean>
     9 
    10 <!-- 使用自定义scope的bean -->
    11 <bean id="scopeTestBean" class="com.jdr.spring.scope.ScopeTestBean" scope="myScope">
    12     <!-- 让Bean符合自定义的作用域 -->
    13     <!--<aop:scoped-proxy/>-->
    14 </bean>
  • 相关阅读:
    bzoj1934 Vote 善意的投票 最小割(最大匹配)
    poj3417 Network 树上差分+LCA
    bzoj1076 奖励关 期望dp
    bzoj1087 互不侵犯King 状压dp+bitset
    bzoj1041 圆上的整点 数学
    bzoj 1085骑士精神 迭代深搜
    CodeForces 1043D Mysterious Crime 区间合并
    2018.12.14 浪在ACM 集训队第九次测试赛
    2018.12.9 中国石油大学第四次新生训练赛题解
    2018.12.8 中国石油大学第三次新生训练赛题解
  • 原文地址:https://www.cnblogs.com/bzfsdr/p/12984608.html
Copyright © 2020-2023  润新知