javascript
Spring WebApplicationContext
WebApplicationContext是專門為web應用準備的,他允許從相對于web根目錄的路勁中裝載配置文件完成初始化工作,從WebApplicationContext中可以獲得ServletContext的引用,整個Web應用上下文對象將作為屬性放置在ServletContext中,以便web應用可以訪問spring上下文,spring中提供WebApplicationContextUtils的getWebApplicationContext(ServletContext src)方法來獲得WebApplicationContext對象
繼承結構
WebApplicationContext
WebApplicationContext擴展了ApplicationContext的Web應用能力。WebApplicationContext中定義了一個常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文啟動時,WebApplicationContext以此為鍵放置在ServletContext屬性列表中。
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";/*** Name of the ServletContext environment bean in the factory.* @see javax.servlet.ServletContext*/String SERVLET_CONTEXT_BEAN_NAME = "servletContext";/*** Name of the ServletContext init-params environment bean in the factory.* <p>Note: Possibly merged with ServletConfig parameters.* 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 attributes environment bean in the factory.* @see javax.servlet.ServletContext#getAttributeNames()* @see javax.servlet.ServletContext#getAttribute(String)*/String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";@NullableServletContext getServletContext();}ConfigurableWebApplicationContext
ConfigurableWebApplicationContext綜合了ConfigurableApplicationContext的配置能力以及WebApplicationContext的Web應用能力。
它允許通過配置的方式實例化WebApplicationContext,同時設置兩個重要方法:
//為spring設置web應用上下文,以便兩者整合 setServletContext(ServletContext context) //設置Spring配置的文件地址 setConfigLocations(String[]locations)?
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.* @see javax.servlet.ServletConfig*/String SERVLET_CONFIG_BEAN_NAME = "servletConfig";void setServletContext(@Nullable ServletContext servletContext);void setServletConfig(@Nullable ServletConfig servletConfig);@NullableServletConfig getServletConfig();void setNamespace(@Nullable String namespace);@NullableString getNamespace();void setConfigLocation(String configLocation);void setConfigLocations(String... configLocations);@NullableString[] getConfigLocations();}AbstractRefreshableApplicationContext
AbstractRefreshableApplicationContext繼承自AbstractApplicationContext,支持多次進行刷新(多次調用refresh方法),每次刷新時在內部創建一個新的bean工廠的實例。子類僅僅需要實現loadBeanDefinitions方法,該方法在每次刷新時都會調用。
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {//允許Bean定義覆蓋@Nullableprivate Boolean allowBeanDefinitionOverriding;@Nullable//允許解決循環引用private Boolean allowCircularReferences;/** Bean factory for this context. */@Nullableprivate DefaultListableBeanFactory beanFactory;/** Synchronization monitor for the internal 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;}/*** 重新加載BeanFactory,先銷毀再創建新的*/@Overrideprotected 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);}}@Overrideprotected void cancelRefresh(BeansException ex) {synchronized (this.beanFactoryMonitor) {if (this.beanFactory != null) {this.beanFactory.setSerializationId(null);}}super.cancelRefresh(ex);}@Overrideprotected final void closeBeanFactory() {synchronized (this.beanFactoryMonitor) {if (this.beanFactory != null) {this.beanFactory.setSerializationId(null);this.beanFactory = null;}}}/*** Determine whether this context currently holds a bean factory,* i.e. has been refreshed at least once and not been closed yet.*/protected final boolean hasBeanFactory() {synchronized (this.beanFactoryMonitor) {return (this.beanFactory != null);}}@Overridepublic 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;}}/*** Overridden to turn it into a no-op: With AbstractRefreshableApplicationContext,* {@link #getBeanFactory()} serves a strong assertion for an active context anyway.*/@Overrideprotected void assertBeanFactoryActive() {}/**默認為DefaultListableBeanFactory*/protected DefaultListableBeanFactory createBeanFactory() {return new DefaultListableBeanFactory(getInternalParentBeanFactory());}protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {if (this.allowBeanDefinitionOverriding != null) {beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.allowCircularReferences != null) {beanFactory.setAllowCircularReferences(this.allowCircularReferences);}}/*** 加載bean定義到給定beanFactory,通常通過 bean definition readers 加載*/protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)throws BeansException, IOException;}AbstractRefreshableConfigApplicationContext
AbstractRefreshableConfigApplicationContext繼承自AbstractRefreshableApplicationContext,添加了對指定的配置文件路徑的公共的處理(ConfigurableApplicationContext接口),可以把他看作基于XML的應用上下文的基類。實現了如下的兩個接口:
- BeanNameAware
用于設置上下文的bean的名稱,只有一個方法:void setBeanName(String name)
- InitializingBean
用于上下文一切就緒后,如果還未刷新,那么就執行刷新操作,只有一個方法:void afterPropertiesSet()
AbstractRefreshableWebApplicationContext
AbstractRefreshableWebApplicationContext繼承自AbstractRefreshableConfigApplicationContext,實現了ConfigurableWebApplicationContext和ThemeSource接口,主要是用于web環境下。在web程序啟動的時候,提供一個configLocations屬性,通過ConfigurableWebApplicationContext接口來進行填充。子類化這個接口是很簡單的,所有你所需要做的事情就是實現loadBeanDefinitions方法,來實現你自己的bean定義的加載邏輯。
?
AnnotationConfigWebApplicationContext
接受注解的類作為輸入(特殊的@Configuration注解類,一般的@Component注解類,與JSR-330兼容的javax.inject注解)。允許一個一個的注入,同樣也能使用類路徑掃描。對于web環境,基本上是和AnnotationConfigApplicationContext等價的。使用AnnotatedBeanDefinitionReader來對注解的bean進行處理,使用ClassPathBeanDefinitionScanner來對類路徑下的bean進行掃描。
屬性
@Nullableprivate BeanNameGenerator beanNameGenerator;@Nullableprivate ScopeMetadataResolver scopeMetadataResolver;private final Set<Class<?>> componentClasses = new LinkedHashSet<>();private final Set<String> basePackages = new LinkedHashSet<>();loadBeanDefinitions
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {//獲取注解bean定義 readerAnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);//獲取classpath bean定義 scannerClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);//獲取bean name生成器BeanNameGenerator beanNameGenerator = getBeanNameGenerator();if (beanNameGenerator != null) {reader.setBeanNameGenerator(beanNameGenerator);scanner.setBeanNameGenerator(beanNameGenerator);beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);}ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();if (scopeMetadataResolver != null) {reader.setScopeMetadataResolver(scopeMetadataResolver);scanner.setScopeMetadataResolver(scopeMetadataResolver);}//組件類,if (!this.componentClasses.isEmpty()) {if (logger.isDebugEnabled()) {logger.debug("Registering component classes: [" +StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");}//注冊組件類reader.register(ClassUtils.toClassArray(this.componentClasses));}if (!this.basePackages.isEmpty()) {if (logger.isDebugEnabled()) {logger.debug("Scanning base packages: [" +StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");}//掃描包scanner.scan(StringUtils.toStringArray(this.basePackages));}String[] configLocations = getConfigLocations();if (configLocations != null) {for (String configLocation : configLocations) {try {Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());if (logger.isTraceEnabled()) {logger.trace("Registering [" + configLocation + "]");}//注冊 配置reader.register(clazz);}catch (ClassNotFoundException ex) {if (logger.isTraceEnabled()) {logger.trace("Could not load class for config location [" + configLocation +"] - trying package scan. " + ex);}int count = scanner.scan(configLocation);if (count == 0 && logger.isDebugEnabled()) {logger.debug("No component classes found for specified class/package [" + configLocation + "]");}}}}}AnnotatedBeanDefinitionReader 參考:Spring BeanDefinition加載
ClassPathBeanDefinitionScanner 參考:Spring BeanDefinition加載???????
XmlWebApplicationContext
使用XML作為配置的Web應用。
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {/** 默認 config location. */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";@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's// resource loading environment.beanDefinitionReader.setEnvironment(getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions.initBeanDefinitionReader(beanDefinitionReader);loadBeanDefinitions(beanDefinitionReader);}/*** 初始化bean definition reader,默認為空*/protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {}/*** Load the bean definitions with the given XmlBeanDefinitionReader.*/protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {String[] configLocations = getConfigLocations();if (configLocations != null) {for (String configLocation : configLocations) {reader.loadBeanDefinitions(configLocation);}}}@Overrideprotected String[] getDefaultConfigLocations() {if (getNamespace() != null) {return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};}else {return new String[] {DEFAULT_CONFIG_LOCATION};}}}XmlBeanDefinitionReader 參考:
?
ServletContext
webApplicationContext初始化需要ServletContext,也就是說需要web容器前提下才能完成啟動工作 ?,可以通過在web.xml中配置自啟動Servlet或Web容器監聽來實現web容器的啟動
Spring提供啟動WebApplicationContext的servlet和Web容器監聽器org.springframework.web.context.ContextLoaderListener?
Xml配置方式
!--從類路徑下加載Spring配置文件,classpath特指類路徑下加載--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:smart-context.xml</param-value></context-param><!--負責啟動spring容器的監聽器 還可以聲明自啟動的Servlet ContextLoaderServlet--><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>@Configuration配置方式
<!--通過指定context參數,讓Spring使用AnnotationConfigWebApplicationContext啟動容器而非XmlWebApplicationContext 默認沒配置時是使用XmlWebApplicationContext--><context-param><param-name>contextClass</param-name><param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value></context-param> <!--指定標注了@Configuration的類,多個可以用逗號分隔--><context-param><param-name>contextConfigLocation</param-name><param-value>com.example.Car,com.example.Boss</param-value></context-param><!--監聽器將根據上面的配置使用AnnotationConfigWebApplicationContext根據contextConfigLocation指定的配置類啟動Spring容器--><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>?
總結
以上是生活随笔為你收集整理的Spring WebApplicationContext的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring DefaultListab
- 下一篇: Spring-- Application