Spring官網閱讀(十三)ApplicationContext詳解(下)

在前面兩篇文章中,我們已經對ApplicationContext的大部分內容做了介紹,包括國際化,Spring中的運行環境,Spring中的資源,Spring中的事件監聽機制,還剩唯一一個BeanFactory相關的內容沒有介紹,這篇文章我們就來介紹BeanFactory,這篇文章結束,關於ApplicationContext相關的內容我們也總算可以告一段落了。本文對應官網中的1.161.15小結

前面我們也提到了ApplicationContext繼承了BeanFactory接口,其繼承關係如下:

在這裏插入圖片描述

下面我們直接進入BeanFactory相關內容的學習

BeanFactory

接口定義

public interface BeanFactory {
	
    // FactroyBean的前綴,如果getBean的時候BeanName有這個前綴,會去獲取對應的FactroyBean
    // 而不是獲取FactroyBean的getObject返回的Bean
	String FACTORY_BEAN_PREFIX = "&";
	
    // 都是用於獲取指定的Bean,根據名稱獲取指定類型獲取
	Object getBean(String name) throws BeansException;
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;
	Object getBean(String name, Object... args) throws BeansException;
	<T> T getBean(Class<T> requiredType) throws BeansException;
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
	
    // 獲取指定的Bean的ObjectProvider,這個有個問題,ObjectProvider是什麼?請參考我《Spring雜談》相關文章
    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
	
    // 檢查容器中是否含有這個名稱的Bean
	boolean containsBean(String name);
	
    // 判斷指定的Bean是否爲單例
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
	
    // 判斷指定的Bean是否爲原型
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
	
    // 判斷指定的Bean類型是否匹配,關於ResolvableType我已經專門寫文章介紹過了,請參考我《Spring雜談》相關文章
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
	
    // 返回指定Bean的類型
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;
	
    // 返回指定Bean的別名
	String[] getAliases(String name);

}

可以看到BeanFactory接口主要提供了查找Bean,創建Bean(在getBean調用的時候也會去創建Bean),以及針對容器中的Bean做一些判斷的方法(包括是否是原型,是否是單例,容器是否包含這個名稱的Bean,是否類型匹配等等)

繼承關係

在這裏插入圖片描述

接口功能

作爲BeanFactory的直接子接口的有三個,分別是HierarchicalBeanFactory,ListableBeanFactory,AutowireCapableBeanFactory

1、HierarchicalBeanFactory

public interface HierarchicalBeanFactory extends BeanFactory {
	// 獲取父容器
    @Nullable
	BeanFactory getParentBeanFactory();
    // 獲取父系容器,只在當前容器中判斷是否包含這個名稱的Bean
	boolean containsLocalBean(String name);
}

HierarchicalBeanFactory對頂層的BeanFactory做了擴展,讓其具有了父子層級關係

2、ListableBeanFactory

public interface ListableBeanFactory extends BeanFactory {
	
    // 1.查找容器中是否包含對應名稱的BeanDefinition
    // 2.忽略層級關係,只在當前容器中查找
	boolean containsBeanDefinition(String beanName);

    // 1.查找容器中包含的BeanDefinition的數量
    // 2.忽略層級關係,只在當前容器中查找
	int getBeanDefinitionCount();

    // 1.獲取當前容器中所有的BeanDefinition的名稱
    // 2.忽略層級關係,只在當前容器中查找
	String[] getBeanDefinitionNames();

	// 根據指定類型獲取容器中的對應的Bean的名稱,可能會有多個
    // 既會通過BeanDefinition做判斷,也會通過FactoryBean的getObjectType方法判斷
	String[] getBeanNamesForType(ResolvableType type);
	String[] getBeanNamesForType(@Nullable Class<?> type);
	
