文档章节

Spring Boot 使用AOP记录日志信息(十二)

老虎是个蛋蛋
 老虎是个蛋蛋
发布于 2018/12/28 18:37
字数 822
阅读 400
收藏 3

在使用spring时,大家往往会使用AOP来做一些统一性功能的操作,比如日志打印,数据拦截预处理等等,那么在spring boot中如何使用呢,本篇以日志打印为例,介绍一下如何在spring boot中使用AOP

  • 引入依赖
<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
	</dependencies>

  • 自定义一个注解
@Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取
@Target(ElementType.METHOD)//目标是方法
@Documented//文档生成时,该注解将被包含在javadoc中,可去掉
public @interface OperationLogger {
    /**
     * 模块名字
     */
    String modelName() default "";
    /**
     * 操作类型
     */
    String option();
}

  • 编写切面
@Aspect
@Component
public class SysLogAspect {
    private static final Logger logger = Logger.getLogger(SysLogAspect.class);
    /**
     * 定义Pointcut,Pointcut的名称,此方法不能有返回值,该方法只是一个标示
     */
    @Pointcut("@annotation(com.quick.aop.OperationLogger)")
    public void controllerAspect() {
        System.out.println("我是一个切入点");
    }
    /**
     * 前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。
     * @param joinPoint
     */
    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println("=====SysLogAspect前置通知开始=====");
        //handleLog(joinPoint, null);
    }

    /**
     * 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
     * @param joinPoint
     */
    @AfterReturning(pointcut = "controllerAspect()")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println("=====SysLogAspect后置通知开始=====");
        //handleLog(joinPoint, null);
    }

    /**
     * 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(value = "controllerAspect()", throwing = "e")
    public void doAfter(JoinPoint joinPoint, Exception e) {
        System.out.println("=====SysLogAspect异常通知开始=====");
        //handleLog(joinPoint, e);
    }

    /**
     * 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。
     * @param joinPoint
     */
    @Around("controllerAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("=====SysLogAspect 环绕通知开始=====");
        //handleLog(joinPoint, null);
        Object obj= joinPoint.proceed();
        System.out.println("=====SysLogAspect 环绕通知结束=====");
        return  obj;
    }

    /**
     * 日志处理
     *
     * @param joinPoint
     * @param e
     */
    private void handleLog(JoinPoint joinPoint, Exception e) {
        try {
            //获得注解
            OperationLogger logger = giveController(joinPoint);
            if (logger == null) {
                return;
            }

            String signature = joinPoint.getSignature().toString(); // 获取目标方法签名
            String methodName = signature.substring(signature.lastIndexOf(".") + 1,
                    signature.indexOf("("));

            String longTemp = joinPoint.getStaticPart().toLongString();
            String classType = joinPoint.getTarget().getClass().getName();

            Class<?> clazz = Class.forName(classType);

            Method[] methods = clazz.getDeclaredMethods();
            System.out.println("methodName: " + methodName);

            for (Method method : methods) {
                if (method.isAnnotationPresent(OperationLogger.class)
                        && method.getName().equals(methodName)) {
                    //OpLogger logger = method.getAnnotation(OpLogger.class);
                    String clazzName = clazz.getName();
                    System.out.println("clazzName: " + clazzName + ", methodName: "
                            + methodName);
                }
            }

        } catch (Exception exp) {
            logger.error("异常信息:{}", exp);
            exp.printStackTrace();
        }
    }

    /**
     * 获得注解
     * @param joinPoint
     * @return
     * @throws Exception
     */
    private static OperationLogger giveController(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(OperationLogger.class);
        }
        return null;
    }
}

  • 启动类中加入@EnableAspectJAutoProxy注解
@SpringBootApplication
@EnableAspectJAutoProxy
public class QuickAoplogApplication {

	public static void main(String[] args) {
		SpringApplication.run(QuickAoplogApplication.class, args);
	}
}

  • 编写测试类
