applicationContext家族
applicationContext家族絕對是spring大劇場的核心成員,spring的幾大核心特性都涉及到的applicationContext,spring官網明白的寫著applicationContext所能做的事情,如下
如上圖所示,applicationContext可以例項化bean,呼叫BeanPostProcessor、BeanFactoryPostProcessor、ApplicationEvent釋出事件。其實這張圖正好也顯示了BeanFactory和ApplicationContext的區別。applicationContext家族絕對是中原第一大家族,分支眾多,盤根錯雜。ApplicationContext類是其家族族長,排名第一位。下面給出applicationContext家族圖譜,藉此試圖縷清applicationContext家族,家族成員間的關係如圖譜所示,主要成員的各自功能下面一一說來
另一個維度
├── ApplicationContext
└── ConfigurableApplicationContext
│ └── AbstractApplicationContext
│ │ └── GenericApplicationContext
│ │ │ └── GenericWebApplicationContext
│ │ │ │ └── EmbeddedWebApplicationContext
│ │ │ │ │ └── AnnotationConfigEmbeddedWebApplicationContext
│ │ │ │ │ └── XmlEmbeddedWebApplicationContext
│ │ │ └── GenericXmlApplicationContext
│ │ │ └── ResourceAdapterApplicationContext
│ │ │ └── StaticApplicationContext
│ │ │ │ └── StaticWebApplicationContext
│ │ └── AbstractRefreshableApplicationContext
│ │ │ └── AbstractRefreshableConfigApplicationContext
│ │ │ │ └── AbstractRefreshableWebApplicationContext
│ │ │ │ │ └── AnnotationConfigWebApplicationContext
│ │ │ │ │ └── XmlWebApplicationContext
│ │ │ └── AbstractXmlApplicationContext
│ │ │ │ │ └── ClassPathXmlApplicationContext
│ │ │ │ │ └── FileSystemXmlApplicationContext
│ └── ConfigurableWebApplicationContext
│ │ └── AbstractRefreshableWebApplicationContext
│ │ │ │ └── ......
│ │ └── GenericWebApplicationContext
│ │ │ └── ......
│ │ └── StaticWebApplicationContext
├── WebApplicationContext
│ │ └── ConfigurableWebApplicationContext
│ │ │ └── ......
│ │ └── StubWebApplicationContext
複製程式碼
從圖中可以看,在ApplicationContext家族族長上面還有幾個大人物,如果ApplicationContext是和珅,那麼這幾大人物就是乾隆、皇后、太后等。 先介紹這幾大人物
BeanFactory
BeanFactory其實也是一個大家族,家族主要負責例項化bean,其詳細介紹見BeanFactory傳
MessageSource
ApplicationEventPublisher
EnvironmentCapable
ResourcePatternResolver
ResourceLoader
下面正式介紹ApplicationContext加入成員
ApplicationContext
/**
* 這個核心介面為一個應用提供了配置,當應用正在執行時,他是僅讀的;但是如果實現類支援的話可以被過載。
* An ApplicationContext provides:
* 1.訪問應用元件的Bean factory methods,繼承自ListableBeanFactory
* 2.以通用的方式載入file resources的能力,繼承自ResourceLoader interface
* 3.釋出事件給註冊的listeners的能力,繼承自ApplicationEventPublisher interface
* 4.resolve messages,支援i18n的能力,繼承自MessageSource interface
* 5.繼承parent context,後代context中的定義始終優先。這意味著,例如,整個Web應用程式可以使用單個parent context,而每個servlet都有自己的子context,該context獨立於任何其他servlet的context.
* 除了有BeanFactory的生命週期的能力外,ApplicationContext實現類們檢查和呼叫 ApplicationContextAware beans、ResourceLoaderAware beans、 ApplicationEventPublisherAware beans、MessageSourceAware beans.
*/
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
/**
* Return the unique id of this application context.
*/
String getId();
/**
* Return a name for the deployed application that this context belongs to
*/
String getApplicationName();
/**
* return a display name for this context (never {@code null})
*/
String getDisplayName();
/**
* Return the timestamp when this context was first loaded.
* @return the timestamp (ms) when this context was first loaded
*/
long getStartupDate();
/**
* Return the parent context, or {@code null} if there is no parent
* and this is the root of the context hierarchy.
*/
ApplicationContext getParent();
/**
* 為此context暴露AutowireCapableBeanFactory功能。它通常不被應用程式程式碼使用。除了例項化那些存活在application context之外的bean instances的目的,將Spring bean生命週期(全部或部分)應用於它們。
* 可替代的,由ConfigurableApplicationContext介面暴露的內部BeanFactory也提供對 AutowireCapableBeanFactory介面的訪問許可權。本方法主要用作ApplicationContext介面上方便的特定工具
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
複製程式碼
WebApplicationContext
- 主要增加了servletContext、contextParameters、contextAttributes屬性和getServletContext()方法
/**
* 這個介面增加getServletContext() 方法給通用的ApplicationContext interface, 和定義了一個眾所周知的application attribute name,這個name必須和the root context繫結。
* 像通用的application contexts一樣, web application contexts也是有層級的,
* 每個應用程式都有一個根上下文, 而在the application中每個servlet都有他自己的子(包括dispatcher servlet)。
* 除了標準的application context 生命週期能力,WebApplicationContext 實現類需要檢查和ServletContextAware beans和呼叫setServletContext method
*/
public interface WebApplicationContext extends ApplicationContext {
/**
* Context attribute to bind root WebApplicationContext to on successful startup.
* @see org.springframework.web.context.support.WebApplicationContextUtils#getRequiredWebApplicationContext和getWebApplicationContext
*/
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
/**
* Scope identifier for request scope: "request".
*/
String SCOPE_REQUEST = "request";
/**
* Scope identifier for session scope: "session".
*/
String SCOPE_SESSION = "session";
/**
* Scope identifier for global session scope: "globalSession".
*/
String SCOPE_GLOBAL_SESSION = "globalSession";
/**
* Scope identifier for the global web application scope: "application".
*/
String SCOPE_APPLICATION = "application";
/**
* Name of the ServletContext environment bean in the factory.
* @see javax.servlet.ServletContext
*/
String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
/**
* Name of the ServletContext/PortletContext init-params environment bean in the factory.
* ServletConfig parameters override ServletContext parameters of the same name.
* @see javax.servlet.ServletContext#getInitParameterNames()
* @see javax.servlet.ServletContext#getInitParameter(String)
* @see javax.servlet.ServletConfig#getInitParameterNames()
* @see javax.servlet.ServletConfig#getInitParameter(String)
*/
String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
/**
* Name of the ServletContext/PortletContext attributes environment bean in the factory.
* @see javax.servlet.ServletContext#getAttributeNames()
* @see javax.servlet.ServletContext#getAttribute(String)
*/
String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
/**
* Return the standard Servlet API ServletContext for this application.
* <p>Also available for a Portlet application, in addition to the PortletContext.
*/
ServletContext getServletContext();
複製程式碼
ConfigurableApplicationContext
- 主要增加了systemProperties、systemEnvironment屬性和addBeanFactoryPostProcessor(BeanFactoryPostProcessor)、addApplicationListener(ApplicationListener<?>)、refresh()、ConfigurableListableBeanFactory getBeanFactory()方法
/**
* 這個一個SPI介面,由大多數應用程式實現。
* 除了ApplicationContext interface的方法外,提供了配置an application context 的工具
* 這裡封裝了配置和生命週期方法以避免使它們對ApplicationContext客戶端程式碼可見. 這些方法通過startup and shutdown code被使用
*/
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
/**
* 在一個字串中多個context config paths的分隔符
* @see org.springframework.context.support.AbstractXmlApplicationContext#setConfigLocation
* @see org.springframework.web.context.ContextLoader#CONFIG_LOCATION_PARAM
* @see org.springframework.web.servlet.FrameworkServlet#setContextConfigLocation
*/
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
/**
* Name of the ConversionService bean in the factory.
*/
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
/**
* Name of the LoadTimeWeaver bean in the factory.
*/
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
/**
* Name of the {@link Environment} bean in the factory.
*/
String ENVIRONMENT_BEAN_NAME = "environment";
/**
* Name of the System properties bean in the factory.
* @see java.lang.System#getProperties()
*/
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
/**
* Name of the System environment bean in the factory.
* @see java.lang.System#getenv()
*/
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
/**
* Set the unique id of this application context.
* @since 3.0
*/
void setId(String id);
/**
* Set the parent of this application context
*/
void setParent(ApplicationContext parent);
/**
* Set the {@code Environment} for this application context.
*/
void setEnvironment(ConfigurableEnvironment environment);
/**
* Return the {@code Environment} for this application context
*/
@Override
ConfigurableEnvironment getEnvironment();
/**
* 增加一個BeanFactoryPostProcessor,在refresh和在bean definitions被評估的時候,這個BeanFactoryPostProcessor被應用在內部的bean factory of this application context. To be invoked during context configuration.
*/
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
/**
* 增加一個在context事件中被通知的ApplicationListener,如context refresh 和context shutdown事件
* @see org.springframework.context.event.ContextRefreshedEvent
* @see org.springframework.context.event.ContextClosedEvent
*/
void addApplicationListener(ApplicationListener<?> listener);
/**
* Register the given protocol resolver with this application context,
* allowing for additional resource protocols to be handled.
*/
void addProtocolResolver(ProtocolResolver resolver);
/**
* 載入或重新整理the configuration的持久化形式,configuration可以是an XML file, properties file, or 一個database schema.
* <p>由於這是一個startup方法,這個方法呼叫後要麼全部要麼沒有singletons被例項化.
*/
void refresh() throws BeansException, IllegalStateException;
/**
* Register a shutdown hook with the JVM runtime, closing this context
* on JVM shutdown unless it has already been closed at that time.
*/
void registerShutdownHook();
/**
* Close this application context, releasing all resources and locks that the implementation might hold.
*/
@Override
void close();
/**
* @return whether the context is still active
*/
boolean isActive();
/**
* Return the internal bean factory of this application context.
* Can be used to access specific functionality of the underlying factory.
* <p>Note: Do not use this to post-process the bean factory; singletons
* will already have been instantiated before. Use a BeanFactoryPostProcessor
* to intercept the BeanFactory setup process before beans get touched.
* <p>Generally, this internal factory will only be accessible while the context
* is active, that is, inbetween refresh() and close().
* The isActive() flag can be used to check whether the context
* is in an appropriate state.
*/
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
複製程式碼
ConfigurableWebApplicationContext
- 主要增加了setConfigLocations(String...configLocations)、setServletContext(ServletContext)、setServletConfig(ServletConfig)方法
/**
* 介面被可配置的web application contexts實現
*
* <p>Note: 這個介面的setters方法需要在ConfigurableApplicationContext.refresh方法呼叫之前被呼叫
* @see ContextLoader#createWebApplicationContext
* @see org.springframework.web.servlet.FrameworkServlet#createWebApplicationContext
*/
public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext {
/**
* Prefix for ApplicationContext ids that refer to context path and/or servlet name.
*/
String APPLICATION_CONTEXT_ID_PREFIX = WebApplicationContext.class.getName() + ":";
/**
* Name of the ServletConfig environment bean in the factory.
*/
String SERVLET_CONFIG_BEAN_NAME = "servletConfig";
/**
* Set the ServletContext for this web application context.
* <p>refresh()需要這個方法呼叫後呼叫
*/
void setServletContext(ServletContext servletContext);
/**
* Set the ServletConfig for this web application context.
* refresh()需要這個方法呼叫後呼叫
*/
void setServletConfig(ServletConfig servletConfig);
/**
* Return the ServletConfig for this web application context, if any.
*/
ServletConfig getServletConfig();
/**
* Set the namespace for this web application context
*/
void setNamespace(String namespace);
/**
* Return the namespace for this web application context, if any.
*/
String getNamespace();
/**
* Set the config locations for this web application context in init-param style,即 被逗號,分號,空格分隔
*/
void setConfigLocation(String configLocation);
/**
* Set the config locations for this web application context.
*/
void setConfigLocations(String... configLocations);
/**
* Return the config locations for this web application context,
* or {@code null} if none specified.
*/
String[] getConfigLocations();
}
複製程式碼
AbstractApplicationContext
- 這個類的具體功能就比較全了
- 增加的主要屬性有
- 增加的主要方法有
上圖列出了主要的方法,可以看出這些方法都是實現了其他類的方法,具有了很多的功能,我們實際開發中可以直接使用這些方法完成我們的需求,這也是我們的終極目的:不僅瞭解了原理,還能靈活使用,鑑於AbstractApplicationContext的功能完備,我們就需要特別關注AbstractApplicationContext及其子類了,實際開發用的上
/**
* 不強制要求用於配置的儲存型別,只需實現常見的context功能,使用Template Method設計模式,需要具體的子類來實現抽象方法。
* 與普通BeanFactory相比,ApplicationContext應該檢測在其內部bean工廠中定義的特殊bean:因此,該類自動註冊BeanFactoryPostProcessors,BeanPostProcessors和ApplicationListeners,它們在context中定義為bean。
* MessageSource可以在這個context中應用,如果沒有MessageSource,則message resolution會委託給父context.
* 此外,ApplicationEventMulticaster類被應用到這個context, 否則, 預設的SimpleApplicationEventMulticaster將被應用.
* 通過擴充套件DefaultResourceLoader實現資源載入. 因此,將非URL資源路徑(non-URL resource paths)視為類路徑資源(class path resources)
*/
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
··· 略 ···
// 這裡特別列出refresh()方法,因為在spring application啟動、例項化的很多功能都是通過此方法完成的
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}finally {
resetCommonCaches();
}
}
}
}
複製程式碼
GenericApplicationContext
- 繼承了AbstractApplicationContext,擁有AbstractApplicationContext的全部強大功能
- 相比AbstractApplicationContext,GenericApplicationContext重要的點是它又實現了BeanDefinitionRegistry介面,即擁有了處理BeanDefinition的功能;同時他有兩個重要的屬DefaultListableBeanFactory beanFactory、ResourceLoader resourceLoader;
/**
* Generic ApplicationContext的實現類持有一個內部的DefaultListableBeanFactory instance和不會假定一個指定的bean definition格式. 實現BeanDefinitionRegistry interface為了應用任意bean definition readers給GenericApplicationContext
* 典型的使用是通過BeanDefinitionRegistry register各種各樣的bean definitions。 然後呼叫#refresh()去例項化those beans,帶著application context語法(處理ApplicationContextAware, 自動檢查BeanFactoryPostProcessors等
* 與為每次重新整理建立新的內部BeanFactory例項的其他ApplicationContext實現相比,此上下文的內部BeanFactory從一開始就可用,以便能夠在其上註冊bean定義。 refresh()只能呼叫一次。
* 對於想以重新整理的方式讀取指定的bean definition formats的那些自定義的 application context實現類,考慮使用AbstractRefreshableApplicationContext來獲取
*/
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
private final DefaultListableBeanFactory beanFactory;
private ResourceLoader resourceLoader;
private final AtomicBoolean refreshed = new AtomicBoolean();
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
public GenericApplicationContext(DefaultListableBeanFactory beanFactory){
Assert.notNull(beanFactory, "BeanFactory must not be null");
this.beanFactory = beanFactory;
}
public final DefaultListableBeanFactory getDefaultListableBeanFactory() {
return this.beanFactory;
}
@Override
public AutowireCapableBeanFactory getAutowireCapableBeanFactory() {
assertBeanFactoryActive();
return this.beanFactory;
}
//---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry
//---------------------------------------------------------------------
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
@Override
public void removeBeanDefinition(String beanName);
@Override
public BeanDefinition getBeanDefinition(String beanName);
@Override
public boolean isBeanNameInUse(String beanName);
@Override
public void registerAlias(String beanName, String alias);
@Override
public void removeAlias(String alias);
@Override
public boolean isAlias(String beanName);
複製程式碼
GenericWebApplicationContext
- 除了擁有GenericApplicationContext的功能,由於還實現了ConfigurableWebApplicationContext介面,所以它可以操作ServletContext類、ServletConfig和setConfigLocations,相當於由於還實現了ConfigurableWebApplicationContext介面的具體方法實現;同時它重寫了postProcessBeanFactory(ConfigurableListableBeanFactory),放入ServletContext相關類(ServletContextAwareProcessor、ServletContextAware)
/**
* 適用於web environments的GenericApplicationContext子類
* 實現ConfigurableWebApplicationContext的目的被設計用來用於程式化設定, 例如用於構建內部的contexts或者和WebApplicationInitializers一起使用
* 如果你想實現一個可以從配置檔案讀取bean definitions的WebApplicationContext
考慮使用AbstractRefreshableWebApplicationContext.loadBeanDefinitions方法
*/
public class GenericWebApplicationContext extends GenericApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {
private ServletContext servletContext;
private ThemeSource themeSource;
public GenericWebApplicationContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public GenericWebApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
}
public GenericWebApplicationContext(DefaultListableBeanFactory beanFactory, ServletContext servletContext) {
super(beanFactory);
this.servletContext = servletContext;
}
@Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext);
}
@Override
protected void initPropertySources() {
ConfigurableEnvironment env = getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
}
}
// ---------------------------------------------------------------------
// Pseudo-implementation of ConfigurableWebApplicationContext
// ---------------------------------------------------------------------
... ...
}
複製程式碼
EmbeddedWebApplicationContext
- 這個context繼承了GenericWebApplicationContext。它關聯一個EmbeddedServletContainerFactory,所以這個類不僅可以操作繼承GenericWebApplicationContext的ServletContext、ServletConfig相關方法,還可以操作EmbeddedServletContainer、ServletContextInitializer。而EmbeddedServletContainer、ServletContextInitializer是用來產生ServletContext、ServletConfig例項的
/**
* 它是一個包含EmbeddedServletContainerFactory類,用於自啟動的WebApplicationContext子類。
* 這個context可以通過在ApplicationContext本身中搜尋單個EmbeddedServletContainerFactory bean來建立、例項化、執行一個EmbeddedServletContainer。EmbeddedServletContainerFactory不受standard Spring concepts(such as dependency injection, lifecycle callbacks and property placeholder variables)的影響
* 此外,定義在context裡的任何Servlet和Filter beans都將自動註冊到嵌入式Servlet容器中。
* 單個Servlet bean時,'/' mapping被使用。多個Servlet beans時,小寫的bean name將作為mapping prefix。名字叫dispatcherServlet的Servlet總是mapped to '/'。Filter beans mapping to all URLs ('/*')
* 對於更多高階的配置,the context能改為定義實現ServletContextInitializer介面的beans(最常見的是ServletRegistrationBeans和/或FilterRegistrationBeans).
* 儘管這個context能直接用,但是大部分開發者應該使用AnnotationConfigEmbeddedWebApplicationContext或XmlEmbeddedWebApplicationContext
*/
public class EmbeddedWebApplicationContext extends GenericWebApplicationContext {
public static final String DISPATCHER_SERVLET_NAME = "dispatcherServlet";
private volatile EmbeddedServletContainer embeddedServletContainer;
private ServletConfig servletConfig;
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(
new WebApplicationContextServletContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
}
@Override
public final void refresh() {super.refresh();}
@Override
protected void onRefresh() {
super.onRefresh();
createEmbeddedServletContainer();}
}
@Override
protected void finishRefresh();
@Override
protected void onClose() {
super.onClose();
stopAndReleaseEmbeddedServletContainer();
}
private void createEmbeddedServletContainer();
protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory();
private ServletContextInitializer getSelfInitializer();
private void selfInitialize(ServletContext servletContext);
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
return new ServletContextInitializerBeans(getBeanFactory());
}
protected void prepareEmbeddedWebApplicationContext(ServletContext servletContext);
private EmbeddedServletContainer startEmbeddedServletContainer();
private void stopAndReleaseEmbeddedServletContainer();
public void setServletConfig(ServletConfig servletConfig);
public EmbeddedServletContainer getEmbeddedServletContainer();
複製程式碼
AnnotationConfigEmbeddedWebApplicationContext
這是spring boot預設例項化和使用的context
- 這個context繼承了EmbeddedWebApplicationContext,所有它擁有EmbeddedWebApplicationContext的能力。此外他有個非常重要的功能:掃描和讀取annotated bean classes和classPath下的classes。分別通過AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner來實現
/**
* 這個context接受annotated classes作為輸入,尤其是@Configuration-annotated classes, @Component 和@inject classes. 逐一註冊classes(指定class names作為 config location) 和指定base packages作為config location).
* Note: 當有多個@Configuration classes時, 較晚載入的@Bean definitions將會重寫較早載入的
*/
public class AnnotationConfigEmbeddedWebApplicationContext
extends EmbeddedWebApplicationContext {
// 可以掃描有兩個重要的屬性
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
private Class<?>[] annotatedClasses;
private String[] basePackages;
public AnnotationConfigEmbeddedWebApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotationConfigEmbeddedWebApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
public AnnotationConfigEmbeddedWebApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
@Override
public void setEnvironment(ConfigurableEnvironment environment) {
super.setEnvironment(environment);
this.reader.setEnvironment(environment);
this.scanner.setEnvironment(environment);
}
/**
* 提供一個自定義的BeanNameGenerator給AnnotatedBeanDefinitionReader and/or ClassPathBeanDefinitionScanner
* Any call to this method must occur prior to calls to #register(Class...) and/or #scan(String...)
*/
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.reader.setBeanNameGenerator(beanNameGenerator);
this.scanner.setBeanNameGenerator(beanNameGenerator);
this.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
beanNameGenerator);
}
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
this.reader.setScopeMetadataResolver(scopeMetadataResolver);
this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
/**
* 註冊一個或多個要處理的帶註釋的類。Register one or more annotated classes to be processed. Note:必須呼叫refresh()才能使the context完全處理新類.對register的呼叫是冪等的
*/
public final void register(Class<?>... annotatedClasses) {
this.annotatedClasses = annotatedClasses;
}
/**
* 對指定的base packages執行scan(掃描). Note:同register方法
*/
public final void scan(String... basePackages) {
this.basePackages = basePackages;
}
@Override
protected void prepareRefresh() {
this.scanner.clearCache();
super.prepareRefresh();
}
// 後置處理來執行scan and/or register方法
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.postProcessBeanFactory(beanFactory);
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
if (this.annotatedClasses != null && this.annotatedClasses.length > 0) {
this.reader.register(this.annotatedClasses);
}
}
}
複製程式碼
總結
- 本文沿著一個層級線介紹了一個線級的ApplicationContext,所以有小部分的子類沒有介紹到。spring boot就是通過這個線來完成自己的強大的功能的。下面總結一下這個層級線