Skip to content

Commit be7dfbd

Browse files
committed
📝proxy
1 parent 10a6550 commit be7dfbd

File tree

6 files changed

+904
-27
lines changed

6 files changed

+904
-27
lines changed

docs/design-pattern/Proxy-Pattern.md

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,37 @@
11
# 代理模式
22

3-
## 意图
3+
![代理设计模式](https://refactoringguru.cn/images/patterns/content/proxy/proxy.png)
4+
5+
6+
7+
## 基本介绍
8+
9+
**代理模式**是一种结构型设计模式。为对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象,并允许在将请求提交给对象前后进行一些处理。
10+
11+
被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象。
12+
13+
代理模式主要有三种不同的形式:
14+
15+
- 静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的 `.class` 文件就已经存在了
16+
- 动态代理(JDK 代理、接口代理):在程序运行时运用反射机制动态创建而成
17+
- Cglib 代理(可以在内存动态的创建对象,而不是实现接口,属于动态代理的范畴)
418

5-
**代理模式**是一种结构型设计模式, 让你能够提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。
619

7-
![代理设计模式](https://refactoringguru.cn/images/patterns/content/proxy/proxy.png)
820

921
## 问题
1022

1123
为什么要控制对于某个对象的访问呢? 举个例子: 有这样一个消耗大量系统资源的巨型对象, 你只是偶尔需要使用它, 并非总是需要。
1224

13-
![代理模式解决的问题](https://refactoringguru.cn/images/patterns/diagrams/proxy/problem-zh.png)
25+
![数据库查询有可能会非常缓慢](https://refactoringguru.cn/images/patterns/diagrams/proxy/problem-zh.png)
26+
1427

15-
数据库查询有可能会非常缓慢。
1628

1729
你可以实现延迟初始化: 在实际有需要时再创建该对象。 对象的所有客户端都要执行延迟初始代码。 不幸的是, 这很可能会带来很多重复代码。
1830

1931
在理想情况下, 我们希望将代码直接放入对象的类中, 但这并非总是能实现: 比如类可能是第三方封闭库的一部分。
2032

33+
34+
2135
## 解决方案
2236

2337
代理模式建议新建一个与原服务对象接口相同的代理类, 然后更新应用以将代理对象传递给所有原始对象客户端。 代理类接收到客户端请求后会创建实际的服务对象, 并将所有工作委派给它。
@@ -28,13 +42,7 @@
2842

2943
这有什么好处呢? 如果需要在类的主要业务逻辑前后执行一些工作, 你无需修改类就能完成这项工作。 由于代理实现的接口与原类相同, 因此你可将其传递给任何一个使用实际服务对象的客户端。
3044

31-
## 真实世界类比
32-
33-
![信用卡是一大捆现金的代理](https://refactoringguru.cn/images/patterns/diagrams/proxy/live-example-zh.png)
3445

35-
信用卡和现金在支付过程中的用处相同。
36-
37-
信用卡是银行账户的代理, 银行账户则是一大捆现金的代理。 它们都实现了同样的接口, 均可用于进行支付。 消费者会非常满意, 因为不必随身携带大量现金; 商店老板同样会十分高兴, 因为交易收入能以电子化的方式进入商店的银行账户中, 无需担心存款时出现现金丢失或被抢劫的情况。
3846

3947
## 代理模式结构
4048

@@ -45,6 +53,22 @@
4553
3. **代理** (Proxy) 类包含一个指向服务对象的引用成员变量。 代理完成其任务 (例如延迟初始化、 记录日志、 访问控制和缓存等) 后会将请求传递给服务对象。 通常情况下, 代理会对其服务对象的整个生命周期进行管理。
4654
4. **客户端** (Client) 能通过同一接口与服务或代理进行交互, 所以你可在一切需要服务对象的代码中使用代理。
4755

56+
57+
58+
59+
60+
打游戏有代练、买卖房子有中介、再比如一般公司投互联网广告也可以找代理公司,这里的代练、中介、广告代理公司扮演的角色都是代理。
61+
62+
这里举个更接近程序员的例子,我们使用 VPN 或代理,隐藏自己的IP也好,绕过网络审核也好,或者是改变虚拟地址,都属于代理模式。
63+
64+
废话不多说,先来个静态代理。
65+
66+
## 静态代理
67+
68+
69+
70+
71+
4872
## 伪代码
4973

5074
本例演示如何使用**代理**模式在第三方腾讯视频 (TencentVideo, 代码示例中记为 TV) 程序库中添加延迟初始化和缓存。

docs/framework/spring/Spring-FAQ.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,14 @@ Spring 容器可以自动配置相互协作 beans 之间的关联关系。这意
382382

383383
## 四、AOP
384384

385+
>👴:描述一下Spring AOP 呗?
386+
>
387+
>​ 你有没有⽤过Spring的AOP? 是⽤来⼲嘛的? ⼤概会怎么使⽤?
388+
>
389+
>
390+
>
391+
>
392+
385393
### 什么是 AOP?
386394

387395
AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统 OOP(Object-Oriented Programming,面向对象编程) 的补充。在 OOP 中, 我们以类(class)作为我们的基本单元,而 AOP 中的基本单元是 **Aspect(切面)**
@@ -395,20 +403,26 @@ AOP 的好处:
395403
- 每个事物逻辑位于一个位置,代码不分散,便于维护和升级
396404
- 业务模块更简洁, 只包含核心业务代码
397405

398-
![AOP - Spring Framework Interview Questions - Edureka!](https://d1jnx9ba8s6j9r.cloudfront.net/blog/wp-content/uploads/2017/05/unnamed.png)
406+
![](https://d1jnx9ba8s6j9r.cloudfront.net/blog/wp-content/uploads/2017/05/unnamed.png)
399407

400408

401409

402410
### **AOP 术语**
403411

404412
- 切面(Aspect):横切关注点(跨越应用程序多个模块的功能),被模块化的特殊对象
405-
- 连接点(Joinpoint):程序执行的某个特定位置,如类某个方法调用前、调用后、方法抛出异常后等。在这个位置我们可以插入一个 AOP 切面,它实际上是应用程序执行 Spring AOP 的位置![img](https://d1jnx9ba8s6j9r.cloudfront.net/blog/wp-content/uploads/2017/05/JoinPoint-1.png)
413+
- 连接点(Joinpoint):程序执行的某个特定位置,如类某个方法调用前、调用后、方法抛出异常后等。在这个位置我们可以插入一个 AOP 切面,它实际上是应用程序执行 Spring AOP 的位置
414+
415+
![](https://d1jnx9ba8s6j9r.cloudfront.net/blog/wp-content/uploads/2017/05/JoinPoint-1.png)
416+
406417
- 通知(Advice): 通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过 SpringAOP 框架触发的代码段。Spring 切面可以应用五种类型的通知:
407418
- before: 前置通知 , 在一个方法执行前被调用
408419
- after:在方法执行之后调用的通知,无论方式执行是否成功
409420
- after-returning:仅当方法成功完成后执行的通知
410421
- after-throwing:在方法抛出异常退出时执行的通知
411-
- around:在方法执行之前和之后调用的通知![advice - Spring Framework Interview Questions - Edureka!](https://d1jnx9ba8s6j9r.cloudfront.net/blog/wp-content/uploads/2017/05/advice-2.png)
422+
- around:在方法执行之前和之后调用的通知
423+
424+
![advice - Spring Framework Interview Questions - Edureka!](https://d1jnx9ba8s6j9r.cloudfront.net/blog/wp-content/uploads/2017/05/advice-2.png)
425+
412426
- 目标(Target):被通知的对象,通常是一个代理对象,也指被通知(advice)对象
413427
- 代理(Proxy):向目标对象应用通知之后创建的对象
414428
- 切点(pointcut):每个类都拥有多个连接点,程序运行中的一些时间点,例如一个方法的执行,或者是一个异常的处理。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 `org.springframework.aop.Pointcut` 接口进行描述,它使用类和方法作为连接点的查询条件
@@ -419,8 +433,8 @@ AOP 的好处:
419433

420434
**Spring AOP**
421435

422-
- **AspectJ:**Java 社区里最完整最流行的 AOP 框架.
423-
- 在 Spring2.0 以上版本中, 可以使用基于 AspectJ注解或基于 XML 配置的 AOP
436+
- **AspectJ:**Java 社区里最完整最流行的 AOP 框架
437+
- 在 Spring2.0 以上版本中, 可以使用基于 AspectJ 注解或基于 XML 配置的 AOP
424438

425439
**在 Spring 中启用 AspectJ 注解支持**
426440

docs/java/JVM/运行时数据区.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,9 +557,19 @@ Perm Generation:
557557

558558
### TLAB
559559

560-
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gfui8zot4pj31je0p6tux.jpg)
560+
#### 什么是 TLAB (Thread Local Allocation Buffer)?
561+
562+
- 从内存模型而不是垃圾回收的角度,对 Eden 区域继续进行划分,JVM 为每个线程分配了一个私有缓存区域,它包含在 Eden 空间内
563+
- 多线程同时分配内存时,使用 TLAB 可以避免一系列的非线程安全问题,同时还能提升内存分配的吞吐量,因此我们可以将这种内存分配方式称为**快速分配策略**
564+
- OpenJDK 衍生出来的 JVM 大都提供了 TLAB 设计
565+
566+
#### 为什么要有 TLAB ?
567+
568+
- 堆区是线程共享的,任何线程都可以访问到堆区中的共享数据
569+
- 由于对象实例的创建在 JVM 中非常频繁,因此在并发环境下从堆区中划分内存空间是线程不安全的
570+
- 为避免多个线程操作同一地址,需要使用加锁等机制,进而影响分配速度
571+
561572

562-
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gfui93g7z8j30rs0cq7b9.jpg)
563573

564574

565575

docs/message-queue/Kafka/Hello-Kafka.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Kafka 是一个**分布式**的基于**发布/订阅模式的消息队列**(Me
1212

1313
![image-20200601141825408](C:\Users\jiahaixin\AppData\Roaming\Typora\typora-user-images\image-20200601141825408.png)
1414

15-
#### 1.2.2 为什么需要消息队列
15+
#### 1.2.2 为什么需要消息队列
1616

1717
1. **解耦**: 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
1818
2. **冗余**:消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
@@ -103,7 +103,7 @@ Kafka是一个分布式的流处理平台。是支持分区的(partition)、
103103

104104
![img](../../_images/message-queue/Kafka/kafka-apis.png)
105105

106-
Kafka的客户端和服务器之间的通信是靠一个简单的,高性能的,与语言无关的TCP协议完成的。这个协议有不同的版本,并保持向后兼容旧版本。Kafka不光提供了一个Java客户端,还有许多语言版本的客户端。
106+
Kafka 的客户端和服务器之间的通信是靠一个简单的,高性能的,与语言无关的 TCP 协议完成的。这个协议有不同的版本,并保持向后兼容旧版本。Kafka 不光提供了一个 Java 客户端,还有许多语言版本的客户端。
107107

108108
#### 主题和日志
109109

@@ -227,7 +227,7 @@ Kafka 可以为分布式系统提供一种外部提交日志(commit-log)服务
227227

228228
**Kafka 中消息是以 topic 进行分类的**,生产者生产消息,消费者消费消息,都是面向 topic 的。
229229

230-
**topic 是逻辑上的概念,而 patition 是物理上的概念**,每个 patition 对应一个 log 文件,而 log 文件中存储的就是producer 生产的数据,patition 生产的数据会被不断的添加到 log 文件的末端,且每条数据都有自己的 offset。消费组中的每个消费者,都是实时记录自己消费到哪个 offset,以便出错恢复,从上次的位置继续消费。
230+
**topic 是逻辑上的概念,而 patition 是物理上的概念**,每个 patition 对应一个 log 文件,而 log 文件中存储的就是 producer 生产的数据,patition 生产的数据会被不断的添加到 log 文件的末端,且每条数据都有自己的 offset。消费组中的每个消费者,都是实时记录自己消费到哪个 offset,以便出错恢复,从上次的位置继续消费。
231231

232232
![img](../../_images/message-queue/Kafka/kafka-partition.jpg)
233233

@@ -250,7 +250,7 @@ Kafka 可以为分布式系统提供一种外部提交日志(commit-log)服务
250250
| | |
251251
| Leader-epoch-checkpoint | 保存了每一任leader开始写入消息时的offset,会定时更新。 follower被选为leader时会根据这个确定哪些消息可用 |
252252

253-
index 和 log 文件以当前 segment 的第一条消息的 offset 命名。偏移量offset是一个64位的长整形数,固定是20位数字,长度未达到,用0进行填补,索引文件和日志文件都由此作为文件名命名规则。所以从上图可以看出,我们的偏移量是从0开始的,`.index``.log`文件名称都为 `00000000000000000000`。下图为 index 文件和 log 文件的结构示意图。
253+
index 和 log 文件以当前 segment 的第一条消息的 offset 命名。偏移量 offset 是一个64位的长整形数,固定是20位数字,长度未达到,用0进行填补,索引文件和日志文件都由此作为文件名命名规则。所以从上图可以看出,我们的偏移量是从0开始的,`.index``.log`文件名称都为 `00000000000000000000`。下图为 index 文件和 log 文件的结构示意图。
254254

255255
![img](../../_images/message-queue/Kafka/kafka-segement.jpg)
256256

@@ -452,7 +452,7 @@ leader 维护了一个动态的 **in-sync replica set**(ISR),意为和 leader
452452

453453
消费者组最为重要的一个功能是实现广播与单播的功能。一个消费者组可以确保其所订阅的Topic的每个分区只能被从属于该消费者组中的唯一一个消费者所消费;如果不同的消费者组订阅了同一个Topic,那么这些消费者组之间是彼此独立的,不会受到相互的干扰。
454454

455-
> 如果我们希望一条消思可以被多个消费者所消费,那么可以将这些消费者放到不同的消费者组中,这实际上就是广播的效果;如果希望一条消息只能被一个消费者所消费,那么可以将这些消费者放到同一个消费者组中,这实际上就是单播的效果。
455+
> 如果我们希望一条消息可以被多个消费者所消费,那么可以将这些消费者放到不同的消费者组中,这实际上就是广播的效果;如果希望一条消息只能被一个消费者所消费,那么可以将这些消费者放到同一个消费者组中,这实际上就是单播的效果。
456456
457457
#### 3.4.2 消费方式
458458

docs/message-queue/Kafka/Kafka-API.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ kafka 提供了两套 consumer API: 高级 Consumer API 和低级 Consumer API
146146

147147
- 高级 API 写起来简单
148148
- 不需要自行去管理 offset,系统通过 zookeeper 自行管理。
149-
- 不需要管理分区,副本等情况, .系统自动管理。 消费者断线会自动根据上一次记录在 zookeeper 中的 offset 去接着获取数据(默认设置 1 分钟更新一下 zookeeper 中存的 offset) 可以使用 group 来区分对同一个 topic 的不同程序访问分离开来(不同的 group 记录不 同的 offset,这样不同程序读取同一个 topic 才不会因为 offset 互相影响)
149+
- 不需要管理分区,副本等情况, 系统自动管理。 消费者断线会自动根据上一次记录在 zookeeper 中的 offset 去接着获取数据(默认设置 1 分钟更新一下 zookeeper 中存的 offset) 可以使用 group 来区分对同一个 topic 的不同程序访问分离开来(不同的 group 记录不同的 offset,这样不同程序读取同一个 topic 才不会因为 offset 互相影响)
150150

151151
- 高级 API 缺点
152152

@@ -206,7 +206,7 @@ kafka 提供了两套 consumer API: 高级 Consumer API 和低级 Consumer API
206206

207207
#### 4.3.2 低级 API(手动提交offset)
208208

209-
虽然自动提交 offset 十分简介便利,但由于其是基于时间提交的,开发人员难以把握 offset 提交的时机。因此 Kafka 还提供了手动提交 offset 的 API。 手动提交 offset 的方法有两种:分别是 commitSync(同步提交)和 commitAsync(异步提交)。两者的相同点是,都会将本次 poll 的一批数据最高的偏移量提交;不同点是, commitSync 阻塞当前线程,一直到提交成功,并且会自动失败重试(由不可控因素导致, 也会出现提交失败);而 commitAsync 则没有失败重试机制,故有可能提交失败。
209+
虽然自动提交 offset 十分简介便利,但由于其是基于时间提交的,开发人员难以把握 offset 提交的时机。因此 Kafka 还提供了手动提交 offset 的 API。
210210

211211
- 低级 API 优点
212212

@@ -269,7 +269,7 @@ public class CommitSyncCounsumer {
269269

270270
##### 2) 异步提交offset
271271

272-
虽然同步提交 offset 更可靠一些,但是由于其会阻塞当前线程,直到提交成功。因此吞 吐量会收到很大的影响。因此更多的情况下,会选用异步提交 offset 的方式
272+
虽然同步提交 offset 更可靠一些,但是由于其会阻塞当前线程,直到提交成功。因此吞吐量会收到很大的影响。因此更多的情况下,会选用异步提交 offset 的方式
273273

274274
```java
275275
while (true) {
@@ -294,7 +294,7 @@ while (true) {
294294

295295
##### 3) 数据漏消费和重复消费分析
296296

297-
无论是同步提交还是异步提交 offset,都有可能会造成数据的漏消费或者重复消费。先 提交 offset 后消费,有可能造成数据的漏消费;而先消费后提交 offset,有可能会造成数据 的重复消费
297+
无论是同步提交还是异步提交 offset,都有可能会造成数据的漏消费或者重复消费。先提交 offset 后消费,有可能造成数据的漏消费;而先消费后提交 offset,有可能会造成数据的重复消费
298298

299299
------
300300

0 commit comments

Comments
 (0)