隨筆 - 9, 文章 - 0, 評論 - 3, 引用 - 0
          數(shù)據(jù)加載中……

          初探spring applicationContext在web容器中加載過程

          轉(zhuǎn)載自www.javaworld.com.tw 袁杰 原文

          首先從WEB.XML入手

          ==>web.xml

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          <context-param>
                      <param-name>webAppRootKey</param-name>
                      <param-value>task.root</param-value>
                      </context-param>
                      <!-- 定義SPRING配置文件 -->
                      
                      <context-param>
                      <param-name>contextConfigLocation</param-name>
                      <param-value>/WEB-INF/taskContext*.xml</param-value>
                      </context-param>
                      
                      <context-param>
                      <param-name>log4jConfigLocation</param-name>
                      <param-value>/WEB-INF/log4j.properties</param-value>
                      </context-param>
                      <!-- 定義LOG4J監(jiān)聽器 -->
                      <listener>
                      <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
                      </listener>
                       
                      <!-- 定義SPRING監(jiān)聽器 -->
                      
                      <listener>
                      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
                      </listener>
                      
                      

          進入contextLoaderListener看看到底加載時做了甚么
          ==>org.springframework.web.context.ContextLoaderListener

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          public class ContextLoaderListener implements ServletContextListener {
                       
                      private ContextLoader contextLoader;
                       
                      /**
                      * Initialize the root web application context.
                      */
                      //當WEB上下文初始化時,系統(tǒng)會調(diào)用此方法
                      public void contextInitialized(ServletContextEvent event) {
                      this.contextLoader = createContextLoader();
                       
                      
                      //監(jiān)聽到WEB上下文初始化的時候執(zhí)行SPRING上下文contextLoader的初始化工作
                      this.contextLoader.initWebApplicationContext(event.getServletContext());
                      
                      }
                       
                      /**
                      * Create the ContextLoader to use. Can be overridden in subclasses.
                      * @return the new ContextLoader
                      */
                      protected ContextLoader createContextLoader() {
                      return new ContextLoader();
                      }
                       
                      /**
                      * Return the ContextLoader used by this listener.
                      */
                      public ContextLoader getContextLoader() {
                      return contextLoader;
                      }
                       
                      /**
                      * Close the root web application context.
                      */
                      public void contextDestroyed(ServletContextEvent event) {
                      if (this.contextLoader != null) {
                      this.contextLoader.closeWebApplicationContext(event.getServletContext());
                      }
                      }
                       
                      }
                      

          看一下是怎么來初始化webapplicationContext的
          ==>contextLoader.initWebApplicationContext

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          50
          51
          52
          53
          54
          55
          56
          57
          58
          59
          60
          public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
                      throws IllegalStateException, BeansException {
                       
                      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!");
                      }
                       
                      long startTime = System.currentTimeMillis();
                      if (logger.isInfoEnabled()) {
                      logger.info("Root WebApplicationContext: initialization started");
                      }
                      servletContext.log("Loading Spring root WebApplicationContext");
                       
                      try {
                      // Determine parent for root web application context, if any.
                      ApplicationContext parent = loadParentContext(servletContext);
                       
                      // Store context in local instance variable, to guarantee that
                      // it is available on ServletContext shutdown.
                       
                      
                      //創(chuàng)建web上下文
                      this.context = createWebApplicationContext(servletContext, parent);
                      servletContext.setAttribute(
                      WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
                      
                       
                      if (logger.isInfoEnabled()) {
                      logger.info("Using context class [" + this.context.getClass().getName() +
                      "] for root WebApplicationContext");
                      }
                      if (logger.isDebugEnabled()) {
                      logger.debug("Published root WebApplicationContext [" + this.context +
                      "] 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;
                      }
                      }
                      

          ==>contextLoader.createWebApplicationContext(servletContext, parent);

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
           protected WebApplicationContext createWebApplicationContext(
                      ServletContext servletContext, ApplicationContext parent) throws BeansException {
                      
                      //根據(jù)servletContext來決定要實例化的WebApplicationContext
                      Class contextClass = determineContextClass(servletContext);
                      if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
                      throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
                      "] is not of type ConfigurableWebApplicationContext");
                      }
                      ConfigurableWebApplicationContext wac =
                      (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
                      wac.setParent(parent);
                      wac.setServletContext(servletContext);
                       
                      //得到WEB.XML中設置的SPRING配置文件位置
                      String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
                      if (configLocation != null) {
                      //把配置文件分段后設置到WebApplicationContext的ConfigLocations中
                      wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,
                      ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
                      }
                      //刷新WebApplicationContext
                      wac.refresh();
                      
                      return wac;
                      }
                      

          ==>contextLoader.determineContextClass(servletContext);

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException {
                      
                      //獲得需要實例化的CONTEXT類名,在web.xml中有設置,如果沒有設置,那么為空
                      String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
                      if (contextClassName != null) {
                      try {
                      return ClassUtils.forName(contextClassName);
                      }
                      catch (ClassNotFoundException ex) {
                      throw new ApplicationContextException(
                      "Failed to load custom context class [" + contextClassName + "]", ex);
                      }
                      }
                      //如果在spring web.xml中沒有設置context類位置,那么取得默認context
                      else {
                      //取得defaultStrategies配置文件中的WebApplicationContext屬性
                      contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
                      try {
                      return ClassUtils.forName(contextClassName);
                      }
                      catch (ClassNotFoundException ex) {
                      throw new ApplicationContextException(
                      "Failed to load default context class [" + contextClassName + "]", ex);
                      }
                      }
                      
                      }
                      

          SPRING上下文默認的策略是甚么呢?
          ==>contextLoader.defaultStrategies

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
            private static final Properties defaultStrategies;
                       
                      static {
                      // Load default strategy implementations from properties file.
                      // This is currently strictly internal and not meant to be customized
                      // by application developers.
                      try {
                      
                      //設置classpath為contextLoader同級目錄
                      ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
                      //加載該目錄下的所有properties文件
                      defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
                      
                      }
                      catch (IOException ex) {
                      throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
                      }
                      }
                      

          找到同級目錄下的配置文件
          ==>ContextLoader.properties

          1
          2
          3
          4
          5
          6
          7
          8
          # Default WebApplicationContext implementation class for ContextLoader.
                      # Used as fallback when no explicit context implementation has been specified as context-param.
                      # Not meant to be customized by application developers.
                       
                      
                      #默認的WebApplicationContext為org.springframework.web.context.support.XmlWebApplicationContext
                      org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
                      
                      

          ==>org.springframework.web.context.support.XmlWebApplicationContext
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          50
          51
          52
          53
          54
          55
          56
          57
          58
          59
          60
          61
          62
          63
          64
          65
          66
          67
          68
          69
          70
          71
          72
          73
          74
          75
          76
          77
          78
          79
          80
          81
          82
          83
          84
          85
          86
          87
          88
          89
          90
          91
          92
          93
          public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
                       
                      /** Default config location for the root context */
                       
                      
                      //配置了默認的spring配置文件
                      public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
                      
                       
                      //配置文件默認BUILD路徑
                      public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
                       
                      //配置文件默認后綴名
                      public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
                       
                      /**
                      * Loads the bean definitions via an XmlBeanDefinitionReader.
                      * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
                      * @see #initBeanDefinitionReader
                      * @see #loadBeanDefinitions
                      */
                      //獲得bean配置
                      protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
                      //從BEAN工廠獲得一個XmlBeanDefinitionReader 來讀取SPRING配置文件
                      XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
                       
                      //設置beanDefinitionReader服務于當前CONTEXT
                      // resource loading environment.
                      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);
                      
                      }
                       
                      /**
                      * Initialize the bean definition reader used for loading the bean
                      * definitions of this context. Default implementation is empty.
                      * <p>Can be overridden in subclasses, e.g. for turning off XML validation
                      * or using a different XmlBeanDefinitionParser implementation.
                      * @param beanDefinitionReader the bean definition reader used by this context
                      * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setValidationMode
                      * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass
                      */
                      protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
                      }
                       
                      /**
                      * Load the bean definitions with the given XmlBeanDefinitionReader.
                      * <p>The lifecycle of the bean factory is handled by the refreshBeanFactory method;
                      * therefore this method is just supposed to load and/or register bean definitions.
                      * <p>Delegates to a ResourcePatternResolver for resolving location patterns
                      * into Resource instances.
                      * @throws org.springframework.beans.BeansException in case of bean registration errors
                      * @throws java.io.IOException if the required XML document isn't found
                      * @see #refreshBeanFactory
                      * @see #getConfigLocations
                      * @see #getResources
                      * @see #getResourcePatternResolver
                      */
                      
                      //讀取配置文件
                      protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
                      String[] configLocations = getConfigLocations();
                      if (configLocations != null) {
                      for (int i = 0; i < configLocations.length; i++) {
                      reader.loadBeanDefinitions(configLocations[i]);
                      }
                      }
                      }
                      
                       
                      /**
                      * The default location for the root context is "/WEB-INF/applicationContext.xml",
                      * and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet"
                      * (like for a DispatcherServlet instance with the servlet-name "test").
                      */
                      //獲得默認的ConfigLocations
                      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};
                      }
                      }
                      

          ==>AbstractBeanDefinitionReader.loadBeanDefinitions()

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
                      ResourceLoader resourceLoader = getResourceLoader();
                      if (resourceLoader == null) {
                      throw new BeanDefinitionStoreException(
                      "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
                      }
                       
                      if (resourceLoader instanceof ResourcePatternResolver) {
                      // Resource pattern matching available.
                      try {
                      
                      //根據(jù)配置文件讀取相應配置
                      Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                      
                      int loadCount = loadBeanDefinitions(resources);
                      if (logger.isDebugEnabled()) {
                      logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                      }
                      return loadCount;
                      }
                      catch (IOException ex) {
                      throw new BeanDefinitionStoreException(
                      "Could not resolve bean definition resource pattern [" + location + "]", ex);
                      }
                      }
                      else {
                      // Can only load single resources by absolute URL.
                      Resource resource = resourceLoader.getResource(location);
                      int loadCount = loadBeanDefinitions(resource);
                      if (logger.isDebugEnabled()) {
                      logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
                      }
                      return loadCount;
                      }
                      }
                      

          這個是其中一個ResourceLoader的實現(xiàn)
          ==>PathMatchingResourcePatternResolver.getResources(String locationPattern);

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
           public Resource[] getResources(String locationPattern) throws IOException {
                      Assert.notNull(locationPattern, "Location pattern must not be null");
                      if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
                      // a class path resource (multiple resources for same name possible)
                      
                      if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
                      // a class path resource pattern
                      return findPathMatchingResources(locationPattern);
                      }
                      else {
                      // all class path resources with the given name
                      return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
                      }
                      
                      }
                      else {
                      // Only look for a pattern after a prefix here
                      // (to not get fooled by a pattern symbol in a strange prefix).
                      int prefixEnd = locationPattern.indexOf(":") + 1;
                      if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
                      // a file pattern
                      return findPathMatchingResources(locationPattern);
                      }
                      else {
                      // a single resource with the given name
                      return new Resource[] {getResourceLoader().getResource(locationPattern)};
                      }
                      }
                      }
                      


          ==>PathMatchingResourcePatternResolver.findPathMatchingResources(String locationPattern);

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
           protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
                      String rootDirPath = determineRootDir(locationPattern);
                      String subPattern = locationPattern.substring(rootDirPath.length());
                      Resource[] rootDirResources = getResources(rootDirPath);
                      
                      //collectionFactory初始化一個set容量為16
                      Set result = CollectionFactory.createLinkedSetIfPossible(16);
                      for (int i = 0; i < rootDirResources.length; i++) {
                      Resource rootDirResource = rootDirResources[i];
                      if (isJarResource(rootDirResource)) {
                      result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));
                      }
                      else {
                      result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
                      }
                      }
                      
                      if (logger.isDebugEnabled()) {
                      logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);
                      }
                      return (Resource[]) result.toArray(new Resource[result.size()]);
                      }
                      


          前面說到有一個刷新WebApplicationContext的操作,但是XmlWebApplicationContext 并沒有實現(xiàn)refresh方法,而方法的實現(xiàn)寫在

          AbstractRefreshableWebApplicationContext 中

          ==>AbstractRefreshableWebApplicationContext.refresh();
          1
          2
          3
          4
          5
          6
          7
          public void refresh() throws BeansException {
                      if (ObjectUtils.isEmpty(getConfigLocations())) {
                      //設置configLocations為默認的getDefaultConfigLocations()
                      setConfigLocations(getDefaultConfigLocations());
                      }
                      super.refresh();
                      }
                      


          ==>AbstractApplicationContext.refresh();
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          50
          51
          52
          53
          54
          55
          56
          57
          58
          59
          60
          61
          62
          63
          64
          65
          66
          67
          68
          69
          70
          71
          72
          73
          74
          75
          76
          77
          78
          public void refresh() throws BeansException, IllegalStateException {
                      synchronized (this.startupShutdownMonitor) {
                      this.startupTime = System.currentTimeMillis();
                       
                      synchronized (this.activeMonitor) {
                      this.active = true;
                      }
                       
                      // Tell subclass to refresh the internal bean factory.
                      refreshBeanFactory();
                      ConfigurableListableBeanFactory beanFactory = getBeanFactory();
                       
                      // Tell the internal bean factory to use the context's class loader.
                      beanFactory.setBeanClassLoader(getClassLoader());
                       
                      // Populate the bean factory with context-specific resource editors.
                      beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this));
                       
                      // Configure the bean factory with context semantics.
                      beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
                      beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
                      beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
                      beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
                      beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
                       
                      // Allows post-processing of the bean factory in context subclasses.
                      postProcessBeanFactory(beanFactory);
                       
                      // Invoke factory processors registered with the context instance.
                      for (Iterator it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) {
                      BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next();
                      factoryProcessor.postProcessBeanFactory(beanFactory);
                      }
                       
                      if (logger.isInfoEnabled()) {
                      if (getBeanDefinitionCount() == 0) {
                      logger.info("No beans defined in application context [" + getDisplayName() + "]");
                      }
                      else {
                      logger.info(getBeanDefinitionCount() + " beans defined in application context [" +
                       
                      getDisplayName() + "]");
                      }
                      }
                       
                      try {
                      // Invoke factory processors registered as beans in the context.
                      invokeBeanFactoryPostProcessors();
                       
                      // Register bean processors that intercept bean creation.
                      registerBeanPostProcessors();
                       
                      // 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 singletons this late to allow them to access the message source.
                      beanFactory.preInstantiateSingletons();
                       
                      // Last step: publish corresponding event.
                      publishEvent(new ContextRefreshedEvent(this));
                      }
                       
                      catch (BeansException ex) {
                      // Destroy already created singletons to avoid dangling resources.
                      beanFactory.destroySingletons();
                      throw ex;
                      }
                      }
                      }
                      

          posted on 2007-11-07 15:06 空杯 閱讀(10739) 評論(1)  編輯  收藏 所屬分類: Spring

          評論

          # 福德宮  回復  更多評論   

          的風格大方
          2014-09-03 17:40 | 梵蒂岡的發(fā)揮

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導航:
           
          主站蜘蛛池模板: 原平市| 乐平市| 三原县| 凤冈县| 灵璧县| 萝北县| 宁南县| 宝鸡市| 闸北区| 库伦旗| 西宁市| 驻马店市| 昌吉市| 仁寿县| 大悟县| 电白县| 怀远县| 武功县| 寿宁县| 呼伦贝尔市| 淮安市| 江津市| 长汀县| 张掖市| 进贤县| 湖南省| 右玉县| 凤庆县| 白沙| 大安市| 林周县| 任丘市| 新沂市| 灵璧县| 宁化县| 远安县| 从化市| 安阳县| 武定县| 钦州市| 安吉县|