    // 根據指定類型獲取容器中的對應的Bean的名稱,可能會有多個
    // 既會通過BeanDefinition做判斷,也會通過FactoryBean的getObjectType方法判斷
    // includeNonSingletons:是否能包含非單例的Bean
    // allowEagerInit:是否允許對”懶加載"的Bean進行實例化,這裏主要針對FactoryBean,因爲FactoryBean
    // 默認是懶加載的,爲了推斷它的類型可能會進行初始化。
	String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);

	// 獲取指定類型的Bean,返回一個map,key爲bean的名稱,value爲對應的Bean
	<T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
    
    // 獲取指定類型的Bean,返回一個map,key爲bean的名稱,value爲對應的Bean
    // includeNonSingletons:是否能包含非單例的Bean
    // allowEagerInit:是否允許對”懶加載"的Bean進行實例化,這裏主要針對FactoryBean,因爲FactoryBean
    // 默認是懶加載的,爲了推斷它的類型可能會進行初始化。
	<T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
			throws BeansException;

	// 獲取添加了指定註解的Bean的名稱
    // 爲了確定類型,會對FactoryBean所創建的Bean進行實例化
	String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);

	// 獲取添加了指定註解的Bean的名稱
    // 爲了確定類型,會對FactoryBean所創建的Bean進行實例化
    // 返回一個map,key爲bean的名稱,value爲對應的Bean
	Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;

	// 查詢指定的Bean上的指定類型的註解,如果沒有這個Bean會拋出NoSuchBeanDefinitionException
    // 如果指定Bean上不存在這個註解,會從其父類上查找
	@Nullable
	<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
			throws NoSuchBeanDefinitionException;

}

從上面的方法中可以看出,相對於BeanFactory,ListableBeanFactory提供了批量獲取Bean的方法。

3、AutowireCapableBeanFactory

public interface AutowireCapableBeanFactory extends BeanFactory {
	
    // 自動注入下的四種模型,如果有疑問請參考之前的文章《自動注入與精確注入》
	int AUTOWIRE_NO = 0;
	int AUTOWIRE_BY_NAME = 1;
	int AUTOWIRE_BY_TYPE = 2;
	int AUTOWIRE_CONSTRUCTOR = 3;
	
    // 已經過時了,不考慮
	@Deprecated
	int AUTOWIRE_AUTODETECT = 4;
	
    //該屬性是一種約定俗成的用法:以類全限定名+.ORIGINAL 作爲Bean Name,用於告訴Spring,在初始化的時候,需要返回原始給定實例,而別返回代理對象
	String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL";


	//-------------------------------------------------------------------------
	// 下面這三個方法通常用於創建跟填充Bean(對Bean進行屬性注入),但是請注意,直接採用下面這些方法創建或者裝	  // 配的Bean不被Spring容器所管理
	//-------------------------------------------------------------------------
	
    // 用指定的class創建一個Bean,這個Bean會經過屬性注入,並且會執行相關的後置處理器,但是並不會放入		// Spring容器中
	<T> T createBean(Class<T> beanClass) throws BeansException;
	
    // 爲指定的一個對象完成屬性注入,這個對象可以不被容器管理,可以是一個Spring容器外部的對象
    // 主要調用populateBean
	void autowireBean(Object existingBean) throws BeansException;
	
	// 配置參數中指定的bean
	// beanName表示在Bean定義中的名稱。
	// populateBean和initializeBean都會被調用
    // existingBean:需要被配置的Bean
    // beanName:對應的Bean的名稱
	Object configureBean(Object existingBean, String beanName) throws BeansException;


	//-------------------------------------------------------------------------
	// 下面這一系列方法主要爲了更細粒度的操縱Bean的生命週期
	//-------------------------------------------------------------------------
    
    // 支持以給定的注入模型跟依賴檢查級別創建,注入Bean。關於注入模型我這裏就不想再說了
    // 依賴檢查的級別如下:
    // 1.DEPENDENCY_CHECK_NONE = 0,代表不進行依賴檢查
	// 2.DEPENDENCY_CHECK_SIMPLE = 2,代表對基本數據類的字段做檢查。如果一個int類型的字段沒有被賦值,那麼會拋出異常
	// 3.DEPENDENCY_CHECK_ALL = 3,對引用類型的字段做檢查。如果一個Object類型的字段沒有被賦值,那麼會拋出異常
	Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
	Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
	void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)
			throws BeansException;

    //就是把Bean定義信息裏面的一些東西,賦值到已經存在的Bean裏面
	void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
	
    // 初始化Bean,執行初始化回調,及下面兩個後置處理器中的方法
	Object initializeBean(Object existingBean, String beanName) throws BeansException;

    // 調用對應的兩個後置處理器
	Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException;
	Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException;
	
    // 執行銷燬相關的回調方法
	void destroyBean(Object existingBean);


	//-------------------------------------------------------------------------
	// 關於注入點的相關方法
	//-------------------------------------------------------------------------
	
    // 查找唯一符合指定類的實例,如果有,則返回實例的名字和實例本身
	// 底層依賴於:BeanFactory中的getBean(Class)方法
	<T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
	
    // DependencyDescriptor:依賴名描述符,描述了依賴的相關情況,比如存在於哪個類,哪個字段,什麼類型
    // 查找指定名稱,指定類型的Bean
    // 底層依賴於:BeanFactory中的getBean(name,Class)方法
	Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException;
	
    // 解析指定的依賴。就是根據依賴描述符的定義在容器中查找符合要求的Bean
	@Nullable
	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
	
	//descriptor 依賴描述 (field/method/constructor)
	//requestingBeanName 依賴描述所屬的Bean
	//autowiredBeanNames 與指定Bean有依賴關係的Bean的名稱
	//typeConverter 用以轉換數組和連表的轉換器
	//備註:結果可能爲null,畢竟容器中可能不存在這個依賴嘛~~~~~~~~~~~~~~~~
	@Nullable
	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;

}

