前言
程式執行了 resolveBeforeInstantiation 函數之後,如果傳回的結果為 null,就需要執行 doCreateBean 函數進行建立 Bean。本篇就來分析 doCreateBean 的代碼邏輯
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
// BeanWrapper是對Bean的包裝
BeanWrapper instanceWrapper = null;
//1、如果是單例,移除緩存
if (mbd.isSingleton()) {
// factoryBeanObjectCache:存的是beanName對應的FactoryBean.getObject()所傳回的對象
// factoryBeanInstanceCache:存的是beanName對應的FactoryBean執行個體對象
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// 2、執行個體化
if (instanceWrapper == null) {
// 建立bean執行個體 1、工廠方法 2、構造函數自動注入 3、簡單初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 包裝的執行個體對象,也就是原始對象
final Object bean = instanceWrapper.getWrappedInstance();
// 包裝的執行個體對象的類型
Class<?> beanType = instanceWrapper.getWrappedClass();
// 如果不是NullBean,則将resolvedTargetType 屬性設定為目前的WrappedClass
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//3、尋找注入點
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 這裡會查找@Autowired、@Value、Resource的注入點(InjectedElement),
// 并把這些注入點添加到mbd的屬性externallyManagedConfigMembers中
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
//4、
//如果目前bean是單例并且支援循環依賴,且目前bean正在建立,
//就通過往singletonFactories(三級緩存)添加一個objectFactory,
//這樣後期如果有其他bean依賴該bean 可以從singletonFactories擷取到bean, 解決循環依賴
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 構造一個 ObjectFactory 添加到singletonFactories中
// getEarlyBeanReference()可以對 傳回的bean進行修改,目前除了可能會傳回動态代理對象(aop) 其他的都是直接傳回bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 5、填充屬性,對 bean 進行填充 将各個屬性注入
populateBean(beanName, mbd, instanceWrapper);
// 6、執行初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// 7、檢測循環依賴
if (earlySingletonExposure) {
// earlySingletonReference 隻有在檢測到有循環依賴的情況下才會不為空
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 如果提前暴露的對象(bean)和經過了完整的生命周期後的對象相等(exposedObject)
// 則把緩存中的earlySingletonReference指派給exposedObject
// 最終會添加到singletonObjects中去
// (初始化之後的bean等于原始的bean,說明不是proxy),
//
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
//檢測該bean的dependon的bean是否都已經初始化好了
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
/*
* 因為 bean 建立後;其所依賴的 bean 一定是建立了的。
* actualDependentBeans 不為空表示當 bean 建立後依賴的 bean 沒有
* 全部建立完,也就是說存在循環依賴
*/
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
// 8、注冊DisposableBean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
}
複制代碼
上述代碼分支挺多的,總結一下關鍵點:
1、如果是單例則需要首先清除緩存
2、執行個體化 Bean,有四種方式:工廠方法,Supplier 回調、有參構造函數自動注入、預設構造函數注入
3、MergedBeanDefinitionPostProcessor 的使用
4、單例模式下的依賴處理
5、屬性填充,将所有屬性填充至 bean 的執行個體中
6、執行初始化方法
7、循環依賴檢查,存在循環依賴則抛出異常
8、注冊 DisposableBean
第一點就不再分析了。我們來看第二點執行個體化Bean createBeanInstance方法。本文就分析其中兩種執行個體化Bean 的方式。分别是:工廠方法,Supplier 回調。其餘兩種放到下一篇。
createBeanInstance
進入到createBeanInstance方法, 該方法位于 AbstractAutowireCapableBeanFactory 類中
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 得到bean的class 使用類加載器根據設定的 class 屬性或者根據 className 來解析 Class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 如果beanclass不是public 且不允許通路非public方法和屬性則抛出異常
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());
}
// 這是Spring提供給開發者的擴充點
// 當一個BeanDefinition中存在一個Supplier類的時候, Spring就利用這個類的get方法來擷取執行個體,
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 通過factoryMethod執行個體化這個bean
// factorMethod這個名稱在xml中還是比較常見的, 即通過工廠方法來建立bean對象
// 如果一個bean對象是由@Bean注解建立的, 也會走instantiateUsingFactoryMethod方法來建立
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean... 重新建立相同bean時的快捷方式
boolean resolved = false;
boolean autowireNecessary = false;
// 當作用域為原型、多次調用getBean()時,不傳入參數,從緩存中擷取這段邏輯才會被執行
// 如果是單例,第二次調用 getBean(),直接從單例池擷取對象了,根本就不會走到這裡
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// resolvedConstructorOrFactoryMethod 緩存了已解析的構造函數或工廠方法
if (mbd.resolvedConstructorOrFactoryMethod != null) {
// resolved為true,表示目前bean的構造方法已經确定了,也代表該Bean之前被解析過
resolved = true;
// constructorArgumentsResolved:将構造函數參數标記為已解析,true就是标記為了已解析
// 預設為 false。
// 如果autowireNecessary為true說明是采用有參構造函數注入
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
// resolved為true,表示目前bean的構造方法已經确定了,也代表該Bean之前被解析過
// autowireNecessary表示采用有參構造函數注入
if (autowireNecessary) {
// 采用有參構造函數注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 如果構造方法已經确定了,但是沒有确定構造方法參數,那就表示沒有構造方法參數,用無參的構造方法來執行個體化bean
return instantiateBean(beanName, mbd);
}
}
// 代碼執行到這,說明是第一次建立該bean
// 根據SmartInstantiationAwareBeanPostProcessor擷取構造函數,
// 具體實作在:AutowiredAnnotationBeanPostProcessor
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 通過BeanPostProcessor找出了構造方法
// 或者BeanDefinition的autowire屬性為AUTOWIRE_CONSTRUCTOR xml中使用了 autowire="constructor"
// 或者BeanDefinition中指定了構造方法參數值 使用了 <constructor-arg>标簽
// 或者在getBean()時指定了args
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 進行有參構造方法推斷并執行個體化
return autowireConstructor(beanName, mbd, ctors, args);
}
// 沒啥用
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// 用無參的構造方法來執行個體化bean
return instantiateBean(beanName, mbd);
}
複制代碼
上面代碼一大堆,其主要的邏輯為:
1、如果存在 Supplier 回調,則調用 obtainFromSupplier() 進行初始化
2、如果存在工廠方法,則使用 instantiateUsingFactoryMethod() 進行初始化
3、判斷 resolvedConstructorOrFactoryMethod是否不為空,如果不為空,則存在緩存,直接使用已經解析了的。然後根據 autowireNecessary 參數來判斷是使用有參構造函數自動注入還是使用預設構造函數注入。
4、如果緩存中沒有,則需要明确使用哪個構造函數來完成解析工作,因為一個類可以有多個構造函數,每個構造函數都有不同的構造參數,是以需要根據參數來鎖定構造函數并完成初始化。如果存在參數則使用相應的帶有參數的構造函數,否則使用預設構造函數。
obtainFromSupplier
Supplier 是 Java8 的一個函數式接口。該接口中就一個 get() 方法。具體介紹不多說,詳情請前往 Java8——Lambda表達式
從上述代碼可以看到 Spring 是從 mbd中得到的 Supplier 。既然可以得到那就可以進行設定。instanceSupplier屬性是屬于 AbstractBeanDefinition 抽象類的。
- set方法 進行設定
public void setInstanceSupplier(@Nullable Supplier<?> instanceSupplier) {
this.instanceSupplier = instanceSupplier;
}
複制代碼
- 構造方法 進行設定
public <T> RootBeanDefinition(@Nullable Class<T> beanClass, @Nullable Supplier<T> instanceSupplier) {
super();
setBeanClass(beanClass);
setInstanceSupplier(instanceSupplier);
}
複制代碼
- 直接進行注冊
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
ctx.registerBean(Person.class, new Supplier<Person>() {
@Override
public Person get() {
return new Person("gongj");
}
});
複制代碼
使用
這裡就對使用 set方式舉例。首先建立兩個普通類對象,Person 和 User。
public class Person{
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
public class User {
}
複制代碼
測試
public static void main(String[] args) {
// 建立 BeanFactory 容器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 建構 BeanDefinition
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(User.class);
// 構造器引用 這裡調用的是無參構造器
rootBeanDefinition.setInstanceSupplier(Person::new);
// 注冊BeanDefinition
factory.registerBeanDefinition("user",rootBeanDefinition);
Object user = factory.getBean("user");
// 傳回的是 Person 對象
System.out.println("結果:" +user);
}
結果:Person{name='null'}
複制代碼
可以看到我們 setBeanClass設定的是User,但結果确是Person。
如果設定了 instanceSupplier 則調用 obtainFromSupplier() 完成 bean 的初始化,如下:
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
Object instance;
String outerBean = this.currentlyCreatedBean.get();
// 設定 beanName到 currentlyCreatedBean 中
this.currentlyCreatedBean.set(beanName);
try {
// 調用 Supplier 的 get(),傳回一個 Bean 對象
instance = instanceSupplier.get();
}
finally {
if (outerBean != null) {
this.currentlyCreatedBean.set(outerBean);
}
else {
this.currentlyCreatedBean.remove();
}
}
// get() 未建立 Bean 對象,則建立 NullBean 對象
if (instance == null) {
instance = new NullBean();
}
// 建立bean的包裝類
BeanWrapper bw = new BeanWrapperImpl(instance);
// 初始化bean的包裝
initBeanWrapper(bw);
return bw;
}
複制代碼
obtainFromSupplier 方法的代碼很簡單,調用 Supplier 的 get() 方法獲得一個執行個體對象,然後根據該執行個體對象構造一個 BeanWrapper 對象 bw,最後初始化該對象。
instantiateUsingFactoryMethod
通過 factory-method 建立對象有兩種方式,一種是靜态工廠注入(其中的方法必須是靜态的),另一種是執行個體工廠注入。具體使用請移步前往:XML檔案的讀取-factory-method的使用
該方法位于 AbstractAutowireCapableBeanFactory 類
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
複制代碼
然後再進入 ConstructorResolver 類的 instantiateUsingFactoryMethod
public BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
// 構造 BeanWrapperImpl 對象
BeanWrapperImpl bw = new BeanWrapperImpl();
// 初始化 BeanWrapperImpl
// 向 BeanWrapper對象中添加 ConversionService 對象和屬性編輯器 PropertyEditor 對象
this.beanFactory.initBeanWrapper(bw);
Object factoryBean;
Class<?> factoryClass;
// 目前factoryMethod是不是靜态的
boolean isStatic;
//擷取 factory-bean 屬性的值,如果有值就說明是 執行個體工廠方式執行個體對象
String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// 根據 factoryBeanName 擷取工廠執行個體
// 直接走 getBean 方法
factoryBean = this.beanFactory.getBean(factoryBeanName);
//如果目前Bean是單例并且單例池中存在該beanName的對象 則抛出異常
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
factoryClass = factoryBean.getClass();
isStatic = false;
}
// 靜态工廠方式
else {
// It's a static factory method on the bean class.
// 靜态工廠建立bean,必須要提供工廠的全類名
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"bean definition declares neither a bean class nor a factory-bean reference");
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}
// 工廠方法
Method factoryMethodToUse = null;
ArgumentsHolder argsHolderToUse = null;
// 參數
Object[] argsToUse = null;
// 開發者在調用 getBean 方法的時候指定了方法參數則直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
// 沒有指定,則嘗試從 mbd 中解析參數
Object[] argsToResolve = null;
// 首先嘗試從緩存中擷取
synchronized (mbd.constructorArgumentLock) {
// 獲得已解析的構造函數或工廠方法
// resolvedConstructorOrFactoryMethod:緩存已解析的構造函數或工廠方法
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
// 找到了mbd中緩存的構造方法
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached factory method...
// 獲得已完全解析的構造函數參數(參數類型已經确定,能夠直接進行使用)
// 正常情況下 resolvedConstructorArguments 的值就是 null
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
//獲得部分準備好的構造函數參數(該參數的類型是不确定的,需要進行解析)
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
//如果存在構造函數參數,那麼則對參數值進行類型轉化
//如給定方法的構造函數 Person(int) 則通過此方法後就會把配置中的
// "5“ 轉換為 5
//<constructor-arg index="0" value="5"/>
//緩存中的值可能是原始值也可能是最終值
if (argsToResolve != null) {
// 什麼時候進入這裡? 當作用域為原型時并多次調用 getBean()時沒有傳遞參數
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
}
}
// 如果目前BeanDefinition中沒有解析出來具體的factoryMethod對象,或者沒有解析出對應的方法參數
// 也就是沒有緩存,第一次進行建立
// 那什麼時候能解析出來緩存呢?當作用域為原型時、多次調用getBean方法時不傳入參數
if (factoryMethodToUse == null || argsToUse == null) {
// 如果目前類是cglib生成的代理類,則擷取其父類,否則傳回class本身
factoryClass = ClassUtils.getUserClass(factoryClass);
// 方法集合
List<Method> candidates = null;
// 工廠方法是否唯一
if (mbd.isFactoryMethodUnique) {
if (factoryMethodToUse == null) {
factoryMethodToUse = mbd.getResolvedFactoryMethod();
}
if (factoryMethodToUse != null) {
candidates = Collections.singletonList(factoryMethodToUse);
}
}
if (candidates == null) {
candidates = new ArrayList<>();
// 擷取工廠類裡所有待定方法
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
// 檢索所有方法 将符合條件的方法添加到集合中
for (Method candidate : rawCandidates) {
// 目前方法是否包含static修飾符,包含則傳回true,否則傳回false,然後與 isStatic 比較
// 目前方法名稱是否與 配置的factoryMethod方法名稱是否相等
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
candidates.add(candidate);
}
}
}
// 找到的方法數量為 1 并且沒有傳入參數 配置檔案也沒有使用 constructor-arg 屬性
if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Method uniqueCandidate = candidates.get(0);
// 該工廠方法的參數個數為 0
if (uniqueCandidate.getParameterCount() == 0) {
// 緩存唯一的工廠方法
mbd.factoryMethodToIntrospect = uniqueCandidate;
synchronized (mbd.constructorArgumentLock) {
// 緩存已解析的構造函數或工廠方法
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
// 将構造函數參數标記為已解析
mbd.constructorArgumentsResolved = true;
// 緩存完全解析的構造函數參數
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
// 建立對象
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
// 比對的方法數量 大于 1,進行方法排序
// 按構造方法的參數個數降序排序,先排序public構造函數,參數降序排列
// 然後排序非public 的構造函數,參數降序排列
if (candidates.size() > 1) {
candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);
}
// 記錄解析後的構造方法參數值
ConstructorArgumentValues resolvedValues = null;
// autowireMode 是構造方法自動注入,則要自動選擇構造方法
boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Method> ambiguousFactoryMethods = null;
// minNrOfArgs:表示所有構造方法中,參數個數最少的構造方法的參數個數是多少
int minNrOfArgs;
// 開發者在調用 getBean 方法的時候指定了方法參數則直接使用方法參數的個數
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}else {
// 如果有為這個bean定義的構造函數參數值,則傳回true
if (mbd.hasConstructorArgumentValues()) {
// 構造函數的參數 值來源于 constructor-arg标簽
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 解析參數個數 值來源于 constructor-arg 标簽中的 index屬性的值
// 也會将該 bean 的構造函數參數解析為 resolvedValues 對象,其中會涉及到其他 bean
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}else {
// 沒有指定參數 也沒有 定義constructor-arg标簽
minNrOfArgs = 0;
}
}
LinkedList<UnsatisfiedDependencyException> causes = null;
for (Method candidate : candidates) {
// 方法的參數個數
int parameterCount = candidate.getParameterCount();
// 目前方法的參數個數 大于等于 最小的構造方法的參數個數
if (parameterCount >= minNrOfArgs) {
ArgumentsHolder argsHolder;
// 目前方法每個參數的參數類型
Class<?>[] paramTypes = candidate.getParameterTypes();
// 調用getBean()時傳遞了參數
if (explicitArgs != null) {
//已經顯式的給出參數->參數長度必須精确比對,不比對則跳過目前方法
if (paramTypes.length != explicitArgs.length) {
continue;
}
// 參數長度已經比對 根據 genBean()方法傳入的參數建構 ArgumentsHolder 對象
argsHolder = new ArgumentsHolder(explicitArgs);
}else {
// 調用getBean()時沒有傳遞參數
try {
String[] paramNames = null;
// ParameterNameDiscoverer用于解析方法、構造函數上的參數名稱
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
// 擷取指定方法的參數名稱
paramNames = pnd.getParameterNames(candidate);
}
// 在獲得 解析的構造函數參數值(resolvedValues) 的情況下,建立一個ArgumentsHolder 對象
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
}
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
// 根據參數類型和參數值計算權重
// Lenient寬松,預設寬松模式是開啟的
// 嚴格模式:解析函數時,必須所有的都需要比對,否則抛出異常
// 寬松模式:使用具有"最接近的模式"進行比對
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// 如果目前方法的權重比較小,則表示目前方法更合适
if (typeDiffWeight < minTypeDiffWeight) {
factoryMethodToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
}
// 如果具有相同參數數量的方法具有相同的類型差異權重,則收集此類型選項
// 但是,僅在非寬松構造函數解析模式下執行該檢查,并顯式忽略重寫方法(具有相同的參數簽名)
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
!mbd.isLenientConstructorResolution() &&
paramTypes.length == factoryMethodToUse.getParameterCount() &&
!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
if (ambiguousFactoryMethods == null) {
ambiguousFactoryMethods = new LinkedHashSet<>();
ambiguousFactoryMethods.add(factoryMethodToUse);
}
ambiguousFactoryMethods.add(candidate);
}
}
}
// 沒有可執行的工廠方法,抛出異常
if (factoryMethodToUse == null || argsToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
List<String> argTypes = new ArrayList<>(minNrOfArgs);
if (explicitArgs != null) {
for (Object arg : explicitArgs) {
argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
}
}
else if (resolvedValues != null) {
Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
valueHolders.addAll(resolvedValues.getGenericArgumentValues());
for (ValueHolder value : valueHolders) {
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
argTypes.add(argType);
}
}
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"No matching factory method found: " +
(mbd.getFactoryBeanName() != null ?
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
"Check that a method with the specified name " +
(minNrOfArgs > 0 ? "and arguments " : "") +
"exists and that it is " +
(isStatic ? "static" : "non-static") + ".");
}
else if (void.class == factoryMethodToUse.getReturnType()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid factory method '" + mbd.getFactoryMethodName() +
"': needs to have a non-void return type!");
}
else if (ambiguousFactoryMethods != null) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous factory method matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousFactoryMethods);
}
if (explicitArgs == null && argsHolderToUse != null) {
mbd.factoryMethodToIntrospect = factoryMethodToUse;
// 将解析的構造函數加入緩存
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
}
// 反射調用factoryBean對象中的工廠方法進行執行個體化得到一個對象
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
return bw;
}
複制代碼
累了累了,這個方法是真的長,而且分支還特别多。各位讀者下去需要多 Debug 幾次了。
接下來總結一下:
上面那麼多代碼其實就是在确認:确定工廠對象,然後确認構造函數和構造參數,最後調用 InstantiationStrategy 對象的 instantiate() 來建立執行個體。
- 1、首先确定 factory-bean 屬性的值,如果值不為 null,則代表是執行個體工廠方式執行個體對象,調用 beanFactory.getBean() 擷取工廠對象。若為空,則代表是靜态工廠方式,對于靜态工廠方法必須提供工廠類的全類名,同時設定 factoryBean = null,isStatic = true。這裡就确定了工廠對象。
- 2、工廠對象确定後,則是确認構造參數。構造參數的确認主要分為三種情況:explicitArgs 參數、緩存中擷取、配置檔案中解析。explicitArgs 參數也就是我們在調用 getBean 方法時指定的方法參數。如果explicitArgs不為空,則可以确認方法參數就是它,那也就沒必要從緩存中擷取了。隻需要确定工廠方法就好了。如果explicitArgs 為空,則需要從緩存中确定了,在緩存中可以确定工廠方法和構造參數。如果工廠方法和構造參數都确定好了直接調用 InstantiationStrategy 對象的 instantiate() 來建立執行個體。
- 3、如果explicitArgs 參數為空、在緩存中也沒有确定,那就隻能從配置檔案中擷取構造參數資訊。如果你閱讀了筆者前面的文章就會知道,配置檔案中的資訊都會轉換為 BeanDefinition 對象,是以可以通過 BeanDefinition 對象進行擷取。
- 3.1、首先擷取到工廠對象裡的所有方法,包括工廠對象父類的方法,然後根據條件進行篩選。如果篩選出來的方法數量為 1 并且explicitArgs 參數為空,配置檔案也沒有使用 constructor-arg 屬性,則使用無參工廠方法進行執行個體對象,調用 InstantiationStrategy 對象的 instantiate() 來建立執行個體。順便進行緩存:
if (uniqueCandidate.getParameterCount() == 0) {
// 緩存唯一的工廠方法
mbd.factoryMethodToIntrospect = uniqueCandidate;
synchronized (mbd.constructorArgumentLock) {
// 緩存已解析的構造函數或工廠方法
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
// 将構造函數參數标記為已解析
mbd.constructorArgumentsResolved = true;
// 緩存完全解析的構造函數參數
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
複制代碼
- 3.2、如果篩選出來的方法數量大于 1 ,對其進行排序處理,排序規則是:public 構造函數優先,參數數量降序;然後是非 public 構造參數數量降序。如果explicitArgs 參數為空,則從配置檔案擷取構造參數資訊,确定構造參數。
// 如果有為這個bean定義的構造函數參數值,則傳回true
if (mbd.hasConstructorArgumentValues()) {
// 構造函數的參數 值來源于 constructor-arg标簽
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 解析參數個數,值來源于 constructor-arg 标簽中的 index 屬性的值 這個值可以随便寫
// 也會将 bean 的構造函數參數解析為 resolvedValues 對象
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
複制代碼
- 3.3、通過循環的方式,周遊篩選出來的方法。再次進行篩選,目前方法的參數個數需要大于等于最小的構造方法的參數個數(parameterCount >= minNrOfArgs)。如果顯示提供了參數(explicitArgs != null),則直接比較兩者的參數個數是否相等,如果相等則表示找到了,根據explicitArgs 參數建構 ArgumentsHolder 對象。如果沒有顯示提供參數,則需要擷取 ParameterNameDiscoverer 對象,主要用于解析方法、構造函數上的參數名稱。 根據 N 多個參數包裝成 ArgumentsHolder 對象,該對象用于儲存參數,我們稱之為參數持有者。當将對象包裝成 ArgumentsHolder 對象後,我們就可以通過它來進行構造函數比對,比對又分為嚴格模式和寬松模式,預設為寬松模式。也就是會使用argsHolder.getTypeDifferenceWeight(paramTypes)方法進行計算。
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// 如果目前方法的權重比較小,則表示目前方法更合适(分越少優先級越高?)
if (typeDiffWeight < minTypeDiffWeight) {
factoryMethodToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
}
複制代碼
為什麼分越少優先級越高?
主要是計算找到的bean和構造方法參數類型比對程度有多高。
假設bean的類型為 A,A 父類是 B,B 的父類是 C。同時 A 實作了接口 D
- 如果構造方法的參數類型為A,那麼完全比對,得分為0
- 如果構造方法的參數類型為B,那麼得分為2
- 如果構造方法的參數類型為C,那麼得分為4
- 如果構造方法的參數類型為D,那麼得分為1
可以直接使用如下代碼進行測試:
Object[] objects = new Object[]{new A()};
// 0
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{A.class}, objects));
// 2
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{B.class}, objects));
// 4
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{C.class}, objects));
// 1
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{D.class}, objects));
複制代碼
到此,工廠對象、工廠方法、參數都已經全部進行确認了,接下來就是調用 InstantiationStrategy 對象的 instantiate() 來建立 bean 執行個體。
instantiate
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Object factoryBean, final Method factoryMethod, Object... args) {
try {
// 忽略。。。
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(factoryMethod);
return null;
});
}
else {
// 設定給定的方法為可通路
ReflectionUtils.makeAccessible(factoryMethod);
}
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
try {
currentlyInvokedFactoryMethod.set(factoryMethod);
// 使用反射建立對象
// 重點也就是這句話
Object result = factoryMethod.invoke(factoryBean, args);
if (result == null) {
result = new NullBean();
}
return result;
}
finally {
if (priorInvokedFactoryMethod != null) {
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
}
else {
currentlyInvokedFactoryMethod.remove();
}
}
}
catch (IllegalArgumentException ex) {
// catch 省略
}
}