自定义注解
简单的Java自定义注解的示例:
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyCustomAnnotation {
String value() default ""; // 定义一个名为"value"的成员,默认值为空字符串
int priority() default 0; // 定义一个名为"priority"的成员,默认值为0
}
在这个示例中,定义了一个名为MyCustomAnnotation的自定义注解,它有两个成员:value和priority。@Retention注解指定了注解在运行时可见,@Target注解指定了注解可以应用在方法上。
@Retention,元注解(元注解(Meta-Annotation)是用于注解其他注解的特殊注解。换句话说,元注解是一种用于定义和配置自定义注解的注解),用于指,定自定义注解的保留策略,即注解在什么级别可见。它有三个预定义的保留策略:
- RetentionPolicy.SOURCE: 注解仅存在于源代码中,在编译后不会包含在编译好的类文件中。这意味着注解仅在开发阶段使用,对运行时没有任何影响。
- RetentionPolicy.CLASS: 注解存在于源代码和编译后的类文件中,但在运行时不可见。这是默认的保留策略,如果你在定义注解时没有显式地指定保留策略,它将被默认为CLASS。
- RetentionPolicy.RUNTIME: 注解存在于源代码、编译后的类文件和运行时环境中。这允许你在运行时通过反射等机制访问和解析注解信息。
通常,如果希望在运行时使用自定义注解,应该将@Retention设置为RetentionPolicy.RUNTIME。这允许通过反射在运行时访问注解信息并执行相应的操作。
@Target,用于指定自定义注解可以应用的目标元素类型。换句话说,它规定了你可以在哪些程序元素上使用自定义注解。
常见的@Target枚举常量: - ElementType.TYPE: 可以应用于类、接口、枚举等类型声明。
- ElementType.FIELD: 可以应用于字段(成员变量)。
- ElementType.METHOD: 可以应用于方法。
- ElementType.PARAMETER: 可以应用于方法参数。
- ElementType.CONSTRUCTOR: 可以应用于构造方法。
- ElementType.LOCAL_VARIABLE: 可以应用于局部变量。
- ElementType.ANNOTATION_TYPE: 可以应用于注解类型声明。
- ElementType.PACKAGE: 可以应用于包声明。
使用注解
在代码中使用这个自定义注解,例如:
public class MyClass {
@MyCustomAnnotation(value = "This is a custom annotation", priority = 2)
public void myMethod() {
// 方法内容
}
}
自定义注解本身并不会提供任何额外的功能,它们只是为了给代码添加元数据。如果你希望在程序中根据注解来执行某些操作,需要使用反射或其他技术来解析注解并采取相应的行动。
AOP 加 注解 实现非侵入式编程
结合AOP(面向切面编程)和自定义注解可以实现在特定方法执行前、执行后、异常抛出等切面点添加额外的逻辑。AOP可以在不修改原有业务逻辑的情况下,通过将横切关注点(如日志、安全性、事务等)从业务逻辑中分离出来,提供更好的可维护性和扩展性。
以下是一个使用自定义注解结合AOP的简单示例,展示如何在方法执行前后记录日志:
定义自定义注解:
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {
}
创建一个切面类来实现日志逻辑:
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.*;
@Aspect
@Component
public class LoggingAspect {
@Before("@annotation(Loggable)") // 在带有 @Loggable 注解的方法执行前执行
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before executing: " + joinPoint.getSignature().getName());
}
@AfterReturning("@annotation(Loggable)") // 在带有 @Loggable 注解的方法正常返回后执行
public void logAfterReturning(JoinPoint joinPoint) {
System.out.println("After returning from: " + joinPoint.getSignature().getName());
}
@AfterThrowing(value = "@annotation(Loggable)", throwing = "ex") // 在带有 @Loggable 注解的方法抛出异常时执行
public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
System.out.println("After throwing exception in: " + joinPoint.getSignature().getName());
System.out.println("Exception: " + ex.getMessage());
}
}
在业务代码中使用自定义注解:
@Service
public class MyService {
@Loggable
public void doSomething() {
System.out.println("Doing something...");
}
public void doAnotherThing() {
System.out.println("Doing another thing...");
}
}
在上述示例中,使用@Loggable注解标记的方法会触发AOP切面中定义的日志逻辑。而未标记的方法不会受到影响。
要使AOP生效,需要确保已经配置了适当的AOP支持,如Spring AOP或AspectJ,具体配置会根据所使用的框架而有所不同。这个示例展示了如何通过自定义注解和AOP结合,将横切关注点(日志记录)从业务逻辑中分离出来