可以看到這個類中的方法都跟裝配Bean,配置Bean相關,另外還有一系列專門處理注入點的方法。可以看到接口有一個很大的作用就是對於一些不受Spring管理的Bean,也能爲其提供依賴注入的功能。例如:

// DmzService沒有被放入容器中
public class DmzService {
	@Autowired
	IndexService indexService;

	public void test(){
		System.out.println(indexService);
	}
}

// 被容器所管理
@Component
public class IndexService {
}

public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
		AutowireCapableBeanFactory beanFactory = ac.getBeanFactory();
		DmzService bean = beanFactory.createBean(DmzService.class);
		// 打印:com.dmz.official.beanfactory.IndexService@6ad5c04e
		bean.test();
		// 拋出NoSuchBeanDefinitionException
		// ac.getBean(DmzService.class);
	}
}

在上面的例子中,DmzService沒有被容器管理,所以在調用ac.getBean(DmzService.class);會拋出NoSuchBeanDefinitionException,但是我們可以看到,indexService被注入到了DmzService中。

4、ConfigurableBeanFactory

public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
	// 單例及原型的常量
	String SCOPE_SINGLETON = "singleton";
	String SCOPE_PROTOTYPE = "prototype";
	
    // 設置父容器,父容器一旦被設置,不可改變
	void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;
	
    // 爲Bean設置指定的類加載器
	void setBeanClassLoader(@Nullable ClassLoader beanClassLoader);
	
    // 獲取類型加載器,可能返回null,代表系統類加載器不可訪問
	@Nullable
	ClassLoader getBeanClassLoader();
	
    // 設置臨時的類加載器,在進行類加載時期織入時會用到(loadTimeWeaver)
	void setTempClassLoader(@Nullable ClassLoader tempClassLoader);
	@Nullable
	ClassLoader getTempClassLoader();
	
    // 是否緩存Bean的元數據,默認是開啓的
	void setCacheBeanMetadata(boolean cacheBeanMetadata);
	boolean isCacheBeanMetadata();
	
    // 定義用於解析bean definition的表達式解析器
	void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver);
	@Nullable
	BeanExpressionResolver getBeanExpressionResolver();

    // 數據類型轉換相關
	void setConversionService(@Nullable ConversionService conversionService);
	@Nullable
	ConversionService getConversionService();
	void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);
	void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);
	void copyRegisteredEditorsTo(PropertyEditorRegistry registry);
	void setTypeConverter(TypeConverter typeConverter);
	TypeConverter getTypeConverter();
	
    // 值解析器,例如可以使用它來處理佔位符
	void addEmbeddedValueResolver(StringValueResolver valueResolver);
	boolean hasEmbeddedValueResolver();
	@Nullable
	String resolveEmbeddedValue(String value);

    // 添加後置處理器
	void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
	int getBeanPostProcessorCount();

    // 註冊指定名稱的Scope
	void registerScope(String scopeName, Scope scope);
	
    // 返回所有的註冊的scope的名稱
	String[] getRegisteredScopeNames();
	
    // 返回指定名稱的已註冊的scope
	@Nullable
	Scope getRegisteredScope(String scopeName);
	
	AccessControlContext getAccessControlContext();
	
    // 從另外一個容器中拷貝配置,不包含具體的bean的定義
	void copyConfigurationFrom(ConfigurableBeanFactory otherFactory);
	
    // 爲Bean註冊別名
	void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException;
	// 解析別名
	void resolveAliases(StringValueResolver valueResolver);
	
    // 合併BeanDefinition,參考我之前的文章,《BeanDefinition下》
	BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
	
    // 是否是一個FactoryBean
	boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException;

    // 循環依賴相關,標誌一個Bean是否在創建中
	void setCurrentlyInCreation(String beanName, boolean inCreation);
	boolean isCurrentlyInCreation(String beanName);
	
	//處理bean依賴問題
	//註冊一個依賴於指定bean的Bean
	void registerDependentBean(String beanName, String dependentBeanName);
	
    // 返回所有指定的Bean從屬於哪些Bean
	String[] getDependentBeans(String beanName);
    
    // 返回指定名稱的bean的所有依賴
	String[] getDependenciesForBean(String beanName);
    
    // 銷燬Bean
	void destroyBean(String beanName, Object beanInstance);
	
    // 先從域中移除,然後再銷燬
	void destroyScopedBean(String beanName);
	
    // 銷燬所有單例
	void destroySingletons();

}

