SpringBoot中使用AspectJ

pom中添加依赖

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

常规切面使用

切入指定包类目录,如@Pointcut("execution(* sb.simple.aspectj.normal.*.*(..))")

@Pointcut参数正则可以自行了解一下

  • 切面类

    package sb.simple.aspectj.normal;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.Arrays;
    
    /**
     * AspectJ
     * 五种通知注解:@Before/@Around/@After/@AfterReturning/@AfterThrowing
     */
    @Configuration
    @Aspect
    public class AJNormal {
    
        @Pointcut("execution(* sb.simple.aspectj.normal.*.*(..))")
        public void point() { }
    
        /**
         * 前置通知
         * 连接点之前执行
         */
        @Before("point()")
        public void before(JoinPoint joinPoint) {
            String methodName = joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
            System.out.println("before() methodName:" + methodName + ", args:" + Arrays.toString(args));
        }
    
        @Around("point()")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            String methodName = joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
            System.out.println("around() before proceed");
            Object proceed = joinPoint.proceed();
            System.out.println("around() after proceed methodName:" + methodName + ", args:" + Arrays.toString(args) + ", result:" + proceed);
            return proceed;
        }
    
        /**
         * 后置通知
         * 连接点方法完成后执行
         * 无论连接点执行成功与否该通知都会执行
         */
        @After("point()")
        public void after(JoinPoint joinPoint) {
            String methodName = joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
            System.out.println("after() methodName:" + methodName + ", args:" + Arrays.toString(args));
        }
    
        /**
         * 连接点方法执行成功后执行
         * 可以拿到返回结果
         */
        @AfterReturning(value = "point()", returning = "result")
        public void result(JoinPoint joinPoint, Object result) {
            String methodName = joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
            System.out.println("AfterReturning() methodName:" + methodName + ", args:" + Arrays.toString(args) + ", result:" + result);
        }
    
        /**
         * 连接点方法执行异常后执行
         * 可以拿到异常信息
         */
        @AfterThrowing(value = "point()", throwing = "exception")
        public void afterThrowing(JoinPoint joinPoint, Exception exception) {
            String methodName = joinPoint.getSignature().getName();
            Object[] args = joinPoint.getArgs();
            System.out.println("afterThrowing() methodName:" + methodName + ", args:" + Arrays.toString(args) + ", exception:" + exception);
        }
    }
    
  • 被切类

    package sb.simple.aspectj.normal;
    
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Service;
    
    @Service
    @Component
    public class CalcService {
    
        public int add(int a, int b) {
            int result = a + b;
            System.out.println("CalcService->add() result:" + result);
            return a + b;
        }
    
        //测试AfterThrowing通知
        public int divider(int a, int b) {
            int result = a / b;
            System.out.println("CalcService->divider() result:" + result);
            return result;
        }
    }
    
  • 测试类

    package sb.simple.aspectj;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import sb.simple.aspectj.annotation.CalcAnClass;
    import sb.simple.aspectj.annotation.CalcAnMethod;
    import sb.simple.aspectj.normal.CalcService;
    
    @SpringBootTest
    public class AJTest {
    
    
        /**普通切入*/
        @Autowired
        private CalcService calcService;
    
        /*
        around() before proceed
        before() methodName:add, args:[1, 2]
        CalcService->add() result:3
        AfterReturning() methodName:add, args:[1, 2], result:3
        after() methodName:add, args:[1, 2]
        around() after proceed methodName:add, args:[1, 2], result:3
         */
        @Test
        public void testAdd() {
            calcService.add(1, 2);
        }
    
        /*
        around() before proceed
        before() methodName:divider, args:[3, 0]
        afterThrowing() methodName:divider, args:[3, 0], exception:java.lang.ArithmeticException: / by zero
        after() methodName:divider, args:[3, 0]
         */
        @Test
        public void testDivider() {
            calcService.divider(3, 0);
        }
    
    
        /*不用@Service注解实例化aspectj就没用
        CalcService->add() result:8
         */
        @Test
        public void testAddNew() {
            new CalcService().add(3, 5);
        }
    }
    

