学习不必那么功利,二师兄带你从更高维度轻松浏览源码~
大家可能看到过很多写 Java 反射机制的文章,但如果在浏览源码的过程中,遇到反射机制的应用,你是否想过为什么要这么用吗?
这篇文章就带大家来看看 Nacos 中对 Java 反射机制的一处实际案例。这篇文章既属于知识点的剖析,也属于 Nacos 设计层面的剖析。
Nacos 中反射机制实际
先来介绍一下 Nacos 反射机制应用的背景。
nacos-client 我的项目中,能够通过 NacosFactory 取得 NamingService,而后基于 NamingService 来进行服务实例的注册性能:
NamingService namingService = NacosFactory.createNamingService(properties);
namingService.registerInstance("nacos.test.1", instance);
而在 NacosFactory 中又是基于 NamingFactory 来实现 NamingService 的创立的:
public static NamingService createNamingService(Properties properties) throws NacosException {return NamingFactory.createNamingService(properties);
}
NamingFactory 具体创立局部代码如下:
public static NamingService createNamingService(Properties properties) throws NacosException {
try {Class<?> driverImplClass = Class.forName("com.alibaba.nacos.client.naming.NacosNamingService");
Constructor constructor = driverImplClass.getConstructor(Properties.class);
return (NamingService) constructor.newInstance(properties);
} catch (Throwable e) {throw new NacosException(NacosException.CLIENT_INVALID_PARAM, e);
}
}
到这里,终于看到了反射机制的应用了,通过 Class#forName 办法获取 Class 对象,而后获取构造方法,创立实例。
如果你浏览源码时只看到这些,可能你会错过一些有意思的设计和事件。你是否思考过,为什么这里要采纳反射机制呢?间接 new 一个对象不行吗?
在解答上述问题之前,咱们先来简略科普一下 Java 发反射机制。
Java 反射机制
这里从基本概念、原理、简略实际说起。
Java 反射简介
Java 是预编的语言,对象的类型在编译期曾经确定。在程序运行时可能须要动静加载某些类,这些类之前用不到,所以就没有被加载到 JVM 中。须要时,可通过反射在运行时动静地创建对象并调用其属性或办法,而不须要在编译期就晓得运行的对象是谁。
Java 反射机制的外围是在程序运行时动静加载类并获取类的详细信息,从而可能操作类或对象的属性和办法。
Java 反射的优缺点
Java 反射的长处:
- 减少程序的灵活性,防止将程序写死到代码里;
- 代码简洁,进步代码的复用率,内部调用不便;
- 对于任意一个类,都可能晓得这个类的所有属性和办法;对于任意一个对象,都可能调用它的任意一个办法;
反射的原理
在理解反射的基本原理之前,咱们须要晓得在 Java 程序编译实现之后,会把所有 class 文件中所蕴含的类的根本元信息装载到 JVM 内存中,以 Class 类的模式保留。Class 类可了解为形容类的类,每一个 Class 类对象代表一个具体类的根本元信息。反射就是在 Class 类的根底上进行的,Class 类对象存储着类的所有相干信息。
对于 JVM 外部的操作步骤,咱们这里不做拓展。须要理解的就是 Class 对象是 JVM 加载.class 文件之后生成的对象,而反射机制提供了获取该对象,能够基于此进行属性拜访或对象结构。而这一步是产生在运行时期间。
反射的根本应用
通常应用反射有三种形式:
// 形式一:应用 Class.forName 静态方法
Class clz = Class.forName("java.lang.String");
// 形式二:应用.class 办法
Class clz = String.class;
// 形式三:应用类对象的 getClass() 办法
String str = new String("Hello");
Class clz = str.getClass();
上述三种形式,个别罕用第一种,字符串参数能够传入也能够写在配置文件中。第二种须要导入类包,依赖太强,不导包就抛编译谬误。第三种对象都有了还要反射干什么。
所以说,通常咱们学习的时候,晓得了很多种形式,而真正应用时,还是须要依据场景进行抉择。而 Nacos 的源码中就采纳了第一种的形式。
对于反射的其余 API 的应用此处就不再开展了,上面回到主题,来思考一下 Nacos 为什么应用反射,同时为什么采纳第一种形式。
Nacos 反射机制原理剖析
在剖析之前,咱们先来看一下我的项目构造。首先,nacos-client 我的项目依赖于 nacos-aip 我的项目,NamingFactory 和 NamingService 位于 nacos-api 我的项目当中。而具体被实例化的对象类 com.alibaba.nacos.client.naming.NacosNamingService,很显著位于 nacos-client 当中。
通过上图咱们能够看到,NamingFactory 中实现了 NamingService 的实例化业务逻辑,但此时 nacos-api 我的项目并没有 NacoNamingService,也就无奈采纳下面提到的其余两种办法,只能通过 Class.forName 形式来进行实现了。
其实这里的设计与数据库驱动程序相似,nacos-api 中通过 NamingService 定义了一个接口,也就是定义了一个规范。而 nacos-client 中实现了这个规范,并且还要满足两个条件:第一,该实现类实现自 NamingService;第二,该类的全路径名要与 NamingFactory 中的实例化对象时的名称一样。
回头再认真设想,Nacos 的用法,也不正是反射机制很典型的应用场景之一吗?
小结
本文从 Nacos 的反射机制登程,深刻思考提出问题,并简略介绍了 Java 的反射机制。最终进一步剖析 Nacos 我的项目构造,解答了最开始的疑难。你会如此浏览源代码吗?你学到了吗?连忙关注上车!后续更多干货输入。
如果文章内容有问题或想技术探讨请分割我(微信:zhuan2quan,备注 Nacos),如果感觉写的还不错,值得一起学习,那就关注一下吧。
Nacos 系列文章
- 01《《跟二师兄学 Nacos 吧》第 1 篇 Nacos 客户端服务注册源码剖析》
- EXT-01《《跟二师兄学 Nacos 吧》EXT-01 篇 看看 Nacos 是怎么活学活用简略工厂模式的!》
- EXT-02《《跟二师兄学 Nacos 吧》EXT-02 篇 面试官问工厂模式,你了解的对吗?》
博主简介:《SpringBoot 技术底细》技术图书作者,热爱钻研技术,写技术干货文章。
公众号:「程序新视界」,博主的公众号,欢送关注~
技术交换:请分割博主微信号:zhuan2quan