Spring如何⾃定义注解实现功能
如何⾃定义注解实现功能
1. 创建⾃定义注解和创建⼀个接⼝相似,但是注解的interface关键字需要以@符号开头。
2. 注解⽅法不能带有参数;
3. 注解⽅法返回值类型限定为:基本类型、String、Enums、Annotation 或者是这些类型的数组;
4. 注解⽅法可以有默认值;
5. 注解本⾝能够包含元注解,元注解被⽤来注解其它注解。
什么是注解?
对于很多初次接触的开发者来说应该都有这个疑问?_Annontation_是Java5开始引⼊的新特征,中⽂名称叫注解。它提供了⼀种安全的类似注释的机制,⽤来将任何的信息或元数据(metadata)与程序元素(类、⽅法、成员变量等)进⾏关联。为程序的元素(类、⽅法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑⽆关,并且供指定的⼯具或框架使⽤。Annontation像⼀种修饰符⼀样,应⽤于包、类型、构造⽅法、⽅法、成员变量、参数及本地变量的声明语句中。
Java注解是附加在代码中的⼀些元信息,⽤于⼀些⼯具在编译、运⾏时进⾏解析和使⽤,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作⽤。包含在 java.lang.annotation 包中。
注解的⽤处:
1、⽣成⽂档。这是最常见的,也是java 最早提供的注解。常⽤的有@param @return 等
2、跟踪代码依赖性,实现替代配置⽂件功能。⽐如Dagger 2 依赖注⼊,未来java 开发,将⼤量注解配置,具有很⼤⽤处;
3、在编译时进⾏格式检查。如@override 放在⽅法前,如果你这个⽅法并不是覆盖了超类⽅法,则编译时就能检查出。
注解的原理:
注解本质是⼀个继承了Annotation 的特殊接⼝,其具体实现类是Java 运⾏时⽣成的动态代理类。⽽我们通过反射获取注解时,返回的是Java 运⾏时⽣成的动态代理对象$Proxy1。通过代理对象调⽤⾃定义注解(接⼝)的⽅法,会最终调⽤AnnotationInvocationHandler 的invoke ⽅法。该⽅法会从memberValues 这个Map 中索引出对应的值。⽽memberValues 的来源是Java 常量池。
元注解:
java.lang.annotation 提供了四种元注解,专门注解其他的注解(在⾃定义注解的时候,需要使⽤到元注解):
@Documented – 注解是否将包含在JavaDoc中
@Retention – 什么时候使⽤该注解
@Target – 注解⽤于什么地⽅
@Inherited – 是否允许⼦类继承该注解
sql语句实现的四种功能1.)@Retention – 定义该注解的⽣命周期
● RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写⼊字节码。@Override,
@SuppressWarnings都属于这类注解。
● RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码⽂件的处理中有⽤。注解默认使⽤这种⽅
式
● RetentionPolicy.RUNTIME : 始终不会丢弃,运⾏期也保留该注解,因此可以使⽤反射机制读取该注解的信息。我们⾃定义的注解通常使⽤这种⽅式。
2.)Target – 表⽰该注解⽤于什么地⽅。默认值为任何元素,表⽰该注解⽤于什么地⽅。可⽤的ElementType 参数包括
● ElementType.CONSTRUCTOR: ⽤于描述构造器
● ElementType.FIELD: 成员变量、对象、属性(包括enum实例)
● ElementType.LOCAL_VARIABLE: ⽤于描述局部变量
● ElementType.METHOD: ⽤于描述⽅法
● ElementType.PACKAGE: ⽤于描述包
● ElementType.PARAMETER: ⽤于描述参数
● ElementType.TYPE: ⽤于描述类、接⼝(包括注解类型) 或enum声明
3.)@Documented – ⼀个简单的Annotations 标记注解,表⽰是否将注解信息添加在java ⽂档中。
4.)@Inherited – 定义该注释和⼦类的关系
@Inherited 元注解是⼀个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。如果⼀个使⽤了@Inherited 修饰的annotation 类型被⽤于⼀个class,则这个annotation 将被⽤于该class 的⼦类。
常见标准的Annotation:
1.)Override
java.lang.Override 是⼀个标记类型注解,它被⽤作标注⽅法。它说明了被标注的⽅法重载了⽗类的⽅法,起到了断⾔的作⽤。如果我们
使⽤了这种注解在⼀个没有覆盖⽗类⽅法的⽅法时,java 编译器将以⼀个编译错误来警⽰。
2.)Deprecated
Deprecated 也是⼀种标记类型注解。当⼀个类型或者类型成员使⽤@Deprecated 修饰的话,编译器将不⿎励使⽤这个被标注的程序元素。所以使⽤这种修饰具有⼀定的“延续性”:如果我们在代码中通过
继承或者覆盖的⽅式使⽤了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为@Deprecated,但编译器仍然要报警。
3.)SuppressWarnings
SuppressWarning 不是⼀个标记类型注解。它有⼀个类型为String[] 的成员,这个成员的值为被禁⽌的警告名。对于javac 编译器来讲,被-Xlint 选项有效的警告名也同样对@SuppressWarings 有效,同时编译器忽略掉⽆法识别的警告名。
@SuppressWarnings("unchecked")
⾃定义注解:
⾃定义注解类编写的⼀些规则:
1. Annotation 型定义为@interface, 所有的Annotation 会⾃动继承java.lang.Annotation这⼀接⼝,并且不能再去继承别的类或是接⼝.
2. 参数成员只能⽤public 或默认(default) 这两个访问权修饰
3. 参数成员只能⽤基本类型byte、short、char、int、long、float、double、boolean⼋种基本数据类型和String、Enum、Class、annotations等数据类型,以及这⼀些类型的数组.
4. 要获取类⽅法和字段的注解信息,必须通过Java的反射技术来获取 Annotation 对象,因为你除此之外没有别的获取注解对象的⽅法
5. 注解也可以没有定义成员,,不过这样注解就没啥⽤了
PS:⾃定义注解需要使⽤到元注解
⾃定义注解实例:
FruitName.java
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* ⽔果名称注解
*/
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitName {
String value() default "";
}
FruitColor.java
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* ⽔果颜⾊注解
*/
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitColor {
/**
* 颜⾊枚举
*/
public enum Color{ BLUE,RED,GREEN};
/**
* 颜⾊属性
*/
Color fruitColor() default Color.GREEN;
}
FruitProvider.java
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* ⽔果供应者注解
*/
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitProvider {
/**
* 供应商编号
*/
public int id() default -1;
/**
* 供应商名称
*/
public String name() default "";
/**
* 供应商地址
*/
public String address() default "";
}
FruitInfoUtil.java
import flect.Field;
/**
* 注解处理器
*/
public class FruitInfoUtil {
public static void getFruitInfo(Class<?> clazz){
String strFruitName=" ⽔果名称:";
String strFruitColor=" ⽔果颜⾊:";
String strFruitProvicer="供应商信息:";
Field[] fields = DeclaredFields();
for(Field field :fields){
if(field.isAnnotationPresent(FruitName.class)){
FruitName fruitName = (FruitName) Annotation(FruitName.class);
strFruitName=strFruitName+fruitName.value();
System.out.println(strFruitName);
}
else if(field.isAnnotationPresent(FruitColor.class)){
FruitColor fruitColor= (FruitColor) Annotation(FruitColor.class);
strFruitColor=strFruitColor+fruitColor.fruitColor().toString();
System.out.println(strFruitColor);
}
else if(field.isAnnotationPresent(FruitProvider.class)){
FruitProvider fruitProvider= (FruitProvider) Annotation(FruitProvider.class);
strFruitProvicer=" 供应商编号:"+fruitProvider.id()+" 供应商名称:"+fruitProvider.name()+" 供应商地址:"+fruitProvider.address(); System.out.println(strFruitProvicer);
}
}
}
}
Apple.java
import test.FruitColor.Color;
/**
* 注解使⽤
*/
public class Apple {
@FruitName("Apple")
private String appleName;
@FruitColor(fruitColor=Color.RED)
private String appleColor;
@FruitProvider(id=1,name="红苹果集团",address="华夏路天⼦脚下1号")
private String appleProvider;
public void setAppleColor(String appleColor) {
this.appleColor = appleColor;
}
public String getAppleColor() {
return appleColor;
}
public void setAppleName(String appleName) {
this.appleName = appleName;
}
public String getAppleName() {
return appleName;
}
public void setAppleProvider(String appleProvider) {
this.appleProvider = appleProvider;
}
public String getAppleProvider() {
return appleProvider;
}
public void displayName(){
System.out.println("⽔果的名字是:苹果");
}
}
FruitRun.java
/**
* 输出结果
*/
public class FruitRun {
public static void main(String[] args) {
}
}
运⾏结果是:
⽔果名称:Apple
⽔果颜⾊:RED
供应商编号:1 供应商名称:红苹果集团供应商地址:华夏路天⼦脚下⼀号转⾃:有梦想的咸鱼
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论