1.概述

之前咱们对Spring相关注解进行全方面的解析与总结,在此期间反复提到了一个中心装备解析类:ConfigurationClassPostProcessor,咱们称之为装备类后置处理器。什么是后置处理器呢?其实后置处理器是**Spring供给给咱们的一个非常重要的扩展点**,而且Spring内部的许多功用也是经过后置处理器来完结的,ConfigurationClassPostProcessor的重要性就阐明这一点,一起该扩展点也便利Spring与其他结构进行集成,如Spring集成mybatis结构,便是经过后置处理器MapperScannerConfigurer完结了扫描mapper接口注入到Spring容器中的。

Spring结构中大致供给了以下三个中心后置处理器:BeanDefinitionRegistryPostProcessor,BeanFactoryPostProcessor,BeanPostProcessor,其他的后置处理器都是承继自这三个。三个扩展点的首要功用效果如下:

  • BeanDefinitionRegistryPostProcessor:这个扩展点咱们称之为beanDefinition后置处理器,能够动态注册自己的beanDefinition,能够加载classpath之外的bean。
  • BeanFactoryPostProcessor:这个扩展点咱们称之为bean工厂后置处理器调用机遇在Spring在读取beanDefinition信息之后,实例化bean之前,首要对beanDefinition的特点进行修正调整,如效果规模scope,是否懒加载lazyInit等。
  • BeanPostProcessor:这个扩展点咱们称之为bean后置处理器,调用机遇是在bean实例化之后,会经过bean的初始化这一过程,该接口有两个办法,postProcessBeforeInitialization()在特点值填充之后,init()初始化办法履行之前调用。postProcessAfterInitialization()是在init初始化办法履行之后调用。

依据上面各个处理器的功用效果描述能够得到三个处理器的履行次序:

BeanDefinitionRegistryPostProcessor → BeanFactoryPostProcessor → BeanPostProcessor

这也是Spring的bean生命周期流程的部分表现,这三个后置处理器调用机遇都在bean的生命周期中,当然bean的生命周期也是一个重要知识点,且生命周期远不止这几个扩展点,后续会安排剖析一波。

项目推荐:根据SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级体系架构底层结构封装,处理业务开发经常见的非功用性需求,防止重复造轮子,便利业务快速开发和企业技术栈结构一致办理。引进组件化的思想完结高内聚低耦合而且高度可装备化,做到可插拔。严厉控制包依靠和一致版别办理,做到最少化依靠。重视代码标准和注释,非常适合个人学习和企业运用

Github地址:github.com/plasticene/…

Gitee地址:gitee.com/plasticene3…

微信大众号Shepherd进阶笔记

2. 三大后置处理器

接下来咱们就别离剖析下这三个后置处理器:

2.1 BeanDefinitionRegistryPostProcessor

界说如下:

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
​
  /**
   * Modify the application context's internal bean definition registry after its
   * standard initialization. All regular bean definitions will have been loaded,
   * but no beans will have been instantiated yet. This allows for adding further
   * bean definitions before the next post-processing phase kicks in.
   * @param registry the bean definition registry used by the application context
   * @throws org.springframework.beans.BeansException in case of errors
   */
  void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
​
}

能够看到BeanDefinitionRegistryPostProcessor承继自上面的BeanFactoryPostProcessor,阐明BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor供给的办法进行了增强扩展,完结BeanDefinitionRegistryPostProcessor就必须完结两个接口界说的办法。从上面代码注释翻译来看:BeanDefinitionRegistryPostProcessor首要完结一切常规beanDefinition现已加载结束,然后能够再增加一些额外的beanDefinition,一句话总结其功用效果便是注册beanDefinition的ConfigurationClassPostProcessor便是完结BeanDefinitionRegistryPostProcessor来完结装备类及其相关注解解析得到beanDefinition注册到Spring上下文中的。

运用示例:

首先咱们先界说一个类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Boo {
  private Long id;
  private String name;
}

然后自界说个BeanDefinitionRegistryPostProcessor:

@Component
// 需要把该后置处理器注入Spring容器中
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
  @Override
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    // 注入boo
    BeanDefinition beanDefinition = new RootBeanDefinition();
    beanDefinition.setBeanClassName("com.shepherd.common.bean.Boo");
    registry.registerBeanDefinition("boo", beanDefinition);
   }
​
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    // 该办法是BeanFactoryPostProcessor的办法,这儿就不做任何逻辑处理,后面会独自演示
​
   }
}

