注解就这么简(二)

简介: 笔记

4.4把自定义注解的基本信息注入到方法上


上面我们已经使用到了注解,但是目前为止注解上的信息和方法上的信息是没有任何关联的

我们使用Servlet注解的时候,仅仅调用注解,那么注解的就生效了。这是Web容器把内部实现了。我们自己写的自定义注解是需要我们自己来处理的

那现在问题来了,我们怎么把注解上的信息注入到方法上呢???我们利用的是反射技术

步骤可分为三部:

  • 反射出该类的方法
  • 通过方法得到注解上具体的信息
  • 将注解上的信息注入到方法上
//反射出该类的方法
        Class aClass = Demo2.class;
        Method method = aClass.getMethod("add", String.class, int.class);
        //通过该方法得到注解上的具体信息
        MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
        String username = annotation.username();
        int age = annotation.age();
        //将注解上的信息注入到方法上
        Object o = aClass.newInstance();
        method.invoke(o, username, age);

当我们执行的时候,我们发现会出现异常…

7.jpg这里写图片描述

此时,我们需要在自定义注解上加入这样一句代码(下面就会讲到,为什么要加入这句代码)

@Retention(RetentionPolicy.RUNTIME)

再次执行的时候,我们就会发现,可以通过注解来把信息注入到方法中了。


五、JDK的元Annotation


前面我们已经介绍了java.lang包下的几个基本Annotation了。在JDK中除了java.lang包下有Annotation,在java.lang.annotation下也有几个常用的元Annotation。

在annotation包下的好几个元Annotation都是用于修饰其他的Annotation定义


5.1@Retention


上面在将注解信息注入到方法中的时候,我们最后加上了@Retention的注解….不然就会报错了..那它是干什么用的呢?

@Retention只能用于修饰其他的Annotation,用于指定被修饰的Annotation被保留多长时间。

@Retention 包含了一个RetentionPolicy类型的value变量,所以在使用它的时候,必须要为value成员变量赋值

value变量的值只有三个:

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,
    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,
    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

java文件有三个时期:编译,class,运行。@Retention默认是class

前面我们是使用反射来得到注解上的信息的,因为@Retention默认是class,而反射是在运行时期来获取信息的。因此就获取不到Annotation的信息了。于是,就得在自定义注解上修改它的RetentionPolicy值


5.2@Target


@Target也是只能用于修饰另外的Annotation它用于指定被修饰的Annotation用于修饰哪些程序单元

@Target是只有一个value成员变量的,该成员变量的值是以下的:

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,
    /** Field declaration (includes enum constants) */
    FIELD,
    /** Method declaration */
    METHOD,
    /** Parameter declaration */
    PARAMETER,
    /** Constructor declaration */
    CONSTRUCTOR,
    /** Local variable declaration */
    LOCAL_VARIABLE,
    /** Annotation type declaration */
    ANNOTATION_TYPE,
    /** Package declaration */
    PACKAGE
}

如果@Target指定的是ElementType.ANNOTATION_TYPE,那么该被修饰的Annotation只能修饰Annotaion


5.3@Documented


@Documented用于指定被该Annotation修饰的Annotation类将被javadoc工具提取成文档

该元Annotation用得挺少的….


5.4@Inherited


@Inherited也是用来修饰其他的Annotation的,被修饰过的Annotation将具有继承性。。。

例子:

  1. @xxx是我自定义的注解,我现在使用@xxx注解在Base类上使用….
  2. 使用@Inherited修饰@xxx注解
  3. 当有类继承了Base类的时候,该实现类自动拥有@xxx注解

六、注入对象到方法或成员变量上


6.1把对象注入到方法上


前面我们已经可以使用注解将基本的信息注入到方法上了,现在我们要使用的是将对象注入到方法上…..

上边已经说过了,注解上只能定义String、枚举类、Double之类的成员变量,那怎么把对象注入到方法上呢?


6.1.2模拟场景:


  • Person类,定义username和age属性,拥有uername和age的getter和setter方法
