自定义注解
Java允许开发者在代码中定义自己的注解类型,用于标记和描述程序中的元素。自定义注解可以用于类、方法、字段等各种元素上,通过注解处理器可以在编译时或运行时对注解进行解析和处理。
代码示例1
java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) // 指定注解的保留策略为运行时
@Target(ElementType.METHOD) // 指定注解的作用目标为方法
@Documented
public @interface MyAnnotation {
String value() default ""; // 定义一个成员变量,默认值为空字符串
int count() default 0; // 定义一个成员变量,默认值为0
}
定义名为MyAnnotation
的自定义注解。注解使用@interface
关键字进行定义。注解的保留策略通过@Retention
注解指定,RetentionPolicy.RUNTIME
,表示注解在运行时仍然可用。注解的作用目标通过@Target
注解指定ElementType.METHOD
,表示注解可以用于方法上。
注解中可以定义成员变量,成员变量的定义方式与接口类似。定义了两个成员变量value
和count
,并分别指定了默认值为空字符串和0。
使用自定义注解时,可以在目标元素上使用注解,并为成员变量赋值。例如:
java
public class MyClass {
@MyAnnotation(value = "Hello", count = 5)
public void myMethod() {
// 方法体
}
}
通过反射机制,可以在运行时获取注解的信息,并根据注解进行相应的处理。例如:
java
public class AnnotationProcessor {
public static void processAnnotations(Class<?> clazz) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
String value = annotation.value();
int count = annotation.count();
// 根据注解进行相应的处理
System.out.println("Method: " + method.getName() + ", value: " + value + ", count: " + count);
}
}
}
}
定义了AnnotationProcessor
类,其中processAnnotations
方法用于处理带有@MyAnnotation
注解的方法。通过isAnnotationPresent
方法判断方法是否带有指定的注解,然后通过getAnnotation
方法获取注解的实例,进而获取注解的成员变量的值。
代码示例2
注解中的属性是数组类型,并且给出了默认值:
java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
String[] value() default {"default"};
}
定义了一个名为 MyAnnotation
的注解,有一个名为 value
的属性,类型为字符串数组。还给出了一个默认值为 {"default"}
。
可以在方法上使用这个注解,并为 value
属性提供自定义值,如下所示:
java
public class MyClass {
@MyAnnotation(value = {"value1", "value2"})
public void myMethod() {
// do something
}
}
在上面的代码中,在 myMethod
方法上使用了 MyAnnotation
注解,并为 value
属性提供了自定义值 {"value1", "value2"}
。
注解的保留策略和作用目标
保留策略参数:
Java中的注解有三种保留策略参数:
java
1. SOURCE:注解只保留在源代码中,编译时会被忽略。
2. CLASS:注解会被编译器保留在class文件中,但在运行时不会被JVM保留。
3. RUNTIME:注解会被编译器保留在class文件中,并在运行时被JVM保留,因此可以通过反射机制读取注解信息。
作用目标参数:
Java中的注解有多种作用目标参数,包括:
java
1. TYPE:用于类、接口、枚举等类型的声明。
2. FIELD:用于字段的声明。
3. METHOD:用于方法的声明。
4. PARAMETER:用于方法的参数声明。
5. CONSTRUCTOR:用于构造函数的声明。
6. LOCAL_VARIABLE:用于局部变量的声明。
7. ANNOTATION_TYPE:用于注解类型的声明。
8. PACKAGE:用于包的声明。
Documented注解的作用:
java
Documented注解是一个标记注解,用于指示被注解的元素应该包含在JavaDoc文档中。当一个注解被标记为Documented时,它将被包含在JavaDoc文档中,以便用户可以查看该注解的文档。
AliasFor注解
AliasFor注解是Spring框架中的一个注解,它用于指定注解属性之间的别名关系。在使用AliasFor注解时,需要指定别名关系的两个属性,其中一个属性作为主属性,另一个属性作为别名属性。当别名属性被设置时,主属性也会被自动设置,反之亦然。
AliasFor注解的使用场景主要有以下两种:
1. 用于注解属性之间的别名关系
在这种场景下,AliasFor注解用于指定注解属性之间的别名关系,以便在使用注解时可以使用别名属性来设置主属性。
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation{
@AliasFor("locations")
String value() default "";
@AliasFor("value")
String locations() default "";
}
@MyAnnotation(value= "test")
public class MyClass {
// ...
}
MyAnnotation注解,该注解含有value和locations两个属性,分别为value设置别名locations,locations设置别名value。在使用@MyAnnotation注解时无论是为value设置值,还是为locations设置值达到的效果相同。
使用限制:
java
- 别名都是成对出现,为value属性设置locations别名,需要含有locations属性并为其设置value别名;
- 成对出现的属性返回值相同;
- 必须为成对出现的属性必须设置默认值;
- 成对出现的属性的默认值必须相同;
- AliasFor注解不能设置annotation属性;
- 用于注解之间的别名关系
2. 用于注解之间的别名关系
在这种场景下,AliasFor注解用于指定不同注解之间的别名关系,以便在使用这些注解时可以使用别名注解来替代主注解。
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation1 {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@MyAnnotation1
public @interface MyAnnotation2 {
@AliasFor(annotation = MyAnnotation1.class, attribute = "value")
String name() default "";
}
@MyAnnotation2(name = "test")
public class MyClass {
// ...
}
MyAnnotation2注解中的name属性和MyAnnotation1注解中的value属性之间存在别名关系。因此,在使用MyAnnotation2注解时,可以使用name属性来替代MyAnnotation1注解中的value属性,如上面的示例所示。
案例
要求:写一个sdk,提供一个color注解,能作用在类或方法上,当color的值为red时,进行拦截,返回500错误
定义注解
java
@Documented
@Target({ TYPE, METHOD})
@Retention(RUNTIME)
public @interface ColorAnnotation {
@AliasFor("color")
String value() default "green";
@AliasFor("value")
String [] color() default "green";
}
定义拦截器
java
@Slf4j
public class ColorInterceptor implements HandlerInterceptor {
//preHandle:在处理请求之前被调用,可以进行一些前置处理操作。如果该方法返回false,则请求将被终止,后续的拦截器和处理器将不会被执行。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("MyInterceptor preHandle");
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
ColorAnnotation methodAnnotation = handlerMethod.getMethodAnnotation(ColorAnnotation.class);
// 可以拿注解上的值 当color为red时进行拦截
if (methodAnnotation != null) {
String color = methodAnnotation.value();
if (color.equals("red")){
PrintWriter writer = response.getWriter();
response.setHeader("content-type", "text/html;charset=UTF-8");
writer.write("<html><head><body>" + "{\"code\":500,\"message\":\"color is red,please change " +
"it.\"}" + "</body></html>");
return false;
}
}
return true;
}
return true;
}
//在处理请求之后、渲染视图之前被调用,可以进行一些后置处理操作。可以通过该方法修改ModelAndView对象
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("MyInterceptor postHandle");
}
//在整个请求完成之后被调用,可以进行一些资源清理操作
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("MyInterceptor afterCompletion");
}
}
拦截器注册到spring容器
java
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ColorInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/static/**");;
}
}
java
@Configuration
public class ColorConfiguration {
@Bean
public WebMvcConfig webMvcConfig(){
return new WebMvcConfig();
}
}
注册到spring.factories文件中
java
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.luxifa.config.ColorConfiguration