在一次项目上线后,发现了一个奇怪的问题,经过对源码的阅读调试终于解决,具体经过是这样的:

问题描述:tomcat7下面部署多个项目,log4j的日志输出会集中输出到一个项目中,就算配置了日志文件的绝对路径也是一样的。

解决方法:log4j.jar在每个项目中单独加到lib下

解决过程:先从log4j入手分析,在项目启动时调试org.apache.log4j.FileAppender,输出获取文件路径是绝对路径,应该是没有问题的,其实在正常的启动下也会输出该日志
信息: Set web app root system property: 'RootPath' = [H:\Project\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\cpa-1.0\]
信息: Set web app root system property: 'CpaRootPath' = [H:\Project\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\cpa\]
log4j是基于spring进行初始化的,到这里怀疑是spring容器实例化作用域是否有问题,但是本地调试又正常的,发布到tomcat才有问题,好奇看了一下之前的部署的项目,发现日志是没有影响的;

  调试log4j的初始化源码,使用PropertyConfigurator.configure(configFilename)进行初始化测试,日志的输出路径配置会被addAppender到LogManager.getLoggerRepository()实例的repositorySelector变量中,而LogManager中的repositorySelector是静态初始化的;当然到目前为止仍然不会有问题,关键是tomcat的jar共享,放在shared/lib下面的共享包会被URLClassLoader加载,单独放到项目lib下面的jar包会被WebAppClassLoader加载,区别就在这里,关于URLClassLoader和WebAppClassLoader加载为什么会引起这种问题还要继续深入分析tomcat启动加载。

  了解Java和JVM的一定知道,JVM中通常有三层默认的类加载器,分别是启动(Bootstrap)类加载器、标准扩展(Extension)类加载器和系统(System)类加载器。这三者每两者间都是父子关系,即前者是后者的父亲或者双亲类加载器,并由此构建了一个“双亲委派关系”,或叫“代理”关系。当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

  • 首先当前线程的类加载器去加载线程中的第一个类(假设为类A)。

    注:当前线程的类加载器可以通过Thread类的getContextClassLoader()获得,也可以通过setContextClassLoader()自己设置类加载器。

  • 如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器去加载类B。
  • 还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

  上面是jvm加载class的加载器,当tomcat启动时会为每个app分配了一个WebappClassLoader ,这样来避免多个app会加载相同jar包的问题,WebappLoader的parent是org.apache.catalina.loader.WebappClassLoaderBase,细看源码WebappClassLoaderBase直接继承于java.net.URLClassLoader类,最终继承于java.lang.ClassLoader类这样多个app就能共享tomcat的类库;WebappClassLoader的源码中发现,在进行findClass时会先试图自己加载类,找不到则请求parent来加载,这里和java的双亲委托模式是不同的,所以如果log4j放到项目lib下面会被当前项目的WebAppClassLoader加载并初始化静态实例,因为每个项目都被单独分配了WebAppClassLoader,这样jvm就能区分来自不同项目的各个类(热部署使用的就是该技术)。

总结:如果不深入的了解jvm和tomcat类加载器是很理解该问题是如何解决的,经过分析源码,并写了demo进行测试才实践出上述结论,实践出真理!