public class Person {
    private String username;
    private int age;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
  • PersonDao类,PersonDao类定义了Person对象,拥有person的setter和getter方法
public class PersonDao {
    private Person person;
    public Person getPerson() {
        return person;
    }
    public void setPerson(Person person) {
        this.person = person;
    }
}
  • 现在我要做的就是:使用注解将Person对象注入到setPerson()方法中,从而设置了PersonDao类的person属性
public class PersonDao {
    private Person person;
    public Person getPerson() {
        return person;
    }
    //将username为zhongfucheng,age为20的Person对象注入到setPerson方法中
    @InjectPerson(username = "zhongfucheng",age = 20)
    public void setPerson(Person person) {
        this.person = person;
    }
}

步骤:

①: 自定义一个注解,属性是和JavaBean类一致的

//注入工具是通过反射来得到注解的信息的,于是保留域必须使用RunTime
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectPerson {
    String username();
    int age();
}

②:编写注入工具

//1.使用内省【后边需要得到属性的写方法】,得到想要注入的属性
        PropertyDescriptor descriptor = new PropertyDescriptor("person", PersonDao.class);
        //2.得到要想注入属性的具体对象
        Person person = (Person) descriptor.getPropertyType().newInstance();
        //3.得到该属性的写方法【setPerson()】
        Method method = descriptor.getWriteMethod();
        //4.得到写方法的注解
        Annotation annotation = method.getAnnotation(InjectPerson.class);
        //5.得到注解上的信息【注解的成员变量就是用方法来定义的】
        Method[] methods = annotation.getClass().getMethods();
        //6.将注解上的信息填充到person对象上
        for (Method m : methods) {
            //得到注解上属性的名字【age或name】
            String name = m.getName();
            //看看Person对象有没有与之对应的方法【setAge(),setName()】
            try {
                //6.1这里假设:有与之对应的写方法,得到写方法
                PropertyDescriptor descriptor1 = new PropertyDescriptor(name, Person.class);
                Method method1 = descriptor1.getWriteMethod();//setAge(), setName()
                //得到注解中的值
                Object o = m.invoke(annotation, null);
                //调用Person对象的setter方法,将注解上的值设置进去
                method1.invoke(person, o);
            } catch (Exception e) {
                //6.2 Person对象没有与之对应的方法,会跳到catch来。我们要让它继续遍历注解就好了
                continue;
            }
        }
        //当程序遍历完之后,person对象已经填充完数据了
        //7.将person对象赋给PersonDao【通过写方法】
        PersonDao personDao = new PersonDao();
        method.invoke(personDao, person);
        System.out.println(personDao.getPerson().getUsername());
        System.out.println(personDao.getPerson().getAge());

③:总结一下步骤

其实我们是这样把对象注入到方法中的:

  • 得到想要类中注入的属性
  • 得到该属性的对象
  • 得到属性对应的写方法
  • 通过写方法得到注解
  • 获取注解详细的信息
  • 将注解的信息注入到对象上
  • 调用属性写方法,将已填充数据的对象注入到方法中


6.2把对象注入到成员变量


上面已经说了如何将对象注入到方法上了,那么注入到成员变量上也是非常简单的。

步骤:

①:在成员变量上使用注解

public class PersonDao {
    @InjectPerson(username = "zhongfucheng",age = 20) private Person person;
    public Person getPerson() {
        return person;
    }
    public void setPerson(Person person) {
        this.person = person;
    }
}

②:编写注入工具

//1.得到想要注入的属性
        Field field = PersonDao.class.getDeclaredField("person");
        //2.得到属性的具体对象
        Person person = (Person) field.getType().newInstance();
        //3.得到属性上的注解
        Annotation annotation = field.getAnnotation(InjectPerson.class);
        //4.得到注解的属性【注解上的属性使用方法来表示的】
        Method[] methods = annotation.getClass().getMethods();
        //5.将注入的属性填充到person对象上
        for (Method method : methods) {
            //5.1得到注解属性的名字
            String name = method.getName();
            //查看一下Person对象上有没有与之对应的写方法
            try {
                //如果有
                PropertyDescriptor descriptor = new PropertyDescriptor(name, Person.class);
                //得到Person对象上的写方法
                Method method1 = descriptor.getWriteMethod();
                //得到注解上的值
                Object o = method.invoke(annotation, null);
                //填充person对象
                method1.invoke(person, o);
            } catch (IntrospectionException e) {
                //如果没有想对应的属性,继续循环
                continue;
            }
        }
        //循环完之后,person就已经填充好数据了
        //6.把person对象设置到PersonDao中
        PersonDao personDao = new PersonDao();
        field.setAccessible(true);
        field.set(personDao, person);
        System.out.println(personDao.getPerson().getUsername());


七、总结


①:注入对象的步骤:得到想要注入的对象属性,通过属性得到注解的信息,通过属性的写方法将注解的信息注入到对象上,最后将对象赋给类

②:注解其实就是两个作用:

