天天看點

spring 入門 之運作機制

技術不太好,對spring在慢慢學習ing.寫的有錯誤還望指正..

spring的運作需要在web.xml加上spring的監聽,
配置spring的xml檔案路徑
	<!-- 配置spring資源 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:config/applicationContext-*.xml</param-value>
	</context-param>
不寫上邊那個的話也行,代表預設路徑在java檔案有展現,下邊是配置監聽
<!-- 配置spring -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
在spring-web.release.jar中的ContextLoadListener這個類
public void contextInitialized(ServletContextEvent event)
    {
        contextLoader = createContextLoader();
        if(contextLoader == null)
            contextLoader = this;
//監聽web上下文初始化spring上下文
       contextLoader.initWebApplicationContext(event.getServletContext());
    }


然後追蹤到ContextLoad這個類
public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
    {
        Log logger;
        long startTime;
        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!");
        logger = LogFactory.getLog(org/springframework/web/context/ContextLoader);
        servletContext.log("Initializing Spring root WebApplicationContext");
        if(logger.isInfoEnabled())
            logger.info("Root WebApplicationContext: initialization started");
        startTime = System.currentTimeMillis();
       
        //建立web上下文
	if(context == null)
            context = createWebApplicationContext(servletContext);
        if(context instanceof ConfigurableWebApplicationContext)
        {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)context;
            if(!cwac.isActive())
            {
                if(cwac.getParent() == null)
                {
                    ApplicationContext parent = loadParentContext(servletContext);
                    cwac.setParent(parent);
                }
                configureAndRefreshWebApplicationContext(cwac, servletContext);
            }
        }
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
        if(ccl == org/springframework/web/context/ContextLoader.getClassLoader())
            currentContext = context;
        else
        if(ccl != null)
            currentContextPerThread.put(ccl, context);
        if(logger.isDebugEnabled())
            logger.debug((new StringBuilder()).append("Published root WebApplicationContext as ServletContext attribute with name [").append(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE).append("]").toString());
        if(logger.isInfoEnabled())
        {
            long elapsedTime = System.currentTimeMillis() - startTime;
            logger.info((new StringBuilder()).append("Root WebApplicationContext: initialization completed in ").append(elapsedTime).append(" ms").toString());
        }
        return context;
        RuntimeException ex;
        ex;
        logger.error("Context initialization failed", ex);
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
        throw ex;
        Error err;
        err;
        logger.error("Context initialization failed", err);
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
        throw err;
    }
