前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring IOC中扩展点

spring IOC中扩展点

作者头像
leobhao
发布2022-06-28 18:11:58
2330
发布2022-06-28 18:11:58
举报
文章被收录于专栏:涓流涓流

IOC中的扩展点

Spring在初始化容器的过程中,提供了一些扩展点,可以让用户添加一些自定义的操作来处理Bean。

这里先贴出ioc创建过程的主要流程代码:

代码语言:javascript
复制
public void refresh() throws BeansException, IllegalStateException {
   // 加锁,防止创建过程中其他线程对容器的影响
   synchronized (this.startupShutdownMonitor) {
      // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符(对整个过程没什么影响)
      prepareRefresh();

      // 解析配置文件成 BeanDefinition, 并注册
      // 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
      prepareBeanFactory(beanFactory);

      try {
         // 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
         // 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类
         postProcessBeanFactory(beanFactory);
         // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
         invokeBeanFactoryPostProcessors(beanFactory);

         // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
         // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
         // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。到这里 Bean 还没初始化
         registerBeanPostProcessors(beanFactory);

         // 初始化当前 ApplicationContext 的 MessageSource(一些国际化的处理,也不重要)
         initMessageSource();

         // 初始化当前 ApplicationContext 的事件广播器
         initApplicationEventMulticaster();

         // 模板方法(钩子方法),
         // 具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
         onRefresh();

         // 注册事件监听器,监听器需要实现 ApplicationListener 接口
         registerListeners();

         // 初始化所有的 singleton beans
         //(lazy-init 的除外)
         finishBeanFactoryInitialization(beanFactory);

         // 最后,广播事件,ApplicationContext 初始化完成
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         // 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // 把异常往外抛
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}

常用的扩展点有:

  • 在构建BeanFactory的时候,有BeanFactoryPostProcessor
  • 在构建Bean的时候,有BeanPostProcessor
  • 在创建和销毁Bean的时候有InitializingBean(在BPP的调用栈附近)和DisposableBean

IOC Bean的扩展点,也是体现Bean生命周期的一部分, Bean的生命周期如图:

BeanFactoryPostProcessor

代码语言:javascript
复制
public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

可以看到这个接口需要实现postProcessBeanFactory, 然后可以通过参数beanFacory来操作,实现该接口,可以在spring的bean创建之前,修改bean的定义属性(这个阶段其实就是修改beandefinitiaon)。也就是说,Spring允许BeanFactoryPostProcessor在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scopesingleton改为prototype,也可以把property的值给修改掉。可以同时配置多个BeanFactoryPostProcessor,并通过设置order属性来控制各个BeanFactoryPostProcessor的执行次序。

ioc加载过程中(refresh方法),真正调用BeanFactoryPostProcessor的方法是invokeBeanFactoryPostProcessors

BeanPostProcessor

如果我们需要在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。它是针对已经初始化的 beans 进行的回调,也就是说是对实例化好以后的 beans 进行的回调

接口定义如下:

代码语言:javascript
复制
public interface BeanPostProcessor {

  //实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;


  //实例化、依赖注入、初始化完毕时执行
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}

BeanPostProcessor的注册是在Ioc的加载过程中的registerBeanPostProcessors(),该过程中会实例化所有的BPP,并根据优先级排序。调用BPP的逻辑是在初始化所有的Bean之后

调用过程是:

代码语言:javascript
复制
finishBeanFactoryInitialization->preInstantiateSingletons
-> getBean -> doGetBean
-> createBean
-> doCreateBean
-> initializeBean

initializeBean里执行具体的回调(BeanPostProcessorsBeforeInitialization,afterPropertiesSet,BeanPostProcessorsAfterInitialization), 代码如下

代码语言:javascript
复制
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
    // 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回调
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
    // 回调 BeanPostProcessor 的 postProcessBeforeInitialization
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // 处理 bean 中定义的 init-method,
       // 或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        // 回调 BeanPostProcessor 的 postProcessAfterInitialization
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

这个过程中可以看到,最后执行的回调方法不止有BeanFactoryPostProcessor接口的, 还有实现InitializingBean的,如:

代码语言:javascript
复制
public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-11-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • IOC中的扩展点
  • BeanFactoryPostProcessor
  • BeanPostProcessor
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档