配合自定义注解使用

  • 自定义注解

    package sb.simple.aspectj.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    //METHOD->注解于方法 | TYPE->注解于类
    @Target({ElementType.METHOD, ElementType.TYPE})
    public @interface Require {
    
        String value();
    }
    
  • 被切类

    package sb.simple.aspectj.annotation;
    
    import org.springframework.stereotype.Service;
    
    //注解于类
    @Service
    @Require("in class")
    public class CalcAnClass {
    
        public void hi(String name) {
            System.out.println(getClass().getSimpleName() + ": hi:" + name);
        }
    }
    

    package sb.simple.aspectj.annotation;
    
    import org.springframework.stereotype.Service;
    
    //注解于方法
    @Service
    public class CalcAnMethod {
    
        @Require("in method")
        public void hi(String name) {
            System.out.println(getClass().getSimpleName() + ": hi:" + name);
        }
    }
    
  • 切面类

    在通知方法@Around中,通过ProceedingJoinPoint实例可以获取被切方法的方法名,方法参数,所在类,注解,注解参数等,可以通过这些数据对方法进行增强

    package sb.simple.aspectj.annotation;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.context.annotation.Configuration;
    
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    @Configuration
    @Aspect
    public class AJAnnotation {
    
        /**注解于类@within*/
        @Pointcut("@within(sb.simple.aspectj.annotation.Require)&&execution(public * *.*(..))")
        public void pointClass() { }
    
        @Around("pointClass()")
        public Object aroundClass(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("aroundClass() in");
    
            //获取在类上的注解中的属性值
            String className = joinPoint.getTarget().getClass().getName();
            Class<?> clz = Class.forName(className);
            Require require = clz.getAnnotation(Require.class);
            System.out.println("annotation(class), clzName:" + clz.getSimpleName());
            String value = require.value();
            System.out.println("annotation(class)->Require->value:" + value);
    
            return joinPoint.proceed();
        }
    
    
        /**注解于方法@annotation*/
        @Pointcut("@annotation(sb.simple.aspectj.annotation.Require)")
        public void point() { }
    
    
        @Around("point()")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("aroundMethod() in");
    
            //获取在方法上的注解的属性值
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Class<?> clz = joinPoint.getTarget().getClass();
            String name = signature.getName();
            Class[] parameterTypes = signature.getParameterTypes();
            Method method = clz.getMethod(name, parameterTypes);
            System.out.println("annotation(method), clzName:" + clz.getSimpleName() + ", name:" + name + ", parameterTypes:" + Arrays.toString(parameterTypes));
            Require require = method.getAnnotation(Require.class);
            String value = require.value();
            System.out.println("annotation(method)->Require->value:" + value);
    
    
            return joinPoint.proceed();
        }
    }
    
  • 测试类

    package sb.simple.aspectj;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import sb.simple.aspectj.annotation.CalcAnClass;
    import sb.simple.aspectj.annotation.CalcAnMethod;
    import sb.simple.aspectj.normal.CalcService;
    
    @SpringBootTest
    public class AJTest {
    
        /**配合自定义注解切入*/
        @Autowired
        CalcAnClass calcAnClass;
    
        @Test
        public void anClass() {
            calcAnClass.hi("akali(class)");
        }
    
        @Autowired
        CalcAnMethod calcAnMethod;
    
        @Test
        public void anMethod() {
            calcAnMethod.hi("annie(method)");
        }
    }
    
Spring Boot整合AspectJ可以实现面向切面编程,用于在应用添加横切关注点(Cross-cutting Concerns)。下面是一个简单的示例步骤: 1. 在Spring Boot项目的`pom.xml`文件添加AspectJ依赖项: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` 2. 创建一个切面类,该类包含一个或多个切点和通知方法。例如,创建一个名为`LoggingAspect`的类: ```java @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.demo.YourService.*(..))") public void beforeMethodExecution(JoinPoint joinPoint) { // 在方法执行前执行的逻辑 System.out.println("Before method execution: " + joinPoint.getSignature().getName()); } @After("execution(* com.example.demo.YourService.*(..))") public void afterMethodExecution(JoinPoint joinPoint) { // 在方法执行后执行的逻辑 System.out.println("After method execution: " + joinPoint.getSignature().getName()); } } ``` 3. 在切面类定义通知方法,并使用注解指定在哪些连接点上触发该通知。在上面的示例,`@Before`和`@After`注解分别表示在目标方法执行前和执行后触发通知。你需要根据自己的需求调整切点表达式。 4. 在启动类上添加`@EnableAspectJAutoProxy`注解,启用AspectJ自动代理。 ```java @SpringBootApplication @EnableAspectJAutoProxy public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } } ``` 5. 运行应用程序,并观察控制台输出。在目标方法执行之前和之后,切面定义的通知方法将分别被触发。 这样,你就成功地将AspectJSpring Boot项目整合起来了。你可以根据具体的需求在切面类添加更多的通知方法和切点表达式。注意,AspectJ提供了丰富的语法和功能,可以处理更复杂的场景。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值