最近讀完《Spring技術內幕》一書,雖然此書評價貌似不高,但邊看書邊讀源碼,感覺還是有點收穫,至少爲閱讀Spring源碼提供了思路。然後這篇文章就記錄一下這幾天看Spring IOC這塊的源碼以及整體思路。
1、 BeanFactory與ApplicationContext
在Spring的IOC容器設計中,主要由兩個容器系列:
- 實現BeanFactory接口的簡單容器,提供了完整IoC容器服務支持,默認延遲初始化(lazy-load)——只有訪問託管對象的時候,纔會對對象進行初始化和依賴注入操作。
- 實現ApplicationContext接口的集成容器,在BeanFactory的基礎上增加了更多複雜的企業級功能,容器啓動時,就默認把所有的單例對象實例化完成。
2、 最簡單的容器StaticListableBeanFactory
整個Spring容器中最簡單的實現就是StaticListableBeanFactory,從它開始分析最合適不過了。
public class StaticListableBeanFactory implements ListableBeanFactory {
/** <BeanName, BeanInstance>的映射 */
private final Map<String, Object> beans;
// 默認構造會創建一個空的Map,自行調用addBean方法添加到容器中
public StaticListableBeanFactory() {
this.beans = new LinkedHashMap<String, Object>();
}
// 由外部預初始化一個Map
public StaticListableBeanFactory(Map<String, Object> beans) {
Assert.notNull(beans, "Beans Map must not be null");
this.beans = beans;
}
// addBean就是簡單的將name和instance加入到Map中
public void addBean(String name, Object bean) {
this.beans.put(name, bean);
}
// 根據beanName從容器中獲取Bean對象
@Override
public Object getBean(String name) throws BeansException {
// 處理"&"開頭的BeanName(dereference解引用)
String beanName = BeanFactoryUtils.transformedBeanName(name);
Object bean = this.beans.get(beanName);
if (bean == null) {
// Bean不存在
throw new NoSuchBeanDefinitionException(beanName,
"Defined beans are [" + StringUtils.collectionToCommaDelimitedString(this.beans.keySet()) + "]");
}
if (BeanFactoryUtils.isFactoryDereference(name) && !(bean instanceof FactoryBean)) {
// BeanName以"&"開頭,但Bean不是FactoryBean
throw new BeanIsNotAFactoryException(beanName, bean.getClass());
}
if (bean instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
// Bean是FactoryBean,但BeanName不是"&"開頭,則由FactoryBean創建Bean對象
try {
return ((FactoryBean<?>) bean).getObject();
}
catch (Exception ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
}
else {
// 其他情況直接返回Bean
return bean;
}
}
// 其餘getBean方法(byName,byType)最終都是調用上面的getBean方法
...
// 判斷bean是否爲共享單例,也就是說調用getBean方法會始終返回同一個對象
// 注意:返回false,不一定說明是prototype的Bean,應該調isPrototype去顯示檢查是否是原型對象
@Override
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
Object bean = getBean(name);
return (bean instanceof FactoryBean && ((FactoryBean<?>) bean).isSingleton());
}
// 判斷bean是否爲原型實例,也就是說調用getBean方法會始終返回一個獨立的新實例
// 注意:返回false,不應定說明是singleton的Bean,應該調isSingleton去顯示檢查是否是單例對象
@Override
public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
Object bean = getBean(name);
return ((bean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) bean).isPrototype()) ||
(bean instanceof FactoryBean && !((FactoryBean<?>) bean).isSingleton()));
}
// 獲取Bean的類型
@Override
public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
String beanName = BeanFactoryUtils.transformedBeanName(name);
Object bean = this.beans.get(beanName);
if (bean == null) {
throw new NoSuchBeanDefinitionException(beanName,
"Defined beans are [" + StringUtils.collectionToCommaDelimitedString(this.beans.keySet()) + "]");
}
if (bean instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
// 如果是FactoryBean, 去看Factory創建的是什麼類型的Bean.
return ((FactoryBean<?>) bean).getObjectType();
}
return bean.getClass();
}
...
}
3、 特殊的Bean對象——FactoryBean
Spring容器中有兩種Bean:普通Bean和工廠Bean。Spring直接使用前者,後者以工廠模式生產Bean對象,並由Spring管理。
Spring設計FactoryBean的目的是爲了將複雜對象的相關構造邏輯封裝在類中,比如常見的ProxyFactoryBean。
另外一個目的是爲了讓我們能將依賴注入到一些第三方庫的對象中,比如LocalContainerEntityManagerFactoryBean
負責JPA的EntityManagerFactory
的創建,ThreadPoolExecutorFactoryBean
負責線程池的創建,ForkJoinPoolFactoryBean
負責ForkJoinPool線程池的創建,ScheduledExecutorFactoryBean
負責調度線程池的創建…
但是Spring3.0基於Java註解的配置開始流行之後,這些FactoryBean基本都用不到了,這些對象我們可以通過@Bean方法的形式配置。
我個人大膽的猜測,FactoryBean是爲了早期以XML配置對象的方式而設計的。
通過在BeanName前加上&
前綴我們能拿到FactoryBean工廠本身。比如:
public class MyBeanFactoryBean implements FactoryBean<MyBean> {
public MyBean getObject() throws Exception {
return new MyBean();
}
public Class<?> getObjectType() {
return MyBean.class;
}
}
// 直接通過beanName獲取的是工廠創建的MyBean對象
beanFactory.getBean("myBean");
// 加&前綴獲取的是MyBeanFactoryBean這個工廠本身
beanFactory.getBean("&myBean");
經常被問的一個問題是BeanFactory與FactoryBean的區別,用一句話總結起來:
BeanFactory代表Spring容器,而FactoryBean表示工廠類,其創建的對象被獲取後作爲容器中的Bean註冊。
4、 核心容器DefaultListableBeanFactory
Spring IOC體系結構中最核心的容器實現類就是DefaultListableBeanFactory,它實現了ConfigurableListableBeanFactory和BeanDefinitionRegistry兩個接口的功能。
4.1 、BeanDefinition、BeanDefinitionRegistry、BeanDefinitionReader
BeanDefinition用於描述一個Bean實例的scope、是否爲懶加載、生命週期方法(init、destroy)、屬性值、構造參數值以及組件依賴等信息。
BeanDefinitionRegistry就是BeanDefinition的註冊表,提供了registerBeanDefinition(beanName, beanDefinition)
和removeBeanDefinition(beanName)
等相關方法。
BeanDefinitionReader負責從Properties、Xml、Groovy等配置文件中讀取BeanDefinition,並將其註冊到BeanDefinitionRegistry中。
4.2、基於Java註解的配置
Spring3.0之前只支持@Component、@Controller、@Service、@Repository這幾個組件級的註解。
Spring3.0開始支持Java註解配置Bean對象,也就是通過@Configuration配置類中方法上的@Bean註解來定義Bean對象。
其中Bean被加入到Spring容器有兩種方式:
1、register()方法直接以組件類的方式註冊AnnotatedGenericBeanDefinition到容器中,具體實現在AnnotatedBeanDefinitionReader
中;
2、scan()方法通過掃描包下的所有組件類以批量的方式註冊若干個ScannedGenericBeanDefinition到容器中,具體實現在ClassPathBeanDefinitionScanner
中;
如果註冊的是@Configuration註解的類,則在ConfigurationClassPostProcessor處理器中將所有@Bean註解方法的Bean註冊到容器中,這部分內容後面會講BeanFactoryPostProcessor的時候再詳細解析。
5、可配置的ConfigurableListableBeanFactory
ConfigurableListableBeanFactory結合了ListableBeanFactory、AutowireCapableBeanFactory、ConfigurableBeanFactory三個接口的功能。這三個接口也分別代表了Spring容器提供的三大基本功能:
ListableBeanFactory:根據類型或註解查找Bean
AutowireCapableBeanFactory:解析Bean的依賴關係並進行自動裝配
ConfigurableBeanFactory:爲容器提供了配置接口,以拓展容器的功能
我們想要拓展Spring IOC容器的功能主要就是通過ConfigurableBeanFactory開出的幾個接口實現的:
5.1、BeanExpressionResolver
ConfigurableBeanFactory有兩個關於Spring EL表達式的方法:
void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver);
BeanExpressionResolver getBeanExpressionResolver();
在Spring中BeanExpressionResolver的實現是StandardBeanExpressionResolver
public class StandardBeanExpressionResolver implements BeanExpressionResolver {
/// ...
/** 該方法用於解析Spring EL表達式 **/
public Object evaluate(@Nullable String value, BeanExpressionContext evalContext) throws BeansException {
if (!StringUtils.hasLength(value)) {
return value;
}
try {
Expression expr = this.expressionCache.get(value);
if (expr == null) {
expr = this.expressionParser.parseExpression(value, this.beanExpressionParserContext);
this.expressionCache.put(value, expr);
}
StandardEvaluationContext sec = this.evaluationCache.get(evalContext);
if (sec == null) {
sec = new StandardEvaluationContext(evalContext);
///...做了一堆的配置
customizeEvaluationContext(sec);
this.evaluationCache.put(evalContext, sec);
}
return expr.getValue(sec);
}
catch (Throwable ex) {
throw new BeanExpressionException("Expression parsing failed", ex);
}
}
// StandardBeanExpressionResolver提供了一個方法允許我們進行重載
protected void customizeEvaluationContext(StandardEvaluationContext evalContext) {
}
}
StandardBeanExpressionResolver提供了一個customizeEvaluationContext
方法允許我們重載,我們唯一能做的就是對StandardEvaluationContext進行一些自定義配置。
5.2、Scope
Spring容器爲我們提供了SCOPE_SINGLETON
和SCOPE_PROTOTYPE
兩種基本的Scope,它還允許我們註冊自己的Scope。比如Web應用中會用到的request
和session
兩個Scope,另外Spring還提供了很多基礎的Scope給我們,如線程級別SimpleThreadScope
、事務級別的SimpleTransactionScope
。
通常我們往容器中註冊Scope只需調用beanFactory.registerScope
方法即可,另外Spring提供了一個BeanFactoryPostProcessor給我們——CustomScopeConfigurer。
關於BeanFactoryPostProcessor後面有一部分會介紹。
5.3、ConversionService
ConversionService,顧名思義,就是Spring提供給我們的類型轉換服務。它主要有幾種用途,解析配置文件中字符串,解析BeanDefinition中的property並綁定到對象中(DataBinder),解析Web應用中的請求參數並綁定到Controller的入參對象中(WebDataBinder),解析Spring EL表達式中的字面量。
除了ConversionService,ConfigurableBeanFactory還提供了PropertyEditorRegistrar、 TypeConverter、 StringValueResolver等接口用於處理Bean對象和類型轉換。
關於Spring Converter的內容可以參考這幾篇教程:
https://www.baeldung.com/spring-type-conversions
https://www.baeldung.com/spring-mvc-custom-data-binder
https://www.baeldung.com/spring-mvc-custom-property-editor
5.4、BeanPostProcessor
這個接口是用於擴展Spring功能的核心接口,事實上Spring容器本身的很多功能特性就是通過這個接口豐富的。
BeanPostProcessor有兩個方法:
public interface BeanPostProcessor {
// 初始化方法之前調用
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
// 初始化方法之後調用
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
很明顯我們只要找到SpringBean什麼時候初始化,就知道這兩個方法什麼時候被調用,Spring Bean的初始化分爲四步:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
/// ...
/// 這裏是整個初始化過程的代碼
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 第一步:調用Aware方法
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
// 第二步:調用BeanPostProcessor的postProcessBeforeInitialization方法
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 第三步:調用初始化方法
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
// 第四步:調用BeanPostProcessor的postProcessAfterInitialization方法
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
///...
}
- 第一步:調用Aware方法
private void invokeAwareMethods(final String beanName, final Object bean) {
/// 如果bean對象實現了相應的Aware接口,那這裏會調用三種Aware方法:
/// BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
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);
}
}
}
- 第二步:調用BeanPostProcessor.postProcessBeforeInitialization方法
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
/// 這個很簡單:就是拿到BeanFactory裏的所有BeanPostProcessor
/// 然後依次調用postProcessBeforeInitialization方法
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
- 第三步:調用bean對象的init方法
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
/// 先看有沒有實現Spring定義的InitializingBean接口
/// 如果有的話就調用InitializingBean的afterPropertiesSet方法
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 {
((InitializingBean) bean).afterPropertiesSet();
}
}
/// 然後調用自定義的init方法
/// 這個init方法是xml或@Bean註解配置的init-method屬性
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);
}
}
}
這裏也許會有人想到使用JSR-250規範中定義的@PostConstruct註解進行初始化。
Spring提供了CommonAnnotationBeanPostProcessor和InitDestroyAnnotationBeanPostProcessor來處理JavaEE標準中的註解,如@PostConstruct、@PreDestroy、@Resource。
在InitDestroyAnnotationBeanPostProcessor中可以看到它是通過實現BeanPostProcessor#postProcessBeforeInitialization方法並在其中調用Bean的@PostConstruct註解方法的:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
/// 這裏的initMethod就是通過@PostConstruct註解解析出來的方法
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
所以關於初始化方法的調用順序是:
@PostConstruct==>InitializingBean.afterPropertiesSet==>Xml或@Bean中定義的init-method
而且Bean中@PostConstruct方法可以定義多個,但InitializingBean因爲是接口所以afterPropertiesSet只有一個方法,init-method也只能有一個。
關於Spring初始化的過程可以參考這篇教程
-
第四步:調用BeanPostProcessor.postProcessAfterInitialization方法
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { /// 這個很簡單:就是拿到BeanFactory裏的所有BeanPostProcessor /// 然後依次調用postProcessBeforeInitialization方法 Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
用一張圖總結一下:
5.5、BeanPostProceesor的常見實現
Spring內部實現各種Aware的ApplicationContextAwareProcessor;
Web應用中裝配ServletContext的ServletContextAwareProcessor;
類加載時編織AspectJ切面的LoadTimeWeaver被LoadTimeWeaverAwareProcessor裝配;
關於加載時編織參考Spring官方文檔和AspectJ官方文檔
另外還有幾個基於AOP實現的BeanPostProceesor,最常用的就是@Async註解實現異步方法,而這個就是AsyncAnnotationBeanPostProcessor處理器實現的。
關於Spring異步方法的使用可以參考這篇教程
5.6、BeanPostProcessor的子接口
BeanPostProcessor有三個字接口:
1、InstantiationAwareBeanPostProcessor:添加了實例化對象的回調方法,以及屬性值被自動裝配時的回調;
2、DestructionAwareBeanPostProcessor:添加了銷燬對象前的回調方法;
3、MergedBeanDefinitionPostProcessor:合併BeanDefinition後調用;
既然InstantiationAwareBeanPostProcessor是實例化和屬性自動裝配的回調,讓我們看一下這塊代碼:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
///...
// Spring創建Bean對象的整個過程
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
/// 解析並加載BeanDefinition中定義的Class
/// ... 代碼省略
/// ...省略異常處理代碼
// 第一步:
// 調用InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
// Processor的方法可能返回一個代理對象,
// 比如Spring AOP的自動代理(@EnableAspectJAutoProxy)。
// 這種情況比較少,可以不考慮
return bean;
}
/// ...省略異常處理代碼
/// 根據BeanDefinition創建對象
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
/// 調用內部的創建方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 第二步: 實例化Bean對象
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 調用MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition
// 讓Processor對BeanDefinition最後再進行一些處理
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
/// ...省略異常處理代碼
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
// 將Bean對象緩存起來以解決循環引用的問題
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
/// ...省略異常處理代碼
// 填充Bean的屬性
populateBean(beanName, mbd, instanceWrapper);
// 初始化Bean對象
exposedObject = initializeBean(beanName, exposedObject, mbd);
///...
/// ...省略異常處理代碼
// 註冊Disposable接口和DestructionAwareBeanPostProcessor的DisposableBeanAdapter
registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
///...
// 調用InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation方法
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 自動裝配對象
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 根據名稱自動裝配
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 根據類型自動裝配
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
/// 調用InstantiationAwareBeanPostProcessor.postProcessPropertyValues
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
if (pvs != null) {
// 將依賴的Bean對象注入到新創建的Bean中
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
///...
}
至此,創建Bean的整個過程可以總結爲下圖:
6. 功能更強大的容器——ApplicationContext
ApplicationContext在BeanFactory容器的基礎上繼承了另外四個接口:
-
EnvironmentCapable接口:暴露了應用當前的環境配置信息的Environment接口。Environment提供了profiles和properties兩方面的配置信息:
profiles指的是一組Bean的集合,這些Bean可以在xml中配置profile或着使用@Profile註解。Environment對於Profile來說,就是用於決定當前哪個profile被激活了,那個profile應該默認被激活。
Spring Profile的相關內容可以參考這篇教程
properties在應用中扮演着重要角色,主要來源形式有:properties文件、JVM系統參數、系統環境變量、JDNI、Servlet容器參數等。
-
MessageSource接口:提供了消息的參數化與國際化,避免了開發人員編寫大量額外的代碼處理各種複雜的情況。
在SpringBoot中使用MessageSource處理校驗報錯信息,可以參考這篇教程
-
ApplicationEventPublisher接口:爲Spring容器提供了事件發佈功能。ApplicationContext容器通過代理ApplicationEventMulticaster實現事件發佈功能(具體可以參看AbstractApplicationContext的相關代碼)。Spring容器本身也會發布各種事件,如ContextRefreshedEvent,ContextStartedEvent,RequestHandledEvent等。
-
ResourcePatternResolver接口:提供瞭解析資源路徑的功能。如
/WEB-INF/*-context.xml
、classpath*:context.xml
這樣的路徑。
其次就是中間過渡的ConfigurableApplicationContext接口:
ConfigurableApplicationContext在ApplicationContext的基礎上提供了一些配置接口,和ConfigurableBeanFactory類似,ConfigurableApplicationContext將配置和生命週期方法封裝在此主要是爲了避免對客戶端代碼可見,ConfigurableApplicationContext接口的方法應該只在應用啓動和關閉的時候調用。這裏面有這麼幾個方法比較重要:
// 啓動容器加載配置並實例化所有的單例Bean
// 所有ApplicationContext容器必須refresh()了才能使用
void refresh();
// 關閉容器釋放所有相關資源,包括銷燬所有緩存的單例Bean
void close();
6.1、AbstractApplicationContext
先讓我們看一下refresh()方法。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 準備ApplicationContext以進行refresh
prepareRefresh();
// 通知子類去刷新內部的BeanFactory
// AbstractApplicationContext提供了三個抽象方法由子類去實現:
// void refreshBeanFactory()
// void closeBeanFactory()
// ConfigurableListableBeanFactory getBeanFactory()
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 對這個BeanFactory進行配置
prepareBeanFactory(beanFactory);
try {
// 讓子類再對BeanFactory進行相應的配置
postProcessBeanFactory(beanFactory);
// 調用BeanFactoryPostProcessor
// 並找到beanFactory容器中實現了BeanFactoryPostProcessor接口的bean,一起調用
// 主要這個這個接口和BeanPostProcessor有所區別
invokeBeanFactoryPostProcessors(beanFactory);
// 找出beanFactory中實現了BeanPostProcessor的Bean
// 並將它們以BeanPostProcessor的角色註冊到beanFactory中
registerBeanPostProcessors(beanFactory);
// 初始化用於i18n的MessageSource
initMessageSource();
// 初始化用於事件分發的ApplicationEventMulticaster
initApplicationEventMulticaster();
// 讓子類做一些其他的初始化,比如web應用中要初始化ThemeSource
onRefresh();
// 找到容器中所有的ApplicationListener並將其註冊到ApplicationEventMulticaster中
registerListeners();
// 對BeanFactory進行最後的初始化,然後凍結配置,預初始化所有的單例對象
finishBeanFactoryInitialization(beanFactory);
// 最後一步:完成最後的刷新工作併發布ContextRefreshedEvent事件
finishRefresh();
}
///...
}
}
AbstractApplicationContext提供了很多模版方法給子類去實現,接下來我們看一下最主要的兩個子類。
6.2、GenericApplicationContext與AbstractRefreshableApplicationContext
GenericApplicationContext和RefreshableApplicationContext兩個體系內的容器實現本質上都是代理了DefaultListableBeanFactory提供的功能。
兩者的區別在於GenericApplicationContext只能refresh()一次,而RefreshableApplicationContext允許refresh()多次。
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
private final DefaultListableBeanFactory beanFactory;
/// ...
public GenericApplicationContext() {
// 在構造的時候就創建了beanFactory
// 之後的refresh()等操作都是對這個beanFactory進行操作
this.beanFactory = new DefaultListableBeanFactory();
}
///...
}
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
///...
@Nullable
private DefaultListableBeanFactory beanFactory;
public AbstractRefreshableApplicationContext() {
}
// 實現AbstractApplicationContext提供的模版方法
// 每次refresh()都會重新創建新的BeanFactory
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
// 銷燬已有的容器
destroyBeans();
closeBeanFactory();
}
try {
// 創建新的容器
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
///...
}
6.3、BeanFactoryPostProcessor
不要將BeanFactoryPostProcessor和前面的BeanPostProcessor搞混,這個接口是BeanFactory初始化後的回調接口。
BeanFactoryPostProcessor可以與BeanDefinition進行交互並進行修改,但不能與Bean實例交互。這樣做可能會導致bean過早實例化,從而違反了容器規則並造成了意外的副作用。如果需要與bean實例交互,請考慮實現BeanPostProcessor。
常見的BeanFactoryPostProcessor有CustomScopeConfigurer(自定義Scope)、CustomAutowireConfigurer(自定義@Qualifier)、CustomEditorConfigurer(自定義PropertyEditor)。它們都是用來擴展BeanFactory功能的。還有一個EventListenerMethodProcessor是用來處理@EventListener註解的。
BeanFactoryPostProcessor另一個核心的實現類就是ConfigurationClassPostProcessor,它是用來解析@Configuration註解類的處理器。
前面提到過Spring3.0開始支持@Configuration的配置,而它是由AnnotationConfigApplicationContext透出的,所以我們從這個類開發分析。
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
///...
@Override
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
this.reader.register(componentClasses);
}
@Override
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
}
///...
}
這裏的AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner都是爲了解析@Component註解並註冊BeanDefinition。
當然這裏的@Component還包括@Repository、@Service、@Controller、@Configuration這幾個複合註解。
Annotate和Class在讀取和掃描過程中都會去調用AnnotationConfigUtils
的registerAnnotationConfigProcessors
方法註冊Spring的註解處理器,其中包括:
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
// 註冊@Configuration、@Bean、@Import、@ComponentScan等註解的ConfigurationClassPostProcessor
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 註冊@Autowired、@Value等註解的AutowiredAnnotationBeanPostProcessor
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 註冊處理@Required註解的RequiredAnnotationBeanPostProcessor
if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 檢查是否有JSR-250的依賴
// 有則註冊處理@PostConstruct、@PreDestroy、@Resource等註解的
// CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 檢查JPA的依賴, 有則註冊處理@PersistenceUnit、@PersistenceContext註解的
// PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 註冊處理@EventListener註解的EventListenerMethodProcessor
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
// 爲@EventListener註解的方法提供一個事件類型適配器
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
這裏我們主要關注ConfigurationClassPostProcessor,因爲它實現了BeanDefinitionRegistryPostProcessor接口,所以它會回調兩次:
1、先回調BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry方法,由ConfigurationClassParser解析出所有的ConfigurationClass,再由ConfigurationClassBeanDefinitionReader將所有的ConfigurationClass讀取並將BeanDefinition註冊到容器中。
2、然後回調BeanFactoryPostProcessor.postProcessBeanFactory方法,其中ConfigurationClassEnhancer使用Cglib對@Configuration類進行動態代理增強,主要是爲了調用@Bean註解方法時由BeanFactory負責創建對象並將其放入容器中。
@Configuration
public class DemoConfiguration {
@Bean
public ObjectA a(){
return new ObjectA();
}
@Bean
public ObjectB b(){
// 正因爲ConfigurationClassEnhancer
// 所以調用a()方法時會從BeanFactory中取出bean,而不是每次創建一個新對象
return new ObjectB(a());
}
}
對於ConfigurationClassPostProcessor更詳細的源碼分析請參考這兩篇文章:
其中比較重要的是@Import註解的處理,因爲Spring中很多@EnableXxx註解都是基於這個實現的。
@Import註解內可以填三種類型:
1、@Configuration註解類,2、ImportSelector接口實現類,3、ImportBeanDefinitionRegistrar接口實現類
@EnableXxx => @Import(XxxConfiguration ==> @Configuration) => XxxBeanPostProcessor
eg. @EnableScheduling
=> @Import(XxxSelector ==> ImportSelector)
eg. @EnableAsync、@EnableDubboConfig
=> @Import(XxxRegistrar ==> ImportBeanDefinitionRegistrar)
eg. @EnableAspectJAutoProxy、@EnableJpaAuditing、@EnableJpaRepositories
看一下這塊的代碼:
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
// 處理ImportSelector實現類
if (candidate.isAssignable(ImportSelector.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
// 如果實現的是DeferredImportSelector接口則延遲處理
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
// 直接拿到import的類,遞歸處理一下
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
// 處理ImportBeanDefinitionRegistrar實現類
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
// 註解將ImportBeanDefinitionRegistrar放到configClass中
// 最後由ConfigurationClassBeanDefinitionReader處理
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 否則當作@Configuration註解的類處理
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
至此已將Spring IOC的大部分核心內容的整體結構理清楚了,更多細節上的知識還需要查看源碼去理解。
參考資料:
https://www.baeldung.com/spring-factorybean
https://www.baeldung.com/spring-profiles
https://spring.io/blog/2007/06/05/more-on-java-configuration
https://spring.io/blog/2014/11/04/a-quality-qualifier
https://spring.io/blog/2011/08/09/what-s-a-factorybean
https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2
https://spring.io/blog/2010/01/05/task-scheduling-simplifications-in-spring-3-0
https://spring.io/blog/2011/02/17/spring-3-1-m1-introducing-featurespecification-support
https://spring.io/blog/2016/03/04/core-container-refinements-in-spring-framework-4-3