Spring容器的扩展点(三)BeanPostProcessor
按照惯例,我们先看看官网对BeanPostProcessor的介绍
从这段文字中我们能获取到如下信息:
1、BeanPostProcessor接口定义了两个回调方法,通过实现这两个方法我们可以提供自己的实例化以及依赖注入等逻辑。而且,如果我们想要在spring容器完成实例化,配置以及初始化一个Bean后进行一些定制的逻辑,我们可以插入一个甚至更多的BeanPostProcesor的实现。
2、我们可以配置多个BeanPostProcessor,并且只要我们配置的BeanFactoryPostProcessor同时实现了Ordered接口的话,我们还可以控制这些BeanPostProcessor的实现。
我们可以通过一个例子看看BeanPostProcessor的作用
应用举例
demo如下:
@Component
public class IndexService {
@Autowired
private YxService yxService;
@Override
public String toString(){
return "IndexService{" + "YxService=" + yxService + "}";
}
}
@Component
public class YxService {
}
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (Objects.equals(beanName,"yxService")) {
System.out.println(bean);
System.out.println("bean config invoke postProcessBeforeInitialization");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (Objects.equals(beanName,"yxService")) {
System.out.println(bean);
System.out.println("bean config invoke postProcessAfterInitialization");
}
return bean;
}
}
public class Main08 {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
}
}
运行上面的程序
com.phr.service.YxService@2a33fae0
bean config invoke postProcessBeforeInitialization
com.phr.service.YxService@2a33fae0
bean config invoke postProcessAfterInitialization
从上面执行的结果我们可以得出结论,BeanPostProcessor两个接口的执行时机是在属性注入之后,因为从打印的结果可以看出YxService已经注入了
接口继承关系
由于BeanPostProcessor这个接口Spring本身内置的实现类就有很多,所以我们这里暂且不分析其实现类,从接口的定义来分析它的作用,其接口的UML图如下:
1、BeanPostProcessor,这个接口是我们Bean的后置处理器的顶级接口,其主要包含了两个方法
//在bean初始化前调用
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
};
//在bean初始化调用
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
1、InstantiationAwareBeanPostProcessor继承自BeanPostProcessor接口,并在此基础上扩展了四个方法,其中方法postProcessPropertyValues已经在5.1版本中被废弃了。
//实例化前
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
//实例化后
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
//我们采用注解时,spring通过这个方法完成了属性注入
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
大部分我们在扩展时都不会用到postProcessProperties和postProcessPropertyValues,如果在某些场景下,不得不用到这个方法,那么注意在实现postProcessProperties必须返回null,否则postProcessPropertyValues这个方法的逻辑不会执行。
2、SmartInstantiationAwareBeanPostProcessor 继续扩展了上面的接口,并多提供了三个方法
//预测bean的类型,主要是在Bean还没有创建前我们可以需要获取bean的类型
@Nullable
default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
//spring使用这个方法完成了构造函数的推断
@Nullable
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
throws BeansException {
return null;
}
//主要为了解决循环依赖,Spring内部使用了这个方法主要是让早期曝光的对象成为一个"合格"的对象
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
这个接口的三个方法一版是spring内部使用,我们可以关注这个接口上的一段java doc
* <p><b>NOTE:</b> This interface is a special purpose interface, mainly for
* internal use within the framework. In general, application-provided
* post-processors should simply implement the plain {@link BeanPostProcessor}
* interface or derive from the {@link InstantiationAwareBeanPostProcessorAdapter}
* class. New methods might be added to this interface even in point releases.
上面这段文字很明确的指出了这个接口的设计是为了一些特殊的目的,主要是在spring框架的内部使用,通常来说我们提供的Bean的后置处理器只要实现了BeanPostProcessor或者InstantiationAwareBeanPostProcessor即可。正常情况下,我们在扩展时不需要考虑这几个方法。
3、DestructionAwareBeanPostProcessor,这个接口直接继承自BeanPostProcessor,同时多提供了两个方法,主要用于Bean在进行销毁时回调
//在Bean被销毁前调用
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
//判断是否需要被销毁,默认都需要
default boolean requiresDestruction(Object bean) {
return true;
}
4、MergedBeanDefinitionPostProcessor,这个接口也直接继承了BeanPostProcessor,但是多提供了两个方法。
//spring内部使用这个方法找出了所有需要注入的字段,同时做了缓存
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
//主要用于在BeanDefinition被修改后,清楚容器中的缓存
default void resetBeanDefinition(String beanName) {
}
源码分析
我们带着两个问题去阅读源码:
1、容器中那么多BeanPostProcessor,他们会按什么顺序执行呢?
2、BeanPostProcessor接口这么多方法,他们的执行时机是什么时候呢?
接下来我们来解决这两个问题
执行顺序
在spring内部,当去执行一个BeanPostProcessor一版都是采用下面这种形式的代码
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
。。。。
}
}
getBeanPostProcessors()获取到的十个list集合,所以我们要分析BeanPostProcessor的执行顺序,其实就是分析这个list集合中的顺序是通过什么样的顺序添加进来的。
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 获取BeanPostProcessor类型的bean
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
//通过addBeanPostProcessor方法添加的以及注册到容器中的BeanPostProcessor的总和
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
//添加一个BeanPostProcessorChecker,主要用于日志记录
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
//保存同时实现了BeanPostProcessor和priorityOrdered接口的后置处理器
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
//保存实现了MergedBeanDefinitionPostProcessor接口的后置处理器
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
//保存同时实现了Ordered和BeanPostProcessor接口的后置处理器的名字
List<String> orderedPostProcessorNames = new ArrayList<>();
// /保存实现了BeanPostProcessor没有实现任务排序接口的后置处理器的名字
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { //PriorityOrdered PriorityOrdered @Order @Priority
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
//将priorityOrderedPostProcessors集合排序
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 把priorityOrderedPostProcessors添加到beanFactory中
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
//遍历所有实现了order接口的后置处理器,并进行创建
//如果实现了MergedBeanDefinitionPostProcessor放入到internalPostProcessors
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
//排序
sortPostProcessors(orderedPostProcessors, beanFactory);
// 把orderedPostProcessors添加到beanFactory中
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
//遍历所有未实现任务排序接口的后置处理器的名字
//如果实现了MergedBeanDefinitionPostProcessor则放入到internalPostProcessors中
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
//常规的不会排序
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
//对internalPostProcessors进行排序并添加到容器中
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
//最后添加的这个后置处理器主要是为了检测到所有的事件监听器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
疑惑代码解读
下面对上述代码中大家可能有疑惑的地方进行一波分析:
1、获取容器中已经注册的Bean的名称,根据BeanDefinition中获取BeanName
这里主要根据已经注册在容器中的BeanDefinition,这些BeanDefinition既包括程序员自己注册到容器中的,也包括Spring自己注册到容器中。注意这些后置处理器目前没有被创建,只是以BeanDefinition的形式存在容器中。如果此时调用getBeanPostProcessors(),是拿不到这些后置处理器的,至于容器什么时候注册了后置处理器的BeanDefinition,这个后面再说。
2、通过addBeanPostProcessor方法添加的BeanPostProcessor的数量再加上已经被扫描出BeanDefinition的后置处理器的数量(这些后置处理器还没有被创建出来),最后再加1,这里就有两个问题。
容器中已经存在的BeanPostProcessor是从哪里来的?
分为两个来源,第一容器启动时,自动调用了addBeanPostProcessor;第二程序员手动调用了addBeanPostProcessor方法添加了后置处理器;第二种方式很少。
类似于这样
public class Main08 {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(AppConfig.class);
applicationContext.getBeanFactory().addBeanPostProcessor(new MyBeanPostProcessor());
applicationContext.refresh();
}
}
容器又是在什么时候添加的后置处理器呢
// 准备BeanFactory
// 1. 设置BeanFactory的类加载器、表达式解析器、类型转化注册器
// 2. 添加三个BeanPostProcessor,注意是具体的BeanPostProcessor实例对象
// 3. 记录ignoreDependencyInterface
// 4. 记录ResolvableDependency
// 5. 添加三个单例Bean
prepareBeanFactory(beanFactory);
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
if (this.servletContext != null) {
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
}
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext);
}
为什么后面还要加1呢?
这个和我们分析的第三行代码相关
1、添加了一个BeanPostProcessorChecker,主要用于日志记录。
我们看下BeanPostProcessorChecker这个类的源码:
/**
* BeanPostProcessor that logs an info message when a bean is created during
* BeanPostProcessor instantiation, i.e. when a bean is not eligible for
* getting processed by all BeanPostProcessors.
*/
private static final class BeanPostProcessorChecker implements BeanPostProcessor {
private static final Log logger = LogFactory.getLog(BeanPostProcessorChecker.class);
private final ConfigurableListableBeanFactory beanFactory;
private final int beanPostProcessorTargetCount;
public BeanPostProcessorChecker(ConfigurableListableBeanFactory beanFactory, int beanPostProcessorTargetCount) {
this.beanFactory = beanFactory;
this.beanPostProcessorTargetCount = beanPostProcessorTargetCount;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (!(bean instanceof BeanPostProcessor) && !isInfrastructureBean(beanName) &&
this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
if (logger.isInfoEnabled()) {
logger.info("Bean '" + beanName + "' of type [" + bean.getClass().getName() +
"] is not eligible for getting processed by all BeanPostProcessors " +
"(for example: not eligible for auto-proxying)");
}
}
return bean;
}
private boolean isInfrastructureBean(@Nullable String beanName) {
if (beanName != null && this.beanFactory.containsBeanDefinition(beanName)) {
BeanDefinition bd = this.beanFactory.getBeanDefinition(beanName);
return (bd.getRole() == RootBeanDefinition.ROLE_INFRASTRUCTURE);
}
return false;
}
}
这段代码主要关注两个方法:
isInfrastructureBean 这个方法主要检查当前处理的Bean是否是一个Spring自身需要创建的Bean,而不是程序员所创建的Bean(通过@Component,@Configuration等注解或者xml配置等)。
postProcessAfterInitialization这个方法内部只是做了一个判断,只有当前bean不是一个后置处理器并且不是一个spring自身创建的bean,最后一个判断的意思是说在创建这个Bean容器中的后置处理器没有完全创建完,这个判断也能解释我们上面遗留的一个问题。之所以加1是为了更加方便的判断,否则需要用等号判断。
//常规的不会排序
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
注意这段代码,对于没有排序的后置处理器,即使你添加@order也没有任何作用,这里只针对Spring framwork。
// 实例化之后,填充属性之前会执行,会把某个ApplicationListener的bean的名字添加到singletonNames中去
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (ApplicationListener.class.isAssignableFrom(beanType)) {
this.singletonNames.put(beanName, beanDefinition.isSingleton());
}
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) { // bean
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
else if (Boolean.FALSE.equals(flag)) {
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
"to be of non-singleton scope.");
}
this.singletonNames.remove(beanName);
}
}
return bean;
}
(“Inner bean '” + beanName + "’ implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
“to be of non-singleton scope.”);
}
this.singletonNames.remove(beanName);
}
}
return bean;
}
这个后置处理器(spring事件监听机制后面介绍)