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

简介: 最近学完 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中神奇的注解有了初步的了解,这对你学习框架很有帮助


相关文章
|
Ubuntu 应用服务中间件 Shell
用shell脚本部署nginx
用shell脚本部署nginx
241 2
|
监控 网络协议 Java
分布式链路追踪- SkyWalking使用手册
分布式链路追踪- SkyWalking使用手册
1889 0
分布式链路追踪- SkyWalking使用手册
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的甘肃旅游服务平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的甘肃旅游服务平台附带文章源码部署视频讲解等
86 0
|
XML NoSQL Java
Java单体项目和分布式项目中的锁
Java单体项目和分布式项目中的锁 Java单体项目和分布式项目中的锁
181 2
|
算法 安全 Java
在Java中实现数据加密和解密
在Java中实现数据加密和解密
|
消息中间件 网络协议 Dubbo
从java BIO到NIO再到多路复用,看这篇就够了
本文从基础概率到引出业界通用c10k问题,然后通过代码演示从BIO,到NIO再到多路复用的演进历程
7596 5
从java BIO到NIO再到多路复用,看这篇就够了
|
安全 Java 程序员
Java并发编程:理解并应用ReentrantLock
【4月更文挑战第30天】 在多线程的世界中,高效且安全地管理共享资源是至关重要的。本文深入探讨了Java中的一种强大同步工具——ReentrantLock。我们将从其设计原理出发,通过实例演示其在解决并发问题中的实际应用,以及如何比传统的synchronized关键字提供更灵活的锁定机制。文章还将讨论在使用ReentrantLock时可能遇到的一些挑战和最佳实践,帮助开发者避免常见陷阱,提高程序性能和稳定性。
|
存储 NoSQL Java
微服务技术系列教程(46)-SpringBoot整合MongoDB(文章评论案例)
微服务技术系列教程(46)-SpringBoot整合MongoDB(文章评论案例)
339 0
|
Web App开发 前端开发 JavaScript
谷歌浏览器chrome神级插件推荐
谷歌浏览器chrome神级插件推荐
|
Dart 小程序 前端开发
WebSocket 解析与应用(包含web前端、服务端、小程序、dart/flutter中的用法)
WebSocket 解析与应用(包含web前端、服务端、小程序、dart/flutter中的用法)
1308 0