可以看到這個接口繼承了HierarchicalBeanFactory,並基於它擴展了非常多的方法。除了繼承了HierarchicalBeanFactory,還繼承了一個SingletonBeanRegistry,其接口定義如下:

public interface SingletonBeanRegistry {
	//以指定的名字將給定Object註冊到BeanFactory中。
	//此接口相當於直接把Bean註冊,所以都是準備好了的Bean。(動態的向容器裏直接放置一個Bean)
	//什麼BeanPostProcessor、InitializingBean、afterPropertiesSet等都不會被執行的,銷燬的時候也不會收到destroy的信息
	void registerSingleton(String beanName, Object singletonObject);
	
    //以Object的形式返回指定名字的Bean,如果僅僅還是隻有Bean定義信息,這裏不會反悔
	// 需要注意的是:此方法不能直接通過別名獲取Bean。若是別名,請通過BeanFactory的方法先獲取到id
	@Nullable
	Object getSingleton(String beanName);
	//是否包含此單例Bean(不支持通過別名查找)
	boolean containsSingleton(String beanName);
	// 得到容器內所有的單例Bean的名字們
	String[] getSingletonNames();
	int getSingletonCount();
	
	// 獲取當前這個註冊表的互斥量(mutex),使用者通過該互斥量協同訪問當前註冊表
	Object getSingletonMutex();
}

從上面可以看到,SingletonBeanRegistry主要是實現了對容器中單例池的管理。

5、ConfigurableListableBeanFactory

// 所有接口的集大成者,擁有上面所有接口的功能
public interface ConfigurableListableBeanFactory
		extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
	// 自動裝配的模式下,忽略這個類型的依賴
	void ignoreDependencyType(Class<?> type);
	
    //自動裝配的模式下,忽略這個接口類型的依賴
	void ignoreDependencyInterface(Class<?> ifc);

    // 注入一個指定類型的依賴。這個方法設計的目的主要是爲了讓容器中的Bean能依賴一個不被容器管理的Bean
	void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue);
	
    // 判斷指定名稱的Bean能否被注入到指定的依賴中
	boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
			throws NoSuchBeanDefinitionException;

    // 獲取指定的BeanDefinition
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
	
    // 獲取包含了所有的Bean的名稱的迭代器
	Iterator<String> getBeanNamesIterator();

	// 清理元數據的緩存
	void clearMetadataCache();
	
	// 凍結所有的Bean配置
	void freezeConfiguration();
	boolean isConfigurationFrozen();
	
	// 實例化當前所有的剩下的單實例
	void preInstantiateSingletons() throws BeansException;
}

6、AbstractBeanFactory

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
	//... 實現了大部分的方法,其中最終的實現爲getBean()/doGetBean()方法的實現,提供了模版。其實createBean抽象方法,還是子類去實現的
	//... isSingleton(String name) / isPrototype(String name) / containsBean(String name) 也能實現精準的判斷了

	// ===其中,它自己提供了三個抽象方法,子類必要去實現的===
	
	// 效果同:ListableBeanFactory#containsBeanDefinition  實現類:DefaultListableBeanFactory
	protected abstract boolean containsBeanDefinition(String beanName);
	// 效果同:ConfigurableListableBeanFactory#getBeanDefinition  實現類:DefaultListableBeanFactory
	protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
	// 創建Bean的複雜邏輯,子類去實現。(子類:AbstractAutowireCapableBeanFactory)
	protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException;
	
}

