建立個實體類
import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter @ToString public class Book { private String name; public Book(String name) { this.name = name; } }
再建立個配置類
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class BookConfig { @Bean public Book book(){ return new Book("BBB"); } }
最后是啟動程序
import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) throws Exception { ApplicationContext context = new AnnotationConfigApplicationContext(BookConfig.class); Book book = context.getBean(Book.class); System.out.println(book); } }
主要看getBean的過程
1. 首先進入org.springframework.context.support.AbstractApplicationContext#getBean(java.lang.Class<T>)
2. 進入org.springframework.context.support.GenericApplicationContext#getBeanFactory
3. 進入org.springframework.beans.factory.support.DefaultListableBeanFactory#getBean(java.lang.Class<T>)
實際上調用的是重載方法getBean,在其中調用的是resolveBean方法,解析bean。
==========================================對比==========================================
等一等??看網上其它教程都會有個doGetBean的東西,到這里怎么沒有了?
我們知道目前常見的創建Application的方式有三種
FileSystemXmlApplicationContext/ClassPathXmlApplicationContext/AnnotationConfigApplicationContext
你以為我想說和上下文類型有關系?但是我告訴你和應用上下文的類型是沒有任何關系的!這三種主要的區別就是讀取配置的來源不同罷了,內部調用的都是refresh方法。
真正導致調用的方法不同,取決於你調用的是AbstractApplicationContext#getBean的哪一個重載方法。
第一個參數為String類型的getBean方法,最終會調用的AbstractBeanFactory#doGetBean
第一個參數為Class類型的getBean方法,最終會調用的DefaultListableBeanFactory#resolveBean
另外,后者resolveBean會調用doGetBean方法。
如紅框的會跑到AbstractBeanFactory類里
藍框的跑到DefaultListableBeanFactory類里
4. 根據傳入的Class,先封裝成ResolvableType。(對於指定的Class,返回一個ResolvableType,僅對原始類執行可分配性檢查,這是一個包裝器。)
5. 帶着ResolveableType進入org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveBean
@Nullable private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) { // 根據傳入的ResolvableType,返回一個NamedBeanHolder(一個持有bean名稱和bean實例的容器) NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull); // 如果namedBean不為空,則直接返回實例 if (namedBean != null) { return namedBean.getBeanInstance(); } // namedBean為空(比如我獲取了一個不存在的bean)則執行以下內容↓ // 獲取父bean工廠 BeanFactory parent = getParentBeanFactory(); // 如果是DefaultListableBeanFactory的實例,則正常解析 if (parent instanceof DefaultListableBeanFactory) { return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull); } // 不是DefaultListableBeanFactory的實例並且不為空(這一步具體干啥還不清楚) else if (parent != null) { ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType); if (args != null) { return parentProvider.getObject(args); } else { return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable()); } } // parent也為空,則返回空 return null; }
這個方法呢,主要調用了resolveNamedBean方法,利用返回持有名稱和實例的容器獲得bean實例。不是核心方法。
6. org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveNamedBean(org.springframework.core.ResolvableType, java.lang.Object[], boolean)
這個方法干的事情就比較多了
@SuppressWarnings("unchecked") @Nullable private <T> NamedBeanHolder<T> resolveNamedBean( ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException { Assert.notNull(requiredType, "Required type must not be null"); // 根據類型獲取bean名稱---① String[] candidateNames = getBeanNamesForType(requiredType); // 如果bean名稱不止一個(比如你定義了多個同類型但是名稱不一樣的Bean) if (candidateNames.length > 1) { // 自動裝配候選者列表 List<String> autowireCandidates = new ArrayList<>(candidateNames.length); // 遍歷bean名稱 for (String beanName : candidateNames) { // 判斷:如果beanDefinitionMap不包含key為beanName的鍵值對或者該bean可以被自動裝配到其他bean中。則添加到候選列表中 if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) { autowireCandidates.add(beanName); } } // 候選列表不為空,則給候選名稱重新賦值 if (!autowireCandidates.isEmpty()) { candidateNames = StringUtils.toStringArray(autowireCandidates); } } // bean名稱只有一個 if (candidateNames.length == 1) { // 因為只有一個,所以是0下標的名稱 String beanName = candidateNames[0]; // 返回一個持有bean名稱和bean實例的容器【getBean方法:繞了一圈,依然回到了AbstractBeanFactory#getBean,准確來說是doGetBean方法】---② return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args)); } else if (candidateNames.length > 1) { Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length); // 遍歷候選名稱 for (String beanName : candidateNames) { // 如果是單例並且args為空 if (containsSingleton(beanName) && args == null) { // getBean實例化bean【getBean方法:繞了一圈,依然回到了AbstractBeanFactory#getBean,准確來說是doGetBean方法】 Object beanInstance = getBean(beanName); // 放進候選Map里,value是bean實例 candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance)); } else { // 否則直接范進Map里,value是bean的Class candidates.put(beanName, getType(beanName)); } } // 因為這個方法只能返回一個實例,而這種情況我們獲取了多個,到底返回哪一個? // 這一步:確定給定bean集合中的主要候選對象。---③ String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass()); if (candidateName == null) { // 這一步:確定給定bean集合中具有最高優先級的對象。---④ candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass()); } // 如果確定了返回哪一個對象 if (candidateName != null) { // 從候選集合中選出目標對象 Object beanInstance = candidates.get(candidateName); // 沒有實例化則實例化 if (beanInstance == null || beanInstance instanceof Class) { beanInstance = getBean(candidateName, requiredType.toClass(), args); } // 返回包裝類 return new NamedBeanHolder<>(candidateName, (T) beanInstance); } // 前面都沒確定出來,那只能拋異常了。 if (!nonUniqueAsNull) { // 比如:No qualifying bean of type 'com.demo.tools.Book' available: expected single matching bean but found 2 throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet()); } } return null; }
總結:
1. 根據傳入的類型獲取bean的所有名稱。
2. 過濾候選bean名稱。
3. 如果bean名稱只有一個,那么直接調用AbstractBeanFactory里的doGetBean進行實例化並返回。
3. 如果bean名稱有多個,則選出主要候選名稱或者最高優先級的名稱來幫助實例化。如果沒有選出可用的名稱,則拋出bean定義沖突異常。
下面看一下其它方法:
①:根據類型獲取名稱列表
@Override public String[] getBeanNamesForType(ResolvableType type) { return getBeanNamesForType(type, true, true); } @Override public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { Class<?> resolved = type.resolve(); // 如果resolved不為空,並且不是泛型參數 if (resolved != null && !type.hasGenerics()) { // 雖然調用了這個方法,但是這個方法實際上調用的也是doGetBeanNamesForType return getBeanNamesForType(resolved, includeNonSingletons, includeNonSingletons); } else { return doGetBeanNamesForType(type, includeNonSingletons, includeNonSingletons); } } @Override public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) { // 正常來講不會走這里,這里是什么情況?? if (!isConfigurationFrozen() || type == null || !allowEagerInit) { return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit); } // 先從緩存中找 Map<Class<?>, String[]> cache = (includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType); String[] resolvedBeanNames = cache.get(type); if (resolvedBeanNames != null) { return resolvedBeanNames; } // 緩存沒有,則創建,並放到緩存中 resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true); if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) { cache.put(type, resolvedBeanNames); } return resolvedBeanNames; } // NamedBeanHolder:持有beanName和beanInstance的包裝類 // BeanDefinitionHolder:包含名稱和別名以及bean定義的Holder。可以注冊為內部bean的占位符。 // 重點類:RootBeanDefinition、DefaultSingletonBeanRegistry private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { List<String> result = new ArrayList<>(); // 檢查全部的bean定義 for (String beanName : this.beanDefinitionNames) { // 只有當bean名稱沒有定義為其他bean的別名時,才認為bean是合格的 if (!isAlias(beanName)) { try { // 返回合並的RootBeanDefinition,如果指定的bean符合子bean定義,則遍歷父bean定義。【為什么要合並定義?后面會講】 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 只有在bean定義完成時才檢查它。 if (!mbd.isAbstract() && (allowEagerInit || (mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) && !requiresEagerInitForType(mbd.getFactoryBeanName()))) { // 檢查給定的bean是否定義為FactoryBean。 boolean isFactoryBean = isFactoryBean(beanName, mbd); // 返回由這個bean定義修飾的目標定義 BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); boolean matchFound = false; // 允許FactoryBean初始化(allowEagerInit==true 或者 這個bean是單例bean) boolean allowFactoryBeanInit = allowEagerInit || containsSingleton(beanName); // boolean isNonLazyDecorated = dbd != null && !mbd.isLazyInit(); // 不是FactoryBean if (!isFactoryBean) { if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) { // 檢查給定名稱的bean是否與指定的類型匹配。允許應用額外的約束,以確保不過早地創建bean。 // 注意這個isTypeMatch方法是@since 5.2新加的,內容過多,暫且不談 matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit); } } // 是FactoryBean else { if (includeNonSingletons || isNonLazyDecorated || (allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) { matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit); } // 不匹配 if (!matchFound) { // In case of FactoryBean, try to match FactoryBean instance itself next. beanName = FACTORY_BEAN_PREFIX + beanName; matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit); } } // 只有匹配的才會記錄下來 if (matchFound) { result.add(beanName); } } } catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) { if (allowEagerInit) { throw ex; } // Probably a placeholder: let's ignore it for type matching purposes. LogMessage message = (ex instanceof CannotLoadBeanClassException) ? LogMessage.format("Ignoring bean class loading failure for bean '%s'", beanName) : LogMessage.format("Ignoring unresolvable metadata in bean definition '%s'", beanName); logger.trace(message, ex); onSuppressedException(ex); } } } // 檢查手動注冊的單例。 for (String beanName : this.manualSingletonNames) { try { // 對於FactoryBean,匹配FactoryBean創建的對象。【org.springframework.beans.factory.FactoryBean】(FactoryBean后面也會講) if (isFactoryBean(beanName)) { if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) { result.add(beanName); // 已經匹配過這個bean,跳過 continue; } // 對於FactoryBean,接下來嘗試匹配FactoryBean本身。 beanName = FACTORY_BEAN_PREFIX + beanName; } // 匹配原始bean實例(可能是原始的FactoryBean)。 if (isTypeMatch(beanName, type)) { result.add(beanName); } } catch (NoSuchBeanDefinitionException ex) { // Shouldn't happen - probably a result of circular reference resolution... logger.trace(LogMessage.format("Failed to check manually registered singleton with name '%s'", beanName), ex); } } return StringUtils.toStringArray(result); }
這么多邏輯,無非作者考慮的很周全,實際上只是一個根據類型獲取bean名稱的過程。另外你還能發現Spring的命名特點,getXXX方法僅僅是做了一些准備工作,真正工作的是doGetXXX方法。
②:doGetBean方法
這個方法比較復雜,涉及到其它的方法也很多,所以我在后面單獨一部分講解,麻煩移步后面。
③:獲取主要候選名稱
protected String determinePrimaryCandidate(Map<String, Object> candidates, Class<?> requiredType) { String primaryBeanName = null; // 遍歷候選名稱集合 for (Map.Entry<String, Object> entry : candidates.entrySet()) { String candidateBeanName = entry.getKey(); Object beanInstance = entry.getValue(); // 如果是主要候選對象。這里返回bean定義里的primary對象的值,具體來說就是如果你定義bean的時候用@Primary注解標注的,則是true if (isPrimary(candidateBeanName, beanInstance)) { // 因為是循環所有的候選名稱,第一次primaryBeanName肯定是null,所以在else語句給它賦值。如果出現了多個Primary注解的bean,那就會拋出異常 if (primaryBeanName != null) { boolean candidateLocal = containsBeanDefinition(candidateBeanName); boolean primaryLocal = containsBeanDefinition(primaryBeanName); if (candidateLocal && primaryLocal) { throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), "more than one 'primary' bean found among candidates: " + candidates.keySet()); } else if (candidateLocal) { primaryBeanName = candidateBeanName; } } else { primaryBeanName = candidateBeanName; } } } return primaryBeanName; }
總結:如果出現了多個候選名稱,則會選出被@Primary注解標注的bean。如果出現多個@Primary的bean,依然會拋出異常。
④:獲取最高優先級名稱
protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) { String highestPriorityBeanName = null; Integer highestPriority = null; for (Map.Entry<String, Object> entry : candidates.entrySet()) { String candidateBeanName = entry.getKey(); Object beanInstance = entry.getValue(); if (beanInstance != null) { // 獲取優先級,通過Primary的例子,這個也可以猜出是標記了@Priority注解,數字越小優先級越高。 // @Priority注解需要單獨引入依賴: // <dependency> // <groupId>javax.annotation</groupId> // <artifactId>javax.annotation-api</artifactId> // <version>1.3.2</version> // </dependency> Integer candidatePriority = getPriority(beanInstance); if (candidatePriority != null) { if (highestPriorityBeanName != null) { if (candidatePriority.equals(highestPriority)) { throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(), "Multiple beans found with the same priority ('" + highestPriority + "') among candidates: " + candidates.keySet()); } else if (candidatePriority < highestPriority) { highestPriorityBeanName = candidateBeanName; highestPriority = candidatePriority; } } else { highestPriorityBeanName = candidateBeanName; highestPriority = candidatePriority; } } } } return highestPriorityBeanName; }
主要方法調用流程
核心方法依然是org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
先看一下重點步驟,然后分步解釋
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 1. 轉換bean名稱 final String beanName = transformedBeanName(name); Object bean; // 2. 檢查單例緩存中手動注冊的單例對象 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } // 3. 獲取給定bean實例的對象,可能是它本身,也可能是FactoryBean創建的對象。 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // 如果指定的原型bean正在創建,則拋出異常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // 獲取父工廠 BeanFactory parentBeanFactory = getParentBeanFactory(); // 當前工廠里不存在這個bean定義則在父工廠里面找 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // 獲取原始bean名稱 String nameToLookup = originalBeanName(name); // 下面都是遞歸尋找過程 if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } // 不僅僅做類型檢查,還要創建,則要先記錄下來 if (!typeCheckOnly) { markBeanAsCreated(beanName); } // 下面就是創建的過程了 try { // 4. 合並bean定義,拿到RootBeanDefinition final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 檢查bean定義 checkMergedBeanDefinition(mbd, beanName, args); // 保證當前bean所依賴的bean的初始化。 String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } // 5. 給當前bean注冊一個依賴bean registerDependentBean(dep, beanName); try { // 遞歸實例化依賴 getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // 6. 創建單實例bean if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // 7. 創建多實例bean else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { // 8. 在指定的scope上實例化bean String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // 9. 檢查所需的類型是否與實際bean實例的類型相匹配。 if (requiredType != null && !requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { if (logger.isTraceEnabled()) { logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }
大概過程:
1. 轉換bean名稱。
2. 查看緩存中有沒有,有則直接返回。
3. 緩存沒有,先找到並確定bean定義。
4. 合並bean定義。
5. 檢查循環依賴。
6. 根據配置,創建單實例bean還是多實例bean還是scope范圍的bean。
7. 做最后的類型檢查,無誤后返回。
下面分步驟
1. 轉換bean名稱。
protected String transformedBeanName(String name) { // beanName轉換分兩部分,一個是去掉工廠的取消引用前綴;一個是將別名解析為規范名稱。 return canonicalName(BeanFactoryUtils.transformedBeanName(name)); } // 返回實際的bean名稱,去掉工廠的取消引用前綴(如果有,也去掉重復的工廠前綴) public static String transformedBeanName(String name) { Assert.notNull(name, "'name' must not be null"); if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { return name; } return transformedBeanNameCache.computeIfAbsent(name, beanName -> { do { beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); } while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)); // 只要發現beanName以&開頭,就會去除&,所以你就算寫一百個&也不會有錯誤。 return beanName; }); } // 確定原始名稱,將別名解析為規范名稱。 public String canonicalName(String name) { String canonicalName = name; // Handle aliasing... String resolvedName; do { // 根據傳入的名稱,從別名Map里查詢 resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while (resolvedName != null); return canonicalName; }
這里涉及兩個擴展內容,第一個就是FactoryBean,第二個就是別名。
BeanFactory和FactoryBean?
BeanFactory是頂級接口,是IDC容器實現的基礎。
FactoryBean是為用戶准備的,用來實例化一些復雜的Bean,給上層應用帶來便利。
來看個例子,重新修改配置類的內容,加入了一個FactoryBean,以及定義了別名。
import org.springframework.beans.factory.FactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class BookConfig { @Bean(name = {"第一個是原始名稱", "book", "tom", "cat"}) public BookFactoryBean book(){ BookFactoryBean bookFactoryBean = new BookFactoryBean(); bookFactoryBean.setBeanInfo("它們隱藏了實例化一些復雜bean 的細節,給上層應用帶來了便利"); return bookFactoryBean; } } class BookFactoryBean implements FactoryBean<Book>{ private String beanInfo; @Override public Book getObject() throws Exception { return new Book("AAA"); } @Override public Class<?> getObjectType() { return Book.class; } public String getBeanInfo() { return beanInfo; } public void setBeanInfo(String beanInfo) { this.beanInfo = beanInfo; } }
運行程序代碼
import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) throws Exception { ApplicationContext context = new AnnotationConfigApplicationContext(BookConfig.class); // Book book = context.getBean(Book.class); Object bean = context.getBean("&&&book"); Object bean1 = context.getBean("第一個是原始名稱"); Object bean2 = context.getBean("cat"); System.out.println(bean); System.out.println(bean1); System.out.println(bean2); } }
輸出結果:
第一個問題:beanName前面加個&,代表獲取FactoryBean。
第二個問題:無論用什么名稱,在內部都會找到它的原始名稱。
根據debug的結果可以看出:定位bean還是需要原始名稱,如果傳入的是原始名稱,則直接返回。
總結:
轉換beanName包含兩部分:一個是去掉工廠的&前綴,另一個是利用AliasMap找到Bean的原始名稱。
2. 檢查單例緩存
這個方法在另一個類里:DefaultSingletonBeanRegistry#getSingleton(java.lang.String)
public Object getSingleton(String beanName) { // allowEarlyReference 為true return getSingleton(beanName, true); } // 根據名稱找到注冊的(原始)單例對象。 // 檢查已經實例化的單例並允許對當前單例的早期引用(解析循環引用)。 protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 這里獲得的可能是bean也可能是FactoryBean Object singletonObject = this.singletonObjects.get(beanName); // 如果沒有獲取到並且發現當前bean正在創建 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 從早期單例對象緩存中嘗試獲取,有的話返回 singletonObject = this.earlySingletonObjects.get(beanName); // 如果從早期單例對象緩存中沒有獲取的,並且允許早期依賴 if (singletonObject == null && allowEarlyReference) { // 則獲取單例工廠 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 用工廠方法創建實例 singletonObject = singletonFactory.getObject(); // 放進早期單例對象緩存中 this.earlySingletonObjects.put(beanName, singletonObject); // 移除工廠緩存中的bean this.singletonFactories.remove(beanName); } } } } // 只要獲取到,即返回 return singletonObject; }
這其中涉及了三個緩存
/** 單例對象緩存: beanName -> beanInstance. 存放創建完成的bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** 單例工廠緩存: beanName -> ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** 早期單例對象緩存: beanName -> beanInstance. 已經實例化但是還沒有創建完成的單例bean被放到這里面,其目的是用來檢測循環引用 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);/** 已經注冊的bean放在這里. */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
獲取過程很簡單:先去緩存中尋找,緩存中沒有去早期緩存中找,早期緩存沒有則獲取單例工廠,利用工廠方法獲取實例,並添加到早期緩存中,同時移除工廠緩存中的bean。最后返回。對於Spring解決循環依賴的問題:
Spring只能解決單例模式下的Setter循環依賴,Spring不能解決prototype作用域的bean之間的循環依賴。
Spring在獲取ClassA的實例時,不等ClassA完成創建就將其曝光加入正在創建的bean緩存中。
在解析ClassA的屬性時,又發現依賴於ClassB,再次去獲取ClassB,當解析ClassB的屬性時,又發現需要ClassA的屬性,
但此時的ClassA已經被提前曝光加入了正在創建的bean的緩存中,則無需創建新的的ClassA的實例,直接從緩存中獲取即可。從而解決循環依賴問題。另外:根據代碼邏輯不難發現,ClassA實例化的時候發現需要依賴ClassB,於是把ClassA先緩存起來,去實例化ClassB。也就是說,優先初始化最底層對象。
根據Debug的結果,這一步可能獲取到的是個FactoryBean:
3. 獲取真正實例對象getObjectForBeanInstance
因為上一步的過程,我們可以知道,返回結果不一定是我們需要的對象。
/** * org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getObjectForBeanInstance * * @since 5.0 * @see #obtainFromSupplier */ @Override protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // 獲取當前ThreadLocal存儲的變量,也就是當前正在創建的bean String currentlyCreatedBean = this.currentlyCreatedBean.get(); if (currentlyCreatedBean != null) { // 如果當前有正在創建的bean,則注冊為beanName所依賴的bean registerDependentBean(beanName, currentlyCreatedBean); } return super.getObjectForBeanInstance(beanInstance, name, beanName, mbd); } protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // 根據name判斷我們需要的是不是FactoryBean(判斷名字里有沒有&) if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass()); } if (mbd != null) { mbd.isFactoryBean = true; } // 返回FactoryBean實例 return beanInstance; } // 走到這里,證明我們需要的是bean實例,而不是FactoryBean實例。而到這里beanInstance可能是個bean,也可能是個FactoryBean。 // 如果它是一個FactoryBean,我們將使用它來創建一個bean實例 if (!(beanInstance instanceof FactoryBean)) { // 不是FactoryBean,直接返回即可。 return beanInstance; } Object object = null; if (mbd != null) { mbd.isFactoryBean = true; } else { // 根據beanName,從FactoryBean緩存中獲取FactoryBean object = getCachedObjectForFactoryBean(beanName); } // FactoryBean緩存中沒找到目標 if (object == null) { // 把當前的beanInstance強制轉換成FactoryBean FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // RootBeanDefinition為空並且beanDefinitionMap中包含次beanName if (mbd == null && containsBeanDefinition(beanName)) { // 合並bean定義,返回一個RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); } // 代表RootBeanDefinition是否是合成得到的 boolean synthetic = (mbd != null && mbd.isSynthetic()); // 從FactoryBean中獲取bean實例 object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; }
這部分的主要邏輯是:
1. 根據name判斷我們需要的是個Bean實例還是FactoryBean實例。
2. 如果需要FactoryBean實例,則做一些校驗后返回上一步得到的對象。
2. 如果需要Bean實例,則判斷上一步返回的對象是不是個純粹的Bean,是則返回;如果是個FactoryBean實例,則用FactoryBean創建一個Bean實例返回。
這部分涉及一個從FactoryBean中獲取bean實例的過程:
// org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { // 是單例並且單例緩存中有此beanName的key if (factory.isSingleton() && containsSingleton(beanName)) { synchronized (getSingletonMutex()) { // 先檢查緩存,這個factoryBeanObjectCache存儲的是由FactoryBean創建的單例對象的緩存。key為FactoryBean名稱。 Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { // factoryBeanObjectCache緩存沒有,則執行FactoryBean的getObject方法,獲取bean實例 object = doGetObjectFromFactoryBean(factory, beanName); // 考慮循環依賴的情況 Object alreadyThere = this.factoryBeanObjectCache.get(beanName); if (alreadyThere != null) { object = alreadyThere; } else { // 后置處理 if (shouldPostProcess) { if (isSingletonCurrentlyInCreation(beanName)) { // Temporarily return non-post-processed object, not storing it yet.. return object; } // 單例創建之前,將單例對象注冊為當前正在創建的狀態(添加到singletonsCurrentlyInCreation里) beforeSingletonCreation(beanName); try { // 在初始化之后應用后置處理 object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", ex); } finally { // 最后將單例對象正在創建的狀態移除(從singletonsCurrentlyInCreation里移除) afterSingletonCreation(beanName); } } // 因為是FactoryBean創建的bean,所以添加到對應的緩存里 if (containsSingleton(beanName)) { this.factoryBeanObjectCache.put(beanName, object); } } } // // 返回結果 return object; } } // 不是單例或者緩存中沒有此beanName else { // 調用factory的getObject方法獲取實例bean Object object = doGetObjectFromFactoryBean(factory, beanName); // 執行后置處理 if (shouldPostProcess) { try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); } } // 返回結果 return object; } }
簡單來講:
1. 先從factoryBeanObjectCache緩存中查看是否存在此FactoryBean創建的單例,有則返回,沒有的話執行FactoryBean的getObject方法來獲取;
2. 獲取完進行后置處理,后置處理之前將次beanName添加到 singletonsCurrentlyInCreation 集合中以示正在創建中,后置處理之后將beanName從 singletonsCurrentlyInCreation 集合中移除,以清除正在創建狀態。
4. 這部分涉及了一個合並BeanDefinition的過程。關於BeanDefinition的結構如下:
-
待續
5. 注冊依賴Bean
/** 別人依賴我:key=我,value=依賴我的人 */ private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64); /** 我依賴別人:key=我,value=我依賴的人 */ private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64); // beanName依賴dep registerDependentBean(dep, beanName); // beanName-被依賴者;dependentBeanName-依賴者 public void registerDependentBean(String beanName, String dependentBeanName) { String canonicalName = canonicalName(beanName); // 別人依賴我:key=beanName,value=Set(dependentBeanName) synchronized (this.dependentBeanMap) { Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); if (!dependentBeans.add(dependentBeanName)) { return; } } // 我依賴別人:key=dependentBeanName,value=Set(beanName) synchronized (this.dependenciesForBeanMap) { Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); } }
這個依賴關系有點繞,要仔細一點捋一下。
dependentBeanMap:dependent【依賴】Bean【我】Map,key是被依賴者,value是依賴者
dependenciesForBeanMap:dependencies【依賴項】For【給】Bean【我】Map,key是依賴者,value是被依賴者不知道我這樣解釋能不能明白這個關系?
6. 創建單實例bean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { if (logger.isTraceEnabled()) { logger.trace("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd; // 確保此時bean已經解析,並在動態解析的類不能存儲在共享的合並bean定義中時,克隆bean定義。【根據Bean定義解析BeanClass】 Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } try { // 驗證&准備在該bean中定義的覆蓋的方法。 // 檢查是否存在具有指定名稱的方法。 mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { // 給 Bean后置處理器 一個機會,返回一個目標bean實例的代理 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 { // 【執行創建bean的具體邏輯】 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("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); } }
這個方法主要有三步:
1. 解析BeanClass
2. 驗證&准備Bean定義中覆蓋的方法
3. 執行創建Bean
來看doCreateBean
// 【執行創建bean的具體邏輯】 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // BeanWrapper是個Bean包裝類 BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { // ☆☆☆【實例化Bean】 instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } } // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. 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"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { // ☆☆☆【屬性賦值】 populateBean(beanName, mbd, instanceWrapper); // ☆☆☆【初始化Bean實例】 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); } } // 如果是提前暴露單例 if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } 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); } } 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."); } } } } // 將bean注冊為一次性的 try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
這部分同樣也主要分為三步,同時這也是Bean生命周期的體現
1. ☆☆☆【實例化Bean】
2. ☆☆☆【屬性賦值】
3. ☆☆☆【初始化Bean實例】
4. ☆☆☆【銷毀】(銷毀在這里沒有體現)
☆☆☆【實例化Bean】☆☆☆
// 通過適當的策略實例化Bean:工廠方法、構造方法自動裝配或者簡單實例化 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); 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()); } // 獲取創建bean實例的回調 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { // 利用instanceSupplier獲取一個Bean實例 return obtainFromSupplier(instanceSupplier, beanName); } // 如果工廠方法不為空 if (mbd.getFactoryMethodName() != null) { // 通過工廠方法實例化Bean(詳見:org.springframework.beans.factory.support.ConstructorResolver#instantiateUsingFactoryMethod) return instantiateUsingFactoryMethod(beanName, mbd, args); } // Shortcut when re-creating the same bean... boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } // 如果已解析 if (resolved) { // 如果自動裝配 if (autowireNecessary) { // 構造方法自動裝配(詳見:org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor) return autowireConstructor(beanName, mbd, null, null); } // 否則是普通的實例化 else { return instantiateBean(beanName, mbd); } } // 返回用於給定bean的候選構造函數,檢查所有已注冊的構造函數 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { // 構造方法自動裝配(詳見:org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor) return autowireConstructor(beanName, mbd, ctors, args); } // 如果有默認的構造函數 ctors = mbd.getPreferredConstructors(); if (ctors != null) { return autowireConstructor(beanName, mbd, ctors, null); } // 沒有特殊的處理器,使用無參構造函數 return instantiateBean(beanName, mbd); }
這個方法主要是選取適當的策略來決定如何創建Bean
1. 利用Bean定義中的instanceSupplier獲取Bean
2. 利用指定的工廠方法名稱實例化Bean
3. 利用構造方法自動裝配實例化Bean
4. 簡單的使用無參構造函數實例化Bean,這個也是默認的處理方式
選擇默認處理方式:
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; if (System.getSecurityManager() != null) { beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, parent), getAccessControlContext()); } else { // org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory) beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); } // 新建一個Bean包裝類 BeanWrapper bw = new BeanWrapperImpl(beanInstance); // 初始化Bean包裝類 initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); } }
這個方法描述了兩個主要步驟
1. 實例化Bean
2. 新建 & 初始化包裝類,並返回。
看實例化
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // 如果沒有覆蓋的方法,則不使用CGLIB覆蓋 if (!bd.hasMethodOverrides()) { Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) { constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; if (constructorToUse == null) { // 獲取Class對象 final Class<?> clazz = bd.getBeanClass(); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { if (System.getSecurityManager() != null) { constructorToUse = AccessController.doPrivileged( (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor); } else { // 獲取Constructor對象 constructorToUse = clazz.getDeclaredConstructor(); } // 給RootBeanDefinition設置已解析的構造函數或工廠方法 bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } // 工具類,實例化Bean(繞了這么多,真正干活的是這個方法) return BeanUtils.instantiateClass(constructorToUse); } else { // Must generate CGLIB subclass. // 子類可以覆蓋這個方法,如果子類可以用給定的RootBeanDefinition中指定的方法注入實例化一個對象。實現該方法的目的是拋出UnsupportedOperationException。 // 實例化應該使用無參數的構造函數。 return instantiateWithMethodInjection(bd, beanName, owner); } } public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { Assert.notNull(ctor, "Constructor must not be null"); try { // 反射方法(ctor.setAccessible(true);) ReflectionUtils.makeAccessible(ctor); if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { return KotlinDelegate.instantiateClass(ctor, args); } else { // 獲得參數類型 Class<?>[] parameterTypes = ctor.getParameterTypes(); // 參數數量校驗 Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters"); Object[] argsWithDefaultValues = new Object[args.length]; // 組裝參數 for (int i = 0 ; i < args.length; i++) { if (args[i] == null) { Class<?> parameterType = parameterTypes[i]; argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null); } else { argsWithDefaultValues[i] = args[i]; } } // 反射方法,利用給定的參數new一個實例 return ctor.newInstance(argsWithDefaultValues); } } catch (InstantiationException ex) { throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex); } catch (IllegalAccessException ex) { throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex); } catch (IllegalArgumentException ex) { throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex); } catch (InvocationTargetException ex) { throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException()); } }
實際上實例化的方法並不復雜,復雜的是前期准備的過程
實例化的過程:組裝參數成一個Object數組(無參的話數組長度為0),傳入Constructor的newInstance方法完成實例化。
實例化全程總結:
1. 根據情況選取合適的創建策略
☆ 利用Bean定義中的instanceSupplier獲取Bean
☆ 利用指定的工廠方法名稱實例化Bean
☆ 利用構造方法自動裝配實例化Bean
☆ 簡單的使用無參構造函數實例化Bean,這個也是默認的處理方式
2. 將實例封裝成一個包裝類
☆ 通過反射方法實例化Bean
☆ 新建 & 初始化Bean的包裝類
另外:我看了下利用工廠方法創建和構造方法自動裝配兩種方式,除了過程比較復雜,其實例化的時候調用的都是org.springframework.beans.factory.support.ConstructorResolver#instantiate(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
進而調用org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory, java.lang.Object, java.lang.reflect.Method, java.lang.Object...)
剛好和上面對上,實例化都是利用反射(當然這樣說也不是很嚴謹),因為實例化策略的實現有兩個,除了反射還有CGLIB,如圖:
☆☆☆【屬性賦值】☆☆☆
// ☆☆☆【屬性賦值】 protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { // Bean實例為空的不用屬性賦值 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; } } // 給任何一個InstantiationAwareBeanPostProcessor在屬性設置之前修改bean狀態的機會。 boolean continueWithPropertyPopulation = true; // 如果Bean定義不是合成的,並且,當前的工廠持有InstantiationAwareBeanPostProcessor列表 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { // 遍歷用於此工廠創建bean的beanpostprocessor列表 for (BeanPostProcessor bp : getBeanPostProcessors()) { // 如果當前Processor是InstantiationAwareBeanPostProcessor的子類實現 if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; // 如果不是實例化之后的處理器,則設置continueWithPropertyPopulation為false,目的不再執行后續屬性設置 if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; } } } } // 注:InstantiationAwareBeanPostProcessor出現在Bean實例化前后,屬性(自動裝配)之前。 // 根據上面的執行結果,決定是否還要繼續 if (!continueWithPropertyPopulation) { return; } // 嘗試獲取Bean定義里的屬性值映射列表 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); // 獲取解析到的自動裝配模式 int resolvedAutowireMode = mbd.getResolvedAutowireMode(); // 如果是根據名稱自動裝配或者根據類型自動裝配,這里僅僅是將屬性名稱-屬性值的映射關系裝配到PropertyValues對象中 if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } // 當前的工廠是否持有InstantiationAwareBeanPostProcessor列表 boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); // 是否需要檢查依賴 boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); PropertyDescriptor[] filteredPds = null; // 如果當前的工廠持有InstantiationAwareBeanPostProcessor列表 if (hasInstAwareBpps) { if (pvs == null) { pvs = mbd.getPropertyValues(); } // 遍歷執行處理器,對屬性進行后置處理 for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } } } // 需要檢查依賴 if (needsDepCheck) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } // 檢查依賴 checkDependencies(beanName, mbd, filteredPds, pvs); } // 最后,如果屬性值列表不為空 if (pvs != null) { // 設置屬性 applyPropertyValues(beanName, mbd, bw, pvs); } }
大概流程是
1. 進行Bean實例化之后的后置處理。
2. 先獲取默認的屬性映射關系對象,然后根據模式判斷按照名稱還是按照類型自動裝配。
3. 遍歷后置處理器,對裝配好的屬性映射關系對象進行后置處理。
4. 檢查依賴。
5. 屬性賦值。
另:autowireByName/autowireByType/applyPropertyValues這三個方法暫時不提,太多了。
☆☆☆【初始化Bean實例】☆☆☆
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
// ☆☆☆【初始化Bean實例】 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 { // 1. 執行Aware子類相關的方法 invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // 2. 初始化之前的后置處理 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { // 3. 執行初始化方法 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()) { // 4. 初始化之后的后置處理 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
1. Aware的子類
private void invokeAwareMethods(final String beanName, final Object bean) { // Aware是個頂級標記接口,作用是能夠感知自己的一些屬性。示例在后面單獨說明。 if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } }
2、3 . 初始化前后的處理
@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; } @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; }
4. 初始化方法
// 初始化 protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); // 這個Bean實現了InitializingBean接口 if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isTraceEnabled()) { logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { // 因為InitializingBean接口里只有一個afterPropertiesSet方法,所以這個是由子類實現的方法。 // 作用顧名思義,在屬性賦值之后做的一些善后工作。該方法允許bean實例在設置了所有bean屬性后執行總體配置驗證和最終初始化。 ((InitializingBean) bean).afterPropertiesSet(); } } // 如果配置了比如:@Bean(initMethod = "myInit"),指定了自定義的初始化方法,就會在這個時候執行 if (mbd != null && bean.getClass() != NullBean.class) { // 獲取初始化方法名稱 String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { // 這里內部實現是利用反射執行初始化方法的 invokeCustomInitMethod(beanName, bean, mbd); } } }
示例
定義一個Bean
import lombok.Getter; import lombok.Setter; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.InitializingBean; @Getter @Setter public class Apple implements BeanNameAware,InitializingBean { private String id; private String name; // 對於Aware接口的子類,實現了的方法會在Bean的初始化階段被調用 public void setBeanName(String name) { this.id = name; } // 對於實現InitializingBean接口的Bean,需要實現這個方法,目的是屬性賦值之后做的一些善后工作 public void afterPropertiesSet() throws Exception { System.out.println("Do Anything"); this.name = "我這里設置了屬性B"; } // 自定義的Bean初始化方法 public void myInitMethod(){ System.out.println("Do Something"); } }
配置類
import com.entity.Apple; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class Config { @Bean(initMethod = "myInitMethod") public Apple apple(){ Apple apple = new Apple(); apple.setName("我這里設置了屬性A"); return apple; } }
運行
import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args){ ApplicationContext app = new AnnotationConfigApplicationContext(Config.class); } }
如果你打斷點,你會在這里攔截到我們配置影響的第一個點【Aware接口】
進入方法,會執行我們定義的setBeanName方法(這樣,我們實現了BeanNameAware接口的Bean就能獲取到自己的Bean名稱)
----------------
接下來到第二個部分(InitializingBean接口)
進入方法,先執行我們定義的 afterPropertiesSet
----------
然后到第三部分,執行我們定義的自定義初始化方法。
初始化部分總結:
1. 如果Bean實現了Aware接口,則會執行其中的方法(方法只有一個)。實際應用比如:寫一個實現ApplicationContextAware接口的工具類,來獲取當前應用程序上下文。進而手動getBean。
2. 執行初始化之前的后置處理器。
3. 初始化:① 如果Bean實現了 InitializingBean 接口,則會執行 afterPropertiesSet。 ② 如果Bean指定了自定義的初始化方法,則會執行此方法。
4. 執行初始化之后的后置處理器。
思考:如果只是一個普通的Bean,則不會執行這么多邏輯。這些額外的處理都是為了應付一些復雜的場景,這里也能體會到作者的用意——擴展性。
☆☆☆【總結:Bean實例化過程,主要過程全部體現在AbstractAutowireCapableBeanFactory類里】☆☆☆
☆☆☆【銷毀Bean】☆☆☆
如果前面創建單例出現了異常,就會執行銷毀操作。
if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // 顯式地從單例緩存中刪除實例:它可能被創建過程提前暴露放在那里,以允許循環引用解析。 // 還要刪除所有接受該bean臨時引用的bean。 destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
如果你想打斷點到這一行,只需要在Apple實體類里加一句話:
打斷點能捕獲到
// 先執行:org.springframework.beans.factory.support.DefaultListableBeanFactory#destroySingleton public void destroySingleton(String beanName) { // 執行父類的邏輯 super.destroySingleton(beanName); // 更新manualSingletonNames集合,從中刪除beanName removeManualSingletonName(beanName); // 清除所有按照Type獲取的BeanName緩存【this.allBeanNamesByType.clear(); this.singletonBeanNamesByType.clear();】 clearByTypeCache(); }
父類邏輯
// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#destroySingleton public void destroySingleton(String beanName) { // 刪除所有此beanName注冊的Bean緩存(singletonObjects、singletonFactories、earlySingletonObjects、registeredSingletons) removeSingleton(beanName); // 銷毀相應的DisposableBean實例 DisposableBean disposableBean; synchronized (this.disposableBeans) { // 從存儲一次性Bean的LinkedHashMap集合中刪除此beanName disposableBean = (DisposableBean) this.disposableBeans.remove(beanName); } // 執行刪除 destroyBean(beanName, disposableBean); }
destroyBean
protected void destroyBean(String beanName, @Nullable DisposableBean bean) { // Trigger destruction of dependent beans first... Set<String> dependencies; synchronized (this.dependentBeanMap) { // Within full synchronization in order to guarantee a disconnected Set // 從依賴Map中移除並獲取依賴此bean的集合 dependencies = this.dependentBeanMap.remove(beanName); } if (dependencies != null) { if (logger.isTraceEnabled()) { logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies); } // 如果存在依賴,則遞歸刪除所有依賴這個beanName的所有bean // 這個地方白話解釋一下:母貓死亡(發生了異常),那么母貓影響的是所有依賴母貓的小貓(Bean) for (String dependentBeanName : dependencies) { destroySingleton(dependentBeanName); } } // Actually destroy the bean now... // 刪除一次性的bean if (bean != null) { try { bean.destroy(); } catch (Throwable ex) { if (logger.isWarnEnabled()) { logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex); } } } // 銷毀當前Bean所包含的bean Set<String> containedBeans; synchronized (this.containedBeanMap) { // Within full synchronization in order to guarantee a disconnected Set containedBeans = this.containedBeanMap.remove(beanName); } if (containedBeans != null) { // 如果包含其它bean,則遞歸刪除 // 這個地方白話解釋一下:母貓死亡(發生了異常),母貓所包含的所以東西比如粑粑(Bean),都要回歸大自然。 for (String containedBeanName : containedBeans) { destroySingleton(containedBeanName); } } // 從其他bean的依賴項中移除被破壞的bean。這里是看一下dependentBeanMap中余下的value里是否含有當前beanName synchronized (this.dependentBeanMap) { for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) { Map.Entry<String, Set<String>> entry = it.next(); Set<String> dependenciesToClean = entry.getValue(); dependenciesToClean.remove(beanName); if (dependenciesToClean.isEmpty()) { it.remove(); } } } // 刪除bean准備好的依賴項信息。 this.dependenciesForBeanMap.remove(beanName); }
主要的銷毀包含:
1. 銷毀所有直接依賴此bean的bean(遞歸刪除)
2. 如果存在的話,刪除一次性注冊的bean
3. 銷毀此bean包含的所有bean(遞歸刪除)
4. 遍歷dependentBeanMap的value,看是否存在此bean
5. 刪除自己已准備好的依賴項信息
這里涉及三個集合
/** 我擁有的人:key=我,value=我擁有的人 */ private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16); /** 別人依賴我:key=我,value=依賴我的人 */ private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64); /** 我依賴別人:key=我,value=我依賴的人 */ private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
圖解一下
7. 創建多實例bean
// 原型模式 else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; // 這里是個局部變量,可以想到這種情況下創建的對象,容器是不會去管理的。 try { // 創建之前 beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { // 創建之后 afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } protected void beforePrototypeCreation(String beanName) { // prototypesCurrentlyInCreation是一個本地線程變量,存儲當前正在創建的多實例Bean Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal == null) { // 如果當前線程沒有創建任務,則設置為當前BeanName this.prototypesCurrentlyInCreation.set(beanName); } else if (curVal instanceof String) { // 如果當前存儲的變量是String類型,則新建一個Set集合,存儲這個String變量以及我們將要創建的beanName Set<String> beanNameSet = new HashSet<>(2); beanNameSet.add((String) curVal); beanNameSet.add(beanName); // 存儲進線程本地變量 this.prototypesCurrentlyInCreation.set(beanNameSet); } else { Set<String> beanNameSet = (Set<String>) curVal; // 轉換成Set集合,然后把當前beanName添加進去 beanNameSet.add(beanName); } } protected void afterPrototypeCreation(String beanName) { // 獲取線程本地變量 Object curVal = this.prototypesCurrentlyInCreation.get(); // 如果是String類型,直接移除 if (curVal instanceof String) { this.prototypesCurrentlyInCreation.remove(); } else if (curVal instanceof Set) { // 如果是Set集合,先移除Set集合中的beanName Set<String> beanNameSet = (Set<String>) curVal; beanNameSet.remove(beanName); // 如果集合為空,才去移除線程本地變量 if (beanNameSet.isEmpty()) { this.prototypesCurrentlyInCreation.remove(); } } }
與單例模式不同的是創建前后有個處理的過程,看過程
1. 創建之前(目的是把任務[beanName]放進本地線程變量中)
線程本地變量獲取為空,則直接設置成當前beanName。
獲取到線程本地變量,並且類型為String,則新建一個Set集合,將新老變量添加到集合中,最后設置成線程本地變量。
獲取到線程本地變量,類型是Set集合,則先做類型轉換,然后添加當前的beanName到集合中,最后設置成線程本地變量。
2. 創建Bean,在doCreateBean方法中有這么一行,如下:
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
目的是用來檢測循環依賴,添加到相應的緩存中,同時它是僅僅針對單例Bean。而多實例Bean的創建不會有這個過程的。
3. 創建之后(目的是把任務[beanName]從本地線程變量中移除)
如果獲取到的變量是String類型,證明只有這一個任務,直接執行remove即可。
如果獲取到的變量類型是Set集合類型,證明不止當前一個任務,要把當前任務從Set集合中刪除;然后再判斷Set集合是否為空,為空才會執行remove方法。
8. 在指定的scope(作用域)上實例化bean
這里呢,與前面兩種不同的地方僅僅是多了個獲取Scope的過程,其他部分都不是事。
-
☆ 擴展——IOC容器的關閉
不賣關子直接上,Java應用程序里可以添加關閉鈎子。
public static void main(String[] args){ Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("關閉之前我要優雅的處理資源"); })); }
這樣,當以下情況會觸發
1. 程序正常退出
2. 使用System.exit()
3. 終端Ctrl+C
4. 系統關閉
5. Kill pid命令干掉進程(不是kill -9 pid)
同樣,在Spring里也是這樣做的(org.springframework.context.support.AbstractApplicationContext#registerShutdownHook)
public void registerShutdownHook() { if (this.shutdownHook == null) { this.shutdownHook = new Thread("SpringContextShutdownHook") { public void run() { synchronized(AbstractApplicationContext.this.startupShutdownMonitor) { AbstractApplicationContext.this.doClose(); } } }; Runtime.getRuntime().addShutdownHook(this.shutdownHook); } } /** @deprecated */ @Deprecated public void destroy() { this.close(); } public void close() { Object var1 = this.startupShutdownMonitor; synchronized(this.startupShutdownMonitor) { this.doClose(); if (this.shutdownHook != null) { try { Runtime.getRuntime().removeShutdownHook(this.shutdownHook); } catch (IllegalStateException var4) { ; } } } }
當然Spring已經寫好了,不用我們去管。但是我們遇到一些業務場景可能會用到,現有框架比如Dubbo,聽說就是利用這個東西實現優雅停機的。
總結
實際上Spring的重點可以說有兩部分
1. 容器(IOC)創建過程:
ApplicationContext app = new AnnotationConfigApplicationContext(Config.class);2. Bean加載過程(也可以說是Bean的實例化過程):
app.getBean("user");
這兩部分並不是井水不犯河水,因為容器創建過程,就涉及到單實例Bean的初始化過程了。
如果作用域是 Singleton,那么在容器創建的時候就會初始化,后面你getBean會直接返回緩存中的實例,生命周期交給容器處理。
如果作用域是 Prototype,那么每次調用getBean都會創建一個新的實例,生命周期交給調用者。
另外你還能發現,在Bean的實例化過程遇到的問題很多都是面試問的問題。比如:
BeanFactory和FactoryBean的區別?
Spring如何解決循環依賴的?
Bean的生命周期?等等
由於這部分內容比較多且復雜,一部分是年前寫的,一部分是在老家寫的,用的測試代碼可能不一樣,但是不影響Spring代碼的思路。