zoukankan      html  css  js  c++  java
  • springboot整合日志+多环境配置+热部署

    前言

    本篇文章主要介绍的是springboot的日志配置,主要包括使用Slf4j+logback记录日志、使用AOP统一处理Web请求日志、多环境切换、热部署。

    GitHub源码链接位于文章底部。

    工程结构

    首先来看工程结构

    POM文件

    pom文件中引入相关依赖

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.3.RELEASE</version>
        </parent>
        <dependencies>
            <!-- SpringBoot 核心组件 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--AOP依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>
            <!--引入@Slf4j注解-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
        </dependencies>
    

    一、使用Slf4j+logback输出日志

    1.在resources资源目录下创建logback.xml文件
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration debug="false">
    
        <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
        <property name="LOG_HOME" value="D:/logs/" ></property>
    
        <!--控制台日志, 控制台输出 -->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符-->
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            </encoder>
        </appender>
    
        <!--文件日志, 按照每天生成日志文件 -->
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--日志文件输出的文件名-->
                <FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/pro.log</FileNamePattern>
                <!--日志文件保留天数-->
                <MaxHistory>30</MaxHistory>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            </encoder>
            <!--日志文件最大的大小-->
            <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
                <MaxFileSize>10MB</MaxFileSize>
            </triggeringPolicy>
        </appender>
    
        <!-- show parameters for hibernate sql 专为 Hibernate 定制 -->
        <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" ></logger>
        <logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" ></logger>
        <logger name="org.hibernate.SQL" level="DEBUG" ></logger>
        <logger name="org.hibernate.engine.QueryParameters" level="DEBUG" ></logger>
        <logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" ></logger>
    
        <!--myibatis log configure-->
        <logger name="com.apache.ibatis" level="TRACE" ></logger>
        <logger name="java.sql.Connection" level="DEBUG" ></logger>
        <logger name="java.sql.Statement" level="DEBUG" ></logger>
        <logger name="java.sql.PreparedStatement" level="DEBUG" ></logger>
    
        <!-- 日志输出级别 -->
        <root level="INFO">
            <appender-ref ref="STDOUT" ></appender-ref>
            <appender-ref ref="FILE" ></appender-ref>
        </root>
    </configuration>
    
    2.application.yml配置文件中配置
    server:
      port: 8080
    
    #配置日志文件路径
    logging:
      config: classpath:logback.xml
    
    2.controller层中创建LogsController,添加getLog函数如下:
    @RestController
    @Slf4j
    public class LogsController {
        @RequestMapping("/log")
        public void getLog() {
            try {
                log.error("错误日志输出");
                log.info("信息日志输出");
                int i = 10 / 0;
            } catch (Exception e) {
                log.error("Exception", e);
            }
        }
    }
    

    Slf4j注解定义了log变量。
    访问http://localhost:8080/log ,可以看到生成了D:logs2019-12-10pro.log文件,这是在logback.xml文件中配置了的。
    这里故意制造了一个除以0的异常,配合抓取的异常信息。
    控制台输出:

    D:logs2019-12-10pro.log文件输出:

    二、springboot的多环境配置

    springboot使用配置简化了xml,极大地方便了开发。但是开发环境、测试环境、生产环境的配置是不一样的,举个例子,当我们连接数据库时,需要在配置文件中配置数据源,如果一直每次部署到线上测试的时候都要修改数据库连接、账户密码等,就会非常麻烦,还容易改错。多环境配置就解决了这个问题,只需要创建多个配置文件,需要修改的时候只切换所选配置文件就行。

    首先创建三个配置文件:application-dev.yml、application-test.yml、application-pro.yml
    在application-dev.yml配置

    lxg:
      msg: 这是开发环境
    

    在application-test.yml配置

    lxg:
      msg: 这是测试环境
    

    在application-pro.yml配置

    lxg:
      msg: 这是生产环境
    

    在application.yml配置文件中引入对应环境的配置文件

    spring:
      profiles:
        active: dev
    

    这里的值是根据之前创建的配置文件的名后缀定义的。

    在LogsController中定义一个全局变量,使用Value注解引入对应的变量,语法如下

    @Value("${lxg.msg}")
    private String msg;
    

    添加接口,输出该变量。

    输出的是我们选择的配置文件中定义的变量。

    三、使用AOP统一处理Web请求日志

    在config目录中创建WebLogAspect切面类

    @Component
    @Aspect
    @Slf4j
    public class WebLogAspect {
        /**
         * 设置切点
         */
        @Pointcut("execution(public * com.lxg.controller.*.*(..))")
        public void webLog() {
        }
    
        @Before("webLog()")
        public void doBefore() {
            // 接收到请求,记录请求内容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            // 记录下请求内容
            log.info("URL : " + request.getRequestURL().toString());
            log.info("HTTP_METHOD : " + request.getMethod());
            log.info("IP : " + request.getRemoteAddr());
            Enumeration<String> enu = request.getParameterNames();
            while (enu.hasMoreElements()) {
                String name = enu.nextElement();
                log.info("name:{},value:{}", name, request.getParameter(name));
            }
        }
    
        @AfterReturning(returning = "ret", pointcut = "webLog()")
        public void doAfterReturning(Object ret){
            // 处理完请求,返回内容
            log.info("RESPONSE : " + ret);
        }
    }
    

    Component注解是将当前类注入到spring容器中,且每次调用该类都是新创建的对象。
    Slf4j注解定义了log变量。
    Pointcut设置了切点的位置
    此时再次访问http://localhost:8080/msg 控制台输出日志,

    日志文件输出:

    四、热部署

    热部署就是在不手动重新部署的情况下,代码修改后自动编译部署。

    spring-boot-devtools 是一个为开发者服务的一个模块,其中最重要的功能就是自动应用代码更改到最新的App上面去。原理是在发现代码有更改之后,重新启动应用,但是速度比手动停止后再启动还要更快,更快指的不是节省出来的手工操作的时间。

    其深层原理是使用了两个ClassLoader,一个Classloader加载那些不会改变的类(第三方Jar包),另一个ClassLoader加载会更改的类,称为restart ClassLoader,这样在有代码更改的时候,原来的restart ClassLoader 被丢弃,重新创建一个restart ClassLoader,由于需要加载的类相比较少,所以实现了较快的重启时间。

    1.打开菜单栏 File -> Settings -> Default Settings -> Build -> Compiler 然后勾选 Build project automatically 。

    2.同时按住 Ctrl + Shift + Alt + / 然后进入Registry ,勾选自动编译并调整延时参数。

    3.选择更新范围

    4.添加依赖

    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-devtools</artifactId>
    	<optional>true</optional>
    	<scope>true</scope>
    </dependency>
    

    启动项目后,修改yml文件中引入的dev,test,pro,访问msg接口会返回不同的结果。

    本文GitHub源码:https://github.com/lixianguo5097/springboot/tree/master/springboot-logs

    CSDN:https://blog.csdn.net/qq_27682773
    简书:https://www.jianshu.com/u/e99381e6886e
    博客园:https://www.cnblogs.com/lixianguo
    个人博客:https://www.lxgblog.com

  • 相关阅读:
    arcgis增大缩放级别
    arcgis地图窗口操作
    arcgis访问百度地图
    内存溢出和内存泄漏的区别、产生原因以及解决方案
    多线程之sleep和wait的区别
    java技术-重点方向
    技术思维VS管理思维
    几个问题
    写完百行代码,一次运行全部案例通过 是什么体验?
    分布式开放消息系统(RocketMQ)的原理与实践
  • 原文地址:https://www.cnblogs.com/lixianguo/p/12522453.html
Copyright © 2011-2022 走看看