一差购、接口介紹
????????spring提供了一個接口類 BeanPostProcessor,我們稱其為后置處理器汉嗽,作用是在 bean 的實例化的過程中對 bean 進行自定義的包裝處理欲逃,其提供了兩個方法。先看看?BeanPostProcessor 的定義饼暑。
public interface BeanPostProcessor{?
? ??????public abstract Object postProcessBeforeInitialization(Object obj, String s) throws BeansException;?
? ? ? ? ??public abstract Object postProcessAfterInitialization(Object obj, String s) throws BeansException;??
}
? ? ? ? 根據(jù)類的名稱稳析,我們可以猜測兩個接口方法執(zhí)行的位置:
? ??????1、在bean初始化之前執(zhí)行弓叛;
2彰居、在bean的初始化之后執(zhí)行。
二撰筷、源碼解析
? ? ? ? 理解其原理以及執(zhí)行的位置陈惰,需要到源碼中尋找答案。跟蹤創(chuàng)建 bean 的實例的 getBean 方法毕籽,層層跟進抬闯,在AbstractAutowireCapableBeanFactory 類中井辆,找到了執(zhí)行方法:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
????????if (System.getSecurityManager() != null) {?
? ??????????????AccessController.doPrivileged(new PrivilegedAction<Object>() {?
? ??????????????????????@Override public?
? ??????????????????????Object run() {?
? ???????????????????????????????invokeAwareMethods(beanName, bean);?
? ??????????????????????????????return null;?
? ??????????????????????}?
? ??????????????}, getAccessControlContext());? ? ? ?
? ? ? ?} else {
? ???????????invokeAwareMethods(beanName, bean);?
? ??????}??
? ??????Object wrappedBean = bean;
? ??????if (mbd == null || !mbd.isSynthetic()) {?
? ??????????????wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);?
? ? ? ? }?
? ? ? ? try {? ? ? ? ??
? ??????????????invokeInitMethods(beanName, wrappedBean, mbd);
? ? ? ? ?} 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;
}? ? ? ?
? ? ? ? 如上加粗部分是主要的代碼,invokeAwareMethods(beanName, bean)画髓、?applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);invokeInitMethods(beanName, wrappedBean, mbd)掘剪、invokeInitMethods(beanName, wrappedBean, mbd)、applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)奈虾。
? ? ? ? 1夺谁、invokeAwareMethods(beanName, bean),對實現(xiàn)了 aware 接口的 bean 進行特殊的處理肉微,實現(xiàn)aware 接口的 bean 在被初始化后匾鸥,可以取得一些相對應的資源。比如碉纳, applicationAware , beanFactoryAware 等勿负。
? ? ? ? 2、applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)劳曹,后置處理器初始化前方法調(diào)用奴愉。
? ? ? ? 3、invokeInitMethods(beanName, wrappedBean, mbd)铁孵,用于用戶初始化方法的調(diào)用锭硼,如實現(xiàn)了?InitializingBean 接口的 bean ,調(diào)用其?afterPropertiesSet 和 用戶配置的 init-method 方法的調(diào)用蜕劝。
? ? ? ? 進入applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)和applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)檀头,查看其源碼:
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {?
? ??????Object result = existingBean;?
? ??????for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {?
? ??????????????result = beanProcessor.postProcessBeforeInitialization(result, beanName);?
? ??????????????if (result == null) {?
? ???????????????????????return result;??
? ??????????????}?
? ???????}? ?
? ???????return result;??
}?
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
? ? ? ? Object result = existingBean;
? ? ? ? for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
? ? ? ? ? ? result = beanProcessor.postProcessAfterInitialization(result, beanName);
? ? ? ? ? ? if(result ==null) {
? ? ? ? ? ? ? ? return result;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return result;
}
三、使用
1岖沛、定義接口和實例?
publi interface DemoService {
? ? public?void sayHello();
}
public interface NameInit {?
? ? ?public void setName(String name);??
}
public class DemoServiceImpl implements DemoService,NameInit {
? ??????String name;?
? ??????@Override?
? ? ? ??public void sayHello() {?
? ??????????????System.out.println("hello "+name);?
? ? ? ??}? ? ?
? ??????@Override? ? ??
? ? ? ??public void setName(String name) {??
? ??????????????this.name=name;? ??
? ? ? ? }
}
2暑始、定義bean的配置
<bean id="demoService" class="com.zjl.beanpostprocessor.DemoServiceImpl"> </bean>
3、定義一個BeanPostProcessor?實例
? ??????凡是繼承了NameInit的接口婴削,均實例化廊镜,注入name值。此處定義接口一方面是要使用接口中提供的setName方法唉俗,另一方面減輕系統(tǒng)壓力嗤朴,防止每個bean都進行注入。
public class NameBeanPostProcessor implements BeanPostProcessor {?
? ??????String name;
????????public String getName() {?
? ??????????????return name;
? ???????}?
? ??????public void setName(String name) {?
? ??????????????this.name = name;?
? ??????}?
? ??????@Override? ? ? ? ?
? ??????public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {?
? ??????????????if(bean instanceof NameInit){?
? ??????????????????((NameInit)bean).setName(name);
? ? ? ? ? ? ? ? ? }??
? ??????????????return bean;?
? ??????}? ? ??
? ??????@Override?
? ??????public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {??
? ??????????????return bean;? ??
? ??????}
?}??
5互躬、定義bean播赁,注入name的值
<bean id="nameBeanPostProcessor" class="com.zjl.beanpostprocessor.NameBeanPostProcessor">
? ??????<property name="name" value="zhangsan"></property>??
</bean>
6颂郎、定義另一個BeanPostProcessor 吼渡,僅打印日志
public class LogBeanPostProcessor implements BeanPostProcessor {?
? ??????@Override? ? ? ? ? ? ? ? ? ??
? ? ? ? ?public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {?
? ??????????????System.out.println("正在處理"+beanName); return bean;??
? ??????}?
? ??????@Override? ? ??
? ??????public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {?
? ??????????????System.out.println("已經(jīng)處理完成"+beanName);? ?
? ???????????????return bean;
?????????}? ?
?}?
7、定義bean
<bean id="logBeanPostProcessor" class="com.zjl.beanpostprocessor.LogBeanPostProcessor"> </bean>
8乓序、測試類
public class BeanPostProcessorTest {?
? ??????public static void main(String[] args) {?
? ??????????????ApplicationContext context=new FileSystemXmlApplicationContext("beanpostprocessor.xml");?
? ??????????????DemoService demoService=(DemoService) context.getBean("demoService");?
? ??????????????demoService.sayHello();
?????????}? ? ? ?
}
9寺酪、測試結(jié)果
正在處理demoService?
已經(jīng)處理完成demoService?
hello zhangsan?
10坎背、總結(jié)
兩個方法均在bean實例化期間已經(jīng)完成;
????name屬性是根據(jù)NameInit接口自動注入寄雀;
由于兩個方法執(zhí)行的時間特殊性得滤,所以打印日志和記錄時間意義不大,主要還是用于注入屬性和完善配置盒犹。