Skip to content

Commit b81ae5b

Browse files
committed
[docs add]Java SPI 机制详解
1 parent f7b77ea commit b81ae5b

7 files changed

+621
-15
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,11 @@
5454
* [为什么 Java 中只有值传递?](docs/java/basis/why-there-only-value-passing-in-java.md)
5555
* [Java 序列化详解](docs/java/basis/serialization.md)
5656
* [泛型&序列化详解](docs/java/basis/generics-and-wildcards.md)
57-
* [反射机制详解](docs/java/basis/reflection.md)
57+
* [Java 反射机制详解](docs/java/basis/reflection.md)
5858
* [Java 代理模式详解](docs/java/basis/proxy.md)
5959
* [BigDecimal 详解](docs/java/basis/bigdecimal.md)
6060
* [Java 魔法类 Unsafe 详解](docs/java/basis/unsafe.md)
61+
* [Java SPI 机制详解](docs/java/basis/spi.md)
6162

6263
### 集合
6364

docs/.vuepress/sidebar.ts

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export const sidebarConfig = defineSidebarConfig({
5656
"proxy",
5757
"bigdecimal",
5858
"unsafe",
59+
"spi",
5960
],
6061
},
6162
],

docs/java/basis/java-basic-questions-02.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public class Student {
117117

118118
**区别**
119119

120-
- 接口主要用于对类的行为进行约束,你实现了某个接口就具有了对应的行为。抽象类主要用于代码复用,强调的是所属关系(比如说我们抽象了一个发送短信的抽象类,)
120+
- 接口主要用于对类的行为进行约束,你实现了某个接口就具有了对应的行为。抽象类主要用于代码复用,强调的是所属关系。
121121
- 一个类只能继承一个类,但是可以实现多个接口。
122122
- 接口中的成员变量只能是 `public static final` 类型的,不能被修改且必须有初始值,而抽象类的成员变量默认 default,可在子类中被重新定义,也可被重新赋值。
123123

docs/java/basis/java-basic-questions-03.md

+56-11
Original file line numberDiff line numberDiff line change
@@ -323,22 +323,23 @@ printArray( stringArray );
323323

324324
## 反射
325325

326-
### 何为反射?
326+
关于反射的详细解读,请看这篇文章 [Java 反射机制详解](./reflection.md)
327327

328-
如果说大家研究过框架的底层原理或者咱们自己写过框架的话,一定对反射这个概念不陌生。
328+
### 何谓反射?
329329

330-
反射之所以被称为框架的灵魂,主要是因为它赋予了我们在运行时分析类以及执行类中方法的能力。通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
330+
如果说大家研究过框架的底层原理或者咱们自己写过框架的话,一定对反射这个概念不陌生。反射之所以被称为框架的灵魂,主要是因为它赋予了我们在运行时分析类以及执行类中方法的能力。通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
331331

332-
### 反射机制优缺点
332+
### 反射的优缺点?
333333

334-
- **优点** : 可以让咱们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利
335-
- **缺点** :让我们在运行时有了分析操作类的能力,这同样也增加了安全问题。比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。另外,反射的性能也要稍差点,不过,对于框架来说实际是影响不大的。[Java Reflection: Why is it so slow?](https://stackoverflow.com/questions/1392351/java-reflection-why-is-it-so-slow)
334+
反射可以让我们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利。
336335

337-
### 反射的应用场景
336+
不过,反射让我们在运行时有了分析操作类的能力的同时,也增加了安全问题,比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。另外,反射的性能也要稍差点,不过,对于框架来说实际是影响不大的。
338337

339-
像咱们平时大部分时候都是在写业务代码,很少会接触到直接使用反射机制的场景
338+
相关阅读:[Java Reflection: Why is it so slow?](https://stackoverflow.com/questions/1392351/java-reflection-why-is-it-so-slow)
340339

341-
但是,这并不代表反射没有用。相反,正是因为反射,你才能这么轻松地使用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。
340+
### 反射的应用场景?
341+
342+
像咱们平时大部分时候都是在写业务代码,很少会接触到直接使用反射机制的场景。但是!这并不代表反射没有用。相反,正是因为反射,你才能这么轻松地使用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。
342343

343344
**这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射。**
344345

@@ -373,7 +374,9 @@ public class DebugInvocationHandler implements InvocationHandler {
373374

374375
## 注解
375376

376-
`Annotation` (注解) 是 Java5 开始引入的新特性,可以看作是一种特殊的注释,主要用于修饰类、方法或者变量。
377+
### 何谓注解?
378+
379+
`Annotation` (注解) 是 Java5 开始引入的新特性,可以看作是一种特殊的注释,主要用于修饰类、方法或者变量,提供某些
377380

378381
注解本质是一个继承了`Annotation` 的特殊接口:
379382

@@ -389,12 +392,51 @@ public interface Override extends Annotation{
389392
}
390393
```
391394

395+
JDK 提供了很多内置的注解(比如 `@Override``@Deprecated`),同时,我们还可以自定义注解。
396+
397+
### 注解的解析方法有哪几种?
398+
392399
注解只有被解析之后才会生效,常见的解析方法有两种:
393400

394401
- **编译期直接扫描** :编译器在编译 Java 代码的时候扫描对应的注解并处理,比如某个方法使用`@Override` 注解,编译器在编译的时候就会检测当前的方法是否重写了父类对应的方法。
395402
- **运行期通过反射处理** :像框架中自带的注解(比如 Spring 框架的 `@Value``@Component`)都是通过反射来进行处理的。
396403

397-
JDK 提供了很多内置的注解(比如 `@Override``@Deprecated`),同时,我们还可以自定义注解。
404+
## SPI
405+
406+
关于 SPI 的详细解读,请看这篇文章 [Java SPI 机制详解](./spi.md)
407+
408+
### 何谓 SPI?
409+
410+
SPI 即 Service Provider Interface ,字面意思就是:“服务提供者的接口”,我的理解是:专门提供给服务提供者或者扩展框架功能的开发者去使用的一个接口。
411+
412+
SPI 将服务接口和具体的服务实现分离开来,将服务调用方和服务实现者解耦,能够提升程序的扩展性、可维护性。修改或者替换服务实现并不需要修改调用方。
413+
414+
很多框架都使用了 Java 的 SPI 机制,比如:Spring 框架、数据库加载驱动、日志接口、以及 Dubbo 的扩展实现等等。
415+
416+
![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/java/basis/spi/22e1830e0b0e4115a882751f6c417857tplv-k3u1fbpfcp-zoom-1.jpeg)
417+
418+
### SPI 和 API 有什么区别?
419+
420+
**那 SPI 和 API 有啥区别?**
421+
422+
说到 SPI 就不得不说一下 API 了,从广义上来说它们都属于接口,而且很容易混淆。下面先用一张图说明一下:
423+
424+
![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/java/basis/spi/1ebd1df862c34880bc26b9d494535b3dtplv-k3u1fbpfcp-watermark.png)
425+
426+
一般模块之间都是通过通过接口进行通讯,那我们在服务调用方和服务实现方(也称服务提供者)之间引入一个“接口”。
427+
428+
当实现方提供了接口和实现,我们可以通过调用实现方的接口从而拥有实现方给我们提供的能力,这就是 API ,这种接口和实现都是放在实现方的。
429+
430+
当接口存在于调用方这边时,就是 SPI ,由接口调用方确定接口规则,然后由不同的厂商去根绝这个规则对这个接口进行实现,从而提供服务。
431+
432+
举个通俗易懂的例子:公司 H 是一家科技公司,新设计了一款芯片,然后现在需要量产了,而市面上有好几家芯片制造业公司,这个时候,只要 H 公司指定好了这芯片生产的标准(定义好了接口标准),那么这些合作的芯片公司(服务提供者)就按照标准交付自家特色的芯片(提供不同方案的实现,但是给出来的结果是一样的)。
433+
434+
### SPI 的优缺点?
435+
436+
通过 SPI 机制能够大大地提高接口设计的灵活性,但是 SPI 机制也存在一些缺点,比如:
437+
438+
- 遍历加载所有的实现类,这样效率还是相对较低的;
439+
- 当多个 `ServiceLoader` 同时 `load` 时,会有并发问题。
398440

399441
## I/O
400442

@@ -472,3 +514,6 @@ Java IO 流共涉及 40 多个类,这些类看上去很杂乱,但实际上
472514
问题本质想问:**不管是文件读写还是网络发送接收,信息的最小存储单元都是字节,那为什么 I/O 流操作要分为字节流操作和字符流操作呢?**
473515

474516
回答:字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还算是非常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以, I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。
517+
518+
519+

docs/java/basis/reflection.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: 反射机制详解
2+
title: Java 反射机制详解
33
category: Java
44
tag:
55
- Java基础

docs/java/basis/serialization.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Java 序列化详解
2+
title: Java 序列化详解
33
category: Java
44
tag:
55
- Java基础

0 commit comments

Comments
 (0)