注解的实现原理

作者: 涛涛123759 | 来源:发表于2018-04-28 16:20 被阅读278次

一、注解的底层实现原理

  • 注解的底层也是使用反射实现的,我们可以自定义一个注解来体会下。注解和接口有点类似,不过申明注解类需要加上@interface,注解类里面,只支持基本类型、String及枚举类型,里面所有属性被定义成方法,并允许提供默认值。

@Target — —注解用于什么地方

ANNOTATION_TYPE,//给注解注解(这貌似把自己不当类来看)
ElementType.FIELD  //注解作用于变量
ElementType.METHOD //注解作用于方法
ElementType.PARAMETER //注解作用于参数
ElementType.CONSTRUCTOR //注解作用于构造方法
ElementType.LOCAL_VARIABLE //注解作用于局部变量
ElementType.PACKAGE //注解作用于包

@Retention — —注解运行状态

 SOURCE, //源码状态运行,
 CLASS, //编译类文件时运行
 RUNTIME //运行时运行

具体的区别如下:

  • 运行时注解就是就是运行时运用反射,动态获取对象、属性、方法等,一般的IOC框架就是这样,可能会牺牲一点效率。
  • 编译时注解就是在程序编译时根据注解进行一些额外的操作,大名鼎鼎的ButterKnife运用的就是编译时注解,ButterKnife在我们编译时,就根据注解,自动生成了一些辅助类。要玩编译时注解呢,你得先依赖apt,然后自己写一个类继承AbstractProcessor,重写process方法,在里面实现如何把配置或注解的信息变成所需要的类。

**@Documented — — 生成说明文档,添加类的解释 **

是否会保存到 Javadoc 文档中

** @Inherited — —允许子类继承父类中的注解**

是否可以被继承,默认为 false

二、实现运行时注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnonation {
   String name() default "";
   int Id()  default 0;
}

注解关键字时@interface,然后上面标注为元注解,表示只能修饰方法并且加载到虚拟机中,里面时这个注解所具有的属性,name, id,我们在给方法加注解的时候设置相应的值。

@TestAnnonation(name = "android" , Id = 1)
private void testAnno(){

}

上面我们在一个方法上面添加注解,然后我们通过下面的方法将这个注解打印出来

private void outputAnnoDetail(Class clazz){
    Method [] methods = clazz.getDeclaredMethods();
    for(Method method  : methods) {
        TestAnnonation testAnnonation  = method.getAnnotation(TestAnnonation.class);
        if (testAnnonation != null) {
            Log.d("anonation", "name------>" + testAnnonation.name() + "------>Id------>" + testAnnonation.Id());
        }
    }
}

三、Android注解框架 ButterKnife

  • ButterKnife注解框架是大家常用的注解框架,它主要作用是绑定View并且绑定View常用的监听事件,下面是其中一个注解

      @Retention(CLASS)
      @Target(FIELD)
      public @interface BindView {
         /** View ID to which the field will be bound. */
         @IdRes int value();
     }
    
  • 通过上面的代码可以看出,ButterKnife的注解保留方式为CLASS模式,也就是会保留到class中但是不会背加载到虚拟机中,这个时候我们就要看下它的AbstractProcessor,一般标注为Class的都会重写AbstractProcessor类,这样在虚拟机进行编译的时候就会做相应的处理。

主要看一下几个方法:

@Override
public Set<String> getSupportedAnnotationTypes() {
    Set<String> types = new LinkedHashSet<>();
    for (Class<? extends Annotation> annotation : getSupportedAnnotations()) {
      types.add(annotation.getCanonicalName());
    }
    return types;
 }

private Set<Class<? extends Annotation>> getSupportedAnnotations() {
    Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();

    annotations.add(BindArray.class);
    annotations.add(BindBitmap.class);
    annotations.add(BindBool.class);
    annotations.add(BindColor.class);
    annotations.add(BindDimen.class);
    annotations.add(BindDrawable.class);
    annotations.add(BindFloat.class);
    annotations.add(BindInt.class);
    annotations.add(BindString.class);
    annotations.add(BindView.class);
    annotations.add(BindViews.class);
    annotations.addAll(LISTENERS);

    return annotations;
}

上面的方法主要表明会处理哪些注解

@Override
public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {
    Map<TypeElement, BindingSet> bindingMap = findAndParseTargets(env);

    for (Map.Entry<TypeElement, BindingSet> entry : bindingMap.entrySet()) {
      TypeElement typeElement = entry.getKey();
      BindingSet binding = entry.getValue();

      JavaFile javaFile = binding.brewJava(sdk);
      try {
        javaFile.writeTo(filer);
      } catch (IOException e) {
       error(typeElement, "Unable to write binding for type %s: %s", typeElement, e.getMessage());
      }
    }

    return true;
 }
  • 然后就是在编译的时候的具体处理过程,这个过程主要时先找到并解析注解,然后生成java文件,这样在虚拟机真正执行的时候就不用去查找和解析,也就不会耗时了。
  • EventBus
  • EventBus是使用运行时注解,主要的作用是在运行的时候会去查找所有被注解的方法,然后再去解析注解。运行时注解会影响程序的性能,毕竟在运行的时候有一个查找的过程,所以运行时注解的作用一般是标记一个作用区。

相关文章

  • java基础之自定义注解

    注解Annotation实现原理与自定义注解例子

  • SpringBoot之自定义注解(基于BeanPostProce

    步骤使用@interface 自定义注解编写注解处理类,实现BeanPostProcessor接口原理实现Bean...

  • 注解

    注解实现原理 底层使用反射实现。申明注解类需要加 @interface 注解类里只支持基本类型、String以及枚...

  • 注解的实现原理

    一、注解的底层实现原理 注解的底层也是使用反射实现的,我们可以自定义一个注解来体会下。注解和接口有点类似,不过申明...

  • Lombok实现原理

    Java插入式注解处理器 3. 实现原理 Lombok 的核心工作原理就是编译时注解(作用于 javac 编译的过...

  • 注解

    Java 注解原理 下面来看看Java中注解是如何实现的 创建注解类Inter: 创建测试类Test: 在程序第二...

  • Spring实现自己的注解-AOP型(二)

    接着上文,我们分析了@Async注解的实现原理,这一片文章我们来一步步实现一个自定义的注解。注解实现的功能很简单,...

  • 组件通讯设计原理及注入实现原理

    组件通讯设计原理及注入实现原理 主要涉及一下核心知识点 注解 注解处理器 自动生成代码 (javapoet/kot...

  • Java注解

    在写java代码的过程中,经常会遇到注解,但是没有去理解注解背后的原理,也没有实现过注解。网上关于java注解的文...

  • 元注解@Target,@Retention,@Document

    借鉴: Spring注解原理的详细剖析与实现 Java注释@interface的用法【转】

网友评论

    本文标题:注解的实现原理

    本文链接:https://www.haomeiwen.com/subject/jtiglftx.html