神奇的注解是怎么实现的,你不好奇吗?

简介: 最近学完 java的ssm框架之后,我有了好多的领悟,许多非常值得学习的思想,其中还有一个让我疑惑的就是框架中推荐的注解式开发,添加一条注解就可以自动注入,哇哇哇……此处省略一万字,它好神奇啊,我想看看它的全貌,点进源码,我蒙了,很短,并不是我想的一堆逻辑处理,于是就查资料学习,总结了以下知识点,一起来学习吧!芜湖,拿下它 🚀

文章目录


离不开的知识:反射机制🤪


java反射快速入门👩‍💻


写一个注解,从而理解它😎


总结🍭


离不开的知识:反射机制🤪



Java开始是静态强类型语言,类型是静态的。


优点


避免了程序在运行时发生变量类型相关的错误,代码更健壮,

提前知道类型,编译器可以针对这些信息进行优化,从而提升程序的执行速度。


缺点


程序员要注意变量的类型,变量的声明会使得代码量增加。

Java语言为了使用社会需求,Java在静态的基础之上引入了反射机制使得自己具有一定的动态性,这使得Java语言更加灵活,也因此诞生了大名鼎鼎的spring框架等等。


java反射快速入门👩‍💻


提一个需求,要求不修改源码,通过配置文件决定实例化哪个对象,Ok


bean.properties配置文件


bean=com.liu.annotation_.Dog


Dog类


package com.liu.annotation_;
public class Dog {
    private Integer id = 1;
    private String name = "小猫";
}


Cat类


package com.liu.annotation_;
public class Cat {
    private Integer id = 1;
    private String name = "小狗";
}


Test类


package com.liu.annotation_;
import java.io.IOException;
import java.util.Properties;
public class Test {
    private static Properties properties;
    static {
        properties = new Properties();
        try {
            /*通过类加载器获取将资源转化为流的方法,加载配置文件*/
            properties.load(Test.class.getClassLoader().getResourceAsStream("bean.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws Exception{
        /*获取配置文件的bean*/
        String bean = properties.getProperty("bean");
        /*获取实例的类名forName,getInstance是创建实例,返回值是一个对象
        * 因为我们知道他的实际类型,因此可以通过多态强制转换,也可以通过getClass获取实际类型*/
        Object o = Class.forName(bean).newInstance();
        System.out.println(o.getClass()); /*class com.liu.annotation_.配置文件的类型*/
    }
}


当配置文件是bean=com.liu.annotation_.Dog时,输出


0bf84d8c9f8d45909e0d68f489c144b4.png


当配置文件是bean=com.liu.annotation_.Cat时,输出


8b7218267eac4bcfafdf40a14c6173c1.png


这就完成了在不修改源码的情况下,动态改变了实例化的对象,使得程序变得更灵活……

它也是很多框架的基础,其中注解也有用到它哦,下面开始注解的解析


写一个注解,从而理解它😎



自定义MyComponent 注解


package com.liu.annotation_;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/*程序运行时注解生效*/
@Retention(RetentionPolicy.RUNTIME)
/*给谁添加*/
@Target(ElementType.TYPE)
public @interface MyComponent {
}


自定义MyValue 注解


package com.liu.annotation_;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyValue {
    String value();
}


给cat类添加自定义注解


package com.liu.annotation_;
@MyComponent
public class Cat {
    @MyValue("0")
    private Integer id;
    @MyValue("招财猫")
    private String name;
    @Override
    public String toString() {
        return "Cat{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}


使用我们自定义的注解 核心


package com.liu.annotation_;
import java.lang.reflect.Field;
public class TestMyAnnotation {
    public static void main(String[] args) throws Exception {
        /*获取类对象*/
        Class<Cat> catClass = Cat.class;
        /*通过getAnnotation()方法获取我们自定义的注解的类对象*/
        MyComponent annotation = catClass.getAnnotation(MyComponent.class);
        /*判断*/
        if(annotation != null){
            System.out.println("添加了 MyComponent 注解");
            /*创建对象*/
            Cat cat = Cat.class.newInstance();
            /*开始赋值*/
            System.out.println(cat);
            Field[] declaredFields = catClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                MyValue valueAnnotation = declaredField.getAnnotation(MyValue.class);
                if(valueAnnotation != null){
                    System.out.println(valueAnnotation + "添加了 value 注解");
                    /*拿到注解对象的值*/
                    String value = valueAnnotation.value();
                    System.out.println("注解添加的值是:" + value);
                    /*私有属性要想赋值可以使用反射爆破*/
                    declaredField.setAccessible(true);
                    /*类型判断并赋值*/
                    if(declaredField.getType().getName().equals("java.lang.Integer")){
                        Integer val = Integer.parseInt(value);
                        declaredField.set(cat,val);
                    }else{
                        declaredField.set(cat,value);
                    }
                }
            }
            System.out.println("最终效果---------------");
            System.out.println(cat);
        }else{
            System.out.println("没有添加 MyComponent 注解");
            /*不赋值*/
        }
    }
}


运行结果,成功赋值


添加了 MyComponent 注解
Cat{id=null, name='null'}
@com.liu.annotation_.MyValue(value=0)添加了 value 注解
注解添加的值是:0
@com.liu.annotation_.MyValue(value=招财猫)添加了 value 注解
注解添加的值是:招财猫
最终效果---------------
Cat{id=0, name='招财猫'}


总结🍭



利用反射机制以及提供的getAnnotation()方法可以获取我们自定义的注解对象,再经过简单判断是否添加,如果添加了@MyComponent,就创建对象,如果没有则不添加,再经过反射机制获取所有字段以及通过getAnnotation()方法循环判断是否添加了自定义的@MyValue注解,如果有就给它赋值,但是有一个问题,字段是私有属性,按理说是无法直接赋值的,确实如此,不过,我们可以通过Java提供的反射爆破,越过检查,从而完成私有属性的直接赋值,只需要一行代码declaredField.setAccessible(true);


即可,另外在赋值时判断一下待赋值的字段的类型,然后再根据类型分别赋值就🆗了,其实也是很简单的,但是这种思想真的很有意思,值得思考和借鉴,因此,我相信你对Java中神奇的注解有了初步的了解,这对你学习框架很有帮助


相关文章
|
2月前
|
Java 编译器 Spring
一文搞懂:什么是注解?
一文搞懂:什么是注解?
20 0
|
3月前
|
Java 编译器 API
【面试问题】注解的实现原理?
【1月更文挑战第27天】【面试问题】注解的实现原理?
|
3月前
|
监控 NoSQL Java
面试官:实际工作中哪里用到了自定义注解?
面试官:实际工作中哪里用到了自定义注解?
58 2
|
安全 Java 大数据
一文搞懂什么是“注解”
一文搞懂什么是“注解”
252 0
一文搞懂什么是“注解”
|
11月前
|
缓存 Java 索引
一文读懂注解的底层原理
一文读懂注解的底层原理
|
安全 Java 编译器
JAVA注解与反射:看这篇文章就够了1
JAVA注解与反射:看这篇文章就够了
116 0
|
XML 缓存 Java
Java注解怎么用
Java注解怎么用
215 0
|
XML 缓存 Java
面试官:讲讲Spring框架Bean的加载过程
面试官:讲讲Spring框架Bean的加载过程
766 0
面试官:讲讲Spring框架Bean的加载过程
|
存储 设计模式 缓存
一直在使用JDK动态代理, 不明白原理如何实现?
一直在使用JDK动态代理, 不明白原理如何实现?
一直在使用JDK动态代理, 不明白原理如何实现?