簡話bean加載

首先看示例代碼:

<!--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的加載遠遠不止這麼複雜,文中有錯誤之處,麻煩指正!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章