详解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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 拆解滴滴大脑 叶杰平谈出行领域算法技术

    拆解滴滴大脑 叶杰平谈出行领域算法技术近日,滴滴研究院副院长叶杰平在上海一场内部分享会上详细解读了滴滴大脑,这是外部首次窥探到较为完整的滴滴算法世界,并且一直潜水的产品“九霄”也首次露出真容。滴滴出行研究院副院长叶杰平滴滴大脑由三部分组成叶杰平将滴滴大脑这个智能系统分为三部分,分别是大数据、机器学习和云计算。其中大数据就像工业革命时代的煤一样举足轻重,人工智能需要数据进行训练,纵观应用级深度学习的成功案例,他们都获得了海量数据,…

    2022年5月5日
    70
  • Intellij IDEA汉化教程[通俗易懂]

    Intellij IDEA汉化教程[通俗易懂]1.首先下载汉化文件提取码:078j2.关闭IDEA,打开安装IDEA的位置并找到以下文件如果不知道IDEA所安装的位置,右键图标–>属性–>打开文件所在的位置–>再打开上一级目录,就可以找到了3.然后将下载好的汉化文件复制到以上目录(lib)4.重新打开IDEA,汉化就完成了…

    2022年5月27日
    111
  • Aria2安装(aria2安卓版手机配置教程)

    1安装sudopacman-Saria22创建配置文件cd~mkdir.aria2cd.aria2toucharia2.confaria2.logaria2.session3修改配置文件aria2.conf需要自己配置rpc-secret和bt-trackerbt-tracker可以去trackerslist网站获取#文件的保存路径(可使用绝对路径或相对路径),默认:当前启动位置dir=${HOME}/Downloads#启用磁盘缓存,0为

    2022年4月14日
    1.1K
  • 2020十大正规现货交易平台排行榜

    2020十大正规现货交易平台排行榜对国内投资者而言,贵金属投资有内、外盘之分,因此者在选择平台,投资者应该从市场成熟度和产品优势出发,先明确自己在哪一个市场进行投资,再挑选那些信誉度极高、以客户利益为大前提、在行业内排名较前平台。其中,上海黄金交易所(SGE)属于国家级的交易场所,也是目前国内唯一能够同时兼营黄金和白银现货产品的交易所。如果投资者想通过排名靠前的平台参与上金所的产品,可以在国内的四大商业银行中作出选择。至于外盘产品方面,我们建议投资者选择香港排名靠前的平台。因为香港的正规平台都持有金银业贸易场(CGSE)颁发的牌照,而只

    2022年6月23日
    64
  • Linux rpm安装jdk1.8

    Linux rpm安装jdk1.8前言每次需要配置JDK的时候都需要去网上搜一下,这次专门写下博客以备后用,虽然这个博客实在是太!简!单!了!亲测CentOS6,CentOS7都没有问题第一步:卸载系统自带的JDKrpm-qa|grepjava#xxxyyyzzz为你要卸载的插件,插件之间以空格隔开rpm-e–nodepsxxxyyyzzz第二步:安装JDK1.8…

    2022年6月11日
    31
  • php统计近一周和近30天的用户数据

    php统计近一周和近30天的用户数据

    2021年10月25日
    38

发表回复

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

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