spring applicationContext家族層級梳理

skyler發表於2018-09-25

applicationContext家族

applicationContext家族絕對是spring大劇場的核心成員,spring的幾大核心特性都涉及到的applicationContext,spring官網明白的寫著applicationContext所能做的事情,如下

spring applicationContext家族層級梳理
如上圖所示,applicationContext可以例項化bean,呼叫BeanPostProcessor、BeanFactoryPostProcessor、ApplicationEvent釋出事件。其實這張圖正好也顯示了BeanFactory和ApplicationContext的區別。

applicationContext家族絕對是中原第一大家族,分支眾多,盤根錯雜。ApplicationContext類是其家族族長,排名第一位。下面給出applicationContext家族圖譜,藉此試圖縷清applicationContext家族,家族成員間的關係如圖譜所示,主要成員的各自功能下面一一說來

spring 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

  • 這個類的具體功能就比較全了
  • 增加的主要屬性有
    屬性
  • 增加的主要方法有

spring applicationContext家族層級梳理

上圖列出了主要的方法,可以看出這些方法都是實現了其他類的方法,具有了很多的功能,我們實際開發中可以直接使用這些方法完成我們的需求,這也是我們的終極目的:不僅瞭解了原理,還能靈活使用,鑑於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就是通過這個線來完成自己的強大的功能的。下面總結一下這個層級線

spring applicationContext家族層級梳理

相關文章