解决tomcat下面部署多个项目log4j的日志输出会集中输出到一个项目中的问题
在一次项目上线后,发现了一个奇怪的问题,经过对源码的阅读调试终于解决,具体经过是这样的:
问题描述: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的日志输出会集中输出到一个项目中的问题的更多相关文章
- 使用log4j将日志输送到控制台、文件或数据库中
转: 使用log4j将日志输送到控制台.文件或数据库中 2018-09-07 00:45:08 keep@ 阅读数 2880更多 分类专栏: 其它 版权声明:本文为博主原创文章,遵循CC 4.0 ...
- 如何在Eclipse中彻底修改一个项目名称
在实际工作中,有时候为了赶时间,往往通过复制项目得到一个成型的框架.那么怎么才可以彻底修改项目名称呢? 1.web.xml 2.工作空间中找到当前项目下.project文件 3.工作空间中找到当前项目 ...
- 如何把VS2015中本地的一个项目建立远程的Git Repository
在项目开发中,我在本地自己电脑上用VS2015建立了一个项目,比如项目名字叫做Luke.Test 那么,接下来,我如何把这个项目签入到远程的Git Repository里去呢. 方法如下 先进入远程R ...
- 解决tomcat同时部署两个SpringBoot应用提示InstanceAlreadyExistsException
问题描述:Caused by: javax.management.InstanceAlreadyExistsException: com.alibaba.druid.pool:name=primary ...
- 解决tomcat同时部署两个SpringBoot应用报异常InstanceAlreadyExistsException
问题描述:Caused by: javax.management.InstanceAlreadyExistsException: com.alibaba.druid.pool:name=primary ...
- 关于Eclipse中复制粘贴一个项目后的操作
今天在做一个小Demo,内容和之前的项目有些类似就直接复制过来了,项目名修改了,web.xml的项目名也修改了,可是部署到Tomcat之后,以这个新项目名进行访问就会出现404的错误,只可以使用复制之 ...
- c# winform 在一个窗体中使用另一个窗体中TextBox控件的值——解决办法
[前提]一个winform应用程序项目中,窗体B,需要使用 窗体A 中一个TextBox控件的值,进行计算等操作. [解决方案] 1.在窗体A中定义:public static double a;// ...
- 如何在maven项目中引用领一个项目
1 有两个项目 maven01 和maven 02,想在maven 02中引用maven01的方法,该如何操作呢 maven01中Factory类中的方法 public class Factory ...
- IDEA中每次拷贝一个项目的时候必须标记一下配置文件resources,否则报错
随机推荐
- 分布式理论:深入浅出Paxos算法
前言 Paxos算法是用来解决分布式系统中,如何就某个值达成一致的算法.它晦涩难懂的程度完全可以跟它的重要程度相匹敌.目前关于paxos算法的介绍已经非常多,但大多数是和稀泥式的人云亦云,却很少有人能 ...
- 父类与子类this相关问题
1.SinglyLinkedList: package No3_PolySinglyList; /*实现 带头结点的单链表SinglyLinkedList类*/ public class Singly ...
- 【SE】Week7 : Silver Bullet & Cathedral and Bazaar & Big Ball of Mud & Waterfall ...
1. Silver Bullet No Silver Bullet: Essence and Accidents of Software Engineering —— 无银弹理论,出自于美国1999年 ...
- 《Linux内核设计与实现》Chapter 2 读书笔记
<Linux内核设计与实现>Chapter 2 读书笔记 一.获取内核源码 1.使用Git 我们曾经在以前的学习中使用过Git方法 $ git clone git://git.kernel ...
- LeetCode 167. 两数之和 II - 输入有序数组
题目: 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值index1 和 index2,其中 index1 必须小于 index2. 说明: 返回的 ...
- Android开发环境的发展演变调研
Android开发环境的发展演变调研 前几年比较多的方法是用JDK+eclipse+ADT,该方法除了要配置JDK的路径之外, 还要在eclipse里面打开SDK Manage进行相应的操作.不过近两 ...
- 【Leetcode】209. Minimum Size Subarray Sum
Question: Given an array of n positive integers and a positive integer s, find the minimal length of ...
- Thinkphp3.2 入口绑定问题记录
// 应用入口文件 // 检测PHP环境if(version_compare(PHP_VERSION,'5.3.0','<')) die('require PHP > 5.3.0 !'); ...
- [转帖] K8S 常用命令
k8s常用命令 原贴地址 查看集群信息: [root@kubernetes-master pods]# kubectl cluster-info kubectl cluster-info展示结果 k ...
- linux下MySQL使用方法
一.登录MySQL 登录MySQL的命令是mysql, mysql 的使用语法如下: mysql [-u username] [-h host] [-p[password]] [dbname] us ...