zoukankan      html  css  js  c++  java
  • Springboot的日志管理&Springboot整合Junit测试&Springboot中AOP的使用

    ==============Springboot的日志管理=============

      springboot无需引入日志的包,springboot默认已经依赖了slf4j、logback、log4j等日志。我习惯用slf4j,下面就用slf4j做配置。

    如果你导入了spring-boot-starter-web,这个会自动依赖上述日志。如下依赖:

    0.日志测试类:

    package daoTest;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import cn.qlq.MySpringBootApplication;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = MySpringBootApplication.class)
    public class PlainTest {
        private static final Logger logger = LoggerFactory.getLogger(PlainTest.class);
    
        @Test
        public void findAll() {
            logger.error("error , msg->{} ", "错误");
            logger.info("info , msg->{} ", "信息");
        }
    }

    1.springboot默认的日志级别是debug

     

    2.如果需要修改日志的相关配置可以修改applications.properties文件

    ############################################################
    #
    # 日志相关配置(默认集成的有slf4j,Logback等)
    #
    ############################################################
    #指定配置文件的位置,只能是xml或者groovy结尾
    #logging.config=classpath:logback.xml
    #默认的日志级别
    logging.level.root=INFO
    # mapper 接口所在的包设置为 debug
    logging.level.cn.qlq.mapper=DEBUG
    #生成日志文件的位置
    logging.file=G:/springboot.log
    #生成日志文件的目录,名称默认为spring.log
    #logging.path=e:/
    #指定日志的格式
    #logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %clr(%logger){cyan} %clr(%msg%n){green}
    #logging.pattern.file=%d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n

         解释:上面logging.level.root可以指定所以包默认的日志级别,logging.level.cn.qlq.mapper是对单独的子包设定日志级别,其级别可低于上面的root,也可以高于root

        logging.file是指定文件日志的输出位置以及名称,logging.path是指定日志文件的位置,默认名称是spring.log(如果两者都配置以logging.file生效)

        最后面是指定控制台和输出文件的日志格式。

        logging.config是指定配置文件的位置,只能是xml或者groovy结尾。

      关于日志级别等大致相同,参考:https://www.cnblogs.com/qlqwjy/p/9275415.html

    ==============Springboot整合Junit测试=============

    Springboot中我们也可以像在普通的SSM环境中进行SpringJunit测试。

    1.引入测试需要的模块

            <!--springboot单元测试 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>

    2.建立测试目录,一般在src/test/java下面和src/test/resources目录下

      mapper文件和配置文件要复制到src/test/resources目录下。

    3.建立测试类进行测试

      SpringBootTest的classes是springboot项目启动的运行类,也就是带有@SpringBootApplication的类。

    package daoTest;
    
    import java.util.List;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import cn.qlq.MySpringBootApplication;
    import cn.qlq.bean.User;
    import cn.qlq.mapper.UserMapper;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = MySpringBootApplication.class)
    public class PlainTest {
        @Autowired
        private UserMapper userMapper;
    
        @Test
        public void findAll() {
            List<User> findAll = userMapper.findAll();
            System.out.println(findAll);
        }
    }

    ==============Springboot的AOP整合=============

      springboot整合Aop非常简单,只用引入AOP模块的依赖即可。然后就可以使用注解AOP。

            <!-- 引入 spring aop 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>

    1.AOP的第一种切入方式:基于切点表达式进行拦截

      如下记录servcice层的所有方法的执行时间的AOP写法

    package cn.qlq.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    /**
     * 记录service层执行时间的AOP切面
     * 
     * @author QiaoLiQiang
     * @time 2019年2月21日下午9:20:15
     */
    @Aspect
    @Component
    public class LogServiceTakeTime {
        private final static Logger log = LoggerFactory.getLogger(LogServiceTakeTime.class);
    
        @Pointcut("execution(* cn.qlq.service..*.*(..))")
        public void performance() {
        }
    
        /**
         * 环绕通知记录时间
         * 
         * @param joinPoint
         * @return
         * @throws Throwable
         */
        @Around("performance()")
        public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
    
            // 记录起始时间
            long begin = System.currentTimeMillis();
            Object result = "";
            /** 执行目标方法 */
            try {
                result = joinPoint.proceed();
            } catch (Exception e) {
                log.error("日志记录发生错误, errorMessage: {}", e.getMessage());
            } finally {
                /** 记录操作时间 */
                long took = (System.currentTimeMillis() - begin) / 1000;
                log.info("Service执行时间为: {}秒", took);
            }
            return result;
        }
    
        /**
         * 前置通知
         * 
         * @param joinPoint
         * @throws Throwable
         */
        @Before("performance()")
        public void doBefore(JoinPoint joinPoint) throws Throwable {
            // 接收到请求,记录请求内容
            log.info("doBefore");
        }
    
    }

    2.第二种切入方式:基于注解

    (1)编写注解

    package cn.qlq.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 自定义注解
     * 
     * @author QiaoLiQiang
     * @time 2019年2月21日下午9:45:17
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyLogAnnotation {
        String operateDescription();// 记录日志的操作类型,不写默认值就是一个必须填的注解
    }

    (2)编写切面进行拦截:一般在环绕通知中处理足够了

    package cn.qlq.aspect;
    
    import java.lang.reflect.Method;
    import java.sql.SQLException;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import cn.qlq.annotation.MyLogAnnotation;
    
    /**
     * @Author: qlq
     * @Description 日志记录切面(拦截自定义注解进行日志记录)
     * @Date: 11:46 2018/5/14
     */
    @Component
    @Aspect
    public class MyLogAspect {
        private final static Logger log = LoggerFactory.getLogger(MyLogAspect.class);
    
        /**
         * 环绕通知处理
         *
         * @param pjp
         * @return
         * @throws Throwable
         */
        @Around("@annotation(cn.qlq.annotation.MyLogAnnotation)")
        public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
            // 1.方法执行前的处理,相当于前置通知
            // 获取方法签名
            MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
            // 获取方法
            Method method = methodSignature.getMethod();
            // 获取方法上面的注解
            MyLogAnnotation logAnno = method.getAnnotation(MyLogAnnotation.class);
            // 获取到类名
            String targetName = pjp.getTarget().getClass().getName();
            // 获取到方法名字
            String methodName = method.getName();
            // 获取操作描述的属性值
            String operateDescription = logAnno.operateDescription();
            Object result = null;
            try {
                // 让代理方法执行
                result = pjp.proceed();
                // 2.相当于后置通知(方法成功执行之后走这里)
            } catch (SQLException e) {
                // 3.相当于异常通知部分
            } finally {
                // 4.相当于最终通知
                log.info("class->{},methodName->{},operateDescription->{}", targetName, methodName, operateDescription);
            }
            return result;
        }
    }

    (3)测试:

    结果:

       关于AOP在之前也研究过了,在这里就只研究其使用,具体的使用方法参考:https://www.cnblogs.com/qlqwjy/p/8729280.html                               https://www.cnblogs.com/qlqwjy/p/8747476.html

  • 相关阅读:
    python_tkinter弹出对话框2
    python_tkinter弹出对话框1
    python生成图片二维码(利用pillow)
    nginx配置ssl证书流程及常见问题
    Django app安装,配置mysql,时区,模板,静态文件,媒体,admin
    使用Git Flow规范!
    python快速生成验证码
    json&pickle模块
    sys模块
    常用模块
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/10412481.html
Copyright © 2011-2022 走看看