解决tomcat下面部署多个项目log4j的日志输出会集中输出到一个项目中的问题的更多相关文章

  1. 使用log4j将日志输送到控制台、文件或数据库中

    转: 使用log4j将日志输送到控制台.文件或数据库中 2018-09-07 00:45:08 keep@ 阅读数 2880更多 分类专栏: 其它   版权声明:本文为博主原创文章,遵循CC 4.0 ...

  2. 如何在Eclipse中彻底修改一个项目名称

    在实际工作中,有时候为了赶时间,往往通过复制项目得到一个成型的框架.那么怎么才可以彻底修改项目名称呢? 1.web.xml 2.工作空间中找到当前项目下.project文件 3.工作空间中找到当前项目 ...

  3. 如何把VS2015中本地的一个项目建立远程的Git Repository

    在项目开发中,我在本地自己电脑上用VS2015建立了一个项目,比如项目名字叫做Luke.Test 那么,接下来,我如何把这个项目签入到远程的Git Repository里去呢. 方法如下 先进入远程R ...

  4. 解决tomcat同时部署两个SpringBoot应用提示InstanceAlreadyExistsException

    问题描述:Caused by: javax.management.InstanceAlreadyExistsException: com.alibaba.druid.pool:name=primary ...

  5. 解决tomcat同时部署两个SpringBoot应用报异常InstanceAlreadyExistsException

    问题描述:Caused by: javax.management.InstanceAlreadyExistsException: com.alibaba.druid.pool:name=primary ...

  6. 关于Eclipse中复制粘贴一个项目后的操作

    今天在做一个小Demo,内容和之前的项目有些类似就直接复制过来了,项目名修改了,web.xml的项目名也修改了,可是部署到Tomcat之后,以这个新项目名进行访问就会出现404的错误,只可以使用复制之 ...

  7. c# winform 在一个窗体中使用另一个窗体中TextBox控件的值——解决办法

    [前提]一个winform应用程序项目中,窗体B,需要使用 窗体A 中一个TextBox控件的值,进行计算等操作. [解决方案] 1.在窗体A中定义:public static double a;// ...

  8. 如何在maven项目中引用领一个项目

    1 有两个项目 maven01  和maven 02,想在maven 02中引用maven01的方法,该如何操作呢 maven01中Factory类中的方法 public class Factory ...

  9. IDEA中每次拷贝一个项目的时候必须标记一下配置文件resources,否则报错

随机推荐

  1. CDH 5.16.1 离线部署 & 通过 CDH 部署 Hadoop 服务

    参考 Cloudera Enterprise 5.16.x Installing Cloudera Manager, CDH, and Managed Services Installation Pa ...

  2. CentOS7安装OpenStack(Rocky版)-01.控制节点的系统环境准备

    分享一下Rocky版本的OpenStack安装管理经验: OpenStack每半年左右更新一版,目前是版本是201808月发布的版本-R版(Rocky),目前版本安装方法优化较好,不过依然是比较复杂 ...

  3. Ubuntu环境如何上传项目到GitHub网站?

    http://blog.csdn.net/ajianyingxiaoqinghan/article/details/70544159

  4. Final阶段基于NABCD评论作品

    组名:杨老师粉丝群 组长:乔静玉 组员:吴奕瑶  刘佳瑞  公冶令鑫  杨磊  刘欣  张宇  卢帝同 一.拉格朗日2018--<飞词> 1.1  NABCD分析 N(Need,需求):该 ...

  5. linux第三章学习笔记

    第三章 进程管理 进程是Unix操作系统抽象概念中最基本的一种. 进程管理是所有操作系统的心脏所在. 一.进程 1. 进程是处于执行期的程序.除了可执行程序代码,还包括打开的文件.挂起的信号.内核内部 ...

  6. 睡眠猴子——Alpha阶段项目总结

    设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 针对广大失眠人群,尤其是程序猿用户的失眠问题.定义的清楚.描述过. 2. 是否有充足的时间来做计划 ...

  7. Github作为图床的一个小坑

    Github作为图床的一个小坑 前言 听了少铭同学建议把github作为图床,结果遇到了一个小坑,总是显示不出来图片. 问题描述与解决 形如下的链接是显示不出来的: https://github.co ...

  8. Android实现Service永久驻留

    说实话,这是一种流氓行为.但有些时候又是不得不需要的.比如微信的NotifyReceiver.现在抛开这些伦理的东西不讲,我们只是来看看技术上怎么实现.在后台运行的service有几个途径可以将其停止 ...

  9. Window环境下RabbitMQ 添加用户、设置角色和权限

    基本上新增用户.角色和权限的方法都一样,大概如下: REM 添加一个帐号 密码 rabbitmqctl.bat add_user zhangfujun zhangfujun123 REM 添加角色 r ...

  10. ES6之Promise用法详解

    一 前言 本文主要对ES6的Promise进行一些入门级的介绍.要想学习一个知识点,肯定是从三个方面出发,what.why.how.下面就跟着我一步步学习吧~ 二 什么是Promise 首先是what ...