7、AbstractAutowireCapableBeanFactory

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {
    ......
        // 1.實現了AbstractBeanFactory中的createBean方法,能夠創建一個完全的Bean
        // 2.實現了AutowireCapableBeanFactory,能對Bean進行實例化,屬性注入,已經細粒度的生命週期管理
}

8、DefaultListableBeanFactory

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
    implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
	.....
        // 沒什麼好說的了,最牛逼的一個BeanFactory,擁有上面的一切功能,額外的它實現了BeanDefinitionRegistry接口,具備註冊管理BeanDefinition的功能
}

ApplicationContext體系彙總

ApplicationContext整體可以分爲兩個體系,一個就是web體系,另外一個就是非web體系。

非web體系

在這裏插入圖片描述

1、ConfigurableApplicationContext

ApplicationContext接口中的方法比較簡單,之前我們也一一分析它繼承的接口以及它所具有的功能。並且ApplicationContext接口的方法都是隻讀的,不能對當前的容器做任何改變。而ConfigurableApplicationContext接口在ApplicationContext的基礎上增加了很多進行配置的方法,比如添加事件監聽器,添加後置處理器等等。

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
	// 配置路徑的分隔符
	String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
	String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
	String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
	String ENVIRONMENT_BEAN_NAME = "environment";
	String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
	String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";

	//設置此應用程序上下文的唯一ID。
	void setId(String id);
	
    //設置父容器,設置後不能再改了
	void setParent(@Nullable ApplicationContext parent);
	
    //設置environment  此處爲ConfigurableEnvironment 也是可以配置的應用上下文
	void setEnvironment(ConfigurableEnvironment environment);
	
    // 此處修改父類返回值爲ConfigurableEnvironment 
	@Override
	ConfigurableEnvironment getEnvironment();

	//添加一個新的BeanFactoryPostProcessor(refresh()的時候會調用的)
	void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
	
    // 添加一個事件監聽器
	void addApplicationListener(ApplicationListener<?> listener);
	
    // 註冊協議處理器  允許處理額外的資源協議
	void addProtocolResolver(ProtocolResolver resolver);

	//加載或刷新配置的持久表示  最最最重要的一個方法
	//表示可以是xml、可以是註解、可以是外部資源文件等等。。。。
	// 這個方法執行完成後,所有的單例Bean都已經被實例化,Bean工廠肯定也就被創建好了
	void refresh() throws BeansException, IllegalStateException;
	
	//JVM運行時註冊一個關閉掛鉤,在關閉JVM時關閉此上下文,除非此時已經關閉
	void registerShutdownHook();
	
	//關閉此應用程序上下文,釋放實現可能持有的所有資源和鎖  包括一些銷燬、釋放資源操作
	@Override
	void close();
	
    //標識上下文是否激活 refresh()後就會激活
	boolean isActive();
	
    // 返回此上下文內部的Bean工廠,可以用來訪問底層工廠的特定功能。通過此工廠可以設置和驗證所需的屬性、自定義轉換服務
	// 備註:父類方法爲獲得AutowireCapableBeanFactory接口,而此處的ConfigurableListableBeanFactory可配置、可列出Bean的工廠是它的子類
	ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

2、AbstractApplicationContext

public abstract class AbstractApplicationContext extends DefaultResourceLoader
    implements ConfigurableApplicationContext {
	// 這個類實現了ConfigurableApplicationContext,具備了上面接口大部分功能,
    // 但是他沒有實現getBeanFactory()方法,這個方法留待子類實現,所以它自己沒有實際的管理Bean的能力,只是定義了一系列規範
}

