Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html
Spring 容器中能夠根據 beanName 查找其類型,其推斷方式和 bean 的建立方式密切相關,而且 Spring 中有一個原則是儘量的不要經過建立 bean 來獲取其類型,除了 FactoryBean 只有經過建立對象調用其 getObjectType 方法,但也只是部分的建立該 FactoryBean(所謂的部分建立是指只實例化對象,而不進行屬性注入和初始化過程):java
(1) 環境準備git
public class User { } // 若是 FactoryBean 沒有指定 User 類型則要部分實例化對象 public class UserFactoryBean implements FactoryBean<User> { @Override public User getObject() throws Exception { return new User(); } @Override public Class<?> getObjectType() { return User.class; } } public class UserFactory { // 1. 實例工廠 public User getObject1() { return new User(); } // 2. 靜態工廠 public static User getObject2() { return new User(); } // 3.1 帶參的工廠方法 public User getObject3(String username, String password) { return new User(); } // 3.2 帶泛型的工廠方法,但返回值類型和泛型無關 public <T, K, V> User getObject4(T t, String username) { return new User(); } // 3.3 帶泛型的工廠方法,但返回值類型由參數決定 public <T, K, V> T getObject5(T t) { return t; } // 4.1 靜態工廠方法返回類型爲 FactoryBean public static FactoryBean<User> getObject6() { return new UserFactoryBean(); } // 4.2 實例工廠方法返回類型爲 FactoryBean public FactoryBean<User> getObject7() { return new UserFactoryBean(); } }
(2) xcml 配置github
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--1. 直接定義 className--> <bean id="bean1" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.User"/> <!--2. FactoryBean--> <bean id="bean2" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactoryBean"/> <!--3. 實例工廠--> <bean id="userFactory" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactory"/> <bean id="bean3" factory-bean="userFactory" factory-method="getObject1"/> <!--4. 靜態工廠--> <bean id="bean4" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactory" factory-method="getObject2"/> <!--5. 帶參的工廠方法,和構造器注入相似--> <!--5.1 工廠方法沒有定義泛型--> <bean id="bean5.1" factory-bean="userFactory" factory-method="getObject3"> <constructor-arg index="0" value="0"/> <constructor-arg index="1" value="1"/> </bean> <!--5.2 工廠方法定義泛型,但返回值類型與泛型無關--> <bean id="bean5.2" factory-bean="userFactory" factory-method="getObject4"> <constructor-arg index="0" value="0"/> <constructor-arg index="1" value="1"/> </bean> <!--5.3 工廠方法定義泛型,返回值類型與參數類型決定--> <bean id="bean5.3" factory-bean="userFactory" factory-method="getObject5"> <constructor-arg index="0" value="0"/> </bean> <!--6 靜態工廠方法的返回值爲一個 FactoryBean 類型--> <bean id="bean6.1" class="com.github.binarylei.spring.beans.factory.test.BeanFactoryTypeInferenceTest.UserFactory" factory-method="getObject6"/> <!--7 實例工廠方法的返回值爲一個 FactoryBean 類型--> <bean id="bean6.2" factory-bean="userFactory" factory-method="getObject7"/> </beans>
(3) 測試一把spring
@Test public void test() { DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(lbf); reader.loadBeanDefinitions(new ClassPathResource("spring-context-factory.xml")); // 1. 直接定義 className Assert.assertTrue(lbf.isTypeMatch("bean1", User.class)); // 2. FactoryBean Assert.assertTrue(lbf.isTypeMatch("bean2", User.class)); // 3. 實例工廠 Assert.assertTrue(lbf.isTypeMatch("bean3", User.class)); // 4. 靜態工廠 Assert.assertTrue(lbf.isTypeMatch("bean4", User.class)); // 5.1 工廠方法沒有定義泛型 Assert.assertTrue(lbf.isTypeMatch("bean5.1", User.class)); // 5.2 工廠方法定義泛型,但返回值類型與泛型無關 Assert.assertTrue(lbf.isTypeMatch("bean5.2", User.class)); // 5.3 工廠方法定義泛型,返回值類型與參數類型決定,沒法獲取 @Spring 5.1.3 Assert.assertFalse(lbf.isTypeMatch("bean5.3", User.class)); // 6.1 靜態工廠方法返回類型爲 FactoryBean Assert.assertTrue(lbf.isTypeMatch("bean6.1", User.class)); // 6.2 實例工廠方法返回類型爲 FactoryBean,若是實例化這個工廠後能夠獲取其類型 Assert.assertFalse(lbf.isTypeMatch("bean6.2", User.class)); lbf.getBean("userFactory"); Assert.assertTrue(lbf.isTypeMatch("bean6.2", User.class)); }
能夠看到工廠方法帶有泛型且返回值類型和泛型有關後 Spring 不能正確處理了,另外實例工廠的工廠方法返回 FactoryBean
@Override public boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException { return isTypeMatch(name, ResolvableType.forRawClass(typeToMatch)); } @Override public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); // 1. 根據實例化後的對象獲取 bean 的類型,注意 FactoryBean 的處理便可 Object beanInstance = getSingleton(beanName, false); if (beanInstance != null && beanInstance.getClass() != NullBean.class) { // 1.1 若是是 FactoryBean 類型,此時須要判斷是否要查找的就是這個工廠對象,判斷 beanName 是不是以 & 開頭 // 若是是其建立的類型,則須要調用 getTypeForFactoryBean 從這個 FactoryBean 實例中獲取真實類型 if (beanInstance instanceof FactoryBean) { if (!BeanFactoryUtils.isFactoryDereference(name)) { Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance); return (type != null && typeToMatch.isAssignableFrom(type)); } else { return typeToMatch.isInstance(beanInstance); } // 1.2 若是是普通 bean 則可直接判斷類型,固然 Spring 還考慮的泛型的狀況 } else if (!BeanFactoryUtils.isFactoryDereference(name)) { if (typeToMatch.isInstance(beanInstance)) { return true; } else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) { // AOP 有關 ???? RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); Class<?> targetType = mbd.getTargetType(); if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance) && typeToMatch.isAssignableFrom(targetType)) { Class<?> classToMatch = typeToMatch.resolve(); return (classToMatch == null || classToMatch.isInstance(beanInstance)); } } } return false; } else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) { // null instance registered return false; } // 2. 父工廠,沒什麼好說的 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch); } // 3. 下面就要從 bean 的定義中獲取該 bean 的類型了 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); Class<?> classToMatch = typeToMatch.resolve(); if (classToMatch == null) { classToMatch = FactoryBean.class; } Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ? new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch}); // 3.1 AOP 代理時會將原始的 BeanDefinition 存放到 decoratedDefinition 屬性中,能夠行忽略這部分 BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) { RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd); Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch); if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) { return typeToMatch.isAssignableFrom(targetClass); } } // 3.2 predictBeanType 推斷 beanName 的類型,主要的邏輯 Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch); if (beanType == null) { return false; } // 3.3 處理 FactoryBean 類型 if (FactoryBean.class.isAssignableFrom(beanType)) { if (!BeanFactoryUtils.isFactoryDereference(name) && beanInstance == null) { // 此時須要從 FactoryBean 中推斷出真實類型 beanType = getTypeForFactoryBean(beanName, mbd); if (beanType == null) { return false; } } // 3.4 beanType 不是 FactoryBean 類型,可是又要獲取 FactoryBean 的類型??? } else if (BeanFactoryUtils.isFactoryDereference(name)) { // Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean // type but we nevertheless are being asked to dereference a FactoryBean... // Let's check the original bean class and proceed with it if it is a FactoryBean. beanType = predictBeanType(beanName, mbd, FactoryBean.class); if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) { return false; } } // 3.5 優先從緩存中判斷,能夠比較泛型 ResolvableType resolvableType = mbd.targetType; if (resolvableType == null) { resolvableType = mbd.factoryMethodReturnType; } if (resolvableType != null && resolvableType.resolve() == beanType) { return typeToMatch.isAssignableFrom(resolvableType); } return typeToMatch.isAssignableFrom(beanType); }
上面的代碼一大堆,邏輯也比較複雜,咱們如今只須要明白三點:緩存
下面咱們就分別介紹一下這兩個方法。app
咱們先從簡單的看起,AbstractBeanFactory#predictBeanType 實現了這個方法,其子類又重載了這個方法 AbstractAutowireCapableBeanFactory#predictBeanType。less
(1) AbstractBeanFactory#predictBeanTypeide
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) { // 1. 直接從緩存中獲取 Class<?> targetType = mbd.getTargetType(); if (targetType != null) { return targetType; } // 2. 工廠方法一概返回 null,子類會重載後解析對應的 getFactoryMethodName if (mbd.getFactoryMethodName() != null) { return null; } // 3. 解析 BeanDefinition 的 className,若是已經加載則直接從緩存中獲取 return resolveBeanClass(mbd, beanName, typesToMatch); }
能夠看到最終是從 BeanDefinition 中解析配置的 className 屬性,將其加載到 JVM 中。它有三個參數,毫無疑問的是 mbd 是必須的,beanName 記錄異常時使用,那 typesToMatch 是幹嗎的呢?帶着這個疑問咱們看一下源碼。
protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch) throws CannotLoadBeanClassException { if (mbd.hasBeanClass()) { return mbd.getBeanClass(); } return doResolveBeanClass(mbd, typesToMatch); } private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch) throws ClassNotFoundException { ClassLoader beanClassLoader = getBeanClassLoader(); ClassLoader classLoaderToUse = beanClassLoader; // 1. Spring 自定義的類型器 DecoratingClassLoader 修改了 JDK 的類加載規則,本身先加載一把,沒有再特派給父加載器 // 這就產生了一個問題,每一個臨時的類加載器可能加載同一個類可能出現多個 // 因此能夠將其加入到 excludeClass 仍採用雙親委派 if (!ObjectUtils.isEmpty(typesToMatch)) { ClassLoader tempClassLoader = getTempClassLoader(); if (tempClassLoader != null) { classLoaderToUse = tempClassLoader; if (tempClassLoader instanceof DecoratingClassLoader) { DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader; for (Class<?> typeToMatch : typesToMatch) { dcl.excludeClass(typeToMatch.getName()); } } } } // 2. 若是 className 含有點位符,解析後發生了變化,則不用緩存,之後每次都解析一次 String className = mbd.getBeanClassName(); if (className != null) { Object evaluated = evaluateBeanDefinitionString(className, mbd); if (!className.equals(evaluated)) { if (evaluated instanceof Class) { return (Class<?>) evaluated; } else if (evaluated instanceof String) { return ClassUtils.forName((String) evaluated, classLoaderToUse); } else { throw new IllegalStateException("Invalid class name expression result: " + evaluated); } } if (classLoaderToUse != beanClassLoader) { return ClassUtils.forName(className, classLoaderToUse); } } // 3. 解析 className 後緩存起來 return mbd.resolveBeanClass(beanClassLoader); }
至此,根據 BeanDefinition 解析 bean 的類型就完成了,最終仍是回到了咱們在 xml 文件中配置的 class 上來了,只是 Spring 的解析考慮了不少狀況,一會兒就複雜起來了。 想必如今對 typesToMatch 也有必定的瞭解了,就是爲了保證要匹配的類型是同一個類加載器加載的,這裏也就是 JDK 的系統類加載器 - AppClassLoader,這樣調用 typeToMatch.isAssignableFrom(type) 方法纔有意義。
(2) AbstractAutowireCapableBeanFactory#predictBeanType
AbstractAutowireCapableBeanFactory 又對 predictBeanType 進行了重載,增長了對工廠方法 factoryMethodName 的解析。
@Override protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) { // 1. 增長了對工廠 factoryMethod 的解析 Class<?> targetType = determineTargetType(beanName, mbd, typesToMatch); // 2. 後置處理器 SmartInstantiationAwareBeanPostProcessors if (targetType != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; Class<?> predicted = ibp.predictBeanType(targetType, beanName); if (predicted != null && (typesToMatch.length != 1 || FactoryBean.class != typesToMatch[0] || FactoryBean.class.isAssignableFrom(predicted))) { return predicted; } } } } return targetType; } // 怎麼樣,邏輯仍是以前的同樣,只是增長對 factoryMethodName 的處理 protected Class<?> determineTargetType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) { Class<?> targetType = mbd.getTargetType(); if (targetType == null) { targetType = (mbd.getFactoryMethodName() != null ? getTypeForFactoryMethod(beanName, mbd, typesToMatch) : resolveBeanClass(mbd, beanName, typesToMatch)); if (ObjectUtils.isEmpty(typesToMatch) || getTempClassLoader() == null) { mbd.resolvedTargetType = targetType; } } return targetType; }
在這裏,咱們重點關注 getTypeForFactoryMethod 方法,Spring 是如何從一個工廠方法中獲取其類型的。
protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) { // 1. 緩存中直接取 ResolvableType cachedReturnType = mbd.factoryMethodReturnType; if (cachedReturnType != null) { return cachedReturnType.resolve(); } Class<?> factoryClass; boolean isStatic = true; // 2. 在 Spring 中有靜態工廠和實例工廠之分,若是是實例工廠名稱不能是當前的 beanName 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"); } // 2.1 獲取實例工廠的類型 factoryClass = getType(factoryBeanName); isStatic = false; } else { // 2.2 靜態工廠只能是靜態方法,解析本身的 BeanDefinition 就能夠了 factoryClass = resolveBeanClass(mbd, beanName, typesToMatch); } if (factoryClass == null) { return null; } // 2.3 若是是 CGLIB 代理,獲取其真實類型 factoryClass = ClassUtils.getUserClass(factoryClass); // 3.1 若是有多個方法同名,則取其返回傎的公有類型,除非爲 null Class<?> commonType = null; // 3.2 緩存這個工廠方法 Method uniqueCandidate = null; // 3.3 若是方法含有泛型,則須要根據傳遞的參數進一步判斷返回值類型 int minNrOfArgs = (mbd.hasConstructorArgumentValues() ? mbd.getConstructorArgumentValues().getArgumentCount() : 0); Method[] candidates = this.factoryMethodCandidateCache.computeIfAbsent( factoryClass, ReflectionUtils::getUniqueDeclaredMethods); // 4. 遍歷全部的名稱爲工廠方法的 for (Method candidate : candidates) { if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate) && candidate.getParameterCount() >= minNrOfArgs) { // 4.1 方法中定義了泛型,則須要將配置的構造參數進行比較了,但彷佛有問題 // 4.1.1 getTypeParameters 獲取定義的泛型個數 if (candidate.getTypeParameters().length > 0) { // 4.1.2 getParameterTypes 獲取該方法的參數列表 Class<?>[] paramTypes = candidate.getParameterTypes(); String[] paramNames = null; ParameterNameDiscoverer pnd = getParameterNameDiscoverer(); if (pnd != null) { paramNames = pnd.getParameterNames(candidate); } ConstructorArgumentValues cav = mbd.getConstructorArgumentValues(); Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length); Object[] args = new Object[paramTypes.length]; // 4.1.3 根據類型和參數名匹配真實的參數 for (int i = 0; i < args.length; i++) { ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue( i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders); if (valueHolder == null) { valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders); } if (valueHolder != null) { args[i] = valueHolder.getValue(); usedValueHolders.add(valueHolder); } } // 4.1.4 解析返回值對應的泛型類型 Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod( candidate, args, getBeanClassLoader()); uniqueCandidate = (commonType == null && returnType == candidate.getReturnType() ? candidate : null); commonType = ClassUtils.determineCommonAncestor(returnType, commonType); if (commonType == null) { return null; } // 4.2 直接獲取方法的返回值類型,若是有多個同名方法取其公共的祖先便可,沒有就直接返回 null } else { // 第一次匹配上會緩存這個方法,但再次匹配上了,很差意思有重名的方法,直接清空 uniqueCandidate = (commonType == null ? candidate : null); commonType = ClassUtils.determineCommonAncestor(candidate.getReturnType(), commonType); if (commonType == null) { return null; } } } } // 5.1 若是同名的方法只有一個,那麼將這個工廠方法直接緩存起來 mbd.factoryMethodToIntrospect = uniqueCandidate; if (commonType == null) { return null; } // 5.2 若是隻有惟一的工廠方法,那麼儘量緩存完型的類型,包括泛型。因此再解析一次用於緩存 cachedReturnType = (uniqueCandidate != null ? ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType)); mbd.factoryMethodReturnType = cachedReturnType; return cachedReturnType.resolve(); }
根據工廠方法推斷 bean 的類型看起來很複雜,但邏輯仍是很清晰的:
對於泛型返回值類型再多說一句,Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod( candidate, args, getBeanClassLoader());
在測試時確實沒有問題,後來發現是 Spring 在解析 xml 文件時對構造參數作了一個封裝,也就是 valueHolder.getValue()
不是配置的類型,而是 TypedStringValue 類型,致使解析出現問題。
getTypeForFactoryBean 相對來講比較簡單,咱們先說這個方法。AbstractBeanFactory#getTypeForFactoryBean 實現了這個方法,其子類又重載了這個方法 AbstractAutowireCapableBeanFactory#getTypeForFactoryBean
(1) AbstractBeanFactory#getTypeForFactoryBean
protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) { if (!mbd.isSingleton()) { return null; } FactoryBean<?> factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true); return getTypeForFactoryBean(factoryBean); } protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) { return factoryBean.getObjectType(); }
怎麼樣是否是很簡單,先建立這個 FactoryBean 的實例,而後調用其 getObjectType 方法獲取真實類型。但問題又來了,咱們僅僅須要獲取這個 bean 的類型,卻要實例化與之相關的一系列對象,是否是代價太昂貴了,怎麼規避這個問題呢?在其子類 AbstractAutowireCapableBeanFactory 中對這個方法作了進一步的加強,一塊兒看一下。
(2) AbstractAutowireCapableBeanFactory#getTypeForFactoryBean
@Override protected Class<?> getTypeForFactoryBean(String beanName, RootBeanDefinition mbd) { // 1. 處理 mbd.getInstanceSupplier(),另一種建立 bean 的方式,@Sping 5.0 提供,咱們先忽略... // if (mbd.getInstanceSupplier() != null) ... // 2. 這個 FactoryBean 也多是其餘的工廠的工廠方法建立的 String factoryBeanName = mbd.getFactoryBeanName(); String factoryMethodName = mbd.getFactoryMethodName(); // 3. 實例工廠建立 FactoryBean<User> if (factoryBeanName != null) { // 3.1 若是實例工廠的 className 已經解析過了,就直接從其工廠方法的返回值類型進行推斷 if (factoryMethodName != null) { BeanDefinition fbDef = getBeanDefinition(factoryBeanName); if (fbDef instanceof AbstractBeanDefinition) { AbstractBeanDefinition afbDef = (AbstractBeanDefinition) fbDef; if (afbDef.hasBeanClass()) { Class<?> result = getTypeForFactoryBeanFromMethod(afbDef.getBeanClass(), factoryMethodName); if (result != null) { return result; } } } } // 3.2 判斷這個實例工廠有沒有實例化,若是沒有則直接 Game Over // 由於下面咱們要調用 FactoryBean#getObjectType(),不能就是要部分實例化這個 FactoryBean 對象 // 若是連建立這個 FactoryBean 的工廠都未實例化,那麼更談不上建立 FactoryBean 了 // Spring 不會爲了獲取一個 bean 的類型去循環建立 bean if (!isBeanEligibleForMetadataCaching(factoryBeanName)) { return null; } } // 4. 如今咱們要先部分實例化這個 FactoryBean,調用其 getObjectType() 來獲取對象類型 FactoryBean<?> fb = (mbd.isSingleton() ? getSingletonFactoryBeanForTypeCheck(beanName, mbd) : getNonSingletonFactoryBeanForTypeCheck(beanName, mbd)); if (fb != null) { // 4.1 調用 FactoryBean#getObjectType() 獲取類型 Class<?> result = getTypeForFactoryBean(fb); if (result != null) { return result; // 4.2 若是部分實例化仍是獲取不到,沒辦法了只有將這個 FactoryBean 所有實例化出來了 } else { return super.getTypeForFactoryBean(beanName, mbd); } } // 5. 靜態工廠建立 FactoryBean,這種狀況下 fb=null,咱們能夠解析該方法的返回值類型 if (factoryBeanName == null && mbd.hasBeanClass()) { // 5.1 解析方法的返回值的泛型類型,FactoryBean<User> if (factoryMethodName != null) { return getTypeForFactoryBeanFromMethod(mbd.getBeanClass(), factoryMethodName); // 5.2 該類就是一個 FactoryBean,則直接解析其泛型就好 FactoryBean<User> } else { return GenericTypeResolver.resolveTypeArgument(mbd.getBeanClass(), FactoryBean.class); } } return null; }
這個方法思路很清晰,就是在儘量不去實例化對象的狀況下,拿到這個 FactoryBean 的真實建立的類型。重點關注下面三個方法:
getTypeForFactoryBeanFromMethod
工廠方法建立 FactoryBean<...>,直接解析其中的泛型getSingletonFactoryBeanForTypeCheck
和 getNonSingletonFactoryBeanForTypeCheck
都先嚐試部分實例化這個 FactoryBean,若是任然沒法獲取,則須要完整的實例化這個對象。private Class<?> getTypeForFactoryBeanFromMethod(Class<?> beanClass, final String factoryMethodName) { class Holder { Class<?> value = null; } final Holder objectType = new Holder(); Class<?> fbClass = ClassUtils.getUserClass(beanClass); // 解析工廠方法的返回值 FactoryBean<User> 類型,若是有多個同名的方法則取公共的類型 ReflectionUtils.doWithMethods(fbClass, method -> { if (method.getName().equals(factoryMethodName) && FactoryBean.class.isAssignableFrom(method.getReturnType())) { // 解析 FactoryBean<User> 中的泛型類型 Class<?> currentType = GenericTypeResolver.resolveReturnTypeArgument(method, FactoryBean.class); if (currentType != null) { objectType.value = ClassUtils.determineCommonAncestor(currentType, objectType.value); } } }); return (objectType.value != null && Object.class != objectType.value ? objectType.value : null); }
getTypeForFactoryBeanFromMethod 其實是在解析方法返回值 FactoryBean
public class UserFactory { public static FactoryBean<User> getObject6() { return new UserFactoryBean(); } }
至於 getSingletonFactoryBeanForTypeCheck 和 getNonSingletonFactoryBeanForTypeCheck 兩個方法也只是實例化了這個 bean。調用了 createBeanInstance
方法。
private FactoryBean<?> getSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) { BeanWrapper bw = createBeanInstance(beanName, mbd, null); instance = bw.getWrappedInstance(); return fb; } }
參考:
1 . 《》:<>
天天用心記錄一點點。內容也許不重要,但習慣很重要!