Spring原理學習系列之五:IOC原理之Bean加載

引言

其實很多同學都想通過閱讀框架的源碼以汲取框架設計思想以及編程營養,Spring框架其實就是個很好的框架源碼學習對象。我們都知道BeanSpring框架的最小操作單元,Spring框架通過對於Bean的統一管理實現其IOC以及AOP等核心的框架功能,那麼Spring框架是如何把Bean加載到環境中來進行管理的呢?本文將圍繞這個話題進行詳細的闡述,並配合Spring框架的源碼解析。

  • Bean創建
  • Bean加載流程
  • 總結

一、Bean創建

在搞清楚Spring框架如何加載Bean之前,我們需要明確Spring框架中的Bean是如何被創建的。那我們就不得不談到BeanFactory。本文采用的AnnotationConfigApplicationContext來進行代碼示例說明,它的類繼承與實現結構如下所示。由圖可知,BeanFactory是作爲頂級接口的形式存在。

在這裏插入圖片描述
示例代碼如下:

public class SpringTest {


    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(UserServiceImpl.class);

        IUserService userService = (UserServiceImpl)ac.getBean("userService");
        //3.執行bean中的方法
        userService.query();
    }
}

如示例代碼所示,在new AnnotationConfigApplicationContext(UserService.class)創建context過程中,實際調用了AnnotationConfigApplicationContext的構造方法,其重載的構造方法如下所示:

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
...
	public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		this();
		register(annotatedClasses);
		refresh();
	}
...
}

該構造方法主要完成三件事情:
1、this():初始化bean讀取器以及掃描器,對應AnnotationConfigApplicationContext的無參構造函數,如下代碼:

public AnnotationConfigApplicationContext() {
		//在IOC容器中初始化一個 註解bean讀取器AnnotatedBeanDefinitionReader
		this.reader = new AnnotatedBeanDefinitionReader(this);
		//在IOC容器中初始化一個 按類路徑掃描註解bean的掃描器
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

2、register(annotatedClasses):進行Bean配置類註冊,如下代碼:

public void register(Class... annotatedClasses) {
        Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
        this.reader.register(annotatedClasses);
    }

AnnotationConfigApplicationContext上下文中,通過AnnotatedBeanDefinitionReader調用register進行註解Bean的讀取與註冊操作。

public void register(Class<?>... annotatedClasses) {
		for (Class<?> annotatedClass : annotatedClasses) {
			registerBean(annotatedClass);
		}
	}

public void registerBean(Class<?> annotatedClass) {
		doRegisterBean(annotatedClass, null, null, null);
	}

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
		//將註解類的數據格式轉換爲Bean容器中的AnnotatedGenericBeanDefinition
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
		//@Conditional裝配條件判斷是否需要跳過註冊
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}
		//設置回調
		abd.setInstanceSupplier(instanceSupplier);
		 //解析bean作用域(單例或者原型),如果有@Scope註解,則解析@Scope,沒有則默認爲singleton 
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		//作用域寫回BeanDefinition數據結構, abd中缺損的情況下爲空,將默認值singleton重新賦值到abd
		abd.setScope(scopeMetadata.getScopeName());
		//生成bean配置類beanName
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

		//通用註解解析到abd結構中,主要是處理Lazy, primary DependsOn, Role ,Description這五個註解
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		// @Qualifier特殊限定符處理
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
				// 如果配置@Primary註解,則設置當前Bean爲自動裝配autowire時首選bean	
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
				//設置當前bean爲延遲加載
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
			customizer.customize(abd);
		}

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		//按照名稱將對應的bean註冊到IOC容器中(在下一篇文章中進行介紹)
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

3、refresh():作用爲刷新Spring的應用上下文;
刷新上下文的操作實際上是在AbstractApplicationContext中完成的。

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
		...
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 準備上下文環境
			prepareRefresh();

			// 創建並初始化BeanFactory(這部分可以繼續追蹤,創建BeanFactory的過程)
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 填充BeanFactory功能
			prepareBeanFactory(beanFactory);

			try {
				// 提供子類覆蓋的額外處理,即子類處理自定義的BeanFactoryPostProcess
				postProcessBeanFactory(beanFactory);

				// 激活各種BeanFactory處理器
				invokeBeanFactoryPostProcessors(beanFactory);

				 // 註冊攔截Bean創建的Bean處理器,即註冊 BeanPostProcessor
				registerBeanPostProcessors(beanFactory);

				 // 初始化上下文中的資源文件,如國際化文件的處理等
				initMessageSource();

				// 初始化上下文事件廣播器
				initApplicationEventMulticaster();

				 // 給子類擴展初始化其他Bean
				onRefresh();

				// 在所有bean中查找listener bean,然後註冊到廣播器中
				registerListeners();

				// 初始化剩下的單例Bean(非延遲加載的)
				finishBeanFactoryInitialization(beanFactory);

				// 完成刷新過程,通知生命週期處理器lifecycleProcessor刷新過程,同時發出ContextRefreshEvent通知別人
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				//銷燬已經創建的Bean
				destroyBeans();

				//重置容器激活標籤
				cancelRefresh(ex);

				// 異常拋出
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}
	...

在這裏插入圖片描述

二、Bean加載

在這裏插入圖片描述
(圖片來自於網絡)
AnnotationConfigApplicationContext繼承了AbstractApplicationContext

ublic abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
		...
		@Override
		public Object getBean(String name) throws BeansException {
			assertBeanFactoryActive();
			return getBeanFactory().getBean(name);
	}
		...
}

BeanFactory接口主要的實現是在AbstractBeanFactory中完成,doGetBean接收以下四個參數:
(1)name:準備獲取 bean 的名字
(2)requiredType:準備獲取 bean 的類型
(3)args:創建 bean 時傳遞的參數。這個參數僅限於創建 bean 時使用
(4)typeCheckOnly:是否爲類型檢查

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

...
	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}
	
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		//轉換Bean名稱
		final String beanName = transformedBeanName(name);
		Object bean;

		// 從緩存中或者實例工廠中獲取 bean
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("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);
			}

			// 如果容器中沒有找到,則從父類容器中加載
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}

			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// 獲取依賴的 Bean
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						registerDependentBean(dep, beanName);
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// 開始創建 Bean 實例,如果是單例的,那麼會創建一個單例的匿名工廠,如果是原型模式的,則不需要創建單例的工廠的,其他的如 request、session 作用域的,則根據自身的需要
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						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);
				}

				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					String scopeName = mbd.getScope();
					final Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							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);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

		// 類型檢查,如果不能進行類型轉換,則拋出異常
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isTraceEnabled()) {
					logger.trace("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}
...

}

三、總結

Spring IOC還有很多內容,本文只是管中窺豹,其他的部分將繼續在後續的文章中進行詳細介紹。

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