然後追蹤到ContextLoad.createWebApplicationContext
 protected WebApplicationContext createWebApplicationContext(ServletContext sc)
    {
	//根據ServletContext來決定要執行個體化的webApplicationContext
        Class contextClass = determineContextClass(sc);
       if(!org/springframework/web/context/ConfigurableWebApplicationContext.isAssignableFrom(contextClass))
            throw new ApplicationContextException((new StringBuilder()).append("Custom context class [").append(contextClass.getName()).append("] is not of type [").append(org/springframework/web/context/ConfigurableWebApplicationContext.getName()).append("]").toString());
        else
            return (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
    }
==>ContextLoader.determineContextClass
 protected Class determineContextClass(ServletContext servletContext)
    {
	//獲得初始化的context類名,在web.xml中設定,沒有則為空
        String contextClassName;
        contextClassName = servletContext.getInitParameter("contextClass");
        if(contextClassName == null)
            break MISSING_BLOCK_LABEL_55;
        return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
        ClassNotFoundException ex;
        ex;
        throw new ApplicationContextException((new StringBuilder()).append("Failed to load custom context class [").append(contextClassName).append("]").toString(), ex);
	//如果在web.xml中沒有設定context類的位置,那麼取預設的context
        //取得defaultStrategies配置中的WebApplocationContext屬性
        contextClassName = defaultStrategies.getProperty(org/springframework/web/context/WebApplicationContext.getName());
        return ClassUtils.forName(contextClassName, org/springframework/web/context/ContextLoader.getClassLoader());
        ex;
        throw new ApplicationContextException((new StringBuilder()).append("Failed to load default context class [").append(contextClassName).append("]").toString(), ex);
    }
spring上下文預設生成政策
==>contextLoader.defaultStrategies
 static 
    {
        try
        {
	//設定properties為ContextLoader同級目錄
            ClassPathResource resource = new ClassPathResource("ContextLoader.properties", org/springframework/web/context/ContextLoader);
       	//加載該目錄下的properties檔案
	    defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
        }
        catch(IOException ex)
        {
            throw new IllegalStateException((new StringBuilder()).append("Could not load 'ContextLoader.properties': ").append(ex.getMessage()).toString());
        }
    }
找到同級目錄下的ContextLoader.properties配置檔案


# 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

找到此包下的XmlWebApplicationContext檔案
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext
{

    public XmlWebApplicationContext()
    {
    }
		
//擷取bean配置
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
        throws BeansException, IOException
    {
	//從bean工廠擷取一個XmlBeanDefinitionReader來讀取Spring配置檔案
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(getEnvironment());
	//設定beanDefinitionReader服務目前CONTEXT
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        initBeanDefinitionReader(beanDefinitionReader);
	//讀取配置檔案
        loadBeanDefinitions(beanDefinitionReader);
    }

	
    protected void initBeanDefinitionReader(XmlBeanDefinitionReader xmlbeandefinitionreader)
    {
    }
	//讀取配置檔案
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader)
        throws IOException
    {
        String configLocations[] = getConfigLocations();
        if(configLocations != null)
        {
            String arr$[] = configLocations;
            int len$ = arr$.length;
            for(int i$ = 0; i$ < len$; i$++)
            {
                String configLocation = arr$[i$];
                reader.loadBeanDefinitions(configLocation);
            }

        }
    }

	//獲得預設的Configlocation
    protected String[] getDefaultConfigLocations()
    {
        if(getNamespace() != null)
            return (new String[] {
                (new StringBuilder()).append("/WEB-INF/").append(getNamespace()).append(".xml").toString()
            });
        else
            return (new String[] {
                "/WEB-INF/applicationContext.xml"
            });
    }
	//配置了預設的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";
}
然後loadBeanDefinitions這個方法在spring-bean.release.jar中的AbstractBeanDefinitionReader中
  public int loadBeanDefinitions(String location)
        throws BeanDefinitionStoreException
    {
        return loadBeanDefinitions(location, null);
    }

    public int loadBeanDefinitions(String location, Set actualResources)
        throws BeanDefinitionStoreException
    {
        ResourceLoader resourceLoader;
        resourceLoader = getResourceLoader();
        if(resourceLoader == null)
            throw new BeanDefinitionStoreException((new StringBuilder()).append("Cannot import bean definitions from location [").append(location).append("]: no ResourceLoader available").toString());
        if(!(resourceLoader instanceof ResourcePatternResolver))
            break MISSING_BLOCK_LABEL_207;
        int loadCount;
	//根據配置檔案讀取相應位置
        Resource resources[] = ((ResourcePatternResolver)resourceLoader).getResources(location);
        loadCount = loadBeanDefinitions(resources);
        if(actualResources != null)
        {
            Resource arr$[] = resources;
            int len$ = arr$.length;
            for(int i$ = 0; i$ < len$; i$++)
            {
                Resource resource = arr$[i$];
                actualResources.add(resource);
            }

        }
        if(logger.isDebugEnabled())
            logger.debug((new StringBuilder()).append("Loaded ").append(loadCount).append(" bean definitions from location pattern [").append(location).append("]").toString());
        return loadCount;
        IOException ex;
        ex;
        throw new BeanDefinitionStoreException((new StringBuilder()).append("Could not resolve bean definition resource pattern [").append(location).append("]").toString(), ex);
        Resource resource = resourceLoader.getResource(location);
        loadCount = loadBeanDefinitions(resource);
        if(actualResources != null)
            actualResources.add(resource);
        if(logger.isDebugEnabled())
            logger.debug((new StringBuilder()).append("Loaded ").append(loadCount).append(" bean definitions from location [").append(location).append("]").toString());
        return loadCount;
    }
分析一個ResourceLoader的實作在spring-core-3.2.1.RELEASE.jar中的 org.springframework.core.io.support包裡
有一個PathMatchingResourcePatternResolver實作其接口
    public Resource[] getResources(String locationPattern)
        throws IOException
    {
        Assert.notNull(locationPattern, "Location pattern must not be null");
        if(locationPattern.startsWith("classpath*:"))
            if(getPathMatcher().isPattern(locationPattern.substring("classpath*:".length())))
                return findPathMatchingResources(locationPattern);
            else
                return findAllClassPathResources(locationPattern.substring("classpath*:".length()));
        int prefixEnd = locationPattern.indexOf(":") + 1;
        if(getPathMatcher().isPattern(locationPattern.substring(prefixEnd)))
            return findPathMatchingResources(locationPattern);
        else
            return (new Resource[] {
                getResourceLoader().getResource(locationPattern)
            });
    }

 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 = new LinkedHashSet(16);
        Resource arr$[] = rootDirResources;
        int len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            Resource rootDirResource = arr$[i$];
            rootDirResource = resolveRootDirResource(rootDirResource);
            if(isJarResource(rootDirResource))
            {
                result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));
                continue;
            }
            if(rootDirResource.getURL().getProtocol().startsWith("vfs"))
                result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher()));
            else
                result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
        }

        if(logger.isDebugEnabled())
            logger.debug((new StringBuilder()).append("Resolved location pattern [").append(locationPattern).append("] to resources ").append(result).toString());
        return (Resource[])result.toArray(new Resource[result.size()]);
    }