AspectJ中JoinPoint和ProceedingJoinPoint注解的使用

本文详细介绍了AOP(面向切面编程)中的JointPoint和ProceedingJoinPoint概念,以及它们在Spring框架中的应用。JointPoint是程序执行过程中的可识别点,而Pointcut则是选择和组合这些点的规则。ProceedingJoinPoint在JointPoint基础上增加了proceed()方法,用于在环绕通知中启动目标方法的执行。通过实例展示了如何使用@Around注解定义环绕通知,并通过CustomLog注解实现日志记录功能。

概念

Joint Point

JointPoint是程序运行过程中可识别的点,这个点可以用来作为AOP切入点。JointPoint对象则包含了和切入相关的很多信息。比如切入点的对象,方法,属性等。我们可以通过反射的方式获取这些点的状态和信息,用于追踪tracing和记录logging应用信息。

Pointcut

pointcut 是一种程序结构和规则,它用于选取join point并收集这些point的上下文信息。
pointcut通常包含了一系列的Joint Point,我们可以通过pointcut来同时操作jointpoint。单从概念上,可以把Pointcut当做jointpoint的集合。

JointPoint和ProceedingJoinPoint区别
JoinPoint
joinpoint的方法如下

# 返回目标对象,即被代理的对象
Object getTarget();

# 返回切入点的参数
Object[] getArgs();

# 返回切入点的Signature
Signature getSignature();

# 返回切入的类型,比如method-call,field-get等等,不重要
 String getKind();

ProceedingJoinPoint
Proceedingjoinpoint 继承了 JoinPoint。是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。

public interface ProceedingJoinPoint extends JoinPoint {
    void set$AroundClosure(AroundClosure var1);

    default void stack$AroundClosure(AroundClosure arc) {
        throw new UnsupportedOperationException();
    }

    Object proceed() throws Throwable;

    Object proceed(Object[] var1) throws Throwable;
}

ProceedingJoinPoint只能用在around(环绕通知)中
环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的

joinPoint使用方法如下

		//1.获取切入点所在的目标对象
       	Object obj = joinPoint.getTarget();  
       	//2.获取修饰符+ 包名+组件名(类名) +方法名
        Signature signature = joinPoint.getSignature();
		//3.获取方法上的注解
		MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null)
        {
            xxxxxx annoObj= method.getAnnotation(xxxxxx.class);
        }
        return null;
        //4.获取切入点方法上的参数列表
        Object[] args = joinPoint.getArgs();


使用案例,环绕通知
1.定义一个注解 模拟记录日志

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

2.定一个切面

@Aspect
@Component
@Slf4j
public class CustomAspect {

    /**
     * 定义切入点
     */
    @Pointcut("@annotation(io.renren.common.annotation.CustomLog)")
    public void CusjoinPoint() {

    }

    /**
     * 环绕通知
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("CusjoinPoint()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed = joinPoint.proceed();
        log(joinPoint);
        return proceed;
    }

    /**
     * 简单打印日志--
     * @param joinPoint
     */
    private void log(ProceedingJoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        String methodName = method.getName();
        CustomLog customLog = method.getDeclaredAnnotation(CustomLog.class);
        String title = customLog.title();
        log.info("methodName =>{},title=>>>>{}",methodName,title);
    }
}

3.把注解打到接口上面,然后调用该接口可以看到打印的日志

