手写spring框架篇二注解

注解

手写spring框架->github地址

系列文章地址

篇一:反射------框架设计的灵魂

篇二:注解------为程序元素关联任何信息或任何元数据

篇三:IOC ------依赖反转

篇四:三级缓存------解决循环依赖

篇五:AOP------面向切面编程

Annotation(注解)就是Java提供了一种为程序元素关联任何信息或任何元数据(metadata)的途径和方法。Annotion(注解)是一个接口,程序可以通过反射来获取指定程序元素的Annotion对象,然后通过Annotion对象来获取注解里面的元数据。

  • 注解是添加到程序元素如包、类型、构造方法、方法、成员变量、参数、本地变量的声明中的额外信息。这些信息被存储在Annotation的“name=value”结构对中。

  • 注解的成员提供了程序元素的关联信息(成员称为参数或注解属性)

  • 注解不会影响程序代码的执行

一.简介

Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java5 开始添加到 Java 的。

二.作用
  • 作为特定的标记,用于告诉编译器一些信息

  • 编译时动态处理,如动态生成代码

  • 运行时动态处理,作为额外信息的载体,如获取注解信息

三.注解分类

1.标准注解:

  • @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

**2.元注解 ** — 作用在其他注解的注解

  • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。生命周期
  • @Documented - 标记这些注解是否包含在用户文档中。
  • @Target - 标记这个注解应该是哪种 Java 成员。 作用目标
  • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类) 是否允许子类继承
1)@Target

Target 是目标的意思,@Target 指定了注解运用的地方。

  • ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
  • ElementType.CONSTRUCTOR 可以给构造方法进行注解
  • ElementType.FIELD 可以给属性进行注解
  • ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
  • ElementType.METHOD 可以给方法进行注解
  • ElementType.PACKAGE 可以给一个包进行注解
  • ElementType.PARAMETER 可以给一个方法内的参数进行注解
  • ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
package java.lang.annotation;

public enum ElementType {
    TYPE,               /* 类、接口(包括注释类型)或枚举声明  */
    FIELD,              /* 字段声明(包括枚举常量)  */
    METHOD,             /* 方法声明  */
    PARAMETER,          /* 参数声明  */
    CONSTRUCTOR,        /* 构造方法声明  */
    LOCAL_VARIABLE,     /* 局部变量声明  */
    ANNOTATION_TYPE,    /* 注释类型声明  */
    PACKAGE             /* 包声明  */
}
2)@Retention

Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。

它的取值如下:

  • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
  • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
  • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
package java.lang.annotation;
public enum RetentionPolicy {
    SOURCE,            /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了  */

    CLASS,             /* 编译器将Annotation存储于类对应的.class文件中。默认行为  */

    RUNTIME            /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}
3)@Documented:

@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

4)@Inherited:

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

四.自定义注解

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

定义注解格式:
  public @interface 注解名 {定义体}

注解参数的可支持数据类型:

1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)

2.String类型
3.Class类型
4.enum类型
5.Annotation类型
6.以上所有类型的数组

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default ""; // 支持默认和公有
}
五.注解与反射

然后通过 getAnnotation() 方法来获取 Annotation 对象。返回指定类型的注解

 public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}

或者是 getAnnotations() 方法。返回注解到这个元素上的所有注解。

public Annotation[] getAnnotations() {}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CourseInfoAnnotation {
    String courseName();

    public String courseTag();

    public int courseIndex() default 11;

}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PersonInfoAnnotation {
    String name() default "name";

    public int age() default 20;

    String gender();

    String[] language();
}
@CourseInfoAnnotation(courseName = "haha",courseTag = "tag",courseIndex = 12)
public class Course {
    @PersonInfoAnnotation(name = "air",gender = "nan",language = {"12"})
    private String author;

    @CourseInfoAnnotation(courseName = "mmmmmm",courseTag = "kkkk")
    public void getCourseInfo(){

    }
}
 // 获取类上注解
    public static void parseTypeAnnotation() throws ClassNotFoundException {
        Class clazz=Class.forName("com.yifeng.annotation.Course");


        Annotation[] annotations=clazz.getAnnotations();
        for (Annotation annotation:annotations){
            CourseInfoAnnotation courseInfoAnnotation= (CourseInfoAnnotation) annotation;
            System.out.println(annotation);
            System.out.println(courseInfoAnnotation.courseName());
        }
    }
    // 获取成员变量上注解
    public static void parseFieldAnnotation() throws ClassNotFoundException {
        Class clazz=Class.forName("com.yifeng.annotation.Course");
        Field[] fields=clazz.getDeclaredFields();
        for (Field field:fields){
            System.out.println(field);
            // 判断成员变量中是否有指定类型的注解
            Boolean hasPersionAnno=field.isAnnotationPresent(PersonInfoAnnotation.class);
            if (hasPersionAnno){
                PersonInfoAnnotation personInfoAnnotation=field.getAnnotation(PersonInfoAnnotation.class);
                System.out.println(personInfoAnnotation.name()+"\n"+personInfoAnnotation.gender());
            }
        }
    }
    // 获取方法上注解
    public static void parseMethodAnnotation() throws ClassNotFoundException {
        Class clazz=Class.forName("com.yifeng.annotation.Course");
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods){
            System.out.println(method);
            // 判断成员变量中是否有指定类型的注解
            Boolean hasPersionAnno=method.isAnnotationPresent(CourseInfoAnnotation.class);
            if (hasPersionAnno){
                CourseInfoAnnotation personInfoAnnotation=method.getAnnotation(CourseInfoAnnotation.class);
                System.out.println(personInfoAnnotation.courseName()+"-----"+personInfoAnnotation.courseTag() );
            }
        }
    }

六.工作原理

  • 通过键值对的形式为注解属性赋值

  • 编译器检查注解的使用范围,将注解信息写入元素属性表

  • 运行时JVM将RUNTIME的所有注解属性取出并最终存入map里

  • 创建AnnotationInvocationHandler实例并传入前面的map

  • JVM使用JDK动态代理为注解生成代理类,并初始化处理器

  • 调用invoke方法,通过传入方法名返回注解对应的属性值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值