履行测验办法:

@ComponentScan(basePackages = {"com.shepherd.common.config"})
@Configuration
public class MyConfig {
​
  public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
    String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    // 遍历Spring容器中的beanName
    for (String beanDefinitionName : beanDefinitionNames) {
      System.out.println(beanDefinitionName);
     }
   }
}

会发现成果打印中有boo,阐明上面后置处理器成功增加beanDefinition,Spring后续进行了bean的注入。

其实中心装备解析类后置处理器ConfigurationClassPostProcessor便是最好的示例,不熟悉的能够跳转到之前总结的@Import的运用和完结原理,看看ConfigurationClassPostProcessor这个后置处理器是怎样完结对@Import的解析的

2.2 BeanFactoryPostProcessor

界说如下

@FunctionalInterface
public interface BeanFactoryPostProcessor {
​
  /**
   * 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 overriding or adding
   * properties even to eager-initializing beans.
   * @param beanFactory the bean factory used by the application context
   * @throws org.springframework.beans.BeansException in case of errors
   */
  void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
​
}

@FunctionalInterface注解表明它是一个函数式接口,能够运用Lambda表达式调用,当然这不是要点,要点看注释,这儿我是特意把源码的注释copy出来的,翻译过来大概意思便是:一切的beanDefinition现已全部加载结束,然后该后置处理器能够对这些beanDefinition做一些特点的修正操作。 这便是对BeanFactoryPostProcessor效果功用的描述

运用示例:

咱们在2.1小节的案例基础中自界说一个BeanFactoryPostProcessor:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    System.out.println("BeanFactoryPostProcessor execute...");
    BeanDefinition beanDefinition = beanFactory.getBeanDefinition("boo");
    if (Objects.nonNull(beanDefinition)) {
      beanDefinition.setDescription("芽儿哟,能够的");
     }
   }
}

这儿便是对上面增加名为boo的beanDefinition进行了特点修正。

调整上面的测验类如下:

@ComponentScan(basePackages = {"com.shepherd.common.config"})
@Configuration
public class MyConfig {
​
  public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
    BeanDefinition beanDefinition = applicationContext.getBeanDefinition("boo");
    System.out.println(beanDefinition.getDescription());
   }
}
​

履行成果控制台打印:

芽儿哟,能够的

由此可见,MyBeanFactoryPostProcessor后置处理器成功修正了boo的特点。当然BeanFactoryPostProcessor也能够注册beanDefinition的,看你怎样用。

2.3 BeanPostProcessor

界说如下:

public interface BeanPostProcessor {
​
  /**
   * Apply this {@code BeanPostProcessor} to the given new bean instance <i>before</i> any bean
   * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
   * or a custom init-method). The bean will already be populated with property values.
   * The returned bean instance may be a wrapper around the original.
   * <p>The default implementation returns the given {@code bean} as-is.
   * @param bean the new bean instance
   * @param beanName the name of the bean
   * @return the bean instance to use, either the original or a wrapped one;
   * if {@code null}, no subsequent BeanPostProcessors will be invoked
   * @throws org.springframework.beans.BeansException in case of errors
   * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
   * 在特点注入结束, init 初始化办法履行之前被回调
   */
  @Nullable
  default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }
​
  /**
   * Apply this {@code BeanPostProcessor} to the given new bean instance <i>after</i> any bean
   * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
   * or a custom init-method). The bean will already be populated with property values.
   * The returned bean instance may be a wrapper around the original.
   * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
   * instance and the objects created by the FactoryBean (as of Spring 2.0). The
   * post-processor can decide whether to apply to either the FactoryBean or created
   * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
   * <p>This callback will also be invoked after a short-circuiting triggered by a
   * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
   * in contrast to all other {@code BeanPostProcessor} callbacks.
   * <p>The default implementation returns the given {@code bean} as-is.
   * @param bean the new bean instance
   * @param beanName the name of the bean
   * @return the bean instance to use, either the original or a wrapped one;
   * if {@code null}, no subsequent BeanPostProcessors will be invoked
   * @throws org.springframework.beans.BeansException in case of errors
   * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
   * @see org.springframework.beans.factory.FactoryBean
   * 在初始化办法履行之后,被增加到单例池 singletonObjects 之前被回调
   */
  @Nullable
  default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }
​
}

