在前面兩篇文章中,我們已經對ApplicationContext的大部分內容做了介紹,包括國際化,Spring中的運行環境,Spring中的資源,Spring中的事件監聽機制,還剩唯一一個BeanFactory相關的內容沒有介紹,這篇文章我們就來介紹BeanFactory,這篇文章結束,關於ApplicationContext相關的內容我們也總算可以告一段落了。本文對應官網中的
1.16
及1.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的方式,基於此又多了兩個子類
ClassPathXmlApplicationContext
,從classPath下加載配置文件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};
}
}
}
進一步指定了配置文件的加載形式
- 需要加載XML類型配置
- 對於根容器,加載路徑爲
/WEB-INF/applicationContext.xml
- 對於子容器,加載路徑爲
/WEB-INF/+'namespace'+.xml
,比如常用的dispatchServlet.xml
5、AnnotationConfigWebApplicationContext
指定了以註解的方式配置web容器
6、GenericWebApplicationContext
類比GenericApplicationContext
,沒有指定配置相關的任何東西,全手動
總結
從上面我們可以看到,整個一套體系下來不可謂不龐大,Spring在單一職責可以說做到了極致。不論是按功能分,比如HierarchicalBeanFactory
,ListableBeanFactory
,AutowireCapableBeanFactory
就是按照不同功能拆分,或者是按照功能實現的層級劃分,比如上面說到的配置文件的加載機制。對類之間的關係進行明確的分層,代表了整個體系會具備非常強大的擴展性,我們可以在每一步進行自己的擴展。這是讓Spring能組件化開發,可插拔,變得如此優秀、普適的重要原因
到此,關於ApplicationContext相關的內容終於也可以告一段落了,代表着IOC已經結束了,粗略看了下官網,接下來還剩數據綁定,數據校驗,類型轉換以及AOP,任重而道遠,加油吧!~