死磕spring源码:5.spring中的factory hook接口BeanPostProcessor详解

5 篇文章 0 订阅

一. 前言

这个接口在之前分析getBean的过程中可以说是频繁出现 ,前边这篇博文主要分析getBean的流程,也没有做过多的总结,但是由于其频繁的出现,也可以看的出来这个接口十分的重要,所以专门写一遍博文来总结一下这个接口,否则估计大家对于spring还是不能够在整体上有一个很好的了解。

二.BeanPostProcessor接口的基本构造

这个接口的构造非常的简单,只定义了两个接口方法,分别是postProcessBeforeInitialization和postProcessAfterInitialization方法,参数也只有两个参数,其UML图如下所示
BeanPostProcessor类结构图
往往最简单的东西也是重要的东西,这个接口在spring内部起了很大的作用,一起来看看它的注释

/**

  • 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}.
  • 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.

*/

这段注释就很明白的诠释了这个接口的作用,一句话总结就是"Factory hook",直译就是钩子。可能有很多对hook这个概念不是很理解,其实hook程序,在windows程序中是一种很常见的机制,hook机制能拦截特定的消息,由hook程序先处理,然后交给指定的窗口处理程序,就是类似一种拦截器和监听器的概念,处理特定的事件和消息。BeanPostProcessor就是定位就是这样的一个结构,它允许用户修改创建一个新的bean实例。

/**

  • Apply this {@code BeanPostProcessor} to the given new bean instance before 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.
  • 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
    */
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
    }

这个方法的定义就是前置处理方法,允许用户在bean初始化之前创建一个新的bean实例来替代原始的bean。其两个参数,前者是bean对象,后者是beanName,返回值为将注册到spring容器中的bean对象,所以说这里就能对spring的bean进行改头换面,完完全全的弄一个新对象放到spring中来替代原始的bean,比如AOP,事务等都是借助了这种手段来实现低侵入,低耦合式的代码来实现极为复杂的功能,由此可见spring的灵活性。postProcessAfterInitialization和这个方法的功能类似,不过它是在bean初始化之后调用的,只是调用的时机有一些区别。

三.常见的BeanPostProcessor接口实现

1.InstantiationAwareBeanPostProcessor

通过这个类的名字就可以发现其发现其式实例化观察者,即,当有bean需要实例化的时候,就会被这个钩子观察到,并可以通过钩子程序来进行处理。其调用时机如下图,AbstractAutowireCapableBeanFactory.createBean方法中,这个方法大家应当也很熟悉,如果记得不太清晰,可能需要在回顾一下spring的getBean流程了
在这里插入图片描述
这个时机就是当spring做好所有的准备,解析好了beanName,class等属性之后准备实例化这个bean的时候,会先调用这个钩子,这里也给出了一句注释"Give BeanPostProcessors a chance to return a proxy instead of the target bean instance",即给我们一个创建代理对象替代原始的bean,具体应用上一篇博文已经讲过的AOP中的AnnotationAwareAspectJAutoProxyCreator即是这个类的子类。具体应用这里不再贴出代码了,大家可以自行写代码来实现一下这个接口试试效果。

2.MergedBeanDefinitionPostProcessor

这个钩子十分的重要,不过从名字好像我们看不出来这个玩意儿究竟能干什么,不过MergedBeanDefinitionPostProcessor也是一个接口,说明具体的功能是在实现类中实现的。先来看一看其调用的时机AbstractAutowireCapableBeanFactory.doCreateBean方法中,这个也是创建bean的过程中调用的,不过比上边介绍的InstantiationAwareBeanPostProcessor要稍微靠后一点,是当bean的实例被创建,但是属性还没有被初始化的时候调用的
在这里插入图片描述
在这个方法中,调用了bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName),然后MergedBeanDefinitionPostProcessor接口中postProcessMergedBeanDefinition方法没有实现,可以找一下它的子类有哪一些
在这里插入图片描述
在这里是不是可以看的到有几个很熟悉的,比如:AutowiredAnnotationBeanPostProcessor这个是处理@Autowrite和@Value这两个注解,这个玩意儿后续在重点讲解自动注入的时候再仔细的分析一下这个玩意儿的构造。还有ScheduledAnnotationBeanPostProcessor这个处理spring的定时任务的。通过这些子类,我们大概可以看出MergedBeanDefinitionPostProcessor的作用是对bean进行功能上的增强,比如处理自动注入,JMS,定时器等注解的

3.SmartInstantiationAwareBeanPostProcessor

从这个名字就可以看出,这个钩子实现智能实例化实例化的,这个钩子应用的比较多,看看SmartInstantiationAwareBeanPostProcessor这个类的注释,注释上说明了这个接口继承自InstantiationAwareBeanPostProcessor这个接口,其主要作用就是在原来的基础加上一个对被处理bean的最终类型确定的回调接口,之前我们已经说过InstantiationAwareBeanPostProcessor就是在bean实例化之前调用的钩子,如果说我们在这个地方修改了原始的bean,那么spring怎么感知最终的bean的类型呢?就是通过实现这个接口来实现的,之前将的AOP中的AnnotationAwareAspectJAutoProxyCreator即是实现的是SmartInstantiationAwareBeanPostProcessor接口

/**

  • Extension of the {@link InstantiationAwareBeanPostProcessor} interface,
  • adding a callback for predicting the eventual type of a processed bean.
  • NOTE: 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.
    */

具体的应用场景可以看如下代码

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;
}

这段代码是spring在创建bean之后,但还没有完成bean的初始化的时候,会先提前暴漏bean的引用,这里就需要判断是否有代理的钩子处理过这个bean,然后返回被代理的bean出来。具体大家可以尝试一下,SmartInstantiationAwareBeanPostProcessor这个接口总结来说就是提供一些辅助的功能。

四.简单应用

后续补充

五.总结

看完本章,你该学会什么东西?

1.BeanPostProcessor是什么东西?

官方解释为Factory hook,直译为钩子,这是在windows重常见的机制,就是用于拦截处理消息用的。在spring中这个东西的作用,就是在创建,实例化或者其他各种场景中添加一个可以供开发者介入的点,来实现对spring内部机制的干预和修改,以实现自己想要的效果。

2.BeanPostProcessor在bean的生命周期中的体现

在文章中我们已经重点介绍过几种常见的BeanPostProcessor实现,那么在spring bean的生命周期中还有好几处关于BeanPostProcessor介入的点,大家可以自己尝试总结,并使用它来达到自己想要的一些效果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值