1. 程式人生 > 其它 >【走近Spring】為脫離Spring IOC容器管理的Bean賦能【依賴注入】的能力,並分析原理(藉助AutowireCapableBeanFactory賦能)

【走近Spring】為脫離Spring IOC容器管理的Bean賦能【依賴注入】的能力,並分析原理(藉助AutowireCapableBeanFactory賦能)

不可否認的是,把Bean交給Spring管理,確實極其的方便,優點一大把,並且還幾乎沒有啥缺點。這也就是為何咱們一言不合就把Bean扔給Spring的原因。(在Spring的技術棧裡這麼做,完全沒有問題)

然而,就Spring框架本身而言。它的強大的依賴注入,不僅僅能給自家的Bean使用,還能賦能給容器之外的Bean,快速的把需要注入的物件給它裝配好。

本來我也一直以為你想用Spring的依賴注入功能,就得交給Spring容器進行管理。

AutowireCapableBeanFactory 的解釋

 * Extension of the {@link org.springframework.beans.factory.BeanFactory}
 * interface to be implemented by bean factories that are capable of
 * autowiring, provided that they want to expose this functionality for
 * existing bean instances.

AutowireCapableBeanFactory在BeanFactory基礎上實現了對存在例項的管理,可以使用這個介面整合其它框架,捆綁並填充並不由Spring管理生命週期並已存在的例項。像整合WebWork的Actions 和Tapestry Page就很實用。

public interface AutowireCapableBeanFactory extends BeanFactory {

	int AUTOWIRE_NO = 0;
	int AUTOWIRE_BY_NAME = 1;
	int AUTOWIRE_BY_TYPE = 2;
	int AUTOWIRE_CONSTRUCTOR = 3;
	@Deprecated
	int AUTOWIRE_AUTODETECT = 4;
	
	// 注意這個CreateBean和下面的CrateBean的不同
	//JavaDoc:It does <i>not</> imply traditional by-name or by-type autowiring of properties;
	// 也就是說它只管給你建立Bean,但是不管給你根據Name或者Type進行注入哦
	// 當然,你可以顯示在對應屬性上指定@Autowired註解,讓他也可以達到相同的效果
	<T> T createBean(Class<T> beanClass) throws BeansException;
	void autowireBean(Object existingBean) throws BeansException;
	Object configureBean(Object existingBean, String beanName) throws BeansException;
	Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
	Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
	void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)
			throws BeansException;
	void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
	Object initializeBean(Object existingBean, String beanName) throws BeansException;
	Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException;
	Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException;
	void destroyBean(Object existingBean);
	<T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
	@Nullable
	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
	@Nullable
	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;

}

以createBean() 方法為例

// 準備一個Child類
@Getter
@Setter
public class Child {

// 注意:這裡並沒有@Autowired註解的
private HelloService helloService;

private String name;
private Integer age;

}


public static void main(String[] args) {
	ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
	// ApplicationContext裡面是持久AutowireCapableBeanFactory這個工具的,它真實的實現類一般都是:DefaultListableBeanFactory
	AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();

	// 我把Child的建立過程都交給Bean工廠去幫我們處理,自己連new都不需要了 (createBean方法執行多次,就會建立多個child例項)
	Child child = (Child) autowireCapableBeanFactory.createBean(Child.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);

	//簡直殘暴,沒有@Autowired註解都給注入進來了~~~  至於為什麼,看看下面的分析,你就知道了
	System.out.println(child.getHelloService()); //com.fsx.service.HelloServiceImpl@6a78afa0

	// 丟擲異常 No qualifying bean of type 'com.fsx.bean.Child' available 
	// 能佐證:我們的Bean並沒交給Spring容器管理,它只是幫我們建立好了,並把對應屬性注入進去了
	Child bean = applicationContext.getBean(Child.class);
	System.out.println(bean);
}

看到這個現象有沒有很驚喜,我們哪怕不是Spring去管理的物件,都能夠依賴注入進來容器內的物件,並且連@Autowired註解都不需要。所以更別談Spring內部的容器,並且還標註了註解的,那就應該更容易去實現了

以createBean() 方法為例的原始碼分析

AbstractAutowireCapableBeanFactory#createBean:

@Override
public Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
	// Use non-singleton bean definition, to avoid registering bean as dependent bean.
	RootBeanDefinition bd = new RootBeanDefinition(beanClass,  autowireMode, dependencyCheck);
	// 這裡看到了,採用的不是單例,而是prototype
	bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
	// For the nullability warning, see the elaboration in AbstractBeanFactory.doGetBean;
	// in short: This is never going to be null unless user-declared code enforces null.
	// doc說得很明白,這裡返回值永遠不可能為null。除非呼叫者強制return null
	// 注意的是:這裡BeanName就是beanClass.getName()
	return createBean(beanClass.getName(), bd, null);
}

