ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java注解的原理剖析

2021-11-12 15:02:18  阅读:154  来源: 互联网

标签:java value 剖析 json 注解 ElementType class


一、元注解

1、@Target(作用目标)

标注注解作用的范围
类型说明
ElementType.TYPE类,接口(包括注解类型)或enum声明
ElementType.FIELD字段,枚举常量
ElementType.METHOD方法声明
ElementType.PARAMETER参数声明
ElementType.CONSTRUCTOR构造器声明
ElementType.LOCAL_VARIABLE局部变量声明
ElementType.PACKAGE包声明
ElementType.LOCAL_VARIABLE局部变量
ElementType.ANNOTATION_TYPE注解

2、@Retention(保留策略)

表示在什么级别保存该注解信息
类型说明
RetentionPolicy.SOURCE注解仅存在于源码中,在class字节码文件中不包含
RetentionPolicy.CLASS默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
RetentionPolicy.RUNTIME注解会在class字节码文件中存在,在运行时可以通过反射获取到首 先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。

3、@Documented

将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。

4、@Inherited

Inherited 是继承的意思,但是他并不是说直接本身可以继承,而是说一个超类被@Inheritedh注解,

二、反射

此处为何会讲解反射,因为注解和反射是密切相关的,没有反射,无法完成注解功能的解析。

1、概念

class
Method
Field
Constructor

2、反射核心类

java.lang.Class;     类
java.lang.reflect.Constructor;    构造器方法
java.lang.reflect.Field;    属性
java.lang.reflect.Method;    方法
java.lang.reflect.Modifier;    修饰符

3、类加载三个阶段

1、源代码(source)
    原代码不是指java文件,是class字节码文件
2、类加载(class)
    class字节码文件经类加载器classloader加载到虚拟机内存中,类加载器解析class文件生成Class类型的对象
3、运行时(runtime)
    newInstance()根据java类型生成对象

4、 获取class类对象三种方法

1、Class class=Class.forName("com.xx.xx.xx.Person");
2、Class<Person> class=Person.class;
3、Person p=new Person();
   Class class=p.getClass();

三、解析注解(源码剖析)

写一个注解,自定义返回自己的toString方法。返回自己想要的格式

完整代码可以去此项目下查看cloud-annotation

1、创建自定义注解

注解名称功能
@JsonFormat格式化功能
@JsonIgnore忽略功能
@JsonProperty属性名
/**
 * 作用于属性上,用户按要求格式化日期
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface JsonFormat {
    String pattern() default "yyyy-MM-dd HH:mm:ss";
}
/**
 * 作用在属性上,用于忽略一些属性
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface JsonIgnore {
}
/**
* 属性别名
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface JsonProperty {
    String value(); //使用的时候必须给值

2、注解定义好后自定义方法toJSONString(类似于toString)方法

package com.xwb.springcloud.annotation.json;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;

@SuppressWarnings("all")
public class JSON {
    public static String toJSONString(Object object) {
        StringBuffer json = new StringBuffer();
        try {
            //1、得到object的Class对象
            Class<?> clazz = object.getClass();
            //2、得到class里面的所有属性
            Field[] fields = clazz.getDeclaredFields();
            //3、循环遍历所有属性病打破属性的访问权限
            int index = 0;
            //得到属性长度
            int length = fields.length;
            json.append("{");
            for (Field field : fields) {
                index++;
                //判断属性上是否有忽略的注解
                if (field.isAnnotationPresent(JsonIgnore.class)) {
                    continue;
                }
                //私有变量可读
                field.setAccessible(true);
                //4得到属性名作为json的key
                String name = field.getName();
                //5、得到属性值作为json的value
                Object value = field.get(object);
                //判断属性上是否有更改名字的注解
                if (field.isAnnotationPresent(JsonProperty.class)) {
                    //有的话取出注解上的名字
                    JsonProperty annotation = field.getAnnotation(JsonProperty.class);
                    name = annotation.value();
                }
                json.append("\"" + name + "\"");
                if (value instanceof String) {
                    json.append(":\"" + value.toString() + "\"");
                } else if (value instanceof Date) {
                    //此处如果是日期的话,则判断是否有日起格式化的注解
                    Date date = (Date) value;
                    if (field.isAnnotationPresent(JsonFormat.class)) {
                        JsonFormat format = field.getAnnotation(JsonFormat.class);
                        json.append(":\"" + parseDateToStr(date, format.pattern()) + "\"");
                    } else {
                        json.append(":\"" + date.getTime() + "\"");
                    }
                } else {
                    json.append(":" + value.toString());
                }
                if (index != length) {
                    json.append(",");
                }
            }
            json.append("}");
            return json.toString();
        } catch (Exception e) {
            System.out.println(e.getCause());
        }
        return null;
    }
    public static String parseDateToStr(Date date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }
}

说明:

定义的注解,没有任何作用,但是想让注解发挥它的作用,就要定义相应的方法去解析他,然后让他发挥作用
谁定义的注解谁去解析。而不是说自己定义的注解让java去解析,他是不识别的

3、调用

public class TestJSON {
    public static void main(String[] args) {
        User user = new User(1, "张三", "宁夏银川", new Date());
        String s = JSON.toJSONString(user);
        System.out.println(s);
    }
}

4、输出结果

{“user_name”:“张三”,“user_address”:“宁夏银川”,“birth”:“2021-11-12”}

在这里插入图片描述

示例

总结:注解本身没有任何作用,只是申明的而已,具体起作用是定义该注解的开发者想让其起到什么功能,然后再对应解析的方法中运用反射获取类、属性、方法、参数…上是否有该注解,有的话(xxx instanceof xxx)根据开发者自己的想法去实现该功能方法。
查找源码中的类或者方法使用的快捷键是【ctrl+n

1、spring的@RequestBody注解

spring-webmvc-5.2.2.RELEASE.jar包下的RequestResponseBodyMethodProcessor类进行解析
关于该注解的详细说明请观看此博客@RequestBody

在这里插入图片描述

2、mybatis的@Mapper注解

mybatis-3.4.4.jar包下的MapperAnnotationBuilder类parse方法RequestResponseBodyMethodProcessor
关于@Mapper请看此博客@Mapper

在这里插入图片描述

3、spring的@Configuration

spring-context-5.2.2.RELEASE.jar包下的ConfigurationClassPostProcessor类
源码具体详解可以查看此博主博客@Configuration

在这里插入图片描述

4、springcloud的@FeignClient注解

spring-cloud-openfeign-core-2.2.1.RELEASE.jar包的FeignClientsRegistrar类
关于@FeignClient的源码解析请看此博客@FeignClient

在这里插入图片描述

标签:java,value,剖析,json,注解,ElementType,class
来源: https://blog.csdn.net/www1056481167/article/details/121282337

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有