SpringBoot(三) 启动过程扩展知识点

下面扩展下上文步骤涉及的一些功能点
Context、Listener、BeanPostProcesser分析

Context

上下文是啥?Spring最核心的功能是IOC容器,BeanFactory是一个顶级接口,只提供基础功能。ApplicationContext(也是接口)继承自BeanFactory,同时增加了很多接口用于扩展功能如事件监听、加载文件资源、国际化等。上下文一般指ApplicationContext的实现以及其派生实现,用以支持更多扩展功能,使spring的bean工厂越来越强大。
SpringBoot(三) 启动过程扩展知识点_第1张图片

Listener

先说说监听器Listener,监听什么呢?监听上下文,也就是上面提到的applicationContext,上下文会在应用启动过程中发布很多事件(如启、停、刷新事件等,顶级类为ApplicationEvent),而上下文监听器注册到上下文中以后,会监听自己关注的事件,然后做一些处理(仅为匹配的事件对象调用侦听器)。

上下文抽象类AbstractApplicationContext提供了发布事件的方法:

public void publishEvent(ApplicationEvent event) {
    this.publishEvent(event, (ResolvableType)null);
}

而ApplicationListener接口提供了监听事件的方法,前面提到的11个监听器都会实现各自的监听方法,区别在于事件可能不一样,但都继承与ApplicationEvent。

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E var1);
}

挑一个监听器看看都做了什么:ClearCachesApplicationListener

上下文加载完成后清理缓存,具体就是清理掉反射工具类缓存以及调用类加载器的clearCache方法逐级清理加载器缓存。

/**
 * {@link ApplicationListener} to cleanup caches once the context is loaded.
 *
 * @author Phillip Webb
 */
class ClearCachesApplicationListener implements ApplicationListener<ContextRefreshedEvent> {

   @Override
   public void onApplicationEvent(ContextRefreshedEvent event) {
      ReflectionUtils.clearCache();
      clearClassLoaderCaches(Thread.currentThread().getContextClassLoader());
   }

   private void clearClassLoaderCaches(ClassLoader classLoader) {
      if (classLoader == null) {
         return;
      }
      try {
         Method clearCacheMethod = classLoader.getClass().getDeclaredMethod("clearCache");
         clearCacheMethod.invoke(classLoader);
      }
      catch (Exception ex) {
         // Ignore
      }
      clearClassLoaderCaches(classLoader.getParent());
   }

}

何时清理呢?自然是上下文加载完成后主动广播发布一个事件:我加载好了!监听器收到广播通知发现正是自己监听的事件,好家伙,等你好久了,终于可以干活了。

再看下上下文何时何地发布这个事件的,finishRefresh在刷新容器的最后阶段执行,发布一个ContextRefreshedEvent事件

protected void finishRefresh() {
    this.clearResourceCaches();
    this.initLifecycleProcessor();
    this.getLifecycleProcessor().onRefresh();
    this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
    LiveBeansView.registerApplicationContext(this);
}

何时注册到上下文开始监听呢?在prepareContext准备上下文时就开始陆续注册不同的监听器。准备上下文后面详解,这里大致介绍下,调用相关postProcesser处理context, 然后应用applyInitializers(此时有几个initializer会加入到监听者里),调用 listeners.contextPrepared(context)执行initializer监听器的处理动作; prepareContext的末尾调用listeners.contextLoaded(context);将SpringApplication 的applicationListener(创建时匹配到的,上文提到的11个)加入到上下文监听者里(后续刷新容器时还有些新的监听器会加入监听者集合里),然后当上下文发布事件是,监听者开始干活。

BeanPostProcesser
BeanPostProcessor简介

俗称bean的后置处理器,spring容器启动过程中多次参与bean实例化,不同时机不同切入点执行匹配的处理器对bean进行增强处理