// 最終都呼叫到了下面這個createBean方法。它也是AbstractBeanFactory提供的一個抽象方法
// 最終也由AbstractAutowireCapableBeanFactory去實現的。 我們熟悉的doGetBean()方法,最終也是呼叫它來建立例項物件  只是doGetBean()把單例物件都快取起來了
// 這個方法很單純:建立一個例項,然後初始化他(給屬性們賦值),然後return出去即可
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {

	if (logger.isDebugEnabled()) {
		logger.debug("Creating instance of bean '" + beanName + "'");
	}
	RootBeanDefinition mbdToUse = mbd;

	// Make sure bean class is actually resolved at this point, and
	// clone the bean definition in case of a dynamically resolved Class
	// which cannot be stored in the shared merged bean definition.
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	// Prepare method overrides.
	// 解析一些@lookup註解之類的  忽略
	try {
		mbdToUse.prepareMethodOverrides();
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
				beanName, "Validation of method overrides failed", ex);
	}

	try {
		// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
		// 這個之前都解釋過了,就不解釋了。若BeanPostProcessors 產生了一個代理物件,就不需要我去建立了,就不繼續往下走了(AOP都走這裡)
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}
	catch (Throwable ex) {
		throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
				"BeanPostProcessor before instantiation of bean failed", ex);
	}

	try {
		// 重點來了。它是本類的一個protected方法,專門用於處理建立Bean的過程(包括屬性賦值之類的)
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isDebugEnabled()) {
			logger.debug("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}
	catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
		// A previously detected exception with proper bean creation context already,
		// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
	}
}

這裡再看看doCreateBean吧,因為之前有講過這個方法,這裡就只看核心步驟。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args){
	BeanWrapper instanceWrapper = null;
	...
	//createBeanInstance 是重點(都是返回一個BeanWrapper)  它也是本類的一個protected方法
	instanceWrapper = createBeanInstance(beanName, mbd, args);

	// Bean已經例項化好了,準備初始化吧
	...
	// 執行MergedBeanDefinitionPostProcessor
	// 處理迴圈引用,現在若我們Bean不在容器裡,肯定是不存在迴圈引用的(但是我依賴的Bean可能還沒建立是真的,也是這裡來處理的)
	...

	// 給Bean例項的各個屬性進行賦值 比如呼叫InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation、給屬性注入值(並不依賴於@Autowired註解)
	// 執行InstantiationAwareBeanPostProcessor#postProcessPropertyValues等等
	populateBean(beanName, mbd, instanceWrapper);

	// 初始化Bean 執行一些初始化方法init @PostContruct方法等等 
	//BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization等等
	exposedObject = initializeBean(beanName, exposedObject, mbd);

}

綜上可以看出,目前最重要的三個步驟為doCreateBean裡面的:createBeanInstance、populateBean、initializeBean,都在AbstractAutowireCapableBeanFactory這裡

createBeanInstance

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	// Make sure bean class is actually resolved at this point.
	Class<?> beanClass = resolveBeanClass(mbd, beanName);
	
	// 如果不為null,並且還不是public的訪問許可權 並且還nonPublicAccessAllowed為false 那就拋異常吧
	// 題外話:nonPublicAccessAllowed為true的情況下(預設值),即使你不是public的也ok
	if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
		throw new BeanCreationException(mbd.getResourceDescription(), beanName,
				"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
	}
	
	// 你可以自己通過Supplier來建立Bean,最終交給obtainFromSupplier包裝成BeanWrapper
	Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
	if (instanceSupplier != null) {
		return obtainFromSupplier(instanceSupplier, beanName);
	}

	//通過工廠方法建立 支援工廠方法方式建立Bean
	if (mbd.getFactoryMethodName() != null)  {
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}

	// Shortcut when re-creating the same bean...
	//一個類可能有多個構造器,所以Spring得根據引數個數、型別確定需要呼叫的構造器
	//在使用構造器建立例項後,Spring會將解析過後確定下來的構造器或工廠方法儲存在快取中,避免再次建立相同bean時再次解析
	boolean resolved = false;
	boolean autowireNecessary = false;
	if (args == null) {
		synchronized (mbd.constructorArgumentLock) {
			if (mbd.resolvedConstructorOrFactoryMethod != null) {
				resolved = true;
				autowireNecessary = mbd.constructorArgumentsResolved;
			}
		}
	}
	
	// 首次進入,resolved為false。
	// 說一下:ConstructorResolver,就是找到合適的構造器給你去例項化一個Bean(會結合Spring容器進行一起解析)
	if (resolved) {
		if (autowireNecessary) {
			return autowireConstructor(beanName, mbd, null, null);
		}
		else {
			return instantiateBean(beanName, mbd);
		}
	}

	// Need to determine the constructor...
	// 執行BeanPostProcesso#determineCandidateConstructors 自己去決定使用哪個構造器,可能會返回一批構造器喲  
	// 這裡我們很熟悉的`AutowiredAnnotationBeanPostProcessor`就實現了這個方法,可以智慧去找出一個合適的構造器.
	// 這裡需要注意了,因為我們的Child的屬性HelloService裡並沒有書寫@Autowired屬性,所以這裡最終的返回結果是null================這個需要注意Spring的處理(空構造就不用交給autowireConstructor處理了,自己直接new吧)
	// 需要注意的是:若我們自己寫了一個構造    public Child(HelloService helloService) {  this.helloService = helloService; } 那麼它就會拿到,然後走下面讓Spring執行構造器的注入的
	// 旁白:如果你只有空構造,那就直接instantiateBean,否則會自動去走Spring的構造器注入的邏輯
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null ||
			mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	// No special handling: simply use no-arg constructor.
	// 所以我們當前的Child,只有空構造器,所以就只能走這裡啦
	// 這個方法的邏輯比較簡單,我就不貼了。主要是用InstantiationStrategy策略器進行例項化,至於它是什麼東東?文末的時候我會解釋的
	return instantiateBean(beanName, mbd);
}