3、AbstractRefreshableApplicationContext

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
	
    // 碰到重複的Bean時,是否允許覆蓋原先的BeanDefinition
	@Nullable
	private Boolean allowBeanDefinitionOverriding;
	
    // 是否允許循環引用
	@Nullable
	private Boolean allowCircularReferences;
	
    // 默認持有一個DefaultListableBeanFactory
	@Nullable
	private DefaultListableBeanFactory beanFactory;

	// 對內部工廠進行操作時所採用的鎖
	private final Object beanFactoryMonitor = new Object();

	public AbstractRefreshableApplicationContext() {
	}

	public AbstractRefreshableApplicationContext(@Nullable ApplicationContext parent) {
		super(parent);
	}

	public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
		this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
	}

	public void setAllowCircularReferences(boolean allowCircularReferences) {
		this.allowCircularReferences = allowCircularReferences;
	}
	
    // 刷新Bean工廠,如果當前上下文中已經存在一個容器的話,會先銷燬容器中的所有Bean,然後關閉Bean工廠
    // 之後在重新創建一個DefaultListableBeanFactory
	@Override
	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);
		}
	}

	@Override
	protected void cancelRefresh(BeansException ex) {
		synchronized (this.beanFactoryMonitor) {
			if (this.beanFactory != null) {
				this.beanFactory.setSerializationId(null);
			}
		}
		super.cancelRefresh(ex);
	}

	@Override
	protected final void closeBeanFactory() {
		synchronized (this.beanFactoryMonitor) {
			if (this.beanFactory != null) {
				this.beanFactory.setSerializationId(null);
				this.beanFactory = null;
			}
		}
	}


	protected final boolean hasBeanFactory() {
		synchronized (this.beanFactoryMonitor) {
			return (this.beanFactory != null);
		}
	}
	
    // 複寫了getBeanFactory,默認返回的是通過createBeanFactory創建的一個DefaultListableBeanFactory
	@Override
	public final ConfigurableListableBeanFactory getBeanFactory() {
		synchronized (this.beanFactoryMonitor) {
			if (this.beanFactory == null) {
				throw new IllegalStateException("BeanFactory not initialized or already closed - " +
						"call 'refresh' before accessing beans via the ApplicationContext");
			}
			return this.beanFactory;
		}
	}

	protected DefaultListableBeanFactory createBeanFactory() {
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}

	.......
	// 提供了一個抽象的加載BeanDefinition的方法,這個方法沒有具體實現,不同的配置方式需要進行不同的實現,
    // 到這裏,配置的方式不能確定,既可能是以XML的方式,也可能是以java config的方式
    // 另外配置文件的加載方式也不能確定
	protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
			throws BeansException, IOException;

}

可以看到這個類可以進一步對上下文進行配置,例如進行是否開啓循環引用,是否允許進行BeanDefinition的覆蓋等等。另外它所提供的一個重要的功能就是使容器具備刷新的功能,換言之凡是需要刷新功能的容器都需要繼承這個類。

4、AbstractRefreshableConfigApplicationContext

public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
		implements BeanNameAware, InitializingBean {
	// 這個變量代表了配置文件的路徑,到這裏配置的信息相比於其父類AbstractRefreshableApplicationContext做了進一步的明確,但是仍然不能確定是XML還是javaconfig,只能確定配置在configLocations裏面
	@Nullable
	private String[] configLocations;
    .....
}


5、AbstractXmlApplicationContext

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
	
    
    // 是否進行XML類型的校驗,默認爲true
    private boolean validating = true;
    
    // .....
	
	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {

		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}

	protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
		reader.setValidating(this.validating);
	}

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}

	@Nullable
	protected Resource[] getConfigResources() {
		return null;
	}

}

可以看到這個類進一步對配置的加載做了進一步的明確,首先明確了配置的類型爲XML,第二明確了要通過getConfigResources方法來加載需要的配置資源,但是並沒有對這個方法做具體實現,因爲對於Resource的定義,可能是通過classpath的方式,也可能是通過URL的方式,基於此又多了兩個子類

  1. ClassPathXmlApplicationContext,從classPath下加載配置文件
  2. FileSystemXmlApplicationContext,基於URL的格式加載配置文件

6、GenericApplicationContext

這個類已經不是抽象類了,我們可以直接使用它。但是這個類有一個很大的缺點,它不能讀取配置,需要我們手動去指定讀取的方式及位置。其實從上文中的分析我們可以看出,從AbstractApplicationContext到AbstractXmlApplicationContext一步步明確了配置的加載方式,Spring通過這種類的繼承將配置的加載分了很多層,我們可以從AbstractXmlApplicationContext的子類開始從任意以及進行擴展。

而GenericApplicationContext只實現了上下文的基本功能,並沒有對配置做任何約束,所以在使用它的我們需要手動往其中註冊BeanDefinition。這樣雖然很靈活,但是也很麻煩,如果我們使用GenericApplicationContext可能需要進行下面這樣的操作

GenericApplicationContext ctx = new GenericApplicationContext();
//使用XmlBeanDefinitionReader,這個地方我們甚至可以自己定義解析器,不使用Spring容器內部的
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
//加載ClassPathResource
xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
//調用Refresh方法
ctx.refresh();

