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

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

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

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

  • 相关阅读:
    查看电脑保存的wifi密码
    数据仓库
    nodejs 中国汉字模糊查询简单(很low)实现
    nodejs express 框架 上传文件
    async样例
    mongodb Map/reduce测试代码
    未释放资源的教训,开发MongoDB连接一定要关闭连接
    采集系统优化:大家接手过的最烂的项目,最坑爹的项目是哪个?
    Android的HttpClient调用,冲突的解决办法
    MongoDBcrud操作,采集部分代码
  • 原文地址:https://www.cnblogs.com/interdrp/p/15601119.html
Copyright © 2011-2022 走看看