在spring管理Bean的初始化过程当中,除了正常管理bean的实例化(初始化、参数注入等)外,还对外提供了丰富的对Bean操做的扩展。例如自定义初始化操做,自定义容器退出时Bean的销毁操做等等。这段时间看源码以为此方面最实际的一个例子就是,咱们在Bean初始化以前以及以后,框架容许咱们作一些统一性的逻辑操做。BeanPostProcessor就完成了这个功能,它可以在装配Bean的过程当中动态去改变Bean的行为,达到对Bean的加强。首先须要了解整个spring容器对bean初始化的流程,其流程图以下:spring
上图中已经完成了容器的初始化(对配置文件的加载和解析),已经进入到实例化阶段。可以看出BeanPostProcessor在整个流程中所处的位置,它正好围绕着bean自定义初始化方法先后。那么有一个问题,就是既然可以使用afterPropertySet或者init-method来自行初始化咱们的bean,那么为何还要这些BeanPostProcessor呢?由于afterPropertySet和init-method更关注自身的业务逻辑处理,而BeanPostProcessor更加通用,好比是否须要感知当前环境的上下文等更具备通用性的逻辑。app
1、使用BeanPostProcessor来完成Bean实例化前、后处理框架
BeanPostProcessor接口定义了两个方法,postProcessBeforeInitialization和postProcessAfterInitialization。一看名字便一目了然它们各自的做用,那就是在初始化的先后进行预处理和后处理。问题的关键在于容器启动后,BeanFactory是怎么感知到这些BeanPostProcessor的存在呢?或者说咱们自定义的BeanPostProcessor怎么可以集成到框架中,让容器感知和使用咱们自定义的processor?首先,咱们要找到BeanFactory对BeanPostProcessor的处理逻辑代码,这段代码在AbstractAutowireCapableBeanFactory类的initializeBean方法中:post
Object wrappedBean = bean; //进入initializeBean方法以前,已经构造了一个Bean对象,不过未经初始化 if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); //前处理 } try { invokeInitMethods(beanName, wrappedBean, mbd);//这里有机会调用Bean的afterPropertySet方法以及自定义的初始化方法 } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);//后处理 } return wrappedBean;
再进一步看applyBeanPostProcessorsBeforeInitialization方法。this
Object result = existingBean; // 在这里容器会遍历全部已经注册的BeanPostProcessor,不管是spring框架自身的仍是咱们自定义的。 for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext();) { BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next(); result = beanProcessor.postProcessBeforeInitialization(result, beanName); } return result;
能够看到,咱们彻底有机会在afterPropertySet方法以前就对Bean进行操做,咱们只要在BeanFactory中注册咱们的BeanPostProcessor(在BeanFactory中注册咱们的processor),那么就会在BeanFactory加载Bean的过程当中,回调咱们本身的BeanPostProcessor来完成咱们的动做(上面代码中循环查找全部注册的BeanPostProcessor)。不过使用BeanPostProcessor带来的一个问题就是任何Bean的加载都会调用你注册过的这个processor,因此一些个性化的业务初始化操做放在这里是不合适的,业务初始化操做应该放到afterPropertySet(须要实现InitializingBean接口,侵入性较大)或者自定义初始化方法(须要在bean配置文件中指定init-method参数,侵入性较小)中完成。因此,BeanPostProcessor的使用应该是通用的业务逻辑处理。好比咱们常用到的自动绑定(Autowired)就是使用BeanPostProcessor来完成的。咱们来简单看一下处理autowired的这个processor是如何完成自动绑定成员变量和方法参数的。Autowired的processor类是:spa
AutowiredAnnotationBeanPostProcessor.class
autowired的过程都是在bean实例化以后作的,因此咱们看postProcessAfterInitialization方法的具体实现。调试
// 根据当前bean对象的class信息获得使用注解autowired的成员变量和方法 InjectionMetadata metadata = findAutowiringMetadata(bean.getClass()); try { /* // 实现了将容器中的bean注入到当前对象成员变量的过程。这里之因此可以拿到容器中的其余bean,是由于AutowiredAnnotationBeanPostProcessor实现了BeanFactoryAware接口,从而获得当前容器的BeanFactory。另外具体看进去里面的实现,autowired的实现实现方式是经过byType实现的。 */ metadata.injectFields(bean, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Autowiring of fields failed", ex); } return true;
spring对bean进行初始化的过程默认使用set方法注入。并且属性注入是在初始化bean以前(参照AbstractAutowireCapableBeanFactory类的doCreateBean方法),也就是说咱们的autowired方式应该是在set方法注入以后,autowired是会覆盖set方法注入的属性。咱们能够作如下实验来验证咱们的猜想:咱们在Apple中准备注入另外一个Bean seed,同时使用了set方法和autowired。Apple类中代码部分以下:code
@Autowired @Qualifier("seed1") private Seed seed; public Sort getSeed() { return seed; } public void setSeed(Seed seed) { this.seed = seed; }
配置文件以下:对象
<bean id="apple" class="com.alibaba.china.Apple" > <property name="seed"> <ref bean="seed0" /> </property> </bean> <bean id="seed0" class="com.alibaba.china.Seed" > <property name="seedName"> <value>苹果种子</value> </property> </bean> <bean id="seed1" class="com.alibaba.china.Seed"> <property name="seedName"> <value>Apple Seed</value> </property> </bean>
咱们用set方法注入seed0,用自动绑定的方式注入seed1。因为BeanPostProcessor在初始化过程当中执行,在set属性注入以后,因此预期结果seed1被注入。可是运行结果发现是seed0注入了apple对象。blog
为何会这样呢?通过调试发现,在使用set方法属性注入的过程以前,会处理一类特殊的BeanPostProcessor------InstantiationAwareBeanPostProcessor,它是BeanPostProcessor的扩展接口,可是容器会在set注入以前优先检查是否存在这类BeanPostProcessor,若是存在InstantiationAwareBeanPostProcessor先执行这类processor。而偏偏巧合的是,AutowiredAnnotationBeanPostProcessor是InstantiationAwareBeanPostProcessor的子类。因此autowired的动做在set方法前作了,set方法的属性覆盖了autowired的属性,因此在上述例子中seed0最终被成功注入到apple这个对象里面。咱们用类图能更加形象地描述InstantiationAwareBeanPostProcessor与BeanPostProcessor接口:
当获取一个bean对象时,主要逻辑在AbstractAutowireCapableBeanFactory类的doCreateBean方法中。其父类中维护一个beanPostProcessors列表,咱们能够在容器启动时加入咱们的processor,在执行到doCreateBean中咱们的processor会被回调。咱们根据具体的须要去实现BeanPostProcessor接口或者InstantiationAwareBeanPostProcessor接口。前者主要是初始化先后的处理动做,然后者主要是执行实例化先后的逻辑。
ApplicationContext更加简单地使用BeanPostProcessor:
若是咱们直接使用BeanFactory,须要把咱们的BeanPostProcessor注册到BeanFactory上,不然BeanFactory感知不到咱们的processor。而ApplicationContext则在此方面作了加强,咱们只需在配置文件里面声明咱们的BeanPostProcessor,ApplicationContext可以自动作到感知。ApplicationContext是如何作到的呢?咱们不妨本身先猜测一下,若是让咱们本身实现这个加强功能应该怎么作?大体方向就是本身去扫描配置文件,看全部的bean中有哪些是BeanPostProcessor,而后咱们不分青红皂白一股脑把全部的BeanPostProcessor都注册进去。spring对ApplicationContext也正是这么实现的,具体的描述在另外一片分享中更具体的提到:
2、