//和其他ApplicationContext方法一樣的使用方式
MyBean myBean = (MyBean) ctx.getBean("myBean");

平常開發中我們基本用不到這個東西

7、AnnotationConfigApplicationContext

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {

	private final AnnotatedBeanDefinitionReader reader;

	private final ClassPathBeanDefinitionScanner scanner;
   
    .......
}

通過AnnotatedBeanDefinitionReader註冊配置類,用ClassPathBeanDefinitionScanner掃描配置類上申明的路徑,得到所有的BeanDefinition。然後其餘的沒啥了。這個我們經常使用,因爲不用再需要xml文件了,使用@Configuration配置類即可,更加的方便。

web體系

在這裏插入圖片描述

1、WebApplicationContext

public interface WebApplicationContext extends ApplicationContext {

	String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

	String SCOPE_REQUEST = "request";

	String SCOPE_SESSION = "session";

	String SCOPE_APPLICATION = "application";

	String SERVLET_CONTEXT_BEAN_NAME = "servletContext";

	String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";

	String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";

	@Nullable
	ServletContext getServletContext();

}

定義了一堆常量,以及一個方法,約束了所有的web容器必須能返回一個Servlet的上下文(ServletContext)

2、ConfigurableWebApplicationContext

public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext {

	String APPLICATION_CONTEXT_ID_PREFIX = WebApplicationContext.class.getName() + ":";

	String SERVLET_CONFIG_BEAN_NAME = "servletConfig";

	void setServletContext(@Nullable ServletContext servletContext);

	void setServletConfig(@Nullable ServletConfig servletConfig);

	@Nullable
	ServletConfig getServletConfig();
	
    // 設置及獲取當前上下文的命名空間,命名空間用於區分不同的web容器的配置,在查找配置時會根據命名空間查找
    // 默認不進行命名空間配置,配置會在/WEB-INF/applicationContext.xml下查找
    // 如果配置了,會在/WEB-INF+"namespace"+/applicationContext.xml下查找
    // 根容器沒有Namespace
	void setNamespace(@Nullable String namespace);
	@Nullable
	String getNamespace();

	void setConfigLocation(String configLocation);

	void setConfigLocations(String... configLocations);

	@Nullable
	String[] getConfigLocations();

}

可以看到使用這個類能指定上下文配置加載的位置

3、AbstractRefreshableWebApplicationContext

public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
		implements ConfigurableWebApplicationContext, ThemeSource {
    .......
}

首先可以看到這個類繼承了AbstractRefreshableConfigApplicationContext,代表它需要從指定的位置加載配置,其次它首先了ConfigurableWebApplicationContext,所以它具有web容器的屬性。

4、XmlWebApplicationContext

public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {

    public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

    public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";


    public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";

	//  .......
    @Override
    protected String[] getDefaultConfigLocations() {
        if (getNamespace() != null) {
            return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
        }
        else {
            return new String[] {DEFAULT_CONFIG_LOCATION};
        }
    }

}

進一步指定了配置文件的加載形式

  1. 需要加載XML類型配置
  2. 對於根容器,加載路徑爲/WEB-INF/applicationContext.xml
  3. 對於子容器,加載路徑爲/WEB-INF/+'namespace'+.xml,比如常用的dispatchServlet.xml

5、AnnotationConfigWebApplicationContext

指定了以註解的方式配置web容器

6、GenericWebApplicationContext

類比GenericApplicationContext,沒有指定配置相關的任何東西,全手動

總結

從上面我們可以看到,整個一套體系下來不可謂不龐大,Spring在單一職責可以說做到了極致。不論是按功能分,比如HierarchicalBeanFactory,ListableBeanFactory,AutowireCapableBeanFactory就是按照不同功能拆分,或者是按照功能實現的層級劃分,比如上面說到的配置文件的加載機制。對類之間的關係進行明確的分層,代表了整個體系會具備非常強大的擴展性,我們可以在每一步進行自己的擴展。這是讓Spring能組件化開發,可插拔,變得如此優秀、普適的重要原因

到此,關於ApplicationContext相關的內容終於也可以告一段落了,代表着IOC已經結束了,粗略看了下官網,接下來還剩數據綁定,數據校驗,類型轉換以及AOP,任重而道遠,加油吧!~

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