/**
 * Factory hook that allows for custom modification of new bean instances —
 * for example, checking for marker interfaces or wrapping beans with proxies.
 *
 * 

Typically, post-processors that populate beans via marker interfaces * or the like will implement {@link #postProcessBeforeInitialization}, * while post-processors that wrap beans with proxies will normally * implement {@link #postProcessAfterInitialization}. * *

Registration

*

An {@code ApplicationContext} can autodetect {@code BeanPostProcessor} beans * in its bean definitions and apply those post-processors to any beans subsequently * created. A plain {@code BeanFactory} allows for programmatic registration of * post-processors, applying them to all beans created through the bean factory. * *

Ordering

*

{@code BeanPostProcessor} beans that are autodetected in an * {@code ApplicationContext} will be ordered according to * {@link org.springframework.core.PriorityOrdered} and * {@link org.springframework.core.Ordered} semantics. In contrast, * {@code BeanPostProcessor} beans that are registered programmatically with a * {@code BeanFactory} will be applied in the order of registration; any ordering * semantics expressed through implementing the * {@code PriorityOrdered} or {@code Ordered} interface will be ignored for * programmatically registered post-processors. Furthermore, the * {@link org.springframework.core.annotation.Order @Order} annotation is not * taken into account for {@code BeanPostProcessor} beans. * * @author Juergen Hoeller * @author Sam Brannen * @since 10.10.2003 * @see InstantiationAwareBeanPostProcessor * @see DestructionAwareBeanPostProcessor * @see ConfigurableBeanFactory#addBeanPostProcessor * @see BeanFactoryPostProcessor */ public interface BeanPostProcessor

允许对一个新的bean实例进行自定义修改。Factory hook,工厂沟子…意思是采用hook的方式实现的,hook—一种程序处理机制,据说在windows系统中很常见很重要(咱也不了解,不细究)。
在这里插入图片描述
使用hook方式对bean的新创建的实例进行自定义修改是什么意思呢?或许使用回调来描述更容易一些,在bean实例化之前和之后,提供回调方法,对需要实例化的bean为所欲为,可以修改,也可以替换(重新生成一个,如aop代理),当然 也可以啥都不做!具体想干啥,取决于这个“自定义”,框架帮我们自定义了一些处理,我们自己也可以使用这个特性做些小动作,如在bean实例化前后对其进行监控,或满足特定条件给他换个子类实例,或者…仅仅想打印一句:hello world。

BeanPostProcessor原理

如何回调呢,这个就要看spring实例化bean时的初始化代码了,spring启动过程中初始化单例bean时,先创建对象实例,然后填充属性,然后执行初始化方法。下面看下如何执行初始化方法
SpringBoot(三) 启动过程扩展知识点_第2张图片

前置处理方法:

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessBeforeInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

后置处理方法

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

入参传的是已经实例化且填充过属性的bean,可以看到如果经过前置或者后置的处理,一旦有所返回,则会影响最终初始化方法的返回值,也就允许可以修改甚至替换实例化对象的。(多提一句:java是值传递,传入的是对象地址,可以根据入参对象地址定位并修改原始对象,如果需要替换对象,则只能返回新对象,挤掉原有对象)。

BeanPostProcessor扩展

关于bean的后置处理其实不仅限于此,这里只是初始化时对bean进行前后处理,springbean创建过程中其实不止一处用到了bean后置处理,只不过实现的都是BeanPostProcessor的派生,毕竟初始化的前后处理也只能用到初始化时,前面提到的创建,填充其实也有类似需求。初次看源码时,对代码中各种调用BeanPostProcessor进行处理看的那叫一个云里雾里,其实仔细看执行的方法名,也是有差异的,下面列举几个例子:

实例化后,填充属性前,需要解决循环依赖,因为可能存在aop循环依赖,需要提前生成代理对象,这里就用到了一种bean的后处理:SmartInstantiationAwareBeanPostProcessor. getEarlyBeanReference

/**
 * Obtain a reference for early access to the specified bean,
 * typically for the purpose of resolving a circular reference.
 * @param beanName the name of the bean (for error handling purposes)
 * @param mbd the merged bean definition for the bean
 * @param bean the raw bean instance
 * @return the object to expose as bean reference
 */
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

之后的填充属性,又用到了一种bean后处理器:InstantiationAwareBeanPostProcessor,而且还是个双黄蛋。

  1. InstantiationAwareBeanPostProcessor. postProcessAfterInstantiation
  2. InstantiationAwareBeanPostProcessor. postProcessProperties

如果1中提前处理了属性注入,则直接返回,即属性填充结束
否则使用自动注入处理器处理属性填充操作。

// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            return;
         }
      }
   }
}

for (BeanPostProcessor bp : getBeanPostProcessors()) {
   if (bp instanceof InstantiationAwareBeanPostProcessor) {
      InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
      PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
      if (pvsToUse == null) {
         if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
         }
         pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
         if (pvsToUse == null) {
            return;
         }
      }
      pvs = pvsToUse;
   }
}

你可能感兴趣的:(spring,boot)