说明
java中的注解(Annotation)是用于为代码添加元数据的信息,编译器可以通过注解进行不同的处理。注解本身并不直接影响程序的运行。
常见内置注解
@Override 标记重写父类方法
@Deprecated
标记类、方法、字段等不推荐使用,可能会在未来的版本中删除。
@SuppressWarnings
抑制编译器的警告。
自定义注解使用
使用@interface来定义,方法可以有默认值,注解并不直接影响代码的语义。
元注解
Java提供了几个元注解(用于注解其他注解),包括@Target、@Retention、@Documented、@Inherited。
@Target: 指定注解的适用范围(类、方法、字段等)。
@Retention: 指定注解的保留策略(源代码、编译期或运行时)。
@Documented: 表明注解应该包含在JavaDoc中。
@Inherited: 表示注解可以被子类继承。
package com.example.annotation;
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 LogMask {
String active();
String value() default "***";
}
新增aop依赖包
compileOnly("org.springframework.boot:spring-boot-starter-aop:2.6.13")
新增aspect配置类
package com.example.config;
import com.example.annotation.LogMask;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Component
public class LogAspect {
@Before(value = "@annotation(logMask)", argNames = "joinPoint,logMask")
public void logBefore(final JoinPoint joinPoint, final LogMask logMask) {
log.info("action:[{}]", logMask.action());
System.out.println("Method " + joinPoint.getSignature().getName() + " is starting...");
}
// 在方法执行后执行
@After(value = "@annotation(com.example.annotation.LogMask)")
public void logAfter(final JoinPoint joinPoint) {
System.out.println("Method " + joinPoint.getSignature().getName() + " has finished.");
}
// 环绕通知(可以在方法执行前后做更多操作,返回值可以控制方法是否执行)
@Around(value = "@annotation(logMask)", argNames = "joinPoint,logMask")
public Object logAround(final ProceedingJoinPoint joinPoint, LogMask logMask) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 执行目标方法
long endTime = System.currentTimeMillis();
System.out.println("Method " + joinPoint.getSignature().getName() + " executed in " + (endTime - startTime) + " ms");
return result;
}
}
在方法上添加自定义注解
package com.example.service;
import com.example.annotation.LogMask;
import org.springframework.stereotype.Service;
@Service
public class LoginService {
@LogMask(action = "login")
public String login(String username, String password) {
System.out.println("username login success:" + username);
return "success";
}
}
JoinPoint 和 ProceedingJoinPoint的区别
JoinPoint
- 用在 @Before 和 @After 通知上
- 只能获取方法信息。
- 不能控制目标方法的执行(不能调用 proceed())。
- 适用于 @Before、@After 等不需要改变方法行为的通知,即不能改变方法的参数值那些,方法的执行过程不受改变
ProceedingJoinPoint
- ProceedingJoinPoint 是 JoinPoint 的子接口
- 主要用于 @Around 通知中。它除了拥有 JoinPoint 的功能外
- 提供了 proceed() 方法,允许在通知中控制目标方法的执行