19-Spring源碼解析之Bean的生命週期(4)——initializeBean

Spring版本:<version>5.2.1.RELEASE</version>

上一篇:18-Spring源碼解析之Bean的生命週期(3)——【doCreateBean】和【createBeanInstance】

上一篇我們講解了doCreateBean方法來創建Bean實例,它首先調用createBeanInstance方法來實例化Bean,其次處理依賴問題,接着對該Bean進行屬性賦值(populateBean)方法,再接着對Bean進行初始化工作(initializeBean),本篇文章就看一下Spring是如何幫我們完成Bean的初始化的。

一、initializeBean

還記得在實體類中我們通過實現InitializingBean接口後需要重寫afterPropertiesSet方法嗎?這個方法的執行時機就是在Bean屬性賦值(populateBean)後調用initiali在這裏插入代碼片zeBean指定的方法來根據用戶業務進行相應的實例化。

	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 {
//-------------------------------------------------【功能一】--二、 詳細介紹----------------------------------------------		
			// 激活Aware方法
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
		
//-------------------------------------------------【功能二】--三、 詳細介紹----------------------------------------------		
			// 應用後處理器
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
//-------------------------------------------------【功能三】--四、 詳細介紹----------------------------------------------			
			// 激活用戶自定義的initMethod或者afterPropertiesSet方法
			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()) {
//-------------------------------------------------【功能四】--五、 詳細介紹----------------------------------------------		
			// 應用後處理器
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

從上面可以看出,該方法一共做了四件事情:

  • 【功能一】激活Aware方法
  • 【功能二】應用所有BeanPostProcessorpostProcessBeforeInitialization方法
  • 【功能三】調用用戶自定義的initMethod或者afterPropertiesSet方法
  • 【功能四】應用所有BeanPostProcessorpostProcessAfterInitialization方法

下面我們就來依次說一下這幾個功能是如何實現的。

二、【功能一】激活Aware方法

在分析這個功能實現的原理之前,我們需要先知道什麼是Aware以及它是幹什麼的。

Spring中提供給了一些Aware接口,比如:

在這裏插入圖片描述
而實現了對應Aware接口的Bean在實例化之後,可以獲取一些相對應的資源,比如:實現了BeanFactoryAware接口的Bean在實例化之後,Spring會給這個Bean注入BeanFactory實例,而實現了ApplicationContextAwareBean,在在實例化之後,Spring會給這個Bean注入ApplicationContextAware實例。我們首先通過示例的方式來了解一下Aware的簡單使用。

1.1 Aware的例子

1.1.1 定義普通的Bean

package com.spring.aware;

import org.springframework.stereotype.Component;

@Component
public class Hello {
    public void say() {
        System.out.println("hello");
    }
}

1.1.2 定義BeanFactoryAware的實現類

package com.spring.aware;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;

@Component
public class BeanFactoryAwareTest implements BeanFactoryAware {
    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public void testAware() {
        Hello hello = beanFactory.getBean(Hello.class);
        hello.say();
    }
}

1.1.3 配置類

@Configuration
@ComponentScan("com.spring")
public class MainConfig {

}

1.1.4 測試類

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        BeanFactoryAwareTest beanFactoryAwareTest = applicationContext.getBean(BeanFactoryAwareTest.class);
        beanFactoryAwareTest.testAware();
    }
}

1.1.5 測試結果

控制檯輸出:

hello

首先,我們要意識到一點,Spring中代表容器的beanFactory我們普通類是無法得到的,因爲他是一個內部類。如果想要得到,我們需要增加一些操作。
接着,我們分析一下上述例子,Hello類是一個普通類,通過Component註解註冊到容器中,BeanFactoryAwareTest類是實現了BeanFactoryAware接口,實現了這個接口後,我們需要實現setBeanFactory方法,而這個方法會在BeanFactoryAwareTest類在創建對應Bean的初始化之前調用,即我們1.節講到的時候調用。這樣,這個BeanFactoryAwareTest類就得到了Spring中代表容器的beanFactory,並且可以根據得到的beanFactory獲取容器中所有的Bean

1.2 invokeAwareMethods方法

現在知道了Aware的作用後,我們就可以看看initializeBean中調用invokeAwareMethods方法,這個invokeAwareMethods的具體實現了。

	private void invokeAwareMethods(final String beanName, final Object bean) {
		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);
			}
		}
	}

可以看到,實際上這個代碼很簡單,就是根據Bean的類型來將對應類型的Bean放到Bean中。

因爲剛剛1.1節的例子實現的是BeanFactoryAware接口,所以走到第三個if判斷條件的地方,然後調用setBeanFactory方法,這個setBeanFactory方法即我們1.1.2節中的代碼:

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

三、【功能二】applyBeanPostProcessorsBeforeInitialization

BeanPostProcessor大家都不陌生,這是Spring開放式架構中一個必不可少的亮點,給用戶充足的權限去更改或者擴展Spring,而除了BeanPostProcessor外還有很多其他的PostProcessor,當然大部分都是以此爲基礎,繼承自BeanPostProcessor

而且在前面BeanPostProcessor大家也有接觸過,這裏就不再詳細的介紹了,而且代碼很簡單。

	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;
	}

四、【功能三】invokeInitMethods

	protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {
			
//-------------------------------------------------【功能一】------------------------------------------------		
		// 判斷當前Bean對應的實體類是否實現了InitializingBean接口
		boolean isInitializingBean = (bean instanceof 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 {
				// 若實現InitializeBean接口,就執行afterPropertiesSet方法
				((InitializingBean) bean).afterPropertiesSet();
			}
		}
//-------------------------------------------------【功能二】------------------------------------------------
		// 判斷當前Bean對應的實體類沒有實現InitializingBean接口,但是有initMethod方法,則執行它的initMethod方法			
		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(initMethod)afterPropertiesSet都是在Bean時執行的,執行順序時afterPropertiesSet先執行, @Bean(initMethod)後執行。

五、總結

initializeBean方法主要包含以下四個功能

  • 【功能一】激活Aware方法
  • 【功能二】應用所有BeanPostProcessorpostProcessBeforeInitialization方法
  • 【功能三】調用用戶自定義的initMethod或者afterPropertiesSet方法
  • 【功能四】應用所有BeanPostProcessorpostProcessAfterInitialization方法

到本篇結束,Bean的生命週期就剩下DisposableBean沒有講解了。DisposableBean是提供了銷燬方法的擴展入口。這個方法很簡單,在以後會添加到之前的文章中。

下一篇講解Spring的一個非常重要的功能!依賴注入!在註解驅動中,就是與@Autowired註解有關的知識。

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