掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
本文轉(zhuǎn)載自微信公眾號「bugstack蟲洞?!?,作者小傅哥 。轉(zhuǎn)載本文請聯(lián)系bugstack蟲洞棧公眾號。

你提出問題,就要給出解決方案!
最近有粉絲小伙伴反饋,與自己的上級溝通總是遇到障礙,感覺不被理解。大部分時候他提出來的事情都可能會被領(lǐng)導(dǎo)說:“我沒get到你的點”、“你想做的這個項目沒有業(yè)務(wù)價值”、“你提出問題,就要給出解決方案”,等等諸如此類的回答。
鑒于具體情況要具體分析,可能我們并不一定能判斷出是誰的問題,導(dǎo)致在每次的交談中出現(xiàn)的分歧??赡苁莑eader有l(wèi)eader的苦衷和視角,也可能是員工有員工的理解和想法,所以最終沒有達成一致。
但就帶團隊來講,有效溝通很重要。就像:如果你說的都對,那我為什么和你爭吵呢?與其壓制遇到的矛盾點,不如都攤開了聊,誰的視角和心胸更大,誰就多有一些同理心。
如果尖銳的批評完全消失,溫和的批評將會變得刺耳。
如果溫和的批評也不被允許,沉默將被認(rèn)為居心叵測。
如果沉默也不再允許,贊揚不夠賣力將是一種罪行。
如果只允許一種聲音存在,那么,唯一存在的那個聲音就是謊言。
謝飛機,小記!,總感覺 Spring 也沒啥看的,怎么面試官一問就能問出花?
面試官:Spring 的 getBean 中,transformedBeanName 的作用是什么?
謝飛機:不知道呀,看單詞意思好像是改變Bean名稱。
面試官:那這么說,你的 Bean 如果有 alias 別名,Spring 在獲取 Bean 時候要怎么處理?
謝飛機:這!
面試官:那如果用了 depends-on 呢?
謝飛機:啊, 我沒用過 depends-on 我不知道!
面試官:那你調(diào)試代碼時候,看見過BeanName前面有 & 的情況嗎,為啥會出現(xiàn)?
謝飛機:我不配知道!再見!
對于剛接觸看 Spring 源碼的伙伴來說,可能很疑惑于怎么就獲取一個 Bean 就這么多流程呢?
所以,它為了適應(yīng)各類的需求,變得越來越復(fù)雜了。而這部分知識的深入學(xué)習(xí)絕對不只是為了應(yīng)付八股文,更多的是考慮到在日常的 Spring 使用中遇到復(fù)雜問題時有沒有一個大致知曉的流程,可以快速定位問題,以及此類需求的技術(shù)實現(xiàn)方案是否能在以后的應(yīng)用開發(fā)中起到一定的指導(dǎo)作用,因為它是一種設(shè)計方案的具體實現(xiàn)。
小傅哥,getBean 核心流程圖
接下來,我們就依次的把關(guān)于獲取 Bean 實例的重點代碼列舉出來做分析,讀者伙伴也可以結(jié)合流程圖一起看,這樣會更方便理解。
- @Test
- public void test_getBean() {
- BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config.xml");
- UserDao userDao = beanFactory.getBean("userDao", UserDao.class);
- logger.info("獲取 Bean:{}", userDao);
- }
在日常應(yīng)用到 Spring 的開發(fā)中基本都是基于注解,幾乎不會自己去使用 beanFactory.getBean 的方式去獲取一個 Bean 實例。
所以在你學(xué)習(xí)的時候如果找不到查看 getBean 源碼的入口,也不方便調(diào)試熟悉源碼時,可以寫這樣一個單元測試類,點入到 getBean 就可以閱讀源碼了。
源碼位置:AbstractBeanFactory -> getBean() -> doGetBean()
- @Override
- public
T getBean(String name, Class requiredType) throws BeansException { - // getBean 就像你的領(lǐng)導(dǎo)其實沒做啥,都在 doGetBean 里
- return doGetBean(name, requiredType, null, false);
- }
- protected
T doGetBean(final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) - throws BeansException {
- // 處理別名BeanName、處理帶&符的工廠BeanName
- final String beanName = transformedBeanName(name);
- Object bean;
- // 先嘗試從緩存中獲取Bean實例,這個位置就是三級緩存解決循環(huán)依賴的方法
- Object sharedInstance = getSingleton(beanName);
- if (sharedInstance != null && args == null) {
- if (logger.isDebugEnabled()) {
- if (isSingletonCurrentlyInCreation(beanName)) {
- logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
- "' that is not fully initialized yet - a consequence of a circular reference");
- }
- else {
- logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
- }
- }
- // 1. 如果 sharedInstance 是普通的 Bean 實例,則下面的方法會直接返回
- // 2. 如果 sharedInstance 是工廠Bean類型,則需要獲取 getObject 方法,可以參考關(guān)于 FactoryBean 的實現(xiàn)類
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
- }
- else {
- // 循環(huán)依賴有三種,setter注入、多實例和構(gòu)造函數(shù),Spring 只能解決 setter 注入,所以這里是 Prototype 則會拋出異常
- if (isPrototypeCurrentlyInCreation(beanName)) {
- throw new BeanCurrentlyInCreationException(beanName);
- }
- // 1. 父 bean 工廠存在
- // 2. 當(dāng)前 bean 不存在于當(dāng)前bean工廠,則到父工廠查找 bean 實例
- BeanFactory parentBeanFactory = getParentBeanFactory();
- if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
- // 獲取 name 對應(yīng)的 beanName,如果 name 是以 & 開頭,則返回 & + beanName
- String nameToLookup = originalBeanName(name);
- // 根據(jù) args 參數(shù)是否為空,調(diào)用不同的父容器方法獲取 bean 實例
- if (args != null) {
- return (T) parentBeanFactory.getBean(nameToLookup, args);
- }
- else {
- return parentBeanFactory.getBean(nameToLookup, requiredType);
- }
- }
- // 1. typeCheckOnly,用于判斷調(diào)用 getBean 方法時,是否僅是做類型檢查
- // 2. 如果不是只做類型檢查,就會調(diào)用 markBeanAsCreated 進行記錄
- if (!typeCheckOnly) {
- markBeanAsCreated(beanName);
- }
- try {
- // 從容器 getMergedLocalBeanDefinition 獲取 beanName 對應(yīng)的 GenericBeanDefinition,轉(zhuǎn)換為 RootBeanDefinition
- final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
- // 檢查當(dāng)前創(chuàng)建的 bean 定義是否為抽象 bean 定義
- checkMergedBeanDefinition(mbd, beanName, args);
- // 處理使用了 depends-on 注解的依賴創(chuàng)建 bean 實例
- String[] dependsOn = mbd.getDependsOn();
- if (dependsOn != null) {
- for (String dep : dependsOn) {
- // 監(jiān)測是否存在 depends-on 循環(huán)依賴,若存在則會拋出異常
- if (isDependent(beanName, dep)) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
- }
- // 注冊依賴記錄
- registerDependentBean(dep, beanName);
- try {
- // 加載 depends-on 依賴(dep 是 depends-on 縮寫)
- getBean(dep);
- }
- catch (NoSuchBeanDefinitionException ex) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
- }
- }
- }
- // 創(chuàng)建單例 bean 實例
- if (mbd.isSingleton()) {
- // 把 beanName 和 new ObjectFactory 匿名內(nèi)部類傳入回調(diào)
- sharedInstance = getSingleton(beanName, new ObjectFactory
- @Override
- public Object getObject() throws BeansException {
- try {
- // 創(chuàng)建 bean
- return createBean(beanName, mbd, args);
- }
- catch (BeansException ex) {
- // 創(chuàng)建失敗則銷毀
- destroySingleton(beanName);
- throw ex;
- }
- }
- });
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
- }
- // 創(chuàng)建其他類型的 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 {
- 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, new ObjectFactory
- @Override
- public Object getObject() throws BeansException {
- 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;
- }
- }
- // 如果需要類型轉(zhuǎn)換,這里會進行操作
- if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
- try {
- return getTypeConverter().convertIfNecessary(bean, requiredType);
- }
- catch (TypeMismatchException ex) {
- if (logger.isDebugEnabled()) {
- logger.debug("Failed to convert bean '" + name + "' to required type '" +
- ClassUtils.getQualifiedName(requiredType) + "'", ex);
- }
- throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
- }
- }
- // 返回 Bean
- return (T) bean;
- }
綜上基本就是 getBean 過程涉及到的核心處理方法,基本包括;
處理 & 符:transformedBeanName() -> BeanFactoryUtils.transformedBeanName(name)
- public static String transformedBeanName(String name) {
- Assert.notNull(name, "'name' must not be null");
- String beanName = name;
- while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
- beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
- }
- return beanName;
- }
別名轉(zhuǎn)換:transformedBeanName() -> canonicalName
- public String canonicalName(String name) {
- String canonicalName = name;
- // Handle aliasing...
- String resolvedName;
- do {
- resolvedName = this.aliasMap.get(canonicalName);
- if (resolvedName != null) {
- canonicalName = resolvedName;
- }
- }
- while (resolvedName != null);
- return canonicalName;
- }
首先 Spring 對 Bean 的存放并不會使用別名作為Map中的key,所以遇到所有別名獲取 Bean 都需要查到對應(yīng)原來名字,才可以。如果你知道這個事,是不遇到此類問題時,就知道從哪下手查了
do...while 循環(huán)會依次像鏈條一樣不斷的尋找別名對應(yīng)的名稱,直到當(dāng)前這個名稱沒有別名了,就返回對應(yīng) BeanName
- protected boolean isDependent(String beanName, String dependentBeanName) {
- synchronized (this.dependentBeanMap) {
- return isDependent(beanName, dependentBeanName, null);
- }
isDependent 處理的是使用了 depends-on 配置的 Bean 定義。
- private boolean isDependent(String beanName, String dependentBeanName, Set
alread - if (alreadySeen != null && alreadySeen.contains(beanName)) {
- return false;
- }
- String canonicalName = canonicalName(beanName);
- Set
dependentBeans = this.dependentBeanMap.get(canonicalName); - if (dependentBeans == null) {
- return false;
- }
- if (dependentBeans.contains(dependentBeanName)) {
- return true;
- }
- for (String transitiveDependency : dependentBeans) {
- if (alreadySeen == null) {
- alreadySeen = new HashSet
(); - }
- alreadySeen.add(beanName);
- if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
- return true;
- }
- }
- return false;
- }
AbstractBeanFactory -> registerDependentBean(dep, beanName) -> DefaultSingletonBeanRegistry
- public void registerDependentBean(String beanName, String dependentBeanName) {
- String canonicalName = canonicalName(beanName);
- synchronized (this.dependentBeanMap) {
- Set
dependentBeans = this.dependentBeanMap.get(canonicalName); - if (dependentBeans == null) {
- dependentBeans = new LinkedHashSet
(8); - this.dependentBeanMap.put(canonicalName, dependentBeans);
- }
- dependentBeans.add(dependentBeanName);
- }
- synchronized (this.dependenciesForBeanMap) {
- Set
dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName - if (dependenciesForBean == null) {
- dependenciesForBean = new LinkedHashSet
(8); - this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
- }
- dependenciesForBean.add(canonicalName);
- }
- }
最后:getBean(dep),就可以獲取到 depends-on 依賴的 Bean 了
AbstractBeanFactory -> mbd.isSingleton()
- if (mbd.isSingleton()) {
- sharedInstance = getSingleton(beanName, new ObjectFactory
- @Override
- public Object getObject() throws BeansException {
- try {
- return createBean(beanName, mbd, args);
- }
- catch (BeansException ex) {
- destroySingleton(beanName);
- throw ex;
- }
- }
- });
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
- }
這一部分是使用 beanName 和 singletonFactory 匿名內(nèi)部類傳入等待回調(diào)的方式創(chuàng)建單實例 Bean 實例
- public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {
- Assert.notNull(beanName, "'beanName' must not be null");
- synchronized (this.singletonObjects) {
- Object singletonObject = this.singletonObjects.get(beanName);
- if (singletonObject == null) {
- if (this.singletonsCurrentlyInDestruction) {
- throw new BeanCreationNotAllowedException(beanName,
- "Singleton bean creation not allowed while singletons of this factory are in destruction " +
- "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
- }
- beforeSingletonCreation(beanName);
- boolean newSingleton = false;
- boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
- if (recordSuppressedExceptions) {
- this.suppressedExceptions = new LinkedHashSet
(); - }
- try {
- singletonObject = singletonFactory.getObject();
- newSingleton = true;
- }
- catch (IllegalStateException ex) {
- singletonObject = this.singletonObjects.get(beanName);
- if (singletonObject == null) {
- throw ex;
- }
- }
- catch (BeanCreationException ex) {
- if (recordSuppressedExceptions) {
- for (Exception suppressedException : this.suppressedExceptions) {
- ex.addRelatedCause(suppressedException);
- }
- }
- throw ex;
- }
- finally {
- if (recordSuppressedExceptions) {
- this.suppressedExceptions = null;
- }
- afterSingletonCreation(beanName);
- }
- if (newSingleton) {
- addSingleton(beanName, singletonObject);
- }
- }
- return (singletonObject != NULL_OBJECT ? singletonObject : null);
- }
- }
doCreateBean -> if (earlySingletonExposure) -> getSingleton(beanName, false)
- protected Object getSingleton(String beanName, boolean allowEarlyReference) {
- // 從 singletonObjects 獲取實例,singletonObjects 中緩存的實例都是完全實例化好的 bean,可以直接使用
- Object singletonObject = this.singletonObjects.get(beanName);
- // 如果 singletonObject 為空,則沒有創(chuàng)建或創(chuàng)建中
- if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
- // 加鎖
- synchronized (this.singletonObjects) {
- // 單例緩存池中,沒有當(dāng)前beanName
- 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);
- this.singletonFactories.remove(beanName);
- }
- }
- }
- }
- return (singletonObject != NULL_OBJECT ? singletonObject : null);
- }
AbstractBeanFactory -> getObjectForBeanInstance(sharedInstance, name, beanName, null)
- protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
- // 如果 beanName 以 & 開頭,但 beanInstance 卻不是 FactoryBean,則會拋出異常
- if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
- throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
- }
- // 這里判斷就是這個 bean 是不是 FactoryBean,不是就直接返回了
- if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
- return beanInstance;
- }
- Object object = null;
- if (mbd == null) {
- // 如果 mbd 為空,則從緩存加載 bean(FactoryBean 生成的單例 bean 實例會緩存到 factoryBeanObjectCache 集合中,方便使用)
- object = getCachedObjectForFactoryBean(beanName);
- }
- if (object == null) {
- // 到這,beanInstance 是 FactoryBean 類型,所以就強轉(zhuǎn)了
- FactoryBean> factory = (FactoryBean>) beanInstance;
- // mbd 為空且判斷 containsBeanDefinition 是否包含 beanName
- if (mbd == null && containsBeanDefinition(beanName)) {
- // 合并 BeanDefinition
- mbd = getMergedLocalBeanDefinition(beanName);
- }
- boolean synthetic = (mbd != null && mbd.isSynthetic());
- // 調(diào)用 getObjectFromFactoryBean 獲取實例
- object = getObjectFromFactoryBean(factory, beanName, !synthetic);
- }
- return object;
- }
- @Test
- public void test_alias() {
- BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-alias.xml");
- UserService userService = beanFactory.getBean("userService-alias02", UserService.class);
- logger.info("獲取 Bean 通過別名:{}", userService);
- }
在單元測試 getBean 的時候,會看到它會把別名逐步處理掉,最終獲取到原有的 BeanName
- @Test
- public void test_depends_on() {
- BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-depends-on.xml");
- UserService userService = beanFactory.getBean(UserService.class, "userService");
- logger.info("獲取 Bean:{}", userService.getUserDao());
- }
- @Test
- public void test_factory_bean() {
- BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring-config-factory-bean.xml");
- UserDao userDao = beanFactory.getBean("userDao", UserDao.class);
- logger.info("獲取 Bean:{}", userDao);
- }
實現(xiàn) FactoryBean 的類會需要實現(xiàn) getObject 方法,所有此類的 Bean 最終都是獲取 getObject

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流