详解contextConfigLocation

详解contextConfigLocationspring的应用初始化流程一直没有搞明白,刚刚又碰到了相关的问题。决定得好好看看这个流程。我们在开发spring的项目当中基本上都会在web.xml通过:来初始化各个spring的配置文件,但是我们只是知道这段代码的功能,并不是很清楚我们配置了这段代码之后为什么就能去初始化配置文件。当然我们还会加上:listener>          li

大家好,又见面了,我是你们的朋友全栈君。

spring的应用初始化流程一直没有搞明白,刚刚又碰到了相关的问题。决定得好好看看这个流程。我们在开发spring的项目当中基本上都会在web.xml通过:

<context-param>          <param-name>contextConfigLocation</param-name>          <param-value>          /WEB-INF/conf/application-*.xml          </param-value>      </context-param>  

来初始化各个spring的配置文件,但是我们只是知道这段代码的功能, 并不是很清楚我们配置了这段代码之后为什么就能去初始化配置文件。当然我们还会加上:

<listener>          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>      </listener> 

这一个listener,我首先就会想contextConfigLocation这个一定能在ContextLoaderListener这个类当中找到,打开了源码,这个listener是实现了ServletContextListener这个接口的,这个接口只有两个方法:

  1. public interface ServletContextListener  
        extends EventListener  
    {  
      
        public abstract void contextInitialized(ServletContextEvent servletcontextevent);  
      
        public abstract void contextDestroyed(ServletContextEvent servletcontextevent);  
    } 

而且它是继承了EventListener这个接口的,打开这个接口的代码让我大吃一惊,里面没有方法啥都没有:

  1. package java.util;  
    
    public interface EventListener  
    {  
    } 

     

而且还是java.util包下的,并不是spring之中的东西。

这样找了之后没有找到,往回退到ContextLoaderListener这个类的方法上,contextInitialized方法是用来初始化上下文的:

  1. public void contextInitialized(ServletContextEvent event)  
        {  
            contextLoader = createContextLoader();  
            contextLoader.initWebApplicationContext(event.getServletContext());  
        } <span style="font-family: 宋体, Arial; background-color: rgb(255, 255, 255);"> </span>

方法中有个createContextLoader方法:

  1. protected ContextLoader createContextLoader()  
        {  
            return new ContextLoader();  
        }  

这个方法返回了一个ContextLoader实例,进入到ContextLoader类中,按ctrl+f来寻找contextConfigLocation,这时没有出现电脑的咚的声音,找到了它:

  1. protected WebApplicationContext createWebApplicationContext(ServletContext servletContext, ApplicationContext parent)  
            throws BeansException  
        {  
            Class contextClass = determineContextClass(servletContext);  
            if(!(org.springframework.web.context.ConfigurableWebApplicationContext.class).isAssignableFrom(contextClass))  
            {  
                throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + (org.springframework.web.context.ConfigurableWebApplicationContext.class).getName() + "]");  
            } else  
            {  
                ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);  
                wac.setParent(parent);  
                wac.setServletContext(servletContext);  
                wac.setConfigLocation(servletContext.getInitParameter("<SPAN style="COLOR: #ff0000">contextConfigLocation</SPAN>"));  
                customizeContext(servletContext, wac);  
                wac.refresh();  
                return wac;  
            }  
        }  

通过代码,ConfigurableWebApplicationContext设置了从servletContext获取到的参数的值,再进入ConfigurableWebApplicationContext的代码中,它只是一个接口,进入StaticWebApplicationContext的setConfigLocation方法:
 
view plain
copy
print
?

  1. public void setConfigLocation(String configLocation)  
        {  
            if(configLocation != null)  
                throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations");  
            else  
                return;  
        }  

这个方法中很奇怪,当参数不为空就抛出异常,查看spring的文档:
The 
StaticWebApplicationContext
 class does not support this method.说是此类不支持这个方法,这下子又卡住了。又要退回去,看这句:

ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass)

spring使用BeanUtils来初始化contextClass这个类实例,contextClass是通过以下代码得到的:

  1. protected Class determineContextClass(ServletContext servletContext)  
            throws ApplicationContextException  
        {  
            String contextClassName = servletContext.getInitParameter("contextClass");  
            if(contextClassName != null)  
                try  
                {  
                    return ClassUtils.forName(contextClassName);  
                }  
                catch(ClassNotFoundException ex)  
                {  
                    throw new ApplicationContextException("Failed to load custom context class [" + contextClassName + "]", ex);  
                }  
            contextClassName = defaultStrategies.getProperty((org.springframework.web.context.WebApplicationContext.class).getName());  
            try  
            {  
                return ClassUtils.forName(contextClassName, (org.springframework.web.context.ContextLoader.class).getClassLoader());  
            }  
            catch(ClassNotFoundException ex)  
            {  
                throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", ex);  
            }  
        }  