該方法執行完成之後,我們物件就被建立了,但僅僅還只是建立好哦。下面繼續看:

populateBean: populate:居住於; 生活於; 大致意思就是給Bean的各個屬性賦值

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	if (bw == null) {
		if (mbd.hasPropertyValues()) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
		}
		else {
			// Skip property population phase for null instance.
			return;
		}
	}

	// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
	// state of the bean before properties are set. This can be used, for example,
	// to support styles of field injection.
	boolean continueWithPropertyPopulation = true;

	// 因為已經例項化了,物件已經建立了,所以這裡立馬執行了InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation方法
	// 單反只有其中一個返回了false,相當於告訴容器我都處理好了,那麼後面的賦值操作就Spring容器就不再處理了
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					continueWithPropertyPopulation = false;
					break;
				}
			}
		}
	}

	if (!continueWithPropertyPopulation) {
		return;
	}
	
	//以物件的方式儲存健值對,比儲存在map會更加靈活
	//PropertyValues  是用來管理PropertyValue的  一般情況下為null
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

	// 那麼接下來,就開始幹正事了~~~~
	// 這裡需要注意的是:我們知道上面我們自己傳進來的是byType,所以這個的if是能夠進來的,最終能夠定位autowireByType讓它去實現注入功能。
	//所以我們的helloService欄位要不要@Autowired要不要無所謂(要了也只是重複操作而已,但是我建議顯示的指明吧)
	
	//但是被Spring掃描Scan管理的Bean們(或者其餘Bean),如果你想要給他欄位注入屬性值,必須必須使用@Autowired註解,從而交給後置處理器AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues這個方法去處理
	if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
			mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

		// Add property values based on autowire by name if applicable.
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
			autowireByName(beanName, mbd, bw, newPvs);
		}

		// Add property values based on autowire by type if applicable.
		// 按型別自動裝配。一般都會走這裡,通過型別的匹配,來給屬性賦值,實現注入
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {

			// 它的步驟相對簡單:顯示BeanUtils.getWriteMethodParameter(pd)拿到set方法(所以,這裡需要注意,若沒有set方法,這裡是注入不進去的,這個沒@Autowired強大)
			// 然後去解析去容器裡面找對應的依賴,也是resolveDependency方法(最終由DefaultListableBeanFactory去實現的)

	
			// 這裡需要注意:注入的時候isSimpleProperty不會被注入的(包括基本資料型別、Integer、Long。。。
			//甚至還包括Enum、CharSequence(顯然就包含了Spring)、Number、Date、URI、URL、Locale、Class等等)
			// 但是,但是,但是標註@Autowired是能夠注入的哦,哪怕是String、Integer等等
			// 標註了@Autowired,沒有找到反倒為報錯 No qualifying bean of type 'java.lang.String' 。。。注意這些區別
			autowireByType(beanName, mbd, bw, newPvs);
		}

		pvs = newPvs;
	}

	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
	boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

	if (hasInstAwareBpps || needsDepCheck) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
		if (hasInstAwareBpps) {

			// 開始執行InstantiationAwareBeanPostProcessor#postProcessPropertyValues
			// 這裡主要施工的又是我們大名鼎鼎的AutowiredAnnotationBeanPostProcessor它了,他會根據所有標註有@Autpwired註解地方,執行注入(非常重要)
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvs == null) {
						return;
					}
				}
			}
		}
		if (needsDepCheck) {
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}
	}
	
	//applyPropertyValues和PropertyValues密切相關,在後面相關專題在詳細講解  會回到這裡的,持續關注~
	// 作用:Apply the given property values, resolving any runtime references
	if (pvs != null) {
		applyPropertyValues(beanName, mbd, bw, pvs);
	}
}

至此,一個Bean的例項化、初始化操作可以完成了一大部分了(各欄位、屬性的賦值也都已經ok了~),那麼還剩下一些收尾工作:比如init方法、post-construct方法之類的,就交給

initializeBean:初始化Bean(呼叫一些初始化方法)

  1. invokeAwareMethods:執行一些感知介面Aware的注入