Bean被实例化后,到终究缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如:特点的填充、初始办法init的履行等,BeanPostProcessor便是这一阶段的对外扩展点,咱们称之为Bean后置处理器。跟上面的Bean工厂后处理器类似,它也是一个接口,完结了该接口并被容器办理的BeanPostProcessor,会在流程节点上被Spring主动调用。

运用示例:

先改造一下上面的bean界说,供给一个实例化结构办法和初始化办法:

@Data
@AllArgsConstructor
public class Boo {
  private Long id;
  private String name;
​
  public Boo() {
    System.out.println("boo实例化结构办法履行了...");
   }
​
  @PostConstruct
  // 该注解表明实例化之后履行该初始化办法
  public void init() {
    System.out.println("boo履行初始化init()办法了...");
   }
}
​

然后自界说一个beanPostProcessor:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("beanPostProcessor的before()履行了...." + beanName);
    return bean;
   }
​
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("beanPostProcessor的after()履行了...."+ beanName);
    return bean;
   }
}

测验办法:

@ComponentScan(basePackages = {"com.shepherd.common.config"})
@Configuration
public class MyConfig {
​
  
  public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
   
}
​

打印成果如下:

boo实例化结构办法履行了...
beanPostProcessor的before()履行了....boo
boo履行初始化init()办法了...
beanPostProcessor的after()履行了....boo

这严厉阐明BeanPostProcessor办法的履行时间点和次序,BeanPostProcessor是在bean实例化之后,对bean的初始化init()办法前后进行回调扩展的,这时候你或许会想如果要对bean的实例化前后进行扩展怎样办?Spring肯定也想到这一点,供给了承继自BeanPostProcessor的扩展类后置处理器:

InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor该接口承继了BeanPostProcess接口,差异如下:

BeanPostProcess接口只在bean的初始化阶段进行扩展,而InstantiationAwareBeanPostProcessor接口在此基础上增加了3个办法,把可扩展的规模增加了实例化阶段和特点注入阶段。

该类首要的扩展点有以下5个办法,首要在bean生命周期的两大阶段:实例化阶段初始化阶段 ,下面一起进行阐明,按调用次序为:

  • postProcessBeforeInstantiation实例化bean之前,相当于new这个bean之前
  • postProcessAfterInstantiation实例化bean之后,相当于new这个bean之后
  • postProcessPropertyValuesbean现已实例化完结,在特点注入时阶段触发,@Autowired,@Resource等注解原理根据此办法完结
  • postProcessBeforeInitialization:初始化bean之前,相当于把bean注入spring上下文之前
  • postProcessAfterInitialization:初始化bean之后,相当于把bean注入spring上下文之后

运用场景:这个扩展点非常有用 ,无论是写中间件和业务中,都能使用这个特性。比如对完结了某一类接口的bean在各个生命期间进行收集,或许对某个类型的bean进行一致的设值等等。

SmartInstantiationAwareBeanPostProcessor

该扩展接口集成自上面的InstantiationAwareBeanPostProcessor,有3个触发点办法:

  • predictBeanType:该触发点发生在postProcessBeforeInstantiation之前(在图上并没有标明,因为一般不太需要扩展这个点),这个办法用于猜测Bean的类型,回来第一个猜测成功的Class类型,如果不能猜测回来null;当你调用BeanFactory.getType(name)时当经过bean的姓名无法得到bean类型信息时就调用该回调办法来决定类型信息。
  • determineCandidateConstructors:该触发点发生在postProcessBeforeInstantiation之后,用于确认该bean的结构函数之用,回来的是该bean的一切结构函数列表。用户能够扩展这个点,来自界说选择相应的结构器来实例化这个bean。
  • getEarlyBeanReference:该触发点发生在postProcessAfterInstantiation之后,当有循环依靠的场景,当bean实例化好之后,为了防止有循环依靠,会提早露出回调办法,用于bean实例化的后置处理。这个办法便是在提早露出的回调办法中触发。

3.总结

Spring注解开发Spring Boot主动安装是当下干流开发首选,咱们一再强调其快捷。高效性。现在在开发中间件和公共依靠工具的时候也会用到主动安装特性。让运用者以最小的代价接入。想要深化掌握主动安装套路,就必须要了解Spring关于bean的结构生命周期以及各个扩展接口,如之前咱们总结的Spring根据相关注解开发,其背后中心原理便是经过ConfigurationClassPostProcessor这个后置处理器完结的,也便是说Spring经过自己供给的后置处理器扩展点完结了注解解析功用,且在别的地方也有大量应用,可见后置处理器这个扩展点的重要性显而易见啦。