注解anoation原理及自定义注解demo实现
来源:互联网 发布:英语教师网络研修心得 编辑:程序博客网 时间:2024/06/08 04:12
在接触ssh框架的时候,我们都会看到框架对注解的广泛使用,如@Resource,@autowired,@component ,@controller等等,一开始的时候我们接触这些注解的时候都会有
较大的疑虑,依照“知道源码知道一切”的思维我们肯定回去看这些源码,但是在观察源码之前,我们应该首先了解注解的实现原理,现在我们就实现一个自定义注解来进行探索。
注解的自定义
在Java 5中给出了4个自定义注解用到的注解:@Target,@Retention,@Document,@Inherited ,这些注解含义和使用方法如下:
CONSTRUCTOR:构造器的声明
FIELD:域声明(包括enum实例)
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口(包括注解类型)或enum声明
@Retention表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括,源码范围,运行范围,编译范围保存时间范围:
SOURCE:注解将被编译器丢弃
CLASS:注解在class文件中可用,但会被VM丢弃
RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。
@Document将注解包含在Javadoc中,这个注解很少使用 @inherited允许子类继承父类中的注解今天只使用前两个注解来自定义注解。
在这里对@Inherited注解有个特殊的解释,解释它为什么会使得注解具有继承性质
在Class类定义中,有一个属性如下,annotations 存放的是一个类中的所有注解,key值为注解类的Class,value值为创建的一个注解代理对象。
// Annotations cache
private transient Map<Class<? extends Annotation>, Annotation> annotations;
private synchronized void initAnnotationsIfNecessary() {
clearCachesOnClassRedefinition();
if (annotations != null)
return;
declaredAnnotations = AnnotationParser.parseAnnotations(
getRawAnnotations(), getConstantPool(), this);
Class<?> superClass = getSuperclass();
if (superClass == null) {
annotations = declaredAnnotations;
} else {
annotations = new HashMap<>();
superClass.initAnnotationsIfNecessary();
for (Map.Entry<Class<? extends Annotation>, Annotation> e : superClass.annotations.entrySet()) {
Class<? extends Annotation> annotationClass = e.getKey();
if (AnnotationType.getInstance(annotationClass).isInherited())//这里进行判别注解是否有继承性质
annotations.put(annotationClass, e.getValue());
}
annotations.putAll(declaredAnnotations);
}
}
在上面的方法中,代码
declaredAnnotations = AnnotationParser.parseAnnotations(
getRawAnnotations(), getConstantPool(), this);
表示的是获取该类使用的所有注解
而接下来的所有代码是获取父类的所有注解,如果父类存在的话。但是在获取父类注解的时候,有一个判断代码
if (AnnotationType.getInstance(annotationClass).isInherited())//这里进行判别注解是否有继承性质
annotations.put(annotationClass, e.getValue());
这里如果isInherited函数返回true则表示父类中的这个注解是支持继承的。因此会将父类中的这个注解对象放到子类的annotations中去。
这就是注解继承特性的逻辑
自定义注解
方法注解
@Target(ElementType.METHOD)//使用在方法上
@Retention(RetentionPolicy.RUNTIME)//注解存在时间是在运行的时候
public @interface MyAnoation {
public String name()default "test";
public String descripet()default "no descript";
public String id();
}
类注解
@Target(ElementType.TYPE)//注解使用范围是类
@Retention(RetentionPolicy.RUNTIME)//注解生命周期到程序运行
public @interface MyAnoation1 {
public int id();
public String name();
}
属性域注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnoationField {
public String defaultValue() default "defaultName";
public boolean nullable();
}
属性注解,生命周期在程序运行时候
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnoationField1 {
public int length();
public boolean nullable();
}
下面是自定义注解的使用
@MyAnoation1(id = 1 , name = "test")
public class TestClass {
@MyAnoationField(defaultValue = "jack" , nullable = false)
private String field1 ;
@MyAnoationField1(length = 1 , nullable = false)
private String field2 ;
@MyAnoation(id = "12",name = "print",descripet="printMethod")
public void print(){
System.out.println("Method:print");
}
@MyAnoation(id = "13")
public void read(){
System.out.println("Method:read");
}
@MyAnoation(id = "14",descripet = "writeMethod")
public void write(){
System.out.println("Method:write");
}
}
在注解的使用过程中,如果注解中一个属性没有在注解定义中声明缺省值,那么这个属性在注解使用时候就一定要赋值,否则报错,如下形式会报错
@MyAnoation()
public void read(){
System.out.println("Method:read");
}
id属性是没有缺省值的,如果不赋值的话,会编译报错。
上面两个类分别对应这自定义注解的声明和使用,自定义注解还需要进行处理,这里使用静态main函数来处理,如下
public class AnoationTest {
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
Class<?> testClass = TestClass.class;
for(Method m : testClass.getDeclaredMethods())
{
MyAnoation test = m.getAnnotation(MyAnoation.class);
if(test != null)
System.out.println("MyAnoation[name :" +test.name()+",id: "+test.id()+",descript:"+test.descripet()+"]");
}
MyAnoation1 anoation1 = testClass.getAnnotation(MyAnoation1.class);
if(anoation1 != null)
System.out.println("MyAnoation1[ id:"+anoation1.id()+",name: "+anoation1.name()+"]");
//这个注解内容存货周期是在源代码时候,编译时就会丢弃注解内容,所以,输出为空
Field field1 = testClass.getDeclaredField("field1");
MyAnoationField anoationField = field1.getAnnotation(MyAnoationField.class);
if(anoationField != null)
System.out.println("MyAnoationField[ defaultValue:"+anoationField.defaultValue() + ",nullable:" + anoationField.nullable()+"]");
Field field2 = testClass.getDeclaredField("field2");
MyAnoationField1 anoationField1 = field2.getAnnotation(MyAnoationField1.class);
if(anoationField1 != null)
System.out.println("MyAnoationField1[ defaultValue:"+anoationField1.length() + ",nullable:" + anoationField1.nullable()+"]");
}
}
这个demo之列出了三种注解处理方式,类注解,域追额,方法注解,其他用在不同范围的注解大家可以自己研究,当然我会在本篇博客的结尾为大家进行总结,分享给大家
但是我的这个main函数注解处理器只能在运行的时候执行生效,但是对于使用范围不是在代码运行时候的注解就没办法处理了,如:SOURCE , CLASS等。
这个问题我还没找到解决方法,但是过段时间我会在博文结尾补上我的理解和分析结果,并会附上一个demo供大家参考。
main函数执行输出结果为:
MyAnoation[name :test,id: 14,descript:writeMethod]
MyAnoation[name :print,id: 12,descript:printMethod]
MyAnoation[name :test,id: 13,descript:no descript]
MyAnoation1[ id:1,name: test]
MyAnoationField1[ defaultValue:1,nullable:false]
从这个输出结果可知,生命周期为Source的注解在main函数中无法获取注解信息。
类,方法,构造方法,域对应的类有Class<T> ,Method,Construct<T>,Field. 这些类中都有存放注解类数据的属性,其中Class<T>属性的数据结构是Map,其他类属性的数据结构是字节数组,不过存取过程中会使用注解解析器将字节数组类型转换为Map数据结构,供用户程序使用。
Class<T>,Method,Field这几个类型都实现了AnnotatedElement接口,获取注解都是使用同一个接口getAnnotation(Class<T> annotationClass)
- 注解anoation原理及自定义注解demo实现
- [java]自定义注解demo
- 自定义注解Demo
- 自定义注解Demo
- Java注解及自定义注解
- spring自定义注解的实现及应用
- JAVA自定义注解实现SQL语句自动生成DEMO
- 自定义注解,及应用
- 注解机制及原理
- SSH 环境搭建及注解实现登录功能 DEMO
- SpringAOP实现自定义注解
- 自定义注解框架实现
- java注解实现原理
- java之注解及自定义注解例程
- Java注解教程及自定义注解
- java自定义注解及注解使用
- Java自定义注解及注解的使用
- Java注解教程及自定义注解
- 生产者/消费者问题的多种Java实现方式
- Collection,List,Set和Map用法和区别
- Spring MVC返回BLOB类型的图片
- jquery使用 Form submission canceled because the form is not connected
- 云上架构和传统IT架构的区别在哪里?(企业CIO、CTO必读)
- 注解anoation原理及自定义注解demo实现
- callback的理解与Java实例
- Object-C知识点 (四)NSObject的继承关系
- Gemini代码摘抄(一)Graph和init
- codeVS 1011 数的计算
- oracle--基本转换函数
- GC日志分析
- nutch 执行流程以及简介
- JZOJ2017.08.15 B组