zoukankan      html  css  js  c++  java
  • Tomcat7、8、9 Jar包加载机制

    Tomcat7加载Jar包原理

    Tomcat自己实现了自己的类加载器,用于加载自己本地项目中jar包中的所有class文件,所以在相同的类加载器下,

    如果有相同路径名和类名那么加载顺序就是根据jar包的顺序来决定的。谁的jar包先进来,那么就先加载哪个类。

    Tomcat7加载jar部分,在WebappLoader.setRepositories()方法中,粘贴出其中重要代码。

     // Looking up directory /WEB-INF/lib in the context
        NamingEnumeration<NameClassPair> enumeration = null;
        try {
            //这一句是获得jar包的路径
            enumeration = libDir.list("");
        } catch (NamingException e) {
            IOException ioe = new IOException(sm.getString(
                    "webappLoader.namingFailure", libPath));
            ioe.initCause(e);
            throw ioe;
        }

    list是获得了应用中WEB-INF下lib下所有jar包的路径。我们跟踪进去发现FileDirContext 的list方法中有下面这一句:

    Arrays.sort(names);             // Sort alphabetically

    我们可以发现在Tomcat7中对获得所有jar包作了一个排序的动作。对jar包进行了首字母a-z进行了排序。

    Tomcat9加载Jar包原理

    Tomcat9在加载源码的时候是通过StandardRoot.processWebInfLib()方法进行加载的

    代码位于

        private final List<List<WebResourceSet>> allResources =
                new ArrayList<>();
        {
            allResources.add(preResources);
            allResources.add(mainResources);
            allResources.add(classResources);
            allResources.add(jarResources);
            allResources.add(postResources);
        }
    

     于是我们可以这样优先加载类:

       <Resources>
            <PreResources base="d://webapps/ROOT/WEB-INF/lib/sms.reyo.cn.jar"
                          className="org.apache.catalina.webresources.JarResourceSet" 
                          webAppMount="/WEB-INF/classes"/>
        </Resources>
    
        protected void processWebInfLib() throws LifecycleException {
            WebResource[] possibleJars = listResources("/WEB-INF/lib", false);

            for (WebResource possibleJar : possibleJars) {
                if (possibleJar.isFile() && possibleJar.getName().endsWith(".jar")) {
                    createWebResourceSet(ResourceSetType.CLASSES_JAR,
                            "/WEB-INF/classes", possibleJar.getURL(), "/");
                }
            }
        }

    在这我们可以看到Tomcat没有对取出来的Jar作任何动作,仅仅是File file = new File()这样遍历出来了。

    那么为什么相同的Tomcat8相同的War包在Windos能启动起来,但是在Linux中都启动不起来呢?

    经过试验发现Java的获取文件夹下面的所有文件是跟操作系统的文件系统有关系的,相同的文件夹内容,在Windows中取出来,输出名字你会发现输出是经过a-z排序过的,

    但是在Linux中你可以根据命令ll -fi就可以输出自然顺序,你会发现没有什么规律可言。

    解决

    到这里上面描述的所有问题我们都能解释通了,接下来就该如何解决了。

    1. 修改Tomcat9的源码,在获取所有Jar包的时候,也对它进行排序
    2. 解决掉有冲突的文件,使用统一的版本。以下命令可以找到重复的jar包引用:
    mvn dependency:tree -Dverbose -Dincludes=io.netty

    第一种解决办法只能解决一时问题,即项目能正常启动起来,但是一旦随后涉及到了相关类的修改,那么冲突类的哪个类呢?那么这个问题肯定是一个定时炸弹。

    第二种方案是找到有冲突的文件,然后找出不用的那个给删除掉,但是发现删除一个又会蹦出其他的,删除了好几个以后发现由于买的项目代码不规范,

    所以这种现象特别多,如果单纯靠手工筛选的话极其麻烦。

  • 相关阅读:
    node
    github
    [模块] pdf转图片-pdf2image
    python 15 自定义模块 随机数 时间模块
    python 14 装饰器
    python 13 内置函数II 匿名函数 闭包
    python 12 生成器 列表推导式 内置函数I
    python 11 函数名 迭代器
    python 10 形参角度 名称空间 加载顺序
    python 09 函数参数初识
  • 原文地址:https://www.cnblogs.com/interdrp/p/15601119.html
Copyright © 2011-2022 走看看