❝你的贊是我最大的動力,期待與你的共同進步。web
❞
文章開篇,不得不前情提要走一波了。還記得 @Configuration
類中的@Bean
方法是如何處理的嗎?@Bean
方法中的對象是如何實例化的?小小的腦殼上面是否有大大的問號呢? 這裏作一個簡要回顧,首先看 @Bean
方法的處理: 而後在經過下面以系列的方法對其解析:
緩存
上述圖片中的最後一步,是否是很親切?是否是看到了熟悉的 registerBeanDefinition()
方法?是否是還能想起 this.beanDefinitionMap.put(beanName , beanDefinition);
?app
最後轉化成相應的 BeanDefinition
註冊到 BeanDefinitionMap
中去: 編輯器
首先咱們其中一個 BeanDefinition
爲例,從上圖中查看這個 BeanDefinition
中都包含哪些信息。 ide
這裏看到,將 BeanDefinition
註冊到 Map
中去了,可是這裏這個註冊並非這麼簡單的。這裏要對一下幾種狀況加以區分,要否則看到後面的 instantiateUsingFactoryMethod()
方法確定會懵圈的。下面咱們緊接着來分析分析 @Bean
的處理情形...函數
驗證幾種情形的須要的類:flex
public class DemoServiceOne {
@Autowired DemoServiceTwo demoServiceTwo; public DemoServiceOne(){ } public DemoServiceOne(DemoServiceTwo demoServiceTwo){ this.demoServiceTwo = demoServiceTwo; } } 複製代碼
@Service
public class DemoServiceTwo { } 複製代碼
public class BeanDemoOne {
} 複製代碼
public class FactoryBeanDemoOne implements FactoryBean<BeanDemoOne> {
@Override public BeanDemoOne getObject() throws Exception { return new BeanDemoOne(); } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; } public FactoryBeanDemoOne (){} public FactoryBeanDemoOne (int i){ } } 複製代碼
@Configuration
@ComponentScan("com.demo") public class DemoConfigOne { @Bean("demoService") public static DemoServiceOne demoServiceOne(){ return new DemoServiceOne(); } } 複製代碼
@Configuration
@ComponentScan("com.demo") public class DemoConfigOne { @Bean public FactoryBeanDemoOne demoFactoryBean() { return new FactoryBeanDemoOne(); } } 複製代碼
@Configuration
@ComponentScan("com.demo") public class DemoConfigOne { @Bean public FactoryBeanDemoOne demoFactoryBean() { return new FactoryBeanDemoOne(); } @Bean public FactoryBeanDemoOne demoFactoryBean() { return new FactoryBeanDemoOne(); } } 複製代碼
@Configuration
@ComponentScan("com.demo") public class DemoConfigOne { @Bean("demoOne") public DemoServiceOne demoServiceOne(DemoServiceTwo demoServiceTwo){ return new DemoServiceOne(demoServiceTwo); } @Bean("demoTwo") public DemoServiceOne demoServiceOne(){ return new DemoServiceOne(); } } 複製代碼
在不由感慨Spring的強大的同時,在看到某些方法的時候,也以爲某些方法好像不是那麼符合Spring的設計?下面這個方法,就是寫的比較繞的方法, 沒有辦法,只能硬着頭皮往下看。。。ui
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; boolean isStatic; // 經過beanDefinition獲取到factoryBeanName ,實際就是@Bean註解的方法 所在的 configuration類 String factoryBeanName = mbd.getFactoryBeanName(); if (factoryBeanName != null) { // factoryBeanName 與 當前的 beanName 相同 拋出異常 if (factoryBeanName.equals(beanName)) { throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "factory-bean reference points back to the same bean definition"); } // 根據 BeanName 獲取 對象,就是 @Configuration 註解的類 這裏獲取到的是被 CGLIB 代理的類 factoryBean = this.beanFactory.getBean(factoryBeanName); if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) { throw new ImplicitlyAppearedSingletonException(); } // 獲取工廠類 factoryClass = factoryBean.getClass(); isStatic = false; } else { // 工廠名稱爲空,則多是一個靜態工廠 // 若是有static 且爲工廠方法,則添加到 candidateList 中 // 這加這個判斷是以防漏掉 加了 static 的 @Bean 方法。固然,沒有加 @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; /* * 工廠方法的參數,若是指定了構造參數,則直接使用 * @Bean註解的方法(工廠方法)的參數,在啓動過程當中實例化的對象 這裏通常都爲null,即通常不指定參數 * 追溯來源:就是 getBean() 方法中的 args 爲null */ if (explicitArgs != null) { argsToUse = explicitArgs; } else { // 沒有指定 Object[] argsToResolve = null; synchronized (mbd.constructorArgumentLock) { // 首先嚐試從緩存中獲取 factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod; // 獲取緩存中的構造函數或者工廠方法,不爲空表示已經使用過工廠方法,那麼這裏會再次使用 // 通常原型模式和Scope模式採用的上,直接使用該工廠方法和緩存的參數 if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) { // 獲取緩存中的構造參數 argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { argsToResolve = mbd.preparedConstructorArguments; } } } // 緩存中存在,則解析存儲在 BeanDefinition 中的參數 // 如給定方法的構造函數 A(int ,int ),則經過此方法後就會把配置文件中的("1","1")轉換爲 (1,1) // 緩存中的值多是原始值也有多是最終值 if (argsToResolve != null) { argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true); } } // getBean() 方法沒有傳參數 或 沒有使用過 工廠方法 if (factoryMethodToUse == null || argsToUse == null) { // 獲取工廠方法的類全名稱 factoryClass = ClassUtils.getUserClass(factoryClass); // 獲取全部聲明的構造方法,默認容許訪問非公開的方法 Method[] rawCandidates = getCandidateMethods(factoryClass, mbd); // 檢索全部方法,這裏是對方法進行過濾 List<Method> candidateList = new ArrayList<>(); for (Method candidate : rawCandidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) { // 添加到候選類裏面去 candidateList.add(candidate); } } /** * candidateList.size() == 1 表示待定的方法只有一個 * explicitArgs == null 調用getBean方法時沒有傳參 * !mbd.hasConstructorArgumentValues() 沒有緩存過參數, * 直接經過調用實例化方法執行該候選方法 */ if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { Method uniqueCandidate = candidateList.get(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; } } Method[] candidates = candidateList.toArray(new Method[0]); // 排序構造函數 // public 構造函數優先參數數量降序,非public 構造函數參數數量降序 AutowireUtils.sortFactoryMethods(candidates); // 用於承載解析後的構造函數參數的值 ConstructorArgumentValues resolvedValues = null; boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); // 初始化最小差別變量 int minTypeDiffWeight = Integer.MAX_VALUE; Set<Method> ambiguousFactoryMethods = null; // 初始化最小的參數個數 int minNrOfArgs; // 若是調用getBean方法時有傳參,那麼工廠方法最少參數個數要等於傳參個數 if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } else { // getBean() 沒有傳遞參數,則須要解析保存在 BeanDefinition 構造函數中指定的參數 if (mbd.hasConstructorArgumentValues()) { // 構造函數的參數 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); // 解析構造函數的參數 // 將該 bean 的構造函數參數解析爲 resolvedValues 對象,其中會涉及到其餘 bean resolvedValues = new ConstructorArgumentValues(); // 解析構造函數的參數 返回對應的參數個數 賦值給最小參數個數變量 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } else { minNrOfArgs = 0; } } LinkedList<UnsatisfiedDependencyException> causes = null; // 遍歷候選方法 (這裏拿到的其實就是實例化 Bean 的構造方法) for (Method candidate : candidates) { // 方法的參數列表 Class<?>[] paramTypes = candidate.getParameterTypes(); if (paramTypes.length >= minNrOfArgs) { // 保存參數的對象 ArgumentsHolder argsHolder; // getBean()傳遞了參數 if (explicitArgs != null) { // 顯示給定參數,參數長度必須徹底匹配 if (paramTypes.length != explicitArgs.length) { continue; } // 根據參數建立參數持有者 argsHolder = new ArgumentsHolder(explicitArgs); } else { // 未提供參數,解析構造參數 try { String[] paramNames = null; // 獲取 ParameterNameDiscoverer 對象 // ParameterNameDiscoverer 是用於解析方法和構造函數的參數名稱的接口,爲參數名稱探測器 ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { // 獲取指定構造函數的參數名稱 paramNames = pnd.getParameterNames(candidate); } // 在已經解析的構造函數參數值的狀況下,建立一個參數持有者對象 argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring, candidates.length == 1); } catch (UnsatisfiedDependencyException ex) { if (logger.isTraceEnabled()) { logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex); } // Swallow and try next overloaded factory method. if (causes == null) { causes = new LinkedList<>(); } causes.add(ex); continue; } } // isLenientConstructorResolution 判斷解析構造函數的時候是否以寬鬆模式仍是嚴格模式 默認寬鬆模式 // 嚴格模式:解析構造函數時,必須全部的都須要匹配,不然拋出異常 // 寬鬆模式:使用具備"最接近的模式"進行匹配 // typeDiffWeight:類型差別權重 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) { 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"); } }