亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發(fā)設計 > 正文

Spring4.3.x 容器在web應用中的初始化過程

2019-11-10 20:16:00
字體:
來源:轉載
供稿:網(wǎng)友

概述

SPRing在web應用中的默認容器類為xmlWebapplicationContext,這個容器類通過xml文件獲取所有的配置信息。它的繼承結構如下圖,(點此查看大圖) XmlWebApplicationContext繼承結構

在web應用中,不管是ContextLoaderListener,還是DispatcherServlet初始化的時候,都是以XmlWebApplicationContext為默認容器。在下面的研究中,我將以ContextLoaderListener的初始化過程介紹spring容器在web應用的初始化。

ContextLoaderListener的初始化過程中最主要的任務時加載spring容器,并把此容器加入到ServletContext中作為整個web應用的跟容器。ContextLoaderListener加載spring容器大致分為兩個階段,第一個階段是解析web.xml文件中的初始化參數(shù)以對spring容器做定制化操作,簡單的說就是定制spring容器;第二階段是spring容器的刷新過程。下面分別對這兩個階段進行探討。

第一階段 定制spring容器

ContextLoaderListener實現(xiàn)了ServletContextListener,因此web容器啟動的時候就會執(zhí)行它的contextInitialized方法,此方法的代碼如下。

