接上文 啃啃老菜: Spring IOC核心源碼學(xué)習(xí)(一) ,本文將以 ClassPathXmlApplicationContext 這個容器的實現(xiàn)作為基礎(chǔ),學(xué)習(xí)容器的初始化過程。
ClassPathXmlApplicationContext 類體系結(jié)構(gòu)
以下是 ClassPathXmlApplicationContext 的類繼承體系結(jié)構(gòu),理解這個結(jié)構(gòu)有助于后面的代碼理解。
左邊黃色部分是 ApplicationContext 體系繼承結(jié)構(gòu),右邊是 BeanFactory 的結(jié)構(gòu)體系,兩個結(jié)構(gòu)是典型模板方法設(shè)計模式的使用。
從該繼承體系可以看出:
1. BeanFactory 是一個 bean 工廠的最基本定義,里面包含了一個 bean 工廠的幾個最基本的方法,getBean(…) 、 containsBean(…) 等 ,是一個很純粹的bean工廠,不關(guān)注資源、資源位置、事件等。ApplicationContext 是一個容器的最基本接口定義,它繼承了 BeanFactory, 擁有工廠的基本方法。同時繼承了ApplicationEventPublisher 、 MessageSource 、 ResourcePatternResolver 等接口,使其 定義了一些額外的功能,如資源、事件等這些額外的功能。
2. AbstractBeanFactory 和 AbstractAutowireCapableBeanFactory 是兩個模板抽象工廠類。AbstractBeanFactory 提供了 bean 工廠的抽象基類,同時提供了 ConfigurableBeanFactory 的完整實現(xiàn)。AbstractAutowireCapableBeanFactory 是繼承了 AbstractBeanFactory 的抽象工廠,里面提供了 bean 創(chuàng)建的支持,包括 bean 的創(chuàng)建、依賴注入、檢查等等功能,是一個核心的 bean 工廠基類。
3. ClassPathXmlApplicationContext之 所以擁有 bean 工廠的功能是通過持有一個真正的 bean 工廠DefaultListableBeanFactory 的實例,并通過 代理 該工廠完成。
4. ClassPathXmlApplicationContext 的初始化過程是對本身容器的初始化同時也是對其持有的DefaultListableBeanFactory 的初始化。
下面通過源碼著重介紹一個容器的初始化過程,并重點理解 bean 的創(chuàng)建過程。
容器初始化過程
通過上文 啃啃老菜: Spring IOC核心源碼學(xué)習(xí)(一) 已經(jīng)可以了解一個容器的大概過程是:
整個過程可以理解為是容器的初始化過程。第一個過程是 ApplicationContext 的職責(zé)范圍,第二步是 BeanFactory的職責(zé)范圍。可以看出 ApplicationContext 是一個運行時的容器需要提供不容資源環(huán)境的支持,屏蔽不同環(huán)境的差異化。而 BeanDifinition 是內(nèi)部關(guān)于 bean 定義的基本結(jié)構(gòu)。 Bean 的創(chuàng)建就是基于它,回頭會介紹一下改結(jié)構(gòu)的定義。下面看一下整個容器的初始化過程。
容器的初始化是通過調(diào)用 refresh() 來實現(xiàn)。該方法是非常重要的一個方法,定義在 AbstractApplicationContext接口里。 AbstractApplicationContext 是容器的最基礎(chǔ)的一個抽象父類。也就是說在該里面定義了一個容器初始化的基本流程,流程里的各個方法有些有提供了具體實現(xiàn),有些是抽象的 ( 因為不同的容器實例不一樣 ) ,由繼承它的每一個具體容器完成定制。看看 refresh 的基本流程:
- public void refresh() throws BeansException, IllegalStateException {
- synchronized (this.startupShutdownMonitor) {
- // Prepare this context for refreshing.
- prepareRefresh();
- // Tell the subclass to refresh the internal bean factory.
- ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
- // Prepare the bean factory for use in this context.
- prepareBeanFactory(beanFactory);
- try {
- // Allows post-processing of the bean factory in context subclasses.
- postProcessBeanFactory(beanFactory);
- // Invoke factory processors registered as beans in the context.
- invokeBeanFactoryPostProcessors(beanFactory);
- // Register bean processors that intercept bean creation.
- registerBeanPostProcessors(beanFactory);
- // Initialize message source for this context.
- initMessageSource();
- // Initialize event multicaster for this context.
- initApplicationEventMulticaster();
- // Initialize other special beans in specific context subclasses.
- onRefresh();
- // Check for listener beans and register them.
- registerListeners();
- // Instantiate all remaining (non-lazy-init) singletons.
- finishBeanFactoryInitialization(beanFactory);
- // Last step: publish corresponding event.
- finishRefresh();
- }
- catch (BeansException ex) {
- // Destroy already created singletons to avoid dangling resources.
- beanFactory.destroySingletons();
- // Reset 'active' flag.
- cancelRefresh(ex);
- // Propagate exception to caller.
- throw ex;
- }
- }
- }
解釋如下:
Bean 的創(chuàng)建過程
Bean的創(chuàng)建過程基本是BeanFactory所要完成的事情.
根據(jù)以上過程,將會重點帶著以下兩個個問題來理解核心代碼:
1.Bean 的創(chuàng)建時機(jī)
bean 是在什么時候被創(chuàng)建的,有哪些規(guī)則。
2.Bean 的創(chuàng)建過程
bean 是怎么創(chuàng)建的,會選擇哪個構(gòu)造函數(shù)?依賴如何注入? InitializingBean 的 set 方法什么時候被調(diào)用?實現(xiàn)ApplicationContextAware, BeanFactoryAware,BeanNameAware, ResourceLoaderAware 這些接口的 bean 的set 方法何時被調(diào)用?
在解釋這兩個問題前,先看一下 BeanDefinition 接口的定義。
從該接口定義可以看出,通過 bean 定義能夠得到 bean 的詳細(xì)信息,如類名子、工廠類名稱、 scope 、是否單例、是否抽象、是否延遲加載等等。基于此,來看一下以下兩個問題:
問題 1 : Bean 的創(chuàng)建時機(jī)
bean 是在什么時候被創(chuàng)建的,有哪些規(guī)則?
容器初始化的時候會預(yù)先對單例和非延遲加載的對象進(jìn)行預(yù)先初始化。其他的都是延遲加載是在第一次調(diào)用getBean 的時候被創(chuàng)建。從 DefaultListableBeanFactory 的 preInstantiateSingletons 里可以看到這個規(guī)則的實現(xiàn)。
- public void preInstantiateSingletons() throws BeansException {
- if (this.logger.isInfoEnabled()) {
- this.logger.info("Pre-instantiating singletons in " + this);
- }
- synchronized (this.beanDefinitionMap) {
- for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
- String beanName = (String) it.next();
- RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
- <span style="color: #ff0000;">if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {</span>
- //對非抽象、單例的和非延遲加載的對象進(jìn)行實例化。
- if (isFactoryBean(beanName)) {
- FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
- if (factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit()) {
- getBean(beanName);
- }
- }
- else {
- getBean(beanName);
- }
- }
- }
- }
- }
從上面來看對于以下配置,只有 singletonBean 會被預(yù)先創(chuàng)建。
- <?xml version="1.0" encoding="GB2312"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
- <beans default-autowire="byName">
- <bean id="otherBean" class="com.test.OtherBean" scope="prototype"/>
- <bean id="myBean" class="com.test.MyBean" lazy-init="true"/>
- <bean id="singletonBean" class="com.test.SingletonBean"/>
- </beans>
問題二:Bean 的創(chuàng)建過程
對于 bean 的創(chuàng)建過程其實都是通過調(diào)用工廠的 getBean 方法來完成的。這里面將會完成對構(gòu)造函數(shù)的選擇、依賴注入等。
無論預(yù)先創(chuàng)建還是延遲加載都是調(diào)用getBean實現(xiàn),AbstractBeanFactory 定義了 getBean 的過程:
- protected Object doGetBean(
- final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
- final String beanName = transformedBeanName(name);
- Object bean = null;
- // Eagerly check singleton cache for manually registered singletons.
- 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 + "'");
- }
- }
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
- }
- else {
- // Fail if we're already creating this bean instance:
- // We're assumably within a circular reference.
- if (isPrototypeCurrentlyInCreation(beanName)) {
- throw new BeanCurrentlyInCreationException(beanName);
- }
- // Check if bean definition exists in this factory.
- BeanFactory parentBeanFactory = getParentBeanFactory();
- if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
- // Not found -> check parent.
- String nameToLookup = originalBeanName(name);
- if (args != null) {
- // Delegation to parent with explicit args.
- return parentBeanFactory.getBean(nameToLookup, args);
- }
- else {
- // No args -> delegate to standard getBean method.
- return parentBeanFactory.getBean(nameToLookup, requiredType);
- }
- }
- if (!typeCheckOnly) {
- markBeanAsCreated(beanName);
- }
- final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
- checkMergedBeanDefinition(mbd, beanName, args);
- // Guarantee initialization of beans that the current bean depends on.
- String[] dependsOn = mbd.getDependsOn();
- if (dependsOn != null) {
- for (int i = 0; i < dependsOn.length; i++) {
- String dependsOnBean = dependsOn[i];
- getBean(dependsOnBean);
- registerDependentBean(dependsOnBean, beanName);
- }
- }
- // Create bean instance.
- <span style="color: #ff0000;">if (mbd.isSingleton()) {//單例對象創(chuàng)建過程,間接通過getSingleton方法來創(chuàng)建,里面會實現(xiàn)將單例對象緩存</span>
- sharedInstance = getSingleton(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- 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);
- }
- <span style="color: #ff0000;">else if (mbd.isPrototype()) {//非單例對象創(chuàng)建</span>
- // It's a prototype -> create a new instance.
- Object prototypeInstance = null;
- try {
- beforePrototypeCreation(beanName);
- prototypeInstance = createBean(beanName, mbd, args);<span style="color: #ff0000;">//直接調(diào)用createBean</span>
- }
- finally {
- afterPrototypeCreation(beanName);
- }
- bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
- }
- else {
- String scopeName = mbd.getScope();
- final Scope scope = (Scope) this.scopes.get(scopeName);
- if (scope == null) {
- throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
- }
- try {
- Object scopedInstance = scope.get(beanName, new ObjectFactory() {
- 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);
- }
- }
- }
- // Check if required type matches the type of the actual bean instance.
- if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
- throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
- }
- return bean;
- }
GetBean 的大概過程:
1. 先試著從單例緩存對象里獲取。
2. 從父容器里取定義,有則由父容器創(chuàng)建。
3. 如果是單例,則走單例對象的創(chuàng)建過程:在 spring 容器里單例對象和非單例對象的創(chuàng)建過程是一樣的。都會調(diào)用父類 AbstractAutowireCapableBeanFactory 的 createBean 方法。 不同的是單例對象只創(chuàng)建一次并且需要緩存起來。 DefaultListableBeanFactory 的父類 DefaultSingletonBeanRegistry 提供了對單例對象緩存等支持工作。所以是單例對象的話會調(diào)用 DefaultSingletonBeanRegistry 的 getSingleton 方法,它會間接調(diào)用AbstractAutowireCapableBeanFactory 的 createBean 方法。
如果是 Prototype 多例則直接調(diào)用父類 AbstractAutowireCapableBeanFactory 的 createBean 方法。
bean的創(chuàng)建是由AbstractAutowireCapableBeanFactory來定義:
- protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
- throws BeanCreationException {
- AccessControlContext acc = AccessController.getContext();
- return AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- if (logger.isDebugEnabled()) {
- logger.debug("Creating instance of bean '" + beanName + "'");
- }
- // Make sure bean class is actually resolved at this point.
- resolveBeanClass(mbd, beanName);
- // Prepare method overrides.
- try {
- mbd.prepareMethodOverrides();
- }
- catch (BeanDefinitionValidationException ex) {
- throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
- beanName, "Validation of method overrides failed", ex);
- }
- try {
- // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
- Object bean = resolveBeforeInstantiation(beanName, mbd);
- if (bean != null) {
- return bean;
- }
- }
- catch (Throwable ex) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "BeanPostProcessor before instantiation of bean failed", ex);
- }
- Object beanInstance = doCreateBean(beanName, mbd, args);
- if (logger.isDebugEnabled()) {
- logger.debug("Finished creating instance of bean '" + beanName + "'");
- }
- return beanInstance;
- }
- }, acc);
- }
createBean 會調(diào)用 doCreateBean 方法:
- protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
- // Instantiate the bean.
- BeanWrapper instanceWrapper = null;
- if (mbd.isSingleton()) {
- instanceWrapper = (BeanWrapper) this.factoryBeanInstanceCache.remove(beanName);
- }
- if (instanceWrapper == null) {
- instanceWrapper = createBeanInstance(beanName, mbd, args);
- }
- final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
- Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
- // Allow post-processors to modify the merged bean definition.
- synchronized (mbd.postProcessingLock) {
- if (!mbd.postProcessed) {
- applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
- 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.isDebugEnabled()) {
- logger.debug("Eagerly caching bean '" + beanName +
- "' to allow for resolving potential circular references");
- }
- addSingletonFactory(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- return getEarlyBeanReference(beanName, mbd, bean);
- }
- });
- }
- // Initialize the bean instance.
- Object exposedObject = bean;
- try {
- populateBean(beanName, mbd, instanceWrapper);
- 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 actualDependentBeans = new LinkedHashSet(dependentBeans.length);
- for (int i = 0; i < dependentBeans.length; i++) {
- String dependentBean = dependentBeans[i];
- 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.");
- }
- }
- }
- }
- // Register bean as disposable.
- registerDisposableBeanIfNecessary(beanName, bean, mbd);
- return exposedObject;
- }
doCreateBean 的流程:
1. 會創(chuàng)建一個 BeanWrapper 對象 用于存放實例化對象。
2. 如果沒有指定構(gòu)造函數(shù),會通過反射拿到一個默認(rèn)的構(gòu)造函數(shù)對象,并賦予beanDefinition.resolvedConstructorOrFactoryMethod 。
3. 調(diào)用 spring 的 BeanUtils 的 instantiateClass 方法,通過反射創(chuàng)建對象。
4. applyMergedBeanDefinitionPostProcessors
5. populateBean(beanName, mbd, instanceWrapper); 根據(jù)注入方式進(jìn)行注入。根據(jù)是否有依賴檢查進(jìn)行依賴檢查。
執(zhí)行 bean 的注入里面會選擇注入類型:
- if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
- mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
- MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
- // Add property values based on autowire by name if applicable.
- if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
- autowireByName(beanName, mbd, bw, newPvs);
- }<span style="color: #ff0000;">//根據(jù)名字注入</span>
- // Add property values based on autowire by type if applicable.
- if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
- autowireByType(beanName, mbd, bw, newPvs);
- }<span style="color: #ff0000;">//根據(jù)類型注入</span>
- pvs = newPvs;
- }
6. initializeBean(beanName, exposedObject, mbd);
判斷是否實現(xiàn)了 BeanNameAware 、 BeanClassLoaderAware 等 spring 提供的接口,如果實現(xiàn)了,進(jìn)行默認(rèn)的注入。同時判斷是否實現(xiàn)了 InitializingBean 接口,如果是的話,調(diào)用 afterPropertySet 方法。
- protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
- if (bean instanceof BeanNameAware) {
- ((BeanNameAware) bean).setBeanName(beanName);
- }
- if (bean instanceof BeanClassLoaderAware) {
- ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
- }
- if (bean instanceof BeanFactoryAware) {
- ((BeanFactoryAware) bean).setBeanFactory(this);
- }
- Object wrappedBean = bean;
- if (mbd == null || !mbd.isSynthetic()) {
- wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
- }
- <span style="color: #ff0000;"> try {
- invokeInitMethods(beanName, wrappedBean, mbd);
- }</span>
- catch (Throwable ex) {
- throw new BeanCreationException(
- (mbd != null ? mbd.getResourceDescription() : null),
- beanName, "Invocation of init method failed", ex);
- }
- if (mbd == null || !mbd.isSynthetic()) {
- wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
- }
- return wrappedBean;
- }
其中invokeInitMethods實現(xiàn)如下:
- protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd)
- throws Throwable {
- boolean isInitializingBean = (bean instanceof InitializingBean);
- if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
- if (logger.isDebugEnabled()) {
- logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
- }
- ((InitializingBean) bean).afterPropertiesSet();<span style="color: #ff0000;">//調(diào)用afterPropertiesSet方法</span>
- }
- String initMethodName = (mbd != null ? mbd.getInitMethodName() : null);
- if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
- !mbd.isExternallyManagedInitMethod(initMethodName)) {
- invokeCustomInitMethod(beanName, bean, initMethodName, mbd.isEnforceInitMethod());
- }
- }
總結(jié)
以上基本描述了 spring 容器的初始化過程和 bean 的創(chuàng)建過程。主要還是從大處著眼,很多細(xì)節(jié)沒有涉及到。代碼閱讀總體感覺就是 spring 的代碼抽象很好,結(jié)合結(jié)構(gòu)讀起來還是蠻順利的。后面的學(xué)習(xí)將從細(xì)節(jié)著手。
下面源碼學(xué)習(xí)預(yù)告:
1. Spring 的聲明式標(biāo)簽如實現(xiàn)
2. Spring aop 代理如何實現(xiàn)