玩轉SpringBoot 2.x 解析BeanPostProcessor原理篇

專題系列分類:玩轉SpringBoot2.x系列教程

1 demo 版本說明

開發工具:Spring Tool Suite (STS)

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() 方法。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章