这里使用了反射,再来看BeanUtils的instantiateClass方法:

return instantiateClass(clazz.getDeclaredConstructor((Class[])null), null);  

通过反射得到contextClass的构造方法。下面是instantiateClass方法的重载,主要是下面两句代码:

ReflectionUtils.makeAccessible(ctor);  
            return ctor.newInstance(args);  

ctor是通过反射得到的contextClass的构造方法,args是构造方法当中的参数。这里为null,说明new了contextClass的无参构造方法。

这时又要退回到determineContextClass 这个方法中,我们主要看:

[html] 
view plain
copy
print
?

  1. contextClassName = defaultStrategies.getProperty((org.springframework.web.context.WebApplicationContext.class).getName());  

这句代码,我们可以猜它是通过Properties的getProperty方法得到
WebApplicationContext 的实例,这时我们又到了WebApplicationContext 这个接口当中,这个接口继承了ApplicationContext这个接口,我们都知道我们进行spring开发都会通过Application ctx=new FileSystemXmlApplicationContext(“beans.xml”);或ApplicationContext ctx=new ClassPathXmlApplicationContext(“beans.xml”);ServletContext servletContext = request.getSession().getServletContext();ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);这三种方法获得一个ApplicationContext,然后就可以对配置文件当中的bean进行操作了。所以这里我们基本上已经搞清楚初始化spring配置文件的流程了。


总结:通过查看这几个类的源代码,java的反射使用范围之广再次体现出来。如看了之后觉得有错误或者不同意见,欢迎提出来,我也是第一次才研究这个问题。


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/158024.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 利用python、tensorflow、opencv实现人脸识别(包会)!「建议收藏」

    利用python、tensorflow、opencv实现人脸识别(包会)!「建议收藏」 一,前言本人是机械专业在读硕士,在完成暑假实践的时候接触到了人脸识别,对这一实现很感兴趣,所以花了大概十天时间做出了自己的人脸识别。这篇文章应该是很详细的了所以帮你实现人脸识别应该没什么问题。先说本博文的最终要达到的效果:通过一系列操作,在摄像头的视频流中识别特定人的人脸,并且予以标记。本人通过网上资料的查询发现这类人脸识别,大多参考了一位日本程序员小哥的文章。链接:http…

    2025年7月25日
    1
  • sublime text如何保存为uft-8无bom编码格式文件

    sublime text如何保存为uft-8无bom编码格式文件

    2021年9月25日
    74
  • MySQL默认事物隔离级别_sqlserver事务隔离级别

    MySQL默认事物隔离级别_sqlserver事务隔离级别mysql数据库事务的隔离级别有4个,而默认的事务处理级别就是【REPEATABLE-READ】,也就是可重复读。下面本篇文章就来带大家了解一下mysql的这4种事务的隔离级别,希望对大家有所帮助。SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。mysql的4种事务隔离级别,如下所示:…

    2022年9月11日
    0
  • vue.js中created()与activated()的个人使用理解

    vue.js中created()与activated()的个人使用理解created():在创建vue对象时,当html渲染之前就触发;但是注意,全局vue.js不强制刷新或者重启时只创建一次,也就是说,created()只会触发一次;activated():在vue对象存活的情况下,进入当前存在activated()函数的页面时,一进入页面就触发;可用于初始化页面数据等…

    2025年7月23日
    1
  • 一分钟学会Python中pip的安装与使用

    一分钟学会Python中pip的安装与使用文章目录一、简单介绍二、下载安装三、最常用命令1、显示版本和路径2、获取帮助3、升级pip4、安装包5、升级包6、卸载包7、搜索包8、显示安装包信息9、列出已安装的包10、查看指定包的详细信息一、简单介绍pip是Python包管理工具,该工具提供了对Python包的查找、下载、安装和卸载的功能,现在大家用到的所有包不是自带的就是通过pip安装的。Python2.7.9+或Python3.4+以上版本都自带pip工具。给出pip官网链接:pip官网。二、下载安装可以通过命令

    2022年4月30日
    83
  • MATLAB2018a安装包免费「建议收藏」

    MATLAB2018a安装包免费「建议收藏」MATLAB2018a安装包免费链接:https://pan.baidu.com/s/1dYMcv7Jb7kHW0WiALKdwsg提取码:5h3j复制这段内容后打开百度网盘手机App,操作更方便哦

    2022年5月27日
    35

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号