Java自定义注解

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Java⾃定义注解
前⾔
随着springboot的流⾏,以前基于XML的spring配置⽤的越来越少,JavaConfig形式使⽤的越来越多,类似于:
@Configuration
public class AppConfig {
@Bean(name="helloBean")
public HelloWorld helloWorld() {
return new HelloWorldImpl();
}
}
可以看出更多的是基于注解(Annotation)实现的,包括springboot的⼊⼝类**Application。

@Configuration
@ComponentScan("com.alibaba.trade")
@EnableAutoConfiguration//(exclude = {PageHelperAutoConfiguration.class})
@ServletComponentScan
@EnableTransactionManagement
@EnableDiscoveryClient
@EnableWebMvc
@MapperScan("com.alibaba.trade.shared.mapper")
public class TradeApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(TradeApplication.class, args);
}
}
Java注解不仅让我们减少了项⽬中XML⽂件,⽅便了维护,同时也使我们代码更简洁。

那么项⽬中我们如何阅读注解以及如何创造⾃⼰的注解呢?
注解说明
Java注解⼜称Java标注,是Java语⾔5.0版本开始⽀持加⼊源代码的特殊语法元数据。

为我们在代码中添加信息提供了⼀种形式化的⽅法,使我们可以在稍后某个时刻⾮常⽅便的使⽤这些数据。

Java语⾔中的类、⽅法、变量、参数和包等都可以被标注。

和Javadoc不同,Java标注可以通过反射获取注解内容。

在编译器⽣成类⽂件时,注解可以被嵌⼊到字节码中。

Java虚拟机可以保留注解内容,在运⾏时可以获取到注解内容。

内置注解
Java 定义了⼀套注解,共有 7 个,3 个在 ng 中,剩下 4 个在 ng.annotation 中。

1、作⽤在代码的注解是
@Override - 检查该⽅法是否是重写⽅法。

如果发现其⽗类,或者是引⽤的接⼝中并没有该⽅法时,会报编译错误。

@Deprecated - 标记过时⽅法。

如果使⽤该⽅法,会报编译警告。

@SuppressWarnings - 指⽰编译器去忽略注解中声明的警告。

2、作⽤在其他注解的注解(或者说元注解)是:
@Retention - 标识这个注解怎么保存,是只在代码中,还是编⼊class⽂件中,或者是在运⾏时可以通过反射访问。

@Documented - 标记这些注解是否包含在⽤户⽂档中。

@Target - 标记这个注解应该是哪种 Java 成员。

@Inherited - 标记这个注解是继承于哪个注解类(默认注解并没有继承于任何⼦类)
3、从 Java 7 开始,额外添加了 3 个注解:
@SafeVarargs - Java 7 开始⽀持,忽略任何使⽤参数为泛型变量的⽅法或构造函数调⽤产⽣的警告。

@FunctionalInterface - Java 8 开始⽀持,标识⼀个匿名函数或函数式接⼝。

@Repeatable - Java 8 开始⽀持,标识某注解可以在同⼀个声明上使⽤多次。

元注解
1、@Retention
@Retention annotation指定标记注释的存储⽅式:
RetentionPolicy.SOURCE - 标记的注释仅保留在源级别中,并由编译器忽略。

RetentionPolicy.CLASS - 标记的注释在编译时由编译器保留,但Java虚拟机(JVM)会忽略。

RetentionPolicy.RUNTIME - 标记的注释由JVM保留,因此运⾏时环境可以使⽤它。

2、@Documented
@Documented 注释表明,⽆论何时使⽤指定的注释,都应使⽤Javadoc⼯具记录这些元素。

(默认情况下,注释不包含在Javadoc中。

)有关更多信息,请参阅 Javadoc⼯具页⾯。

3、@Target
@Target 注释标记另⼀个注释,以限制可以应⽤注释的Java元素类型。

⽬标注释指定以下元素类型之⼀作为其值
ElementType.TYPE 可以应⽤于类的任何元素。