@RestController
@RequestMapping("/test")
public class AopTestController {
    @RequestMapping("/test")
    @OperationLogger(modelName="test",option="test")
    public String test(){
        return "success";
    }
}

  • 启动服务,调用测试Controller看一下打印结果
=====SysLogAspect 环绕通知开始=====
=====SysLogAspect前置通知开始=====
=====SysLogAspect 环绕通知结束=====
=====SysLogAspect后置通知开始=====

ok,以上便是一个简单的日志打印的demo,以上的源码地址:https://gitee.com/wangGet/spring-boot-quick.git

© 著作权归作者所有

老虎是个蛋蛋
粉丝 173
博文 31
码字总数 40085
作品 0
朝阳
高级程序员
私信 提问
SpringBoot(四)之优雅地日志处理

一、简介 日志功能在j2ee项目中是一个相当常见的功能,在一个小项目中或许你可以在一个个方法中,使用日志表的Mapper生成一条条的日志记录,但这无非是最烂的做法之一,因为这种做法会让日志...

郑加威
2018/12/23
525
0
spring boot 集成shiro ,使用aspect记录日志不生效

现在我用了spring boot shiro 做我权限控制,用spring boot aspect来做我的日志记录,拦截的是controller层。但是现在我的shiro配置没有什么问题,权限可以控制。但是我用aspect记录日志的地...

王晓哲
2018/08/13
1K
1
恒宇少年/spring-boot-chapter

简书整套文档以及源码解析 专题 专题名称 专题描述 001 Spring Boot 核心技术 讲解SpringBoot一些企业级层面的核心组件 002 Spring Cloud 核心技术 对Spring Cloud核心技术全面讲解 003 Quer...

恒宇少年
2018/04/19
0
0
SpringBoot | 第二十四章:日志管理之AOP统一日志

前言 上一章节,介绍了目前开发中常见的及日志框架的整合知识。在很多时候,我们在开发一个系统时,不管出于何种考虑,比如是审计要求,或者防抵赖,还是保留操作痕迹的角度,一般都会有个全...

oKong
2018/08/24
1K
4
【HAVENT原创】使用 Spring Boot 的 AOP 自定义注解

关于 Spring Boot 引用 AOP 请参考前文:【HAVENT原创】使用 Spring Boot 的 AOP 全局记录执行时间日志 接下来我们要使用自定义的注解: 1. 首先定义一个注解接口对象 2. 在 HHWebLogAspect...

HAVENT
2018/08/13
68
0

没有更多内容

加载失败,请刷新页面

加载更多

前端技术之:Prisma Demo服务部署过程记录

安装前提条件: 1、已经安装了docker运行环境 2、以下命令执行记录发生在MackBook环境 3、已经安装了PostgreSQL(我使用的是11版本) 4、Node开发运行环境可以正常工作 首先需要通过Node包管...

popgis
27分钟前
4
0
数组和链表

数组 链表 技巧一:掌握链表,想轻松写出正确的链表代码,需要理解指针获引用的含义: 对指针的理解,记住下面的这句话就可以了: 将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指...

code-ortaerc
43分钟前
4
0
栈-链式(c/c++实现)

上次说“栈是在线性表演变而来的,线性表很自由,想往哪里插数据就往哪里插数据,想删哪数据就删哪数据...。但给线性表一些限制呢,就没那么自由了,把线性表的三边封起来就变成了栈,栈只能...

白客C
今天
40
0
Mybatis Plus service

/** * @author beth * @data 2019-10-20 23:34 */@RunWith(SpringRunner.class)@SpringBootTestpublic class ServiceTest { @Autowired private IUserInfoService iUserInfoS......

一个yuanbeth
今天
5
0
php7-internal 7 zval的操作

## 7.7 zval的操作 扩展中经常会用到各种类型的zval,PHP提供了很多宏用于不同类型zval的操作,尽管我们也可以自己操作zval,但这并不是一个好习惯,因为zval有很多其它用途的标识,如果自己...

冻结not
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部