SpringBoot利用自定义注解实现AOP

SpringBoot利用自定义注解实现AOP

java

本文主要讲解利用SpringBoot的自定义注解来实现AOP思想。

在开始所有的操作之前,需要导入aop坐标:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

如何自定义注解?

实际上注解本质上是一个@interface类,在这个类前面可以通过一些注解来限制这个注解类的使用范围,比如@Target@Retention等等,有关这方面的文章用搜索引擎可以搜出一大把。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WriteLog {
    String note() default "";
}

自定义注解AOP的切面

切面是有一系列切点与增强组成,所以在@Aspect所注解的类中,需要配置切点增强

切点

使用@Pointcut注解,然并通过@annontationexecution()等方法缺陷切点的范围;

这里因为是使用自定义注解的形式来指定切点,所以是使用@annontation的形式,前提是需要在被增强的方法或者类前面添加自定义的注解。

/**
 * 定义切点
 * @param writeLog
 */
@Pointcut("@annotation(writeLog)")
public void writeLogPoincut(WriteLog writeLog) {

}
/**
 * 还可以这样定义,但是这样增强就无法获取切点信息
 */
@Pointcut("@annotation(com.songwh.annontation.annontation.WriteLog)")
public void writeLogPoincut() {
}

增强

AOP中的增强主要是以下几种:

  1. Before,在被增强的代码执行之前执行;
  2. After,在被增强的代码执行之后执行
  3. AfterReturning,在被增强的代码正确返回后执行,通过returning可以获取返回值;
  4. Around,在被增强的代码执行前和执行后都会执行,主要是通过ProceedingJoinPoint.process()方法来调用被增强代码;
  5. AgterThrowing,在被增强代码出现异常后执行,可以捕捉到异常的信息,可以通过throwing来获取异常对象。
@Component
@Aspect
public class WriteLogAspect {

    private final static Logger LOGGER = LoggerFactory.getLogger(WriteLogAspect.class);
    private final static String POINT_CUT = "writeLogPoincut(writeLog)";

    /**
     * 定义切点
     * @param writeLog
     */
    @Pointcut("@annotation(writeLog)")
    public void writeLogPoincut(WriteLog writeLog) {

    }
    /**
     * 还可以这样定义,但是这样,增强就无法获取切点信息
     */
//    @Pointcut("@annotation(com.songwh.annontation.annontation.WriteLog)")
//    public void writeLogPoincut() {
//
//    }

    /**
     * 在主程序出现异常后执行
     * @param joinPoint
     * @param ex
     * @param writeLog
     */
    @AfterThrowing(value = POINT_CUT, throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable ex, WriteLog writeLog) {
        commonLog(joinPoint, writeLog, "AfterThrowing");
        LOGGER.info("出现异常:" + ex.getMessage());
    }

    /**
     * 在主程序执行前执行
     * @param joinPoint
     * @param writeLog
     */
    @Before(value = POINT_CUT)
    public void doBefore(JoinPoint joinPoint, WriteLog writeLog) {
        commonLog(joinPoint, writeLog, "Before");
    }

    /**
     * 在主程序执行后的增强
     * @param joinPoint
     * @param writeLog
     */
    @After(value = POINT_CUT)
    public void doAfter(JoinPoint joinPoint, WriteLog writeLog) {
        commonLog(joinPoint, writeLog, "After");
    }

    /**
     * 正确返回后执行的增强
     * @param joinPoint
     * @param rt
     * @param writeLog
     */
    @AfterReturning(value = POINT_CUT, returning = "rt")
    public void doAfterReturning(JoinPoint joinPoint, Object rt, WriteLog writeLog) {
        commonLog(joinPoint, writeLog, "AfterReturning");
        LOGGER.info("返回值:" + rt);
    }

    /**
     * 此处必须有返回值,不然是无法
     *
     * @param proceedingJoinPoint
     * @param writeLog
     * @return
     */
    @Around(value = POINT_CUT)
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint, WriteLog writeLog) throws Throwable {
        commonLog(proceedingJoinPoint, writeLog, "doAround-before");
        Object proceed = null;
        // 如果需要使用异常捕获AfterThrowing,此处的异常一改抛出,不能try catch
        proceed = proceedingJoinPoint.proceed();
        //此处对返回值的修改是有效的
        proceed = "around修改后的返回值";

        commonLog(proceedingJoinPoint, writeLog, "doAround-after");
        return proceed;
    }
    private void commonLog(JoinPoint joinPoint, WriteLog writeLog, String action) {
        Object[] args = joinPoint.getArgs();
        LOGGER.info("******************" + action + ":" + writeLog.note() + "******************");
        LOGGER.info("方法名:" + joinPoint.getSignature().getName());
        LOGGER.info("参数:" + new Gson().toJson(args));
    }
}

