首先看示例代碼:
<!--no-lazy-init scope=singleton--> <bean class="com.lios.service.test.LiosTestA" id="liosTestA"/> <bean class="com.lios.service.test.LiosTestB" id="liosTestB"/> <bean class="com.lios.service.test.LiosServiceServiceImpl" id="liosServiceService"/> ClassPathXmlApplicationContext resource = new ClassPathXmlApplicationContext("app.xml"); BeanFactory beanFactory = resource.getBeanFactory(); LiosServiceServiceImpl liosServiceService = (LiosServiceServiceImpl) beanFactory.getBean("liosServiceService"); liosServiceService.t();
LiosServiceServiceImpl:
@Service public class LiosServiceServiceImpl { private int i = 1; @Autowired LiosTestA liosTestA; public void t(){ try { liosTestA.testA(); } catch (Exception e) { e.printStackTrace(); } System.out.println("===========>"); } }
LiosTestA:
@Service public class LiosTestA { @Autowired LiosTestB liosTestB; public void testA(){ liosTestB.testB(); } }
以上代碼就是LiosServiceServiceImpl類中引用了LiosTestA,LiosTestA類中引用了LiosTestB,今天的問題是LiosServiceServiceImpl如何引用LiosTestA,LiosTestA如何引用LiosTestB? 看過源碼的同學肯定知道, org.springframework.context.support.AbstractApplicationContext#refresh
是spring解析xml、初始化bean的入口,該方法裏會調用:
// Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory);
這個方法會實例化所有的non-lazy-init單例的bean,毫無疑問,這個方法是分析問題的入口,緊跟進去:
// Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons();
再跟進去,調用了 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
方法,再跟進去 getBean(beanName);
方法,調用了 org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
方法:
@Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); }
進入doGetBean方法中,繞了那麼多,這個方法纔是會真正幹事:
//獲取beanName final String beanName = transformedBeanName(name); //從緩存裏獲取bean,第一次時毫無疑問,sharedInstance爲null Object sharedInstance = getSingleton(beanName); //獲取RootBeanDefinition,其實用BeanDefinition初始化 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 創建bean createBean(beanName, mbd, args)
下面分析 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.Class<T>)
方法,明顯這是把具體實現委託給子類實現了,繼續跟: org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
,該方法裏有一段這樣的代碼:
instanceWrapper = createBeanInstance(beanName, mbd, args);
繼續跟:
// Make sure bean class is actually resolved at this point. Class<?> beanClass = resolveBeanClass(mbd, beanName); //.... 後面省略
繼續跟 resolveBeanClass()
方法,其實該方法裏利用反射創建了bean實例,createBeanInstance()方法主要是返回BeanWrapper對象,該對象用bean實例初始化,getWrappedInstance()即可返回bean對象:
/** * Return the bean instance wrapped by this object, if any. * @return the bean instance, or {@code null} if none set */ Object getWrappedInstance();
所以上面的LiosServiceServiceImpl、LiosTestA、LiosTestB都是通過resolveBeanClass()方法創建實例,但是裏面的引用的屬性如何創建呢,那回到 doCreateBean()
方法,繼續看下面的代碼:
// Initialize the bean instance. Object exposedObject = bean; try { //初始化bean屬性的值 populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { exposedObject = initializeBean(beanName, exposedObject, mbd); } }
首先分析 populateBean(beanName,mbd,instanceWrapper)
,爲了直接點,直接看後置處理器BeanPostProcessor:
for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } }
再看InstantiationAwareBeanPostProcessor的實現類, org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessPropertyValues
:
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs); metadata.inject(bean, beanName, pvs);
一直跟進去到 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
:
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
再跟進去:
result = doResolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
繼續跟進去:
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
doResolveDependency方法會根據屬性的屬性類型去獲取引用,繼續跟,可以看到 org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
方法裏的這段代碼:
result.put(candidateName, getBean(candidateName));
getBean(candidateName)這個不是調用 org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
麼,沒錯,是的!
回到 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
中:
if (value != null) { ReflectionUtils.makeAccessible(field); field.set(bean, value); }
這段代碼會設置bean中的屬性的值,一個真正的bean已經完成了. 再回到 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
方法中,看這句代碼:
initializeBean(beanName, exposedObject, mbd);
跟進後再進入 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods
方法:
boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { ((InitializingBean) bean).afterPropertiesSet(); return null; } }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } }
看到InitializingBean、afterPropertiesSet()是否會想起什麼呢,如果一個bean實現了InitializingBean接口後,在bean被容器加載時,自動調用afterPropertiesSet()方法,現在明白是咋回事了吧. 說了那麼多,總結下LiosServiceServiceImpl類的加載過程,首先容器會加載LiosServiceServiceImpl或者LiosTestA或者LiosTestB,默認是沒有明確順序之分,如果按照先加載LiosTestA的話,會先創建LiosTestA實例,裏面的屬性LiosTestB值還是爲空,然後設置其屬性的值,其實就是調用getBean方法,完成LiosTestA的實例創建後,創建LiosServiceServiceImpl套路完全一樣,其屬性LiosTestA已經在緩存有了,直接獲取即可. 最後,bean的加載遠遠不止這麼複雜,文中有錯誤之處,麻煩指正!