專題系列分類:玩轉SpringBoot2.x系列教程
1 demo 版本說明
springboot版本:2.0.5.RELEASE
jdk版本:1.8.0_144
在閱讀該博客前建議大家一定要把demo寫下來 在自己的環境下,根據操作靜下心來一步步看。閱讀源碼本身是一個比較費神的操作,建議大家一定要多看 看明白後自己在把大體思路捋一下。 因爲springboot用的也是spirng 所以下面介紹主要是spirng 而不是springboot 特此說明。
2 通過BeanPostProcessor 進行Bean 初始化回調前後進行自定義操作
我們知道spring可以爲我們創建bean對象實例 和以及Bean 屬性注入,但是如果我們想要在Bean自動裝配完成後自定義操作怎麼處理呢?我們需要BeanPostProcessor 接口來完成自定義操作處理。當你還不知道我在說什麼的情況下,那就直接看下面的代碼吧。
定義一個名稱爲IMyBean的接口其中有2個方法 一個獲取自定義值getCustomValue 一個進行設置自定義值的方法 setCustomValue
package cn.lijunkui.customBean;
public interface IMyBean {
void setCustomValue(String v);
String getCustomValue();
}
創建名稱爲MyBean的實體類 並實現IMyBean 並通過@Component 直接聲明該類爲spirng的bean
package cn.lijunkui.customBean;
import org.springframework.stereotype.Component;
@Component
public class MyBean implements IMyBean{
private String customValue;
@Override
public void setCustomValue(String customValue) {
this.customValue = customValue;
}
@Override
public String getCustomValue() {
return customValue;
}
}
創建實現BeanPostProcessor 的實現類完成對MyBean的初始化後自定義操作 如果在初始化MyBean 後customValue的值如果爲空則將其設置爲“defaultValue”
package cn.lijunkui.customBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
private Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof IMyBean) {
log.info("=======>postProcessAfterInitialization");
IMyBean mybean = (IMyBean) bean;
if (mybean.getCustomValue() == null) {
mybean.setCustomValue("defaultValue");
}
}
return bean;
}
}
通過在啓動類中獲取ConfigurableApplicationContext 獲取MyBean測試customValue的值是否改變。(這裏我們額外說一下Spirng中的bean都是通過BeanFactory進行管理的,在Spirng中默認使用的是DefaultListableBeanFactory 也就是BeanFactory的實現。 而下面代碼中ConfigurableApplicationContext getBean 就是BeanFactory中的方法)
package cn.lijunkui;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import cn.lijunkui.customBean.MyBean;
@SpringBootApplication
public class PrincipleApplication {
private static Logger log=LoggerFactory.getLogger(PrincipleApplication.class);
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(PrincipleApplication.class, args);
MyBean mybean = run.getBean(MyBean.class);
log.info("getCustomValue:"+mybean.getCustomValue());
}
}
測試結果: 我們看到下圖中加載的過程中進行了回調並且將customValue的值設置成了 defaultValue
爲什麼實現 BeanPostProcessor就可以進行bean初始化後的操作呢?想知道其中的原理我們就要去看看spring的源碼了。
第一步在MyBeanPostProcessor postProcessAfterInitialization方法中打一個段斷點 然後啓動spirngboot項目
當斷點走到 postProcessAfterInitialization 方法上事 如下圖它的調用鏈就出來了,是不是很清晰。
根據上圖調用鏈我們繼續查看 AbstractAutowireCapableBeanFactory.initializeBean 方法 該方法中我們看到和BeanPostProcessor 有關的2個方法
applyBeanPostProcessorsBeforeInitialization 和applyBeanPostProcessorsBeforeInitialization 是不是感覺和BeanPostProcessor 相關,下面是initializeBean 具體邏輯實現
/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* <p>Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @return the initialized bean instance (potentially wrapped)
* @see BeanNameAware
* @see BeanClassLoaderAware
* @see BeanFactoryAware
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
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;
}
applyBeanPostProcessorsBeforeInitialization 方法的具體實現邏輯如下
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
當我們看到Object current = processor.postProcessBeforeInitialization(result, beanName); 是不是知道了 這裏會獲取所有的BeanPostProcessor 然後調用postProcessBeforeInitialization
BeanPostProcessors 邏輯如下:
獲取AbstractBeanFactory 中的 beanPostProcessors
/**
* Return the list of BeanPostProcessors that will get applied
* to beans created with this factory.
*/
public List<BeanPostProcessor> getBeanPostProcessors() {
return this.beanPostProcessors;
}
applyBeanPostProcessorsAfterInitialization 邏輯和applyBeanPostProcessorsBeforeInitialization邏輯基本一直 代碼如下
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
BeanPostProcessor 調用時序圖如下:中間很多流程做了簡化 畫的是核心的邏輯。
。
還有一個問題就是我們的 BeanPostProcessor 集合是在什麼時添加的?關閉到我們的springboot服務
還是下圖的斷點 在次一debug方式啓動
通過調用的鏈路往下找 知道找到 AbstractApplicationContext 中的refresh() 方法中的 registerBeanPostProcessors(beanFactory)
通過PostProcessorRegistrationDelegate.registerBeanPostProcessors 將 放入到beanFactory 中
registerBeanPostProcessors 方法中獲取到所有的BeanPostProcessor 然後放入集合中
然後再將BeanPostProcessor集合 放入到 beanFactory 中
PostProcessorRegistrationDelegate registerBeanPostProcessors 具體源碼邏輯如下
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
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.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
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.
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
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.
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));
}
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
通過下圖瞭解springboot啓動後如何執行到 AbstractApplicationContext refresh 方法流程。
大致流程如下:
在 Spring 初始化完成後會回調 GenericApplicationContext 中的 refresh 方法,然後再通過AbstractApplicationContext 抽象類中的 refresh 來實現。
在refresh 方法中registerBeanPostProcessors 調用了 PostProcessorRegistrationDelegate,將 BeanFactory 作爲參數傳入,在registerBeanPostProcessors中獲取所有的BeanPostProcessor獲取完所有實現類後,根據實現類上的順序進行排序,然後將排序好的集合對象調用BeanFactory.addBeanPostProcessor 註冊到 BeanFactory 中。
這樣在 AbstractAutowireCapableBeanFactory 中就可以從它的父類 AbstractBeanFactory 中直接獲取到 BeanPostProcessor 集合對象了,也就是上面調用的 getBeanPostProcessors() 方法。