ElementType.FIELD 可以应⽤于字段或属性。

ElementType.METHOD 可以应⽤于⽅法级注释。

ElementType.PARAMETER 可以应⽤于⽅法的参数。

ElementType.CONSTRUCTOR 可以应⽤于构造函数。

ElementType.LOCAL_VARIABLE 可以应⽤于局部变量。

ElementType.ANNOTATION_TYPE 可以应⽤于注释类型。

ElementType.PACKAGE 可以应⽤于包声明。

ElementType.TYPE_PARAMETER
ElementType.TYPE_USE
4、@Inherited
@Inherited 注释表明注释类型可以从超类继承。

当⽤户查询注释类型并且该类没有此类型的注释时,将查询类的超类以获取注释类型(默认情况下不是这样)。

此注释仅适⽤于类声明。

5、@Repeatable
Repeatable Java SE 8中引⼊的,@Repeatable注释表明标记的注释可以多次应⽤于相同的声明或类型使⽤(即可以重复在同⼀个类、⽅法、属性等上使⽤)。

⾃定义注解
Java中⾃定义注解和创建⼀个接⼝相似,⾃定义注解的格式是以@interface为标志的。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
/**
* default extension name
*/
String value() default "";
}
我们知道ng.annotation包中有⼀个Annotation的接⼝,它是所有注解类型扩展的公共接⼝。

那我们是否可以直接通过实现该接⼝来实现⾃定义注解呢?import ng.annotation.Annotation;
public class MyAnnotation implements Annotation {
@Override
public Class<? extends Annotation> annotationType() {
return null;
}
}
发现Annotation接⼝中只有⼀个annotationType的⽅法,⽽且通过源码的注释我们可以发现答案是不能。

汉译即为:Annotaion被所有注解类型继承,但是要注意:⼿动扩展继承此接⼝的接⼝不会定义注解类型。

另请注意,此接⼝本⾝不定义注解类型。

使⽤场景
⾃定义注解的使⽤场景很多,我们在造轮⼦写框架的过程经常会使⽤到,例如我最近就遇到了⼀个业务场景:像⼀些编辑业务信息的接⼝,产品要求信息编辑后的新旧值对⽐,对⽐的业务功能,我们的实现⽅式是拿到前端填写的Form表单(新值)和数据库中查询出来的Dto(旧值)通过反射技术获取到相同属性字段名,再⽐较属性值就可以得出新旧值。

得到值之后我们也知道该字段的Dto中的字段名,但是如何将⽐较得到的新旧值字段的中⽂名返回给前端呢?例如:
public class Stedent {
private String name;
private int age;
private String sex;
//省略setter,getter
}
⽐较后我们的结果是 name : "xiaoming "-> "daming",age : 24 -> 26。

但是我们不能直接将name和age返回给前端,他们需要的格式是:姓名: "xiaoming "-> "daming",年龄 : 24 -> 26。

这时候就可以考虑⾃定义⼀个注解@FieldName,
@Deprecated
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldName {
String value() default "";
}
然后将该注解加在属性字段上⾯
public class Student {
@FieldName(value = "姓名")
private String name;
@FieldName(value = "年龄")
private int age;
@FieldName(value = "性别")
private String sex;
//省略setter,getter
}
之后就可以通过反射获取该字段中⽂名
// 如果 oldField 属性值与 newField 属性值的内容不相同
if (!isEmpty(newValue)) {
Map<String, Object> map = new HashMap<>();
String newFieldName = newField.getName();
//在这⾥获取注解的信息
if (newField.isAnnotationPresent(FieldName.class)) {
FieldName fieldNameAnno = newField.getAnnotation(FieldName.class); newFieldName = ();
}
map.put(FIELD_NAME, newFieldName);
map.put(OLD_VALUE, oldValue);
map.put(NEW_VALUE, newValue);
list.add(map);
}。

相关文档
最新文档