SpringBoot 自定义注解+AOP进行方法增强

2 篇文章 0 订阅
1 篇文章 0 订阅


GitHub: link. 欢迎star

注意:本篇博客风格(不多比比就是撸代码!!!)

一、maven依赖

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

二、DemoAnnotation.java

import java.lang.annotation.*;

/**
 * @author Andon
 * 2021/12/9
 * <p>
 * 自定义注解
 */
@Target(ElementType.METHOD) //定义注解使用位置
@Retention(RetentionPolicy.RUNTIME) //注解声明周期
@Documented //可以被工具文档化
public @interface DemoAnnotation {

    String testValue() default "testValue";
}

三、DemoAspect.java

import com.alibaba.fastjson.JSONObject;
import com.andon.springbootutil.annotation.DemoAnnotation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

/**
 * @author Andon
 * 2021/12/9
 * <p>
 * 切面类
 */
@Slf4j
@Aspect //定义切面类
@Component //交给Spring来管理
public class DemoAspect {

    /**
     * 声明切入点,包名表达式或者注解路径
     */
    @Pointcut("@annotation(com.andon.springbootutil.annotation.DemoAnnotation)")
    public void pointCut() {
    }

    /**
     * 前置通知,关注点执行前运行的方法
     * && @annotation与参数上的注解参数名对应,则可以获取被增强方法上注解的属性
     */
    @Before("pointCut() && @annotation(demoAnnotation)")
    public void before(JoinPoint joinPoint, DemoAnnotation demoAnnotation) {
        String testValue = demoAnnotation.testValue();
        Object[] args = joinPoint.getArgs();
        log.info("before [{}-{}] 前置通知!! args:{} testValue:{}", Thread.currentThread().getName(), Thread.currentThread().getId(), JSONObject.toJSONString(args), testValue);
    }

    /**
     * 后置通知,不论一个方法是如何结束的,最终通知都会运行
     */
    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        log.info("after [{}-{}] 后置通知!! args:{}", Thread.currentThread().getName(), Thread.currentThread().getId(), JSONObject.toJSONString(args));
    }

    /**
     * 后置通知,获取方法的返回值
     * returning赋值的参数,用来接收被增强方法的任意类型的返回值
     */
    @AfterReturning(value = "pointCut()", returning = "returnValue")
    public Object afterReturning(JoinPoint joinPoint, Object returnValue) {
        Object[] args = joinPoint.getArgs();
        log.info("afterReturning [{}-{}] 返回后通知!! args:{} returnValue:{}", Thread.currentThread().getName(), Thread.currentThread().getId(), JSONObject.toJSONString(args), JSONObject.toJSONString(returnValue));
        return returnValue;
    }

    /**
     * 异常通知
     * 如果想要限制通知只在某种特定的异常被抛出的时候匹配,同时还想知道异常的一些信息。
     * 那我们就需要使用throwing属性声明响应
     */
    @AfterThrowing(value = "pointCut()", throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint, Exception exception) {
        Object[] args = joinPoint.getArgs();
        log.info("afterThrowing [{}-{}] 异常通知!! args:{} error:{}", Thread.currentThread().getName(), Thread.currentThread().getId(), JSONObject.toJSONString(args), exception.getMessage());
    }

    /**
     * 环绕通知
     */
    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String remoteHost = request.getRemoteHost(); //访问者ip
        String method = request.getMethod(); //请求方式
        String uri = request.getRequestURI(); //请求路径
        String methodName = pjp.getSignature().getName(); //获取方法名
        Enumeration<String> headerNames = request.getHeaderNames();
        JSONObject headers = new JSONObject();
        while (headerNames.hasMoreElements()) {
            String s = headerNames.nextElement();
            headers.put(s, request.getHeader(s)); //请求头
        }
        Object[] args = pjp.getArgs(); //获取入参
        log.info("around [{}-{}] 环绕通知start!! remoteHost:{} method:{} uri:{} methodName:{} headers:{} args:{}", Thread.currentThread().getName(), Thread.currentThread().getId(), remoteHost, method, uri, methodName, headers.toJSONString(), JSONObject.toJSONString(args));
        Object obj = pjp.proceed();
        log.info("around [{}-{}] 环绕通知end!!", Thread.currentThread().getName(), Thread.currentThread().getId());
        return obj;
    }
}

四、TestAopController.java

import com.alibaba.fastjson.JSONObject;
import com.andon.springbootutil.annotation.DemoAnnotation;
import com.andon.springbootutil.vo.TestSwaggerTest2Req;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

/**
 * @author Andon
 * 2021/12/9
 */
@Slf4j
@Api(tags = "aop")
@RestController
@RequestMapping(value = "/aop")
public class TestAopController {

    @DemoAnnotation(testValue = "test!!")
    @ApiOperation("测试")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "value", value = "值", required = true)
    })
    @GetMapping(value = "/test")
    public String test(String value) {
        log.info("test!! value:{}", value);
        return value;
    }

    @DemoAnnotation
    @ApiOperation("测试2")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "value", value = "值", required = true)
    })
    @GetMapping(value = "/test2")
    public String test2(String value) throws Exception {
        log.info("test!! value:{}", value);
        throw new Exception("throw new Exception!!");
    }

    @DemoAnnotation
    @ApiOperation("测试3")
    @PostMapping(value = "/test3")
    public TestSwaggerTest2Req test3(@RequestBody TestSwaggerTest2Req test) {
        log.info("test3!! test:{}", JSONObject.toJSONString(test));
        return test;
    }
}

五、测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
GitHub: link. 欢迎star

好的,关于SpringBoot自定义注解AOP的问题,我可以为您提供一些基本的介绍和示例代码。 首先,AOP(Aspect-Oriented Programming)是一种编程范式,它可以在不修改业务逻辑代码的情况下,对应用程序进行横切关注点的切面处理。而Spring AOP作为Spring框架的一部分,提供了一种基于代理模式的AOP实现。 在使用Spring AOP的过程中,自定义注解可以作为切点表达式的一部分,通过对注解的解析,实现对被注解的方法或类的切面处理。下面是一个简单的示例代码,演示如何通过自定义注解实现对方法AOP处理: 首先,定义一个自定义注解: ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyAnnotation { String value() default ""; } ``` 然后,在需要被拦截的方法上添加该注解: ```java @Service public class MyService { @MyAnnotation("myAnnotation") public void doSomething() { System.out.println("do something..."); } } ``` 接下来,使用AspectJ的@Aspect注解定义一个切面类,并在该类中定义一个切点,用于匹配被@MyAnnotation注解的方法: ```java @Aspect @Component public class MyAspect { @Pointcut("@annotation(com.example.demo.annotation.MyAnnotation)") public void myAnnotationPointcut() {} @Before("myAnnotationPointcut()") public void beforeMyAnnotation() { System.out.println("before myAnnotation..."); } } ``` 最后,启动SpringBoot应用程序,调用MyService的doSomething方法,就可以看到输出结果: ```java before myAnnotation... do something... ``` 以上就是一个简单的SpringBoot自定义注解AOP的示例。通过使用自定义注解,可以更加方便地实现对应用程序的切面处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值