解釋
InitializingBean:自己被初始化之后進(jìn)行調(diào)用锈至,針對(duì)的對(duì)象是實(shí)現(xiàn)該接口的bean剪况,必須實(shí)現(xiàn)方法afterPropertiesSet
BeanPostProcessor:接口吕粗,有兩個(gè)可以復(fù)寫的方法(接口有默認(rèn)實(shí)現(xiàn))试读,針對(duì)的對(duì)象是所有的bean锨咙,可以在內(nèi)部過(guò)濾自己需要處理的bean嘶炭,兩個(gè)方法
-
postProcessBeforeInitialization
:某個(gè)bean在初始化之前會(huì)進(jìn)行調(diào)用餐济,初始化意思為填充了bean的屬性值耘擂,但是還未調(diào)用InitializingBean 的afterPropertiesSet方法 -
postProcessAfterInitialization
:某個(gè)bean在初始化之后進(jìn)行調(diào)用
思考來(lái)源
在查看阿里的分布式事務(wù)解決方案Seata源碼時(shí),發(fā)現(xiàn)如果項(xiàng)目中使用了openfegin絮姆,seata會(huì)向ioc容器中添加一個(gè)SeataFeignContext的bean醉冤,但是openfegin自己也向容器中添加了一個(gè)FeignContext的實(shí)例bean,這也就是seata巧妙的地方篙悯,使用BeanPostProcessor實(shí)現(xiàn)了對(duì)FeignContext的一個(gè)包裝蚁阳,應(yīng)該也屬于靜態(tài)代理吧,SeataFeignContext繼承自FeignContext并且實(shí)現(xiàn)了seata自己的邏輯鸽照,然后使用SeataContextBeanPostProcessor將openfegin自己添加的FeignContext類型轉(zhuǎn)換為了SeataFeignContext
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
// 當(dāng)要向容器中注冊(cè)FeignContext時(shí)會(huì)判斷是否是SeataFeignContext螺捐,如果不是SeataFeignContext類型,說(shuō)明他是openfegin自己注冊(cè)的矮燎,我們給他包裝為SeataFeignContext類型
if (bean instanceof FeignContext && !(bean instanceof SeataFeignContext)) {
return new SeataFeignContext(getSeataFeignObjectWrapper(),
(FeignContext) bean);
}
return bean;
}
嘗試(使用BeanPostprocessor實(shí)現(xiàn)靜態(tài)代理)
結(jié)合上一篇文章SpringBoot之@Import注解(Registrar使用)最后定血,向容器中添加一個(gè)用戶Wangwu(name='王五',age=100)
@AllArgsConstructor
@Data
public class Wangwu {
private String name;
private int age;
}
新建一個(gè)代理類WangwuProxy,并在調(diào)用其get方法時(shí)打印一些日志诞外,并且將年齡+100
@Slf4j
public class WangwuProxy extends Wangwu {
public WangwuProxy(String name, int age) {
super(name, age);
}
@Override
public int getAge() {
log.error("調(diào)用了王五的getAge()澜沟,將其年齡+100");
return super.getAge()+100;
}
@Override
public String getName() {
log.error("調(diào)用了王五的getName()");
return super.getName();
}
}
新建一個(gè)WangwuPostProcessor,并且實(shí)現(xiàn)接口BeanPostProcessor和InitializingBean(實(shí)現(xiàn)afterPropertiesSet()方法打印日志)
@Component
@Slf4j
public class WangwuPostProcessor implements BeanPostProcessor, InitializingBean {
/**
* 當(dāng)某個(gè)bean初始化之前調(diào)用該方法峡谊,可以修改bean的一些屬性
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Wangwu&&!(bean instanceof WangwuProxy)){
// 如果是Wangwu的實(shí)例茫虽,進(jìn)行包裝一下
return new WangwuProxy(((Wangwu) bean).getName(),((Wangwu) bean).getAge());
}
return bean;
}
/**
* 當(dāng)某個(gè)bean初始化結(jié)束之后就會(huì)調(diào)用該方法,還可以修改bean的一些信息
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Wangwu){
// 經(jīng)過(guò)postProcessBeforeInitialization方法之后既们,wangwu這個(gè)bean已經(jīng)是WangwuProxy這個(gè)類的一個(gè)實(shí)例了
log.error("wangwu instance WangwuProxy =="+(bean instanceof WangwuProxy));
log.error("wangwu instance age is "+((Wangwu) bean).getAge());
}
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
@Override
public void afterPropertiesSet() throws Exception {
log.error("成功注冊(cè)WangwuPostProcessor");
}
}
- 實(shí)現(xiàn)afterPropertiesSet()方法濒析,打印日志
- 類似seata處理,我們將Wangwu這個(gè)實(shí)例修改為了WangwuProxy
- 初始化之后對(duì)wangwu進(jìn)行打印啥纸,最后可以看到wangwu這個(gè)bean已經(jīng)是WangwuProxy的一個(gè)實(shí)例
輸出結(jié)果:
2021-09-03 16:20:30.832 ERROR 62484 --- [main] c.e.j.s.processor.WangwuPostProcessor : 成功注冊(cè)WangwuPostProcessor
2021-09-03 16:20:33.156 ERROR 62484 --- [main] c.e.j.s.processor.WangwuPostProcessor : wangwu instance WangwuProxy ==true
2021-09-03 16:20:33.156 ERROR 62484 --- [main] c.e.jpa.scanner.processor.WangwuProxy : 調(diào)用了王五的getAge()号杏,將其年齡+100
2021-09-03 16:20:33.156 ERROR 62484 --- [main] c.e.j.s.processor.WangwuPostProcessor : wangwu instance age is 200