public void contextInitialized(ServletContextEvent event) { // 獲取ContextLoader對象 this.contextLoader = createContextLoader(); if (this.contextLoader == null) { this.contextLoader = this; } this.contextLoader.initWebApplicationContext(event.getServletContext()); } @Override public void contextInitialized(ServletContextEvent event) { // 執(zhí)行父類ContextLoader的initWebApplicationContext方法 initWebApplicationContext(event.getServletContext()); }

這段代碼主要是調(diào)用父類ContextLoader的initWebApplicationContext(ServletContext servletContext)方法,下面是initWebApplicationContext方法在ContextLoader類中的代碼。

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { // 檢查ServletContext是否已經(jīng)有了根容器 if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader* definitions in your web.xml!"); } Log logger = LogFactory.getLog(ContextLoader.class); servletContext.log("Initializing Spring root WebApplicationContext"); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } long startTime = System.currentTimeMillis(); try { if (this.context == null) { // 創(chuàng)建容器,據(jù)contextClass初始化參數(shù)指定或者使用默認的XmlWebApplicationContext類 this.context = createWebApplicationContext(servletContext); } if (this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; if (!cwac.isActive()) { // 如果容器沒有被刷新,執(zhí)行以下操作 // 設置父容器 if (cwac.getParent() == null) { // 加載父容器。 // 通過locatorFactorySelector上下文初始化參數(shù)指定父容器所在的配置文件路徑 // 通過parentContextKey上下文初始化參數(shù)指定父容器的名稱 ApplicationContext parent = loadParentContext(servletContext); cwac.setParent(parent); } // 配置并執(zhí)行容器刷新操作 configureAndRefreshWebApplicationContext(cwac, servletContext); } } // 把spring容器加入到ServletContext中作為根容器 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ClassLoader ccl = Thread.currentThread().getContextClassLoader(); if (ccl == ContextLoader.class.getClassLoader()) { currentContext = this.context; } else if (ccl != null) { currentContextPerThread.put(ccl, this.context); } if (logger.isDebugEnabled()) { logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); } if (logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); } return this.context; } catch (RuntimeException ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; } catch (Error err) { logger.error("Context initialization failed", err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; } }

這段代碼分成4步,首先通過調(diào)用ContextLoader的createWebApplicationContext(ServletContext sc)方法來創(chuàng)建spring容器,然后設置spring容器的父容器,接著調(diào)用ContextLoader的configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc)方法來配置并刷新spring容器,最后把容器保存到servlet容器中。最后一步的代碼已經(jīng)在上面體現(xiàn)了,下面我們來解析前三步的代碼。

1. 創(chuàng)建spring容器。

調(diào)用ContextLoader的createWebApplicationContext(ServletContext sc)方法,這個方法的代碼如下。

protected WebApplicationContext createWebApplicationContext(ServletContext sc) { // 獲取容器類對象 Class<?> contextClass = determineContextClass(sc); if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); } // 使用容器類對象來實例化容器 return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); }

上面主要是通過ContextLoader的determineContextClass(ServletContext servletContext)方法獲取容器類對象,然后實例化容器。下面是determineContextClass方法的代碼。

/** * 獲取容器類對象 **/ protected Class<?> determineContextClass(ServletContext servletContext) { // 聲明:public static final String CONTEXT_CLASS_PARAM = "contextClass"; String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); if (contextClassName != null) { try { return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader()); } catch (ClassNotFoundException ex) { throw new ApplicationContextException( "Failed to load custom context class [" + contextClassName + "]", ex); } } else { contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); try { return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); } catch (ClassNotFoundException ex) { throw new ApplicationContextException( "Failed to load default context class [" + contextClassName + "]", ex); } } }

determineContextClass從ServletContext對象中獲取contextClass初始化參數(shù)的值,如果這個參數(shù)有值,則使用這個參數(shù)指定的容器類,否則使用默認的容器類XmlWebApplicationContext。如果不使用spring的默認容器,可以在web.xml中通過配置contextClass指定其他容器類,比如。

<!-- 定義contextClass參數(shù) --> <context-param> <param-name>contextClass</param-name> <param-value> com.chyohn.context.XmlWebApplicationContext </param-value> </context-param>

2. 指定父容器。

創(chuàng)建完spring容器后,initWebApplicationContext中會調(diào)用ContextLoader的 loadParentContext(ServletContext servletContext)方法來獲取父容器,并把這個父容器與剛創(chuàng)建的容器關聯(lián)上。loadParentContext方法的代碼如下。

protected ApplicationContext loadParentContext(ServletContext servletContext) { ApplicationContext parentContext = null; // 聲明:public static final String LOCATOR_FACTORY_SELECTOR_PARAM = "locatorFactorySelector"; String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM); // 聲明:public static final String LOCATOR_FACTORY_KEY_PARAM = "parentContextKey"; String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM); if (parentContextKey != null) { // locatorFactorySelector可能會為null, 則會使用默認的 "classpath*:beanRefContext.xml" BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector); Log logger = LogFactory.getLog(ContextLoader.class); if (logger.isDebugEnabled()) { logger.debug("Getting parent context definition: using parent context key of '" + parentContextKey + "' with BeanFactoryLocator"); } this.parentContextRef = locator.useBeanFactory(parentContextKey); parentContext = (ApplicationContext) this.parentContextRef.getFactory(); } return parentContext; }

這里通過ServletContext 獲取初始化參數(shù)locatorFactorySelector指定的定義父容器的xml文件的地址,同時獲取初始化參數(shù)parentContextKey指定的父容器在前面xml文件中設置的bean名稱。下面是一個列子。

第一步在classes路徑下創(chuàng)建名為parentBeanRefContext.xml的xml文件(名稱可以隨便取),我這里的內(nèi)容如下。

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <!-- 指定容器 --> <bean id="parentContext" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <list> <value>parentOfRootContext.xml</value> </list> </constructor-arg> </bean></beans>

其中parentOfRootContext.xml文件為一個普通的spring配置文件,這里就不舉例了。

第二步,在web.xml文件中做如下配置。

<!-- 定義locatorFactorySelector參數(shù) --> <context-param> <param-name>locatorFactorySelector</param-name> <param-value> classpath:parentBeanRefContext.xml </param-value> </context-param> <!-- 定義parentContextKey參數(shù) --> <context-param> <param-name>parentContextKey</param-name> <param-value>parentContext</param-value> </context-param>

這樣就向容器中指定了一個父容器。在這里如果在第一步中創(chuàng)建的xml文件的名稱為beanRefContext.xml,那么在web.xml文件中就不用配置locatorFactorySelector參數(shù)。

3. 配置并刷新spring容器

設置了父容器后,執(zhí)行ContextLoader的configureAndRefreshWebApplicationContext方法,在容器刷新前對容器進行初始化配置,代碼如下

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // 為容器設置一個有用的ID // 聲明:public static final String CONTEXT_ID_PARAM = "contextId"; String idParam = sc.getInitParameter(CONTEXT_ID_PARAM); if (idParam != null) { wac.setId(idParam); } else { // 生成一個默認ID if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) { // servlet 2.5以前的版本 wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getServletContextName())); } else { // servlet 2.5及其以上的版本wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath())); } } } // 把ServletContext保存到容器中 wac.setServletContext(sc); // 設置容器要加載的配置文件所在的路徑 // 通過contextConfigLocation上下文參數(shù)指定配置文件路徑 // 聲明:public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation"; String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM); if (initParameter != null) { wac.setConfigLocation(initParameter); } // 在容器刷新前,自定義容器。 // 執(zhí)行用戶通過contextInitializerClasses上下文參數(shù)指定的容器初始化器 customizeContext(sc, wac); // 刷新容器 wac.refresh(); } protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // 為容器設置一個有用的ID // 聲明:public static final String CONTEXT_ID_PARAM = "contextId"; String idParam = sc.getInitParameter(CONTEXT_ID_PARAM); if (idParam != null) { wac.setId(idParam); } else { // 創(chuàng)建一個默認的id wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath())); } } // 把ServletContext保存到容器中 wac.setServletContext(sc); // 設置容器要加載的配置文件所在的路徑 // 通過contextConfigLocation上下文參數(shù)指定配置文件路徑 // 聲明:public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation"; String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM); if (configLocationParam != null) { wac.setConfigLocation(configLocationParam); } // 提前執(zhí)行容器環(huán)境對象的initPropertySources方法,以確保servlet屬性資源可應用于容器刷新前的任何初始化操作。 ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(sc, null); } // 在容器刷新前,自定義容器。 // 執(zhí)行用戶通過contextInitializerClasses上下文參數(shù)指定的容器初始化器 customizeContext(sc, wac); // 刷新容器 wac.refresh(); }

這段代碼處理配置在web.xml中的2個初始化參數(shù),第一個是用于標志容器id的contextId初始化參數(shù),第二是用于指定配置文件地址的contextConfigLocation初始化參數(shù)。對于contextId參數(shù)沒有過多的探討,至于contextConfigLocation參數(shù),可以配置,也可以不配置。如果需要通過contextConfigLocation參數(shù)指定多個配置文件,配置文件地址之間可以通過英文逗號、分號、空格、制表符、換行符隔開。如果沒有配置contextConfigLocation參數(shù),XmlWebApplicationContext將使用WEB-INF目錄下的默認配置文件地址,代碼如下。

/** Default config location for the root context */ public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"; /** Default prefix for building a config location for a namespace */ public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"; /** Default suffix for building a config location for a namespace */ 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 { // 返回配置地址/WEB-INF/applicationContext.xml return new String[] {DEFAULT_CONFIG_LOCATION}; } }

根據(jù)這段代碼,可以獲得兩個信息。 其一:如果spring容器有命名空間,則開發(fā)者可以在WEB-INF目錄下創(chuàng)建以命名空間為名稱的xml配置文件。 其二:如果spring容器沒有命名空間,則開發(fā)者可以在WEB-INF目錄下創(chuàng)建以applicationContext為名稱的xml配置文件。

在configureAndRefreshWebApplicationContext方法中還調(diào)用ContextLoader的customizeContext方法來執(zhí)行用戶指定ApplicationContextInitializer對象,下面是customizeContext方法的代碼。

protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) { // 獲取ApplicationContextInitializer類對象列表 List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses = determineContextInitializerClasses(servletContext); if (initializerClasses.size() == 0) { // 沒有指定任何 ApplicationContextInitializers對象,則什么都不做,直接返回 return; } Class<?> contextClass = applicationContext.getClass(); ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerInstances = new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>(); for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) { // 從initializerClass對象獲取ApplicationContextInitializer的泛型類對象 Class<?> initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class); // 檢查contextClass是否是initializerContextClass類對象指定的類的實現(xiàn) Assert.isAssignable(initializerContextClass, contextClass, String.format( "Could not add context initializer [%s] as its generic parameter [%s] " + "is not assignable from the type of application context used by this " + "context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(), contextClass.getName())); initializerInstances.add(BeanUtils.instantiateClass(initializerClass)); } ConfigurableEnvironment env = applicationContext.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { // 初始化Property資源 ((ConfigurableWebEnvironment)env).initPropertySources(servletContext, null); } // 一個一個的執(zhí)行ApplicationContextInitializer對象 Collections.sort(initializerInstances, new AnnotationAwareOrderComparator()); for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : initializerInstances) { initializer.initialize(applicationContext); } }

這段代碼主要是調(diào)用ContextLoader對象的determineContextInitializerClasses方法來獲取ApplicationContextInitializer類對象列表,并使用每個ApplicationContextInitializer對象來對spring容器做更多的初始化操作。下面是determineContextInitializerClasses的代碼。

protected List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> determineContextInitializerClasses(ServletContext servletContext) { List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> classes = new ArrayList<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>>(); // 從ServletContext中獲取應用于所有spring web應用容器的ApplicationContextInitializer實現(xiàn)類全名稱 // 聲明有:public static final String GLOBAL_INITIALIZER_CLASSES_PARAM = "globalInitializerClasses"; String globalClassNames = servletContext.getInitParameter(GLOBAL_INITIALIZER_CLASSES_PARAM); if (globalClassNames != null) { for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) { classes.add(loadInitializerClass(className)); } } // 從ServletContext中獲取專為為此容器指定的ApplicationContextInitializer實現(xiàn)類全名稱 // 聲明:public static final String CONTEXT_INITIALIZER_CLASSES_PARAM = "contextInitializerClasses"; String localClassNames = servletContext.getInitParameter(CONTEXT_INITIALIZER_CLASSES_PARAM); if (localClassNames != null) { for (String className : StringUtils.tokenizeToStringArray(localClassNames, INIT_PARAM_DELIMITERS)) { classes.add(loadInitializerClass(className)); } } return classes; } private Class<ApplicationContextInitializer<ConfigurableApplicationContext>> loadInitializerClass(String className) { try { Class<?> clazz = ClassUtils.forName(className, ClassUtils.getDefaultClassLoader()); Assert.isAssignable(ApplicationContextInitializer.class, clazz); return (Class<ApplicationContextInitializer<ConfigurableApplicationContext>>) clazz; } catch (ClassNotFoundException ex) { throw new ApplicationContextException("Failed to load context initializer class [" + className + "]", ex); } }

determineContextInitializerClasses方法從ServletContext中獲取初始化參數(shù)contextInitializerClasses和globalInitializerClasses的值,這個值指定了用戶自定義的ApplicationContextInitializer實現(xiàn)類全名稱。然后根據(jù)類的全名稱創(chuàng)建Class對象。其中如果需要指定多個ApplicationContextInitializer實現(xiàn)類,那么實現(xiàn)類的全名稱之間使用英文逗號隔開,比如下面的配置。

<!-- 定義globalInitializerClasses參數(shù) --> <context-param> <param-name>globalInitializerClasses</param-name> <param-value> com.damuzee.web.app.GlobalApplicationContextInitializer1, com.damuzee.web.app.GlobalApplicationContextInitializer2, com.damuzee.web.app.GlobalApplicationContextInitializer3 </param-value> </context-param> <!-- 定義contextInitializerClasses參數(shù) --> <context-param> <param-name>contextInitializerClasses</param-name> <param-value> com.damuzee.web.app.XmlApplicationContextInitializer1, com.damuzee.web.app.XmlApplicationContextInitializer2, com.damuzee.web.app.XmlApplicationContextInitializer3 </param-value> </context-param>

到此,在web應用中spring容器初始化的第一個階段就完成了。configureAndRefreshWebApplicationContext方法通過調(diào)用容器的refresh()方法進入容器初始化的第二階段——容器的刷新過程

第二階段: 容器的刷新過程

關于spring容器的刷新過程已經(jīng)在另一篇文章中描述了,詳見 Spring ApplicationContext的刷新過程

總結

在spring容器初始化的第一個階段,我們可以通過web.xml文件的配置來定制spring容器。通過web.xml文件,我們可以指定其他容器類、父容器、容器的id、需要加載的配置文件地址、以及自定義容器初始化器ApplicationContextInitializer對象。具體例子如下。

通過設置contextClass參數(shù)指定容器,例如 <context-param> <param-name>contextClass</param-name> <param-value> com.chyohn.context.XmlWebApplicationContext </param-value> </context-param>設置locatorFactorySelector和parentContextKey參數(shù)指定父容器,例如 <!-- 定義locatorFactorySelector參數(shù) --> <context-param> <param-name>locatorFactorySelector</param-name> <param-value> classpath:parentBeanRefContext.xml </param-value> </context-param> <!-- 定義parentContextKey參數(shù) --> <context-param> <param-name>parentContextKey</param-name> <param-value>parentContext</param-value> </context-param>

上面的parentBeanRefContext.xml配置如下

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <!-- 指定容器 --> <bean id="parentContext" class="org.springframework.context.support.ClassPathXmlApplicationContext"> <constructor-arg> <list> <value>parentOfRootContext.xml</value> </list> </constructor-arg> </bean></beans> 設置contextId參數(shù)指定容器的Id,配置如下。 <context-param> <param-name>contextId</param-name> <param-value>myContextId</param-value> </context-param>設置contextConfigLocation參數(shù)指定加載的配置文件地址,配置如下。 <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:webApplicationContent.xml classpath:application-service.xml </param-value> </context-param>設置contextInitializerClasses參數(shù)指定容器初始化器,該初始化器將在容器刷新前執(zhí)行,如果有多個初始化器,使用英文逗號“,”隔開,例如 <!-- 定義contextInitializerClasses參數(shù) --> <context-param> <param-name>contextInitializerClasses</param-name> <param-value> com.damuzee.web.app.XmlApplicationContextInitializer1, com.damuzee.web.app.XmlApplicationContextInitializer2, com.damuzee.web.app.XmlApplicationContextInitializer3 </param-value> </context-param>設置globalInitializerClasses參數(shù)指定所有容器公共的初始化器,該初始化器將在容器刷新前執(zhí)行,如果有多個初始化器,使用英文逗號“,”隔開,例如 <!-- 定義globalInitializerClasses參數(shù) --> <context-param> <param-name>globalInitializerClasses</param-name> <param-value> com.damuzee.web.app.GlobalApplicationContextInitializer1, com.damuzee.web.app.GlobalApplicationContextInitializer2, com.damuzee.web.app.GlobalApplicationContextInitializer3 </param-value> </context-param>

有了ApplicationContextInitializer對象,可以對容器的初始化做更多操作,比如設置容器id、設置父容器、設置加載的配置文件地址、添加容器級的bean工廠后處理器、監(jiān)聽器等等。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
黄色成人在线观看| 毛片电影在线| 亚洲开发第一视频在线播放| 精品国产鲁一鲁一区二区三区| 亚洲欧美日韩精品| 日韩电影在线一区二区| 超碰中文字幕在线观看| 美女精品久久久| 91黄色在线| 国产精品探花在线观看| 午夜视频在线| 午夜激情视频在线| 黄色动漫在线免费看| 麻豆国产欧美一区二区三区| 亚洲精品国产综合久久| 日韩a∨精品日韩在线观看| 在线精品国精品国产尤物884a| 久久这里只有精品首页| 第一区第二区在线| 日韩欧美激情四射| 亚洲精品国产欧美在线观看| 亚洲精品中文在线观看| 色狠狠av一区二区三区香蕉蜜桃| 久久久人成影片一区二区三区在哪下载| 色婷婷激情五月| 精品视频1区2区| 久久激情五月丁香伊人| 日韩精品中文字幕在线| 黄色激情在线观看| 国产在线精品一区二区三区不卡| 日韩乱码一区二区| 91精品国产免费久久久久久| 欧洲亚洲视频| 国产特级毛片| 国产xxx在线观看| 中文字幕av一区二区三区谷原希美| sesexxxx| 中文字幕久久久av一区| 久久亚洲精品石原莉奈| 一区二区三区在线免费播放| 蜜桃视频m3u8在线观看| 欧美tickling网站挠脚心| 97超碰人人爱| 懂色av蜜臀av粉嫩av分享吧| 欧美日韩在线网站| 免费观看91视频大全| 亚洲精品无码久久久久久久| 亚洲欧美日韩国产综合| 麻豆精品久久久| 狠狠色伊人亚洲综合网站l| 中文字幕精品一区| 亚洲一区二区三区四区五区黄| 特级毛片www| 精品一区在线观看视频| 亚洲黄色av一区| 亚洲国产精品v| 亚洲最大成人免费视频| 久久国内精品自在自线400部| 国产精品偷伦免费视频观看的| 综合激情国产一区| 欧美黄页在线免费观看| 亚洲999一在线观看www| 国产风韵犹存在线视精品| 欧美日韩国产免费观看视频| 欧美男女交配| 国产一区免费电影| 日韩高清不卡在线| 91福利国产成人精品播放| 欧美性感美女一区二区| 日本理论中文字幕| 午夜福制92视频| 看全色黄大色大片免费久久久| 性感少妇一区| 亚洲一区二区在线免费观看视频| 欧美日韩成人精品| 中国女人做爰视频| 午夜大片在线观看| 日韩欧美视频第二区| 美女视频黄 久久| 午夜精品久久久久久99热| 91亚洲大成网污www| 亚洲丁香日韩| 国产精品亚洲网站| 国产黄在线播放| 亚洲视频你懂的| 尤物视频在线观看视频| 久久久久久亚洲精品中文字幕| 日本在线人成| 亚洲欧美另类图片| 激情偷乱视频一区二区三区| 黄页网站大全在线观看| 欧美一级黑人aaaaaaa做受| 在线观看国产91| 狠狠色丁香久久婷婷综合_中| 91丨九色丨黑人外教| 成人激情视频在线| 在线观看一区二区三区四区| 久久精品夜夜夜夜夜久久| 91高清视频免费观看| 免费成年网站| 国产呦系列欧美呦日韩呦| 免费国产成人av| av黄色免费网站| 亚洲小说欧美另类激情| 日日夜夜免费精品视频| 丝袜美腿高跟呻吟高潮一区| 欧美一级黄色录像| 可以在线观看的av网站| 99精品在线观看| 国产激情视频一区| 伊人免费在线观看高清版| 国产精品一区二区三区久久| 电影在线观看一区| 成人情视频高清免费观看电影| 欧美一区二区三区网站| 中文字幕 自拍| 天堂电影在线| 国产98在线|日韩| 日韩mv欧美mv国产网站| 国产1区2区在线观看| 日本v片在线免费观看| 色偷偷av亚洲男人的天堂| 激情成人综合| 成年人午夜视频在线观看| 欧美日韩亚洲国产综合| 午夜精品福利视频网站| 99国产精品久久一区二区三区| 国产少妇在线观看| 国产精品丝袜久久久久久消防器材| 亚洲自拍偷拍一区二区三区| 欧美激情女人20p| 成人av免费在线看| 丰满人妻一区二区三区四区| 亚洲成人一级片| 欧美日韩国产丝袜美女| 四季av一区二区三区| 日本成年人网址| 北条麻妃av高潮尖叫在线观看| 日本精品视频一区二区| 国内自拍在线观看| 国产日韩v精品一区二区| 午夜精品福利一区二区蜜股av| 成人一对一视频| 精品国产一区二区三区香蕉沈先生| 国产亚洲精品久久久久久打不开| 亚洲图片欧美日韩| 精品欧美激情在线观看| 久久国内精品视频| 手机在线看片日韩| 国产精品乱码一区二区三区软件| a级黄色毛片| 性日韩欧美在线视频| 欧美在线激情| 色综合天天综合网中文字幕| 亚洲综合日韩中文字幕v在线| 久久久一区二区三区不卡| jizzjizzjizz亚洲女| 国产成人亚洲精品无码h在线| 午夜不卡在线视频| 不卡视频一区二区| 亚洲人的天堂男人爽爽爽| 国产精品日韩成人| 国产淫片在线观看| 麻豆精品国产自产在线| 麻豆一区二区三区精品视频| 五月天在线免费视频| 亚洲天堂色网站| 久久无码精品丰满人妻| 精品成人自拍视频| 欧美精品久久久久久久久久| 欧美日韩中文字幕视频| 国精品日韩欧美一区二区三区| 亚洲人成电影网站色xx| 亚洲精品免费在线观看| 97干com| 亚洲女与黑人做爰| 青青青青久久精品国产一百度| 欧美色成人综合| 青春草国产成人精品久久| 99re国产在线播放| 蜜臀在线观看| 污污网站免费看| 手机在线精品视频| 在线不卡欧美精品一区二区三区| 乱中年女人av三区中文字幕| 国产精品 日产精品 欧美精品| 免费福利在线视频| 日本在线观看视频| 精品国产麻豆| 成视频在线观看免费观看| 日韩免费视频一区二区| 成人午夜精品在线| 成人黄色网页| 欧美日韩性视频一区二区三区| 国产一区不卡在线观看| 超污网站在线观看| 国产三级精品三级在线观看国产| 一区二区三区中文字幕在线观看| 国产精品欧美大片| 欧美亚洲丝袜| 18成人免费观看视频| 欧美在线二区| 久久大香伊蕉在人线观看热2| 18视频在线观看| 欧美片在线播放| 亚洲午夜免费福利视频| 精品无人区乱码1区2区3区在线| 精品欧美国产一区二区三区| 国产情侣自拍小视频| 欧美xxxx性xxxxx高清视频| 欧美性受xxxx免费视频| 精品爆乳一区二区三区无码av| 黄色的电影在线-骚虎影院-骚虎视频| 欧美午夜电影在线播放| 国产又黄又粗又爽| 国内精品久久久久国产| 成人私拍视频| 亚洲 欧美 激情 另类| 亚洲草久电影| 美女一区二区久久| 一级片免费在线观看| 国产人成一区二区三区影院| 日韩欧美高清视频| 美女一区二区三区视频| 日韩成人黄色片| 久久白虎精品| 精品免费av在线| 午夜影院免费看| 性欧美长视频免费观看不卡| 国产视频三区| 日本成人网址| 二区三区四区高清视频在线观看| 香蕉久久精品| 国产一区二区三区精品欧美日韩一区二区三区| 在线观看毛片av| 欧美极品在线观看| 午夜精彩视频| 日韩av在线天堂网| 软萌小仙自慰喷白浆| 99热这里有精品| 久久午夜宅男免费网站| 亚洲综合网在线| 伊人久久大香线蕉精品| 亚洲一区美女视频在线观看免费| 狠狠躁少妇一区二区三区| 91国产精品一区| 国产欧美日韩精品a在线观看| 日本黄色免费在线| a网站在线观看| 狠狠噜天天噜日日噜| 欧美日韩五区| 538prom精品视频线放| 国产精品一区二区果冻传媒| 自拍偷拍你懂的| 亚洲男女自偷自拍| japan高清日本乱xxxxx| 2023av视频| 男女视频一区二区| 久久精彩视频| 51色欧美片视频在线观看| 嫩草香蕉在线91一二三区| 电影一区电影二区| 成人小视频免费观看| 成人黄色中文字幕| 136导航精品福利| 一道在线中文一区二区三区| 特级毛片在线观看| 欧美又粗又大又爽| 欧美日韩午夜精品| 爱情电影社保片一区| 国产精品高清网站| 无码人妻久久一区二区三区| 99国产精品久久久| 日本福利一区| 欧美日韩久久一区二区| 99久精品国产| 欧美日韩一区二区三区免费| 成人网视频在线观看| 美女高潮网站| 性中国古装videossex| 国产欧美综合一区二区三区| 亚洲一区二区三区午夜| 免费日韩成人| xxxx性bbbb欧美野外| 久久夜色精品国产欧美乱极品| 99re免费视频精品全部| 国产精品日韩欧美大师| 久久久久久欧美精品色一二三四| 欧美在线性爱视频| 国产又猛又黄的视频| 成人综合色站| 色欧美自拍视频| 老司机午夜网站| 成人在线免费观看视视频| 日韩欧美三级视频| 成人在线视频首页| shkd中文字幕久久在线观看| 97超碰免费在线| 久久婷婷成人综合色| 日本视频www色| 三级成人黄色影院| 国产伦精品一区二区三区视频| 写真福利精品福利在线观看| 成人精品久久av网站| 九九视频免费观看| 福利小视频在线| 国产欧美三级电影| 成人免费91在线看| 夜色激情一区二区| 在线www天堂网在线| 免费国产精品视频| 久久久久无码国产精品一区李宗瑞| 久久精品不卡| 色94色欧美sute亚洲线路二| 免费涩涩18网站入口| 欧美精品一区二区三区精品| 国产一区二区不卡视频在线观看| 黄a免费视频| 亚洲在线免费播放| 亚洲欧美se| 久久久婷婷一区二区三区不卡| 亚洲福利一区二区三区| 7777精品伊人久久久大香线蕉经典版下载| zztt21.su黑料网站| 国内精品伊人久久久久av一坑| 亚洲av少妇一区二区在线观看| 国产成人一区二| 久久99久国产精品黄毛片入口|