AOP的运行顺序

在面向切面编程的过程中AOP的执行顺序是:Around-before>>Befer>>主程序执行>>Around-after>>After>>AfterReturning>>End

各切点增强的执行顺序

如果是AfterThrowing则则执行顺序是:Around-before>>Befer>>主程序执行>>AfterThrowing>>End

程序出现异常的增强执行顺序

重点

  1. Around增强执行后的返回值一定要返回,否则返回值是null;
  2. 如果既有Around又有AfterThrowing两个增强,那么Around增强里面执行主程序的异常不能进行try catch,否则,AfterThrowing将无法正常捕获异常。![enter

原文地址:https://www.cnblogs.com/alltoforever/p/10308365.html

时间: 2024-11-05 13:34:59

SpringBoot利用自定义注解实现AOP的相关文章

通过自定义注解与aop统一存储操作记录

模块开发完成后,接到通知需要添加操作记录功能,看着那一堆接口,如果一个方法一个方法的加,那真是太麻烦了.为了偷懒,就百度了一下,发现可以通过自定义注解和aop的形式来统一添加操作记录,只需要在每个方法上面添加自定义的注解就可以了.我在这里用的是springboot2.0以及jpa,废话不多说,直接上代码~ 自定义注解serverLog import java.lang.annotation.ElementType; import java.lang.annotation.Retention; i

基于 自定义注解 和 aop 实现使用memcache 对数据库的缓存 示例

好久没更新blog了,在新公司打拼了两个月,每天都从早忙到晚,学到了很多东西,但是没有时间来更新blog了.... 下面开始讲解这次的主题 公司老大让我研究 ocs 就是阿里云的 开放缓存服务 点击打开链接 其实就是一个memcache的服务 memchech 就是用内存来存放 key -value  在一些情况下就不必频繁的访问 数据库了(其实就是个map) 如何在常用的Dao中方便的使用这个map呢,我首先想到了 aop,然后又想到了自定义注解,那么就开始干吧.... aop动态代理要使用的

自定义注解实现AOP日志记录

自定义注解 package com.annotation; import java.lang.annotation.*; /** *自定义注解 拦截Controller */ @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface SystemLog { String module() default ""

使用自定义注解和AOP管理shiro权限

一.场景 在使用shiro框架的时候,遇到了这样的需求:本系统有多个用户,每个用户分配不同角色,每个角色的权限也不一致.比如A用户拥有新闻列表的增删改查权限,而B用户只有查看新闻列表的权限,而没有删除.新增.修改的权限,此时有3种方案:1.不给B用户分配删除.新增.修改的菜单,这样用户就无法点击从而无法操作.2.给B用户分配菜单,后台中进行增删改查操作时都要进行权限验证.  3.给B用户分配菜单并且进行操作的时候校验权限. 显然,第2.3种方案比第1中方案要安全.本系统中使用第二种方案. 二.为

自定义注解-基于AOP

依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> 注解1(不带参数): /** * sea test 使用 AOP 自定义注解(不带参数) * @author sea * */ @Target({ElementType.METHOD}) @

利用自定义注解在SpringMVC中实现自定义权限检查

先描述一下应用场景,基于Spring MVC的WEB程序,需要对每个Action进行权限判断,当前用户有权限则允许执行Action,无权限要出错提示.权限有很多种,比如用户管理权限.日志审计权限.系统配置权限等等,每种权限还会带参数,比如各个权限还要区分读权限还是写权限. 想实现统一的权限检查,就要对Action进行拦截,一般是通过拦截器来做,可以实现HandlerInterceptor或者HandlerInterceptorAdapter,但是每个Action都有不同的权限检查,比如getUs

springboot项目自定义注解实现的多数据源切换

一.主要依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> <relativePath/> </parent> <dependency> <groupId

参数上使用自定义注解在aop中无法获取到该参数

https://ask.csdn.net/questions/769477 /** * 环绕增强,验证权限 * @param joinPoint 目标对象 * @param authCheck 自定义的注解,Around必须这样写,否则自定义的注解无法传入 * */ @Around("pointAll() && @annotation(authCheck)") public Object before(ProceedingJoinPoint joinPoint, Aut

自定义注解的应用

在项目中经常会用到自定义注解,下面列举二个使用自定义注解的案例. 一.利用自定义注解打印接口调用时长日志 #创建ServiceLog类用来自定义注解 @Retention(RetentionPolicy.Runtime) @Target(ElementType.METHOD) public @interface ServiceLog { } #定义ServiceLogAspect类用来定义日志打印信息 @Component @Aspect public class ServiceLogAspec