1. @Target
@Target
注解用于指定自定义注解可以应用的Java元素范围。它的参数是ElementType
的枚举值,可以指定一个或多个范围。使用@Target
可以限制注解只能用于特定的程序元素,如类、方法、字段等。
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;@Target(ElementType.METHOD) // 只能用于方法
public @interface CustomAnnotation {// 注解的成员
}
ElementType
的常用值包括:
TYPE
: 类、接口(包括注解类型)或枚举声明FIELD
: 字段声明(包括枚举常量)METHOD
: 方法声明PARAMETER
: 参数声明CONSTRUCTOR
: 构造方法声明LOCAL_VARIABLE
: 局部变量声明ANNOTATION_TYPE
: 注解类型声明PACKAGE
: 包声明
2.@Retention
@Retention
注解指定自定义注解的保留策略,即注解的信息保留到哪个阶段。它的参数是RetentionPolicy
的枚举值,决定了注解在源代码(Source)、字节码(Class)或运行时(Runtime)被保留。
例如下面的代码定义了一个注解@CustomAnnotation
,它在运行时依然可用:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;@Retention(RetentionPolicy.RUNTIME) // 在运行时保留
public @interface CustomAnnotation {// 注解的成员
}
RetentionPolicy
的常用值包括:
SOURCE
: 注解只在源代码中保留,编译器编译时会被忽略。CLASS
: 注解在编译到字节码文件中,但在运行时不会被虚拟机保留。这是默认的保留策略。RUNTIME
: 注解在运行时保留,可以通过反射获取到。
@Target
和@Retention
一起使用,可以精确控制自定义注解的使用场景和生命周期,使得注解的设计更加灵活和强大。
比如说苍穹外卖Day3中自定义注解AutoFill时,为了这个注解能够加在方法(ElementType.METHOD)上,来标识某个方法需要进行功能字段自动填充处理,就是通过下面这段代码实现的:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {//数据库操作类型:UPDATE INSERTOperationType value();
}
其中
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
可以简单记忆成固定搭配
3. @Aspect
@Aspect
是一个用于定义切面的注解。在面向切面编程(AOP)中,切面是一个可以包含多个通知(Advice)和切点(Pointcut)的模块。通知是在特定的程序执行点插入的代码片段,而切点定义了那些执行点。@Aspect
注解告诉Spring框架,该类包含AOP切面的定义。
4.@Component
@Component
是一个通用的立体注解,它用来标识一个Spring管理的组件。当Spring框架的扫描器检测到这个注解时,它会在Spring应用上下文中创建一个该类的实例。这是实现依赖注入的一种方式。@Component
可以被视为告诉Spring,“这是一个组件,我希望你管理它”。
5.@slf4j
@slf4j
是一个来自Lombok库的注解,用于自动注入一个SLF4J(Simple Logging Facade for Java)类型的日志对象。它在编译时会自动生成一个日志对象,这样你就可以在你的类中使用日志对象来记录日志,而不需要手动创建它。通常,这能让日志记录变得更加简洁。6.6.
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;@Aspect
@Component
@Slf4j
public class MyService {public void performAction() {log.info("Performing an action in MyService");// ... method implementation}
}
6. @PointCut
切面类定义过程中需要两个注解,一个是@PointCut,一个是通知,我们先来说接入点。
@Pointcut
注解用于定义一个切点(Pointcut),即一组满足特定条件的连接点(Join Point),其中连接点代表了程序执行的某个特定位置,例如方法的执行或异常的处理。切点表达式决定了在哪些连接点上应用通知(Advice)。这样,你可以重用切点表达式,并将其与不同的通知关联起来。
@Aspectpublic class MyAspect {@Pointcut("execution(* com.example.service.*.*(..))")public void serviceMethods() {// 切点表达式}}
@Pointcut("execution(* com.example.service.*.*(..))")表示serviceMethods()
方法标记有@Pointcut
注解,其表达式表示应用于com.example.service
包下所有类的所有方法。
苍穹外卖Day3里用到了
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
这个注解的含义是:
匹配com.sky.mapper
包下所有类(*
代表所有类)的所有方法(第二个*
代表所有方法),但仅应用于那些被指定注解com.sky.annotation.AutoFill
标记的方法。
7.@Before
@Before
注解用于定义一个前置通知(Before Advice),它将在匹配的方法执行之前执行。你可以指定一个切点表达式或引用一个已经定义的切点来决定这个前置通知应用的位置。前置通知用于在方法实际执行之前执行某些操作,例如安全检查、初始化资源、日志记录等。
@Aspectpublic class MyAspect {@Before("serviceMethods()")public void beforeServiceMethods(JoinPoint joinPoint) {// 前置通知的逻辑System.out.println("Before executing method: " + joinPoint.getSignature().getName());}}
在这个例子中,beforeServiceMethods()
方法标记有@Before
注解,并引用了serviceMethods()
定义的切点。这意味着在com.example.service
包中的任何方法执行之前,都会先执行beforeServiceMethods()
中的代码。
8. @annotation
在@Pointcut
注解中使用@annotation
可以让你根据方法上的注解来过滤方法,你可以根据自定义的注解来选择哪些方法将触发通知的执行。
// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Audit {// 注解中可以定义属性,例如记录操作类型等
}// 切面类
@Aspect
public class AuditAspect {// 切点表达式,匹配所有被@Audit注解标记的方法@Pointcut("@annotation(Audit)")public void auditMethods() {}// 通知方法,将在匹配的方法执行前执行@Before("auditMethods()")public void beforeAudit(JoinPoint joinPoint) {// 通知中的逻辑,例如记录日志System.out.println("Audit action before method: " + joinPoint.getSignature().getName());}
}
该切点只匹配那些被@Audit
注解标记的方法。