### Spring Boot 中自定义注解的创建与使用 在 Spring Boot 中,自定义注解是一种非常灵活且强大的工具,它可以显著提升代码的可读性、可维护性模块化程度。下面将详细介绍如何创建使用自定义注解。 --- #### 1. 创建自定义注解 ##### 定义注解 首先需要定义一个新的注解,并指定其作用范围 (`@Target`) 生命周期 (`@Retention`)。以下是一个示例: ```java import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) // 注解可以应用于方法上 @Retention(RetentionPolicy.RUNTIME) // 注解会在运行时保留,可通过反射获取 public @interface CustomAnnotation { String value() default ""; // 可选参数,默认为空字符串 int count() default 1; // 可选参数,默认值为1 } ``` 在这个例子中: - `@Target(ElementType.METHOD)` 表明该注解只能应用在方法上[^3]。 - `@Retention(RetentionPolicy.RUNTIME)` 表明该注解将在运行时可用,通常配合 AOP 或其他框架功能使用[^3]。 --- #### 2. 使用自定义注解 ##### 在方法上应用注解 一旦定义好注解,就可以将其应用到具体的方法中。例如: ```java public class ExampleService { @CustomAnnotation(value = "This is a custom annotation", count = 5) public void exampleMethod() { System.out.println("Executing method with custom annotation"); } } ``` 在这里,`exampleMethod` 被标注了一个 `@CustomAnnotation`,其中指定了两个属性:`value` `count`。 --- #### 3. 解析自定义注解 为了让自定义注解生效,我们需要解析它的内容。这通常通过 Java 的反射机制或者结合 Spring AOP 来实现。 ##### 使用反射解析注解 以下是如何通过反射获取注解的内容: ```java import java.lang.reflect.Method; public class AnnotationProcessor { public static void processAnnotations(Object bean) throws Exception { Class<?> clazz = bean.getClass(); for (Method method : clazz.getDeclaredMethods()) { if (method.isAnnotationPresent(CustomAnnotation.class)) { CustomAnnotation annotation = method.getAnnotation(CustomAnnotation.class); System.out.println("Found annotation on method: " + method.getName()); System.out.println("Value: " + annotation.value()); System.out.println("Count: " + annotation.count()); } } } public static void main(String[] args) throws Exception { ExampleService service = new ExampleService(); processAnnotations(service); } } ``` 运行这段代码会打印出注解的相关信息。 --- ##### 结合 Spring AOP 切面编程 如果希望在 Spring 应用程序上下文中使用自定义注解,可以通过 AOP 编写切面逻辑来拦截带注解的方法调用。例如: ###### 定义切面类 ```java import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Component @Aspect public class CustomAnnotationAspect { @Around("@annotation(customAnnotation)") public Object handleCustomAnnotation(ProceedingJoinPoint joinPoint, CustomAnnotation customAnnotation) throws Throwable { System.out.println("Before executing method annotated with @CustomAnnotation"); System.out.println("Annotation Value: " + customAnnotation.value()); System.out.println("Annotation Count: " + customAnnotation.count()); try { Object result = joinPoint.proceed(); // 执行目标方法 System.out.println("After executing method annotated with @CustomAnnotation"); return result; } catch (Throwable throwable) { System.err.println("Error occurred while executing method annotated with @CustomAnnotation"); throw throwable; } } } ``` ###### 启用 AOP 支持 确保在 Spring Boot 配置类或主类上添加 `@EnableAspectJAutoProxy` 注解以启用 AOP 功能。 ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.EnableAspectJAutoProxy; @SpringBootApplication @EnableAspectJAutoProxy public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 现在每当有方法被 `@CustomAnnotation` 标记时,AOP 切面都会捕获并执行额外的日志记录或其他逻辑。 --- #### 4. 自定义注解的实际应用场景 除了上述简单示例外,自定义注解还可以用于更复杂的应用场景,例如日志记录、权限校验等。 ##### 日志记录示例 以下展示了如何通过自定义注解实现方法级别的日志记录功能[^4]: ###### 定义日志注解 ```java import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Log { String value() default ""; LogLevel level() default LogLevel.INFO; } public enum LogLevel { INFO, DEBUG, ERROR } ``` ###### 实现日志切面 ```java import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component @Aspect public class LoggingAspect { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Before("@annotation(log)") public void logBefore(JoinPoint joinPoint, Log log) { logger.info("[LOG-BEGIN] Method: {}, Message: {}", joinPoint.getSignature().getName(), log.value()); } @AfterReturning(pointcut = "@annotation(log)", returning = "result") public void logAfterReturning(Object result, Log log) { logger.info("[LOG-END] Result: {}, Level: {}", result, log.level()); } } ``` 这样每次调用带有 `@Log` 注解的方法时,都会自动记录开始结束的信息。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值