  • 让编译器检查代码
  • 将数据注入到方法、成员变量、类上

③:在JDK中注解分为了

  • 基本Annotation
  • 在lang包下,用于常用于标记该方法,抑制编译器警告等
  • 元Annotaion
  • 在annotaion包下,常用于修饰其他的Annotation定义

8.jpg

目录
相关文章
|
4月前
|
XML Java 数据格式
爆肝15000字!Spring框架基础详解!
        因为开学要做项目的原因,花了整整一天的事件来复习spring的知识,并且对Spring中常用的东西进行总结,红字部分是相对重要的,大家可以多注意!如果本文有写的不对或者不明确的地方还希望大家可以在评论中指出。
|
4月前
|
JSON 前端开发 Java
数据映射框架之三大神器:反射、注解、动态代理
数据映射框架之三大神器:反射、注解、动态代理
45 3
数据映射框架之三大神器:反射、注解、动态代理
|
4月前
|
Java 编译器 Android开发
Java注解你知多少?
Java注解你知多少?
33 1
|
Java Spring 容器
Spring框架:第六章:注解功能
Spring框架:第六章:注解功能
114 0
Spring框架:第六章:注解功能
|
架构师 Java 容器
|
数据采集 算法 Java
今天拿SpringAOP和自定义注解的通用性开🔪
SpringAOP和自定义注解的通用性
105 0
今天拿SpringAOP和自定义注解的通用性开🔪
|
XML Java 应用服务中间件
SpringBoot 注解原理,自动装配原理,图文并茂,万字长文!
点进@SpringBootApplication来看,发现@SpringBootApplication是一个组合注解。
SpringBoot 注解原理,自动装配原理,图文并茂,万字长文!
|
监控 前端开发 Java
过滤器与拦截器的N个区别,别傻傻分不清了
过滤器与拦截器的N个区别,别傻傻分不清了
215 0
过滤器与拦截器的N个区别,别傻傻分不清了
|
存储 Java API
@lombok注解背后的原理是什么,让我们走近自定义Java注解处理器
本文介绍了如何自定义Java注解处理器及涉及到的相关知识,看完本文可以很轻松看懂并理解各大开源框架的注解处理器的应用。
|
人工智能 Dubbo Java
【Spring注解驱动开发】二狗子让我给他讲讲@EnableAspectJAutoProxy注解
最近,二狗子入职了新公司,新入职的那几天确实有点飘。不过慢慢的,他发现他身边的人各个身怀绝技啊,有Spring源码的贡献者,有Dubbo源码的贡献者,有MyBatis源码的贡献者,还有研究AI的大佬,个个都是大神级别的人物。二狗子有点慌,想起自己虽然入职了,但是比起其他人确实差点远啊。怎么办呢?先从基础补起呗,他发现自己对于Spring的理解还不算太深。于是乎,他让我给他讲讲Spring的@EnableAspectJAutoProxy注解。
179 0
【Spring注解驱动开发】二狗子让我给他讲讲@EnableAspectJAutoProxy注解