注:仅仅只是针对Spring的项目,不涉及SpringBoot,SpringCloud
项目框架是Spring+SpringMVC+MyBatis。项目启动的时候是加载不同的配置文件然后达到不同的环境的这种效果。可以这样理解,项目中存在a.properties,b.properties,c.properties,d.properties四个配置文件,然后还有一个配置叫boot.properties文件。部署是这样的,当你要部署环境的时候,你部署a环境,那么war包中得boot.properties是必须约定加载a.properties,其他环境同理。也就是说现在有四套环境,只是他们的boot.properties是不同的,其他都是一模一样的代码。现在的问题log4j2.xml文件的日志文件是写死的,比如说是/data/log/。如果同一台机器上同时布置了a,b两套环境,那么它们的日志将会被覆盖。解决方法就是 [每个war包中得log4f2.xml单独修改],针对这个问题作出优化。
存在a.war,b.war,c.war,d.war,四个war包中boot.properties加载各自的配置问价,a.war中boot.properties只加载a.properties,同时a.war中log4f.xml中日志文件路径修改为/data/a/log。b.war,c.war,d.war同理。
针对以上问题作出优化
a.war中boot.properties的配置
a.properties
#b.properties
#c.properties
#d.properties
//
log4j2.xml日志的配置
<>/data/a/log</>
b.war中boot.properties的配置
#a.properties
b.properties
#c.properties
#d.properties
//
log4j2.xml日志的配置
/data/b/log
优化的主要点是把log4f2.xml的日志配置写在各自的配置文件中,比如我在a环境中a.properties中配置如下
a.properties中的配置
log-uri=/data/a/log
b.properties中的配置
log-uri=/data/b/log
这样我只需要取到这个日志地址,后面及时a,b部署到同一台机器上,日志也不会冲突的。
现在要做的是,配置我们写好了,那么如何让log4j2.xml取到你自己的配置,这是本文的重点
通常情况下,日志的加载是在Spring容器加载之前的,因为我日志加载完成之后我我就需要把日志写在文件中,所以我不可能把日志的加载放在最后面,那么启动的日志全都记录不到,就没有任何的意义。
所以这里暂时不能通过Spring的一些方式处理(ps:如果可以,评论区讨论)
利用jvm参数,这个就比较简单了。
a.war ,b.war,c.war,d.war在各自服务启动的时候加上自定义的jvm参数,比如
a.war -Dlog-uri=/data/a/log
b.war -Dlog-uri=/data/b/log
c.war -Dlog-uri=/data/c/log
d.war -Dlog-uri=/data/d/log
这些配置都是在各自的properties中
那么log4j2.xml日志文件地址仅这样配置就行了
log4j2.xml中日志文件的配置
<configuration status="info">
<{Properties>
<properties name="logBaseFolder">${sys:log-uri}</properties>
...
和jvm参数同样的道理,但是不需要在启动的时候指定jvm参数
tomcat监听器ServletContextListener
这个监听器就很好的帮我们解决了这个问题,这个知识点可以看一下。
他帮我们能干得事情有
1、读取当前环境中要加载的配置文件,就是查看一下boot.properties中当前环境要加载那个配置文件,同时将配置文件中的配置加载到Property,就写个工具类,方便以后读取配置。
2、读取指定的属性名log-uri,将log-uri加载到系统环境变量中。
具体见如下步骤:
第一步:配置配置文件
a.war log-uri=/data/a/log
b.war log-uri=/data/b/log
c.war log-uri=/data/c/log
d.war log-uri=/data/d/log
第二步:配置日志文件
所有的war包都配置成这样的
log4j2.xml中日志文件的配置
<configuration status="info">
<{Properties>
<properties name="logBaseFolder">${sys:log-uri}</properties>
...
第三步:自定义ServletContextListener
实现这个接口,重写
第四步:在web.zml中配置文件中配置监听器,一定要在日志文件的配置之前配置,要不然没有意义。
(1)加载配置文件
(2)对应的属性加到系统环境变量中
package com.anik.csdnblog;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class LogContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//加载配置文件的属性
//将日志文件属性加载到系统环境变量中,configUtil 需要自己写,主要逻辑就是读取流文件,设置到Property中
System.setProperty("log-uri",configUtil.getProperties("log-uri","/data/log/"));
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
//以下配置一定要在日志文件之前配置
<listener>
<listener-class>com.csdnblog.anik.listener.LogContextListener</listener-class>
</listener>
之前有想过这样的方式,直接写一个静态代码块,主要逻辑就是将配置文件加载到工具类中,同时将日志的配置加载到系统环境变量中,按理说这样的逻辑也是没问题的,因为类加载肯定实在web.xml之前的,所以当加载web.xml加载日志的地址时,一定能读取到,事实上不是的。这个必须参考类加载的知识点,类加载时机。
事实上,类加载的时候静态代码块是没有被执行的,当只有类第一次被调用的时候才会执行这部分的静态代码块,而且只会执行一次。当服务启动的时候并没有任何地方调用这个类。
(ps:理解的有问题的话,欢迎评论区讨论)
那么静态代码块负责将配置文件加载到工具类中,tomcat监听器负责将指定的属性加载到系统环境变量中(必然要通过工具类读取配置,所以静态代码块会被执行),这样就行了。