-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathatom.xml
596 lines (363 loc) · 780 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Guest997</title>
<subtitle>一个在互联网下的小小 Coder</subtitle>
<link href="http://guest997.tk/atom.xml" rel="self"/>
<link href="http://guest997.tk/"/>
<updated>2022-07-28T14:58:47.519Z</updated>
<id>http://guest997.tk/</id>
<author>
<name>Guest997</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>SpringCloud 详解(十二)</title>
<link href="http://guest997.tk/2022/05/31/springcloud-expound12/"/>
<id>http://guest997.tk/2022/05/31/springcloud-expound12/</id>
<published>2022-05-31T04:01:59.000Z</published>
<updated>2022-07-28T14:58:47.519Z</updated>
<content type="html"><![CDATA[<p>微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。</p><h2 id="Config"><a href="#Config" class="headerlink" title="Config"></a>Config</h2><p>SpringCloud Config 为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。分为<strong>服务端</strong>和<strong>客户端</strong>两部分。</p><ul><li> 服务端:也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息、加密/解密信息等访问接口。</li><li> 客户端:通过指定的配置中心来管理应用资源以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。配置服务器默认采用 git 来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过 git 客户端工具来方便地管理和获取配置内容。</li></ul><h3 id="服务端搭建"><a href="#服务端搭建" class="headerlink" title="服务端搭建"></a>服务端搭建</h3><h4 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h4><p>在 Github 或 Gitee 上新建个仓库,并将三个配置文件上传上去。(推荐使用国内的 Gitee)</p><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#config-dev.yaml</span></span><br><span class="line"><span class="symbol">config:</span></span><br><span class="line"><span class="symbol"> info:</span> <span class="string">"master branch,springcloud-config/config-dev.yaml version=1.0"</span></span><br></pre></td></tr></table></figure><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#config-prod.yaml</span></span><br><span class="line"><span class="symbol">config:</span></span><br><span class="line"><span class="symbol"> info:</span> <span class="string">"master branch,springcloud-config/config-prod.yaml version=1.0"</span></span><br></pre></td></tr></table></figure><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#config-test.yaml</span></span><br><span class="line"><span class="symbol">config:</span></span><br><span class="line"><span class="symbol"> info:</span> <span class="string">"master branch,springcloud-config/config-test.yaml version=1.0"</span> </span><br></pre></td></tr></table></figure><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-config-server<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-client<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependencies</span>></span></span><br></pre></td></tr></table></figure><h4 id="编写配置文件"><a href="#编写配置文件" class="headerlink" title="编写配置文件"></a>编写配置文件</h4><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">3344</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">configServer</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line"> <span class="attr">config:</span></span><br><span class="line"> <span class="attr">server:</span></span><br><span class="line"> <span class="attr">git:</span></span><br><span class="line"> <span class="attr">uri:</span> <span class="string">https://gitee.com/Guest997/springcloud-config.git</span> <span class="comment">#仓库地址</span></span><br><span class="line"> <span class="attr">username:</span> <span class="comment">#使用的是邮箱</span></span><br><span class="line"> <span class="attr">password:</span></span><br><span class="line"> <span class="attr">label:</span> <span class="string">master</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka</span></span><br></pre></td></tr></table></figure><h4 id="主启动类"><a href="#主启动类" class="headerlink" title="主启动类"></a>主启动类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.config.server.EnableConfigServer;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableConfigServer</span> <span class="comment">//启动 ConfigServer</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfigServer</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(ConfigServer.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server 和 Config-Server 模块后,浏览器访问:127.0.0.1:3344/master/config-test.yaml,发现返回了相应的配置。</p><p>配置读取规则:</p><ul><li> /{label}/{application}-{profile}.yaml(推荐)</li><li> /{application}-{profile}.yaml</li><li> /{application}/{profile}/{label}</li></ul><h3 id="客户端搭建"><a href="#客户端搭建" class="headerlink" title="客户端搭建"></a>客户端搭建</h3><h4 id="准备工作-1"><a href="#准备工作-1" class="headerlink" title="准备工作"></a>准备工作</h4><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-config-client<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-bootstrap<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-client<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependencies</span>></span></span><br></pre></td></tr></table></figure><p>创建主启动类</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.eureka.EnableEurekaClient;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfigClient</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(ConfigClient.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="编写配置文件(bootstrap-yaml)"><a href="#编写配置文件(bootstrap-yaml)" class="headerlink" title="编写配置文件(bootstrap.yaml)"></a>编写配置文件(bootstrap.yaml)</h4><p>applicaiton.yaml 是用户级的资源配置项,bootstrap.yaml 是系统级的,优先级更加高。</p><p>Bootstrap 属性有高优先级,默认情况下,它们不会被本地配置覆盖。Bootstrap context 和 Application Context 有着不同的约定,所以新增了一个 bootstrap.yaml 文件,保证 Bootstrap Context 和 Application Context 配置的分离。</p><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="symbol">server:</span></span><br><span class="line"><span class="symbol"> port:</span> <span class="number">3355</span></span><br><span class="line"><span class="symbol"></span></span><br><span class="line"><span class="symbol">spring:</span></span><br><span class="line"><span class="symbol"> application:</span></span><br><span class="line"><span class="symbol"> name:</span> configClient</span><br><span class="line"><span class="symbol"> cloud:</span></span><br><span class="line"><span class="symbol"> config:</span></span><br><span class="line"> <span class="meta">#下面的配置合起来就是读取:http:<span class="comment">//localhost:3344/master/config-dev.yaml</span></span></span><br><span class="line"><span class="symbol"> label:</span> master</span><br><span class="line"><span class="symbol"> name:</span> config</span><br><span class="line"><span class="symbol"> profile:</span> dev</span><br><span class="line"><span class="symbol"> uri:</span> http:<span class="comment">//localhost:3344</span></span><br><span class="line"><span class="symbol"></span></span><br><span class="line"><span class="symbol">eureka:</span></span><br><span class="line"><span class="symbol"> client:</span></span><br><span class="line"> service-url:</span><br><span class="line"><span class="symbol"> defaultZone:</span> http:<span class="comment">//eureka7001.com:7001/eureka</span></span><br></pre></td></tr></table></figure><h4 id="Controller-层"><a href="#Controller-层" class="headerlink" title="Controller 层"></a>Controller 层</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.<span class="keyword">annotation</span>.Value;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfigController</span> </span>{</span><br><span class="line"> <span class="meta">@Value(<span class="meta-string">"<span class="subst">${config.info}</span>"</span>)</span></span><br><span class="line"> <span class="keyword">private</span> String configInfo;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/configInfo"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> String getConfigInfo() {</span><br><span class="line"> <span class="keyword">return</span> configInfo;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试-1"><a href="#测试-1" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Config-Server 和 Config-Client 模块后,浏览器访问:127.0.0.1:3344/master/config-dev.yaml,能够正常返回配置信息。再次访问:127.0.0.1:3355/configInfo,也能够正常返回配置信息。</p><h3 id="动态刷新配置"><a href="#动态刷新配置" class="headerlink" title="动态刷新配置"></a>动态刷新配置</h3><p>如果在 git 上修改了配置文件,会发现服务端能够及时刷新配置,但是客户端却不会,只有重启或重新加载客户端才能够刷新配置。如果有很多个客户端,岂不是每个都要重启或重新加载,这显然是不合适的。</p><h4 id="添加配置"><a href="#添加配置" class="headerlink" title="添加配置"></a>添加配置</h4><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#暴露监控端点</span></span><br><span class="line"><span class="symbol">management:</span></span><br><span class="line"><span class="symbol"> endpoints:</span></span><br><span class="line"><span class="symbol"> web:</span></span><br><span class="line"><span class="symbol"> exposure:</span></span><br><span class="line"><span class="symbol"> include:</span> <span class="string">"*"</span></span><br></pre></td></tr></table></figure><h4 id="添加-Controller-注解"><a href="#添加-Controller-注解" class="headerlink" title="添加 Controller 注解"></a>添加 Controller 注解</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.<span class="keyword">annotation</span>.Value;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.context.config.<span class="keyword">annotation</span>.RefreshScope;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.RestController;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RefreshScope</span> <span class="comment">//实现配置自动更新</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfigController</span> </span>{</span><br><span class="line"> <span class="meta">@Value(<span class="meta-string">"<span class="subst">${config.info}</span>"</span>)</span></span><br><span class="line"> <span class="keyword">private</span> String configInfo;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/configInfo"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> String getConfigInfo() {</span><br><span class="line"> <span class="keyword">return</span> configInfo;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试-2"><a href="#测试-2" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Config-Server 和 Config-Client 模块后,git 上修改 config-dev.yaml 文件后,浏览器访问:127.0.0.1:3344/master/config-dev.yaml,能够及时刷新配置。再次访问:127.0.0.1:3355/configInfo,还是没能够及时刷新配置。需要发送一次 post 请求进行刷新。</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">curl</span> -X POST <span class="string">"http://localhost:3355/actuator/refresh"</span></span><br></pre></td></tr></table></figure><p>再次访问:127.0.0.1:3355/configInfo,发现已经刷新配置了。</p><h3 id="备注:"><a href="#备注:" class="headerlink" title="备注:"></a>备注:</h3><p>存在的问题:</p><ul><li> 有多个客户端,每个都要发送—次 post 请求进行刷新。(这个可以通过自动化脚本实现)</li><li> 能否通过广播,一次通知,全部生效。</li><li> 只想要通知部分客户端,并不想全部都刷新。</li></ul><p>想要解决上面的问题,可以通过消息总线实现。</p>]]></content>
<summary type="html"><p>微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。</p>
<h2 id="Config"><a href="#Config" class="headerlink" title="Config"></a>Config</h2><p>SpringCloud Config 为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。分为<strong>服务端</strong>和<strong>客户端</strong>两部分。</p>
<ul>
<li> 服务端:也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息、加密/解密信息等访问接口。</li>
<li> 客户端:通过指定的配置中心来管理应用资源以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。配置服务器默认采用 git 来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过 git 客户端工具来方便地管理和获取配置内容。</li>
</ul>
<h3 id="服务端搭建"><a href="#服务端搭建" class="headerlink" title="服务端搭建"></a>服务端搭建</h3></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>SpringCloud 详解(十一)</title>
<link href="http://guest997.tk/2022/04/21/springcloud-expound11/"/>
<id>http://guest997.tk/2022/04/21/springcloud-expound11/</id>
<published>2022-04-21T03:10:59.000Z</published>
<updated>2022-07-28T14:58:47.510Z</updated>
<content type="html"><![CDATA[<h2 id="GateWay"><a href="#GateWay" class="headerlink" title="GateWay"></a>GateWay</h2><p>基于 WebFlux 框架实现,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty(<strong>非阻塞异步</strong>)。提供统一的路由方式且基于 Filter 链的方式提供了网关基本的功能。</p><p><img data-src="/images/springcloud-expound11.md-0.png"></p><h3 id="三大核心"><a href="#三大核心" class="headerlink" title="三大核心"></a>三大核心</h3><ul><li> Route(路由):路由是构建网关的基本模块,它由 ID、目标 URI、一系列的断言和过滤器组成。</li><li> Predicate(断言):开发人员可以匹配 HTTP 请求中的所有内容,如果请求与断言相匹配则进行路由。</li><li> Filter(过滤):可以在请求被路由之前或者之后对请求进行修改。</li></ul><h3 id="工作流程"><a href="#工作流程" class="headerlink" title="工作流程"></a>工作流程</h3><p><img data-src="/images/springcloud-expound11.md-1.png"></p><p>客户端向 SpringCloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 GatewayWeb Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。</p><p>过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前或之后执行业务逻辑。过滤之前可以做参数校验、权限校验、流量监控、日志输出和协议转换等,过滤之后可以做响应内容、响应头的修改,日志的输出和流量监控等。过滤器有着非常重要的作用。</p><p><strong>核心逻辑:路由转发 + 执行过滤器链</strong>。</p><h3 id="搭建"><a href="#搭建" class="headerlink" title="搭建"></a>搭建</h3><h4 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h4><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight dust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="tag"><<span class="name">dependencies</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-gateway<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-client<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>ml.guest997<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>Commons<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{project.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"><span class="tag"></<span class="name">dependencies</span>></span></span></span><br></pre></td></tr></table></figure><p>创建主启动类。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.eureka.EnableEurekaClient;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Gateway</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Gateway.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="编写配置文件"><a href="#编写配置文件" class="headerlink" title="编写配置文件"></a>编写配置文件</h4><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">9527</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">gateway</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line"> <span class="attr">gateway:</span></span><br><span class="line"> <span class="attr">routes:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">payment_routh</span> <span class="comment">#路由的 ID,没有固定规则但要求唯一,建议配合服务名。</span></span><br><span class="line"> <span class="attr">uri:</span> <span class="string">http://localhost:8001</span> <span class="comment">#提供服务的路由地址</span></span><br><span class="line"> <span class="attr">predicates:</span> <span class="comment">#断言,相匹配的才进行路由。</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">Path=/payment/get/**</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">payment_routh2</span></span><br><span class="line"> <span class="attr">uri:</span> <span class="string">http://localhost:8001</span></span><br><span class="line"> <span class="attr">predicates:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">Path=/payment/lb</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">gateway</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka</span></span><br></pre></td></tr></table></figure><h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment 和 Gateway 模块后,浏览器访问:127.0.0.1:8001/payment/get/1,能够正常调用。再访问:127.0.0.1:9527/payment/get/1,发现也是能够正常调用的。(/payment/lb 路径同理)</p><h3 id="Config-路由"><a href="#Config-路由" class="headerlink" title="Config 路由"></a>Config 路由</h3><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.gateway.route.RouteLocator;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.<span class="keyword">annotation</span>.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.<span class="keyword">annotation</span>.Configuration;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GatewayConfig</span> </span>{</span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {</span><br><span class="line"> RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();</span><br><span class="line"> routes.route(<span class="string">"path_route_blog"</span>, r -> r.path(<span class="string">"/articles"</span>).uri(<span class="string">"https://guest997.ml/articles"</span>)).build();</span><br><span class="line"> <span class="keyword">return</span> routes.build();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试-1"><a href="#测试-1" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server 和 Gateway 模块后,浏览器访问:127.0.0.1:9527/articles,会发现请求被转发到了我的博客地址。</p><h3 id="动态路由"><a href="#动态路由" class="headerlink" title="动态路由"></a>动态路由</h3><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">gateway</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line"> <span class="attr">gateway:</span></span><br><span class="line"> <span class="attr">discovery:</span></span><br><span class="line"> <span class="attr">locator:</span></span><br><span class="line"> <span class="attr">enabled:</span> <span class="literal">true</span> <span class="comment">#利用微服务名进行路由。</span></span><br><span class="line"> <span class="attr">routes:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">payment_routh</span> <span class="comment">#路由的 ID,没有固定规则但要求唯一,建议配合服务名。</span></span><br><span class="line"><span class="comment"># uri: http://localhost:8001 #提供服务的路由地址</span></span><br><span class="line"> <span class="attr">uri:</span> <span class="string">lb://payment</span></span><br><span class="line"> <span class="attr">predicates:</span> <span class="comment">#断言,相匹配的才进行路由</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">Path=/payment/get/**</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">payment_routh2</span></span><br><span class="line"><span class="comment"># uri: http://localhost:8001</span></span><br><span class="line"> <span class="attr">uri:</span> <span class="string">lb://payment</span></span><br><span class="line"> <span class="attr">predicates:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">Path=/payment/lb</span></span><br></pre></td></tr></table></figure><h4 id="测试-2"><a href="#测试-2" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment、Payment2 和 Gateway 模块后,浏览器多次访问:127.0.0.1:9527/payment/lb,会发现端口是互相切换的。</p><h3 id="常用断言"><a href="#常用断言" class="headerlink" title="常用断言"></a>常用断言</h3><ul><li> The After Route Predicate Factory</li><li> The Before Route Predicate Factory</li><li> The Between Route Predicate Factory</li><li> The Cookie Route Predicate Factory</li><li> The Header Route Predicate Factory</li><li> The Host Route Predicate Factory</li><li> The Method Route Predicate Factory</li><li> The Path Route Predicate Factory</li><li> The Query Route Predicate Factory</li></ul><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">predicates: #能够使用正则表达式</span><br><span class="line"><span class="comment">#表示在什么时间之前和之后和之间,发送请求才有效。</span></span><br><span class="line"> - <span class="attribute">After</span>=2022-03-24T14:56:33.082+08:00[Asia/Shanghai] #ZonedDateTime 类的地区时间显示</span><br><span class="line"> - <span class="attribute">Before</span>=2022-03-23T14:56:33.082+08:00[Asia/Shanghai]</span><br><span class="line"> - <span class="attribute">Between</span>=2022-03-23T14:56:33.082+08:00[Asia/Shanghai], 2022-03-24T14:56:33.082+08:00[Asia/Shanghai]</span><br><span class="line"><span class="comment">#表示 Cookie 中需要携带的参数和值</span></span><br><span class="line"> - <span class="attribute">Cookie</span>=username, guest997</span><br><span class="line"><span class="comment">#表示匹配的 Header 的类型和值</span></span><br><span class="line"> - <span class="attribute">Header</span>=X-Request-Id, \d+</span><br><span class="line"><span class="comment">#表示匹配的 Host 主机列表</span></span><br><span class="line"> - <span class="attribute">Host</span>=**.guest997.ml, **.guest997.cf</span><br><span class="line"><span class="comment">#表示匹配的请求类型</span></span><br><span class="line"> - <span class="attribute">Method</span>=GET</span><br><span class="line"><span class="comment">#表示匹配的路径</span></span><br><span class="line"> - <span class="attribute">Path</span>=/articles/**</span><br><span class="line"><span class="comment">#表示请求需要携带的参数和值</span></span><br><span class="line"> - <span class="attribute">Query</span>=password, guest.</span><br></pre></td></tr></table></figure><h3 id="过滤"><a href="#过滤" class="headerlink" title="过滤"></a>过滤</h3><p>其本身具有几十种过滤器,有兴趣的可以自己去网上找一下,下面讲的是自定义的全局过滤器。</p><figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997.<span class="keyword">filter</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.gateway.<span class="keyword">filter</span>.GatewayFilterChain;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.gateway.<span class="keyword">filter</span>.GlobalFilter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.Ordered;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.HttpStatus;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.<span class="keyword">server</span>.ServerWebExchange;</span><br><span class="line"><span class="keyword">import</span> reactor.core.publisher.Mono;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"></span><br><span class="line">@Component</span><br><span class="line">@Slf4j</span><br><span class="line"><span class="built_in">public</span> <span class="keyword">class</span> MyLogGateWayFilter implements GlobalFilter, Ordered {</span><br><span class="line"> @Override</span><br><span class="line"> <span class="built_in">public</span> Mono<<span class="type">Void</span>> <span class="keyword">filter</span>(ServerWebExchange exchange, GatewayFilterChain chain) {</span><br><span class="line"> <span class="keyword">log</span>.<span class="keyword">info</span>("进入过滤器的时间:" + <span class="built_in">new</span> <span class="type">Date</span>());</span><br><span class="line"> String uname = exchange.getRequest().getQueryParams().getFirst("uname");</span><br><span class="line"> <span class="keyword">if</span> (uname == <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">log</span>.<span class="keyword">info</span>("用户名不存在");</span><br><span class="line"> exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);</span><br><span class="line"> <span class="keyword">return</span> exchange.getResponse().setComplete();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> chain.<span class="keyword">filter</span>(exchange);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //表示当前过滤器的优先级</span><br><span class="line"> @Override</span><br><span class="line"> <span class="built_in">public</span> <span class="type">int</span> getOrder() {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试-3"><a href="#测试-3" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment、Payment2 和 Gateway 模块后,浏览器访问:127.0.0.1:9527/payment/lb,会发现访问失败,而访问:127.0.0.1:9527/payment/lb?uname=Guest997,就能正常访问。</p>]]></content>
<summary type="html"><h2 id="GateWay"><a href="#GateWay" class="headerlink" title="GateWay"></a>GateWay</h2><p>基于 WebFlux 框架实现,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty(<strong>非阻塞异步</strong>)。提供统一的路由方式且基于 Filter 链的方式提供了网关基本的功能。</p>
<p><img data-src="/images/springcloud-expound11.md-0.png"></p>
<h3 id="三大核心"><a href="#三大核心" class="headerlink" title="三大核心"></a>三大核心</h3><ul>
<li> Route(路由):路由是构建网关的基本模块,它由 ID、目标 URI、一系列的断言和过滤器组成。</li>
<li> Predicate(断言):开发人员可以匹配 HTTP 请求中的所有内容,如果请求与断言相匹配则进行路由。</li>
<li> Filter(过滤):可以在请求被路由之前或者之后对请求进行修改。</li>
</ul></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>SpringCloud 详解(十)</title>
<link href="http://guest997.tk/2022/04/20/springcloud-expound10/"/>
<id>http://guest997.tk/2022/04/20/springcloud-expound10/</id>
<published>2022-04-20T01:52:43.000Z</published>
<updated>2022-07-28T14:58:41.019Z</updated>
<content type="html"><![CDATA[<h2 id="Hystrix(续二)"><a href="#Hystrix(续二)" class="headerlink" title="Hystrix(续二)"></a>Hystrix(续二)</h2><h3 id="服务熔断"><a href="#服务熔断" class="headerlink" title="服务熔断"></a>服务熔断</h3><h4 id="添加-Controller"><a href="#添加-Controller" class="headerlink" title="添加 Controller"></a>添加 Controller</h4><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping</span>(<span class="string">"/payment/circuit/{id}"</span>)</span><br><span class="line"><span class="meta">@HystrixCommand</span>(fallbackMethod = <span class="string">"paymentCircuitBreakerHandler"</span>, commandProperties = {</span><br><span class="line"> <span class="meta">@HystrixProperty</span>(name = <span class="string">"circuitBreaker.enabled"</span>, value = <span class="string">"true"</span>), <span class="comment">//是否启动断路器</span></span><br><span class="line"> <span class="meta">@HystrixProperty</span>(name = <span class="string">"circuitBreaker.requestVolumeThreshold"</span>, value = <span class="string">"10"</span>), <span class="comment">//请求阈值</span></span><br><span class="line"> <span class="meta">@HystrixProperty</span>(name = <span class="string">"circuitBreaker.sleepWindowInMilliseconds"</span>, value = <span class="string">"10000"</span>), <span class="comment">//睡眠窗口</span></span><br><span class="line"> <span class="meta">@HystrixProperty</span>(name = <span class="string">"circuitBreaker.errorThresholdPercentage"</span>, value = <span class="string">"60"</span>), <span class="comment">//错误阀值</span></span><br><span class="line">})</span><br><span class="line"><span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">paymentCircuitBreaker</span>(<span class="params"><span class="meta">@PathVariable</span>(<span class="string">"id"</span>) Integer id</span>)</span> {</span><br><span class="line"> <span class="keyword">if</span> (id < <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"id 不能为负数"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">String</span> serialNumber = IdUtil.simpleUUID();</span><br><span class="line"> <span class="keyword">return</span> Thread.currentThread().getName() + <span class="string">"\t"</span> + <span class="string">"调用成功,流水号:"</span> + serialNumber;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">paymentCircuitBreakerHandler</span>(<span class="params">Integer id</span>)</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"id 不能为负数,请重试。当前 id:"</span> + id;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server 和 Payment5 模块后,浏览器访问:127.0.0.1:8005/payment/circuit/997,能够正常调用。然后连续快速地多次访问:127.0.0.1:8005/payment/circuit/-997,调用的都是 fallback 方法,最后再多次访问:127.0.0.1:8005/payment/circuit/997,会发现一开始还是调用的 fallback 方法,但是多试几次之后就又恢复正常了。</p><p><strong>断路器开启和关闭的条件:</strong></p><ul><li> 到达以下阀值,断路器将会开启:</li><li> 当满足一定的阀值的时候(默认10秒内超过20个请求次数)</li><li> 当失败率达到一定的时候(默认10秒内超过50%的请求失败)</li><li> 当开启的时候,所有请求都不会进行转发。</li><li> 一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。</li></ul><h4 id="备注:"><a href="#备注:" class="headerlink" title="备注:"></a>备注:</h4><p>上面的注解参数,不懂的可以点击下面的链接进行查看。<br><a href="https://segmentfault.com/a/1190000016024957">https://segmentfault.com/a/1190000016024957</a></p><h3 id="工作流程"><a href="#工作流程" class="headerlink" title="工作流程"></a>工作流程</h3><p><img data-src="/images/springcloud-expound10.md-0.png"></p><ol><li> 创建 HystrixCommand (用在依赖的服务返回单个操作结果的时候)或 HystrixObserableCommand(用在依赖的服务返回多个操作结果的时候)对象。</li><li> 执行命令。</li><li> 响应是否已缓存?如果为此命令启用了请求缓存,并且请求的响应在缓存中可用,则此缓存的响应将立即返回。</li><li> 检查断路器是否为打开状态?如果断路器是打开的,那么 Hystrix 不会执行命令,而是转接到 fallback 处理逻辑;如果断路器是关闭的,检查是否有可用资源来执行命令。</li><li> 线程池/队列/信号量是否占满?如果已经被占满,那么 Hystrix 也不会执行命令,而是转接到 fallback 处理理辑。</li><li> Hystrix 根据我们使用的对象来决定采取什么样的方式去请求依赖服务。</li><li> Hystix 将处理后的信息报告给断路器,而断路器会维护一组计数器来统计这些数据。断路器会使用这些统计数据来决定是否要将断路器打开,来对某个依赖服务的请求进行熔断。</li><li> 当命令执行失败的时候,Hystix 会进入 fallback 尝试回退处理,通常也称此操作为“服务降级”。</li><li> 当 Hystrix 命令执行成功之后,它会将处理结果直接返回或是以 Observable 的形式返回。</li></ol><h3 id="图形化仪表盘"><a href="#图形化仪表盘" class="headerlink" title="图形化仪表盘"></a>图形化仪表盘</h3><h4 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h4><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-hystrix-dashboard<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.10.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependencies</span>></span></span><br></pre></td></tr></table></figure><h4 id="编写配置文件"><a href="#编写配置文件" class="headerlink" title="编写配置文件"></a>编写配置文件</h4><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">9001</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#仪表盘允许的监控服务域名</span></span><br><span class="line"><span class="attr">hystrix:</span></span><br><span class="line"> <span class="attr">dashboard:</span></span><br><span class="line"> <span class="attr">proxy-stream-allow-list:</span> <span class="string">"localhost"</span></span><br></pre></td></tr></table></figure><h4 id="主启动类"><a href="#主启动类" class="headerlink" title="主启动类"></a>主启动类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableHystrixDashboard</span> <span class="comment">//启动 Hystrix 仪表盘</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Dashboard</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Dashboard.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="添加配置(Payment5-模块)"><a href="#添加配置(Payment5-模块)" class="headerlink" title="添加配置(Payment5 模块)"></a>添加配置(Payment5 模块)</h4><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#配置服务监控路径</span></span><br><span class="line"><span class="symbol">management:</span></span><br><span class="line"><span class="symbol"> endpoints:</span></span><br><span class="line"><span class="symbol"> web:</span></span><br><span class="line"><span class="symbol"> exposure:</span></span><br><span class="line"><span class="symbol"> include:</span> <span class="string">"hystrix.stream"</span></span><br></pre></td></tr></table></figure><h4 id="测试-1"><a href="#测试-1" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment5 和 Dashboard 模块后,浏览器访问:127.0.0.1/hystrix,输入监控路径:<a href="http://localhost:8005/actuator/hystrix.stream%EF%BC%8C%E5%A6%82%E4%B8%8B%E5%9B%BE%E3%80%82">http://localhost:8005/actuator/hystrix.stream,如下图。</a></p><p><img data-src="/images/springcloud-expound10.md-1.png"></p><p>浏览器开一个新窗口访问:127.0.0.1:8005/payment/circuit/997,会出现如下图的画面。</p><p><img data-src="/images/springcloud-expound10.md-2.png"></p>]]></content>
<summary type="html"><h2 id="Hystrix(续二)"><a href="#Hystrix(续二)" class="headerlink" title="Hystrix(续二)"></a>Hystrix(续二)</h2><h3 id="服务熔断"><a href="#服务熔断" class="headerlink" title="服务熔断"></a>服务熔断</h3><h4 id="添加-Controller"><a href="#添加-Controller" class="headerlink" title="添加 Controller"></a>添加 Controller</h4><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping</span>(<span class="string">&quot;/payment/circuit/&#123;id&#125;&quot;</span>)</span><br><span class="line"><span class="meta">@HystrixCommand</span>(fallbackMethod = <span class="string">&quot;paymentCircuitBreakerHandler&quot;</span>, commandProperties = &#123;</span><br><span class="line"> <span class="meta">@HystrixProperty</span>(name = <span class="string">&quot;circuitBreaker.enabled&quot;</span>, value = <span class="string">&quot;true&quot;</span>), <span class="comment">//是否启动断路器</span></span><br><span class="line"> <span class="meta">@HystrixProperty</span>(name = <span class="string">&quot;circuitBreaker.requestVolumeThreshold&quot;</span>, value = <span class="string">&quot;10&quot;</span>), <span class="comment">//请求阈值</span></span><br><span class="line"> <span class="meta">@HystrixProperty</span>(name = <span class="string">&quot;circuitBreaker.sleepWindowInMilliseconds&quot;</span>, value = <span class="string">&quot;10000&quot;</span>), <span class="comment">//睡眠窗口</span></span><br><span class="line"> <span class="meta">@HystrixProperty</span>(name = <span class="string">&quot;circuitBreaker.errorThresholdPercentage&quot;</span>, value = <span class="string">&quot;60&quot;</span>), <span class="comment">//错误阀值</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">paymentCircuitBreaker</span>(<span class="params"><span class="meta">@PathVariable</span>(<span class="string">&quot;id&quot;</span>) Integer id</span>)</span> &#123;</span><br><span class="line"> <span class="keyword">if</span> (id &lt; <span class="number">0</span>) &#123;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;id 不能为负数&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="built_in">String</span> serialNumber = IdUtil.simpleUUID();</span><br><span class="line"> <span class="keyword">return</span> Thread.currentThread().getName() + <span class="string">&quot;\t&quot;</span> + <span class="string">&quot;调用成功,流水号:&quot;</span> + serialNumber;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">paymentCircuitBreakerHandler</span>(<span class="params">Integer id</span>)</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;id 不能为负数,请重试。当前 id:&quot;</span> + id;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>SpringCloud 详解(九)</title>
<link href="http://guest997.tk/2022/04/19/springcloud-expound09/"/>
<id>http://guest997.tk/2022/04/19/springcloud-expound09/</id>
<published>2022-04-19T01:44:53.000Z</published>
<updated>2022-07-28T14:58:31.684Z</updated>
<content type="html"><![CDATA[<h2 id="Hystrix(续一)"><a href="#Hystrix(续一)" class="headerlink" title="Hystrix(续一)"></a>Hystrix(续一)</h2><h3 id="服务降级(服务生产者)"><a href="#服务降级(服务生产者)" class="headerlink" title="服务降级(服务生产者)"></a>服务降级(服务生产者)</h3><p>服务生产者超时或宕机了,服务消费者不能一直卡死等待,服务生产者就必须要有服务降级。</p><h4 id="Controller-层"><a href="#Controller-层" class="headerlink" title="Controller 层"></a>Controller 层</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.Controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.netflix.hystrix.contrib.javanica.<span class="keyword">annotation</span>.HystrixCommand;</span><br><span class="line"><span class="keyword">import</span> com.netflix.hystrix.contrib.javanica.<span class="keyword">annotation</span>.HystrixProperty;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PaymentController</span> </span>{</span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/payment/ok/{id}"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> String paymentOK(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> Integer id) {</span><br><span class="line"> String s = <span class="string">"当前线程:"</span> + Thread.currentThread().getName() + <span class="string">" paymentOK id:"</span> + id;</span><br><span class="line"> log.info(<span class="string">"result:"</span> + s);</span><br><span class="line"> <span class="keyword">return</span> s;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/payment/timeout/{id}"</span>)</span></span><br><span class="line"> <span class="meta">@HystrixCommand(fallbackMethod = <span class="meta-string">"paymentTimeOutHandler"</span>, commandProperties = {</span></span><br><span class="line"><span class="meta"> @HystrixProperty(name = <span class="meta-string">"execution.isolation.thread.timeoutInMilliseconds"</span>, value = <span class="meta-string">"2000"</span>)</span> <span class="comment">//超时2秒将调用 fallbackMethod</span></span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">public</span> String paymentTimeOut(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> Integer id) {</span><br><span class="line"> String s = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> TimeUnit.MILLISECONDS.sleep(<span class="number">3000</span>);</span><br><span class="line"> s = <span class="string">"当前线程:"</span> + Thread.currentThread().getName() + <span class="string">" paymentTimeOut id:"</span> + id + <span class="string">" 耗时3秒"</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> log.info(<span class="string">"result:"</span> + s);</span><br><span class="line"> <span class="keyword">return</span> s;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> String paymentTimeOutHandler(Integer id) { <span class="comment">//fallback 方法一定要与原方法参数一致</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">"当前线程:"</span> + Thread.currentThread().getName() + <span class="string">" 系统繁忙或者运行报错,请稍后再试。"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="主启动类"><a href="#主启动类" class="headerlink" title="主启动类"></a>主启动类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.eureka.EnableEurekaClient;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.hystrix.EnableHystrix;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="meta">@EnableHystrix</span> <span class="comment">//启动 Hystrix</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Payment5</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Payment5.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="超时测试"><a href="#超时测试" class="headerlink" title="超时测试"></a>超时测试</h4><p>分别启动 Eureka-Server、Payment5 和 Order3 模块后,浏览器访问:127.0.0.1/consumer/payment/timeout/997,会发现调用的是 fallback 方法并且显示的线程是 HystrixTimer。</p><h4 id="程序错误测试"><a href="#程序错误测试" class="headerlink" title="程序错误测试"></a>程序错误测试</h4><p>修改 Controller 层中的 paymentTimeOut 方法,如下图。</p><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping</span>(<span class="string">"/payment/timeout/{id}"</span>)</span><br><span class="line"><span class="meta">@HystrixCommand</span>(fallbackMethod = <span class="string">"paymentTimeOutHandler"</span>, commandProperties = {</span><br><span class="line"> <span class="meta">@HystrixProperty</span>(name = <span class="string">"execution.isolation.thread.timeoutInMilliseconds"</span>, value = <span class="string">"2000"</span>) <span class="comment">//超时2秒将调用 fallbackMethod 中的方法</span></span><br><span class="line">})</span><br><span class="line"><span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">paymentTimeOut</span>(<span class="params"><span class="meta">@PathVariable</span>(<span class="string">"id"</span>) Integer id</span>)</span> {</span><br><span class="line"> <span class="built_in">String</span> s = <span class="literal">null</span>;</span><br><span class="line"><span class="comment">// try {</span></span><br><span class="line"><span class="comment">// TimeUnit.MILLISECONDS.sleep(3000);</span></span><br><span class="line"><span class="comment">// s = "当前线程:" + Thread.currentThread().getName() + " paymentTimeOut id:" + id + " 耗时3秒";</span></span><br><span class="line"><span class="comment">// } catch (InterruptedException e) {</span></span><br><span class="line"><span class="comment">// e.printStackTrace();</span></span><br><span class="line"><span class="comment">// }</span></span><br><span class="line"> s = <span class="built_in">String</span>.valueOf(<span class="number">1</span>/<span class="number">0</span>); <span class="comment">//程序错误</span></span><br><span class="line"> log.info(<span class="string">"result:"</span> + s);</span><br><span class="line"> <span class="keyword">return</span> s;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>分别启动 Eureka-Server、Payment5 和 Order3 模块后,浏览器访问:127.0.0.1/consumer/payment/timeout/997,会发现依旧调用的是 fallback 方法并且显示的线程是 hystrix。</p><h3 id="服务降级(服务消费者)"><a href="#服务降级(服务消费者)" class="headerlink" title="服务降级(服务消费者)"></a>服务降级(服务消费者)</h3><p>服务生产者没问题,服务消费者自己出了故障或有自我要求(自己的等待时间小于服务生产者响应回来的时间),服务消费者就可以自己进行服务降级。</p><h4 id="Controller-层-1"><a href="#Controller-层-1" class="headerlink" title="Controller 层"></a>Controller 层</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.netflix.hystrix.contrib.javanica.<span class="keyword">annotation</span>.HystrixCommand;</span><br><span class="line"><span class="keyword">import</span> com.netflix.hystrix.contrib.javanica.<span class="keyword">annotation</span>.HystrixProperty;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.service.PaymentService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.<span class="keyword">annotation</span>.Resource;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OrderController</span> </span>{</span><br><span class="line"> <span class="meta">@Resource</span></span><br><span class="line"> <span class="keyword">private</span> PaymentService paymentService;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/consumer/payment/ok/{id}"</span>)</span></span><br><span class="line"> String paymentOK(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> Integer id) {</span><br><span class="line"> <span class="keyword">return</span> paymentService.paymentOK(id);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/consumer/payment/timeout/{id}"</span>)</span></span><br><span class="line"> <span class="meta">@HystrixCommand(fallbackMethod = <span class="meta-string">"paymentTimeOutHandler"</span>, commandProperties = {</span></span><br><span class="line"><span class="meta"> @HystrixProperty(name = <span class="meta-string">"execution.isolation.thread.timeoutInMilliseconds"</span>, value = <span class="meta-string">"1500"</span>)</span></span><br><span class="line"> })</span><br><span class="line"> String paymentTimeOut(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> Integer id) {</span><br><span class="line"> <span class="keyword">return</span> paymentService.paymentTimeOut(id);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> String paymentTimeOutHandler(Integer id){</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"支付系统繁忙请稍后再试,或者自己运行出错请检查自己。"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="主启动类-1"><a href="#主启动类-1" class="headerlink" title="主启动类"></a>主启动类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.hystrix.EnableHystrix;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.openfeign.EnableFeignClients;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableFeignClients</span></span><br><span class="line"><span class="meta">@EnableHystrix</span> <span class="comment">//启动 Hystrix</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Order3</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Order3.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="超时测试-1"><a href="#超时测试-1" class="headerlink" title="超时测试"></a>超时测试</h4><p>分别启动 Eureka-Server、Payment5 和 Order3 模块后,浏览器访问:127.0.0.1/consumer/payment/timeout/997,会发现调用的是 fallback 方法。</p><h4 id="程序错误测试-1"><a href="#程序错误测试-1" class="headerlink" title="程序错误测试"></a>程序错误测试</h4><p>修改 Controller 层中的 paymentTimeOut 方法,如下图。</p><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">@GetMapping</span>(<span class="string">"/consumer/payment/timeout/{id}"</span>)</span><br><span class="line"><span class="variable">@HystrixCommand</span>(fallbackMethod = <span class="string">"paymentTimeOutHandler"</span>, commandProperties = {</span><br><span class="line"> <span class="variable">@HystrixProperty</span>(name = <span class="string">"execution.isolation.thread.timeoutInMilliseconds"</span>, value = <span class="string">"1500"</span>)</span><br><span class="line">})</span><br><span class="line">public String paymentTimeOut(<span class="variable">@PathVariable</span>(<span class="string">"id"</span>) Integer id) {</span><br><span class="line"><span class="comment">// return paymentService.paymentTimeOut(id);</span></span><br><span class="line"> <span class="selector-tag">return</span> <span class="selector-tag">String</span><span class="selector-class">.valueOf</span>(<span class="number">1</span>/<span class="number">0</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>分别启动 Eureka-Server、Payment5 和 Order3 模块后,浏览器访问:127.0.0.1/consumer/payment/timeout/997,会发现依旧调用的是 fallback 方法。</p><h3 id="全局服务降级"><a href="#全局服务降级" class="headerlink" title="全局服务降级"></a>全局服务降级</h3><p>每个业务方法对应一个降级方法,代码膨胀。我们希望的是特殊业务才有特殊的降级方法,平常的普通业务只需要个通用的降级方法即可。这样就避免了代码膨胀,合理减少了代码量。</p><h4 id="Controller-层-2"><a href="#Controller-层-2" class="headerlink" title="Controller 层"></a>Controller 层</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.netflix.hystrix.contrib.javanica.<span class="keyword">annotation</span>.DefaultProperties;</span><br><span class="line"><span class="keyword">import</span> com.netflix.hystrix.contrib.javanica.<span class="keyword">annotation</span>.HystrixCommand;</span><br><span class="line"><span class="keyword">import</span> com.netflix.hystrix.contrib.javanica.<span class="keyword">annotation</span>.HystrixProperty;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.service.PaymentService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.<span class="keyword">annotation</span>.Resource;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@DefaultProperties(defaultFallback = <span class="meta-string">"GlobalFallbackMethod"</span>)</span> <span class="comment">//注解表示全局的 fallback 方法</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OrderController</span> </span>{</span><br><span class="line"> <span class="meta">@Resource</span></span><br><span class="line"> <span class="keyword">private</span> PaymentService paymentService;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/consumer/payment/ok/{id}"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> String paymentOK(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> Integer id) {</span><br><span class="line"> <span class="keyword">return</span> paymentService.paymentOK(id);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/consumer/payment/timeout/{id}"</span>)</span></span><br><span class="line"><span class="comment">// @HystrixCommand(fallbackMethod = "paymentTimeOutHandler", commandProperties = {</span></span><br><span class="line"><span class="comment">// @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")</span></span><br><span class="line"><span class="comment">// })</span></span><br><span class="line"> <span class="meta">@HystrixCommand</span> <span class="comment">//使用全局的 fallback 方法</span></span><br><span class="line"> <span class="keyword">public</span> String paymentTimeOut(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> Integer id) {</span><br><span class="line"><span class="comment">// return paymentService.paymentTimeOut(id);</span></span><br><span class="line"> <span class="keyword">return</span> String.valueOf(<span class="number">10</span> / <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> String GlobalFallbackMethod() {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"异常处理信息,请稍后再试。"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> String paymentTimeOutHandler(Integer id) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"支付系统繁忙请稍后再试,或者自己运行出错请检查自己。"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment5 和 Order3 模块后,浏览器访问:127.0.0.1/consumer/payment/timeout/997,会发现调用的是全局 fallback 方法。</p><h3 id="通配服务降级(FeignFallback)"><a href="#通配服务降级(FeignFallback)" class="headerlink" title="通配服务降级(FeignFallback)"></a>通配服务降级(FeignFallback)</h3><p>可以从上面的代码看到,Controller 层的代码有异常处理的代码,耦合度高。我们可以通过为 Feign 客户端定义的接口添加一个服务降级处理的实现类即可实现解耦。</p><h4 id="添加配置"><a href="#添加配置" class="headerlink" title="添加配置"></a>添加配置</h4><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#启动 feign 断路器</span></span><br><span class="line"><span class="attr">feign:</span></span><br><span class="line"> <span class="attr">circuitbreaker:</span></span><br><span class="line"> <span class="attr">enabled:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><h4 id="服务降级实现类"><a href="#服务降级实现类" class="headerlink" title="服务降级实现类"></a>服务降级实现类</h4><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997.service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PaymentFallbackService</span> <span class="title">implements</span> <span class="title">PaymentService</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">paymentOK</span>(<span class="params">Integer id</span>)</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"服务处理异常,请稍后再试。"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">paymentTimeOut</span>(<span class="params">Integer id</span>)</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"服务处理异常,请稍后再试。"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="修改-Service-层"><a href="#修改-Service-层" class="headerlink" title="修改 Service 层"></a>修改 Service 层</h4><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">package</span> <span class="selector-tag">ml</span><span class="selector-class">.guest997</span><span class="selector-class">.service</span>;</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">import</span> <span class="selector-tag">org</span><span class="selector-class">.springframework</span><span class="selector-class">.cloud</span><span class="selector-class">.openfeign</span><span class="selector-class">.FeignClient</span>;</span><br><span class="line"><span class="selector-tag">import</span> <span class="selector-tag">org</span><span class="selector-class">.springframework</span><span class="selector-class">.stereotype</span><span class="selector-class">.Component</span>;</span><br><span class="line"><span class="selector-tag">import</span> <span class="selector-tag">org</span><span class="selector-class">.springframework</span><span class="selector-class">.web</span><span class="selector-class">.bind</span><span class="selector-class">.annotation</span><span class="selector-class">.GetMapping</span>;</span><br><span class="line"><span class="selector-tag">import</span> <span class="selector-tag">org</span><span class="selector-class">.springframework</span><span class="selector-class">.web</span><span class="selector-class">.bind</span><span class="selector-class">.annotation</span><span class="selector-class">.PathVariable</span>;</span><br><span class="line"></span><br><span class="line">@<span class="selector-tag">Component</span></span><br><span class="line">@<span class="selector-tag">FeignClient</span>(value = <span class="string">"PAYMENT"</span>, fallback = PaymentFallbackService.class) <span class="comment">//使用该接口的实现类统一进行服务降级处理</span></span><br><span class="line"><span class="selector-tag">public</span> <span class="selector-tag">interface</span> <span class="selector-tag">PaymentService</span> {</span><br><span class="line"> <span class="variable">@GetMapping</span>(<span class="string">"/payment/ok/{id}"</span>)</span><br><span class="line"> String paymentOK(<span class="variable">@PathVariable</span>(<span class="string">"id"</span>) Integer id);</span><br><span class="line"></span><br><span class="line"> <span class="variable">@GetMapping</span>(<span class="string">"/payment/timeout/{id}"</span>)</span><br><span class="line"> String paymentTimeOut(<span class="variable">@PathVariable</span>(<span class="string">"id"</span>) Integer id);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试-1"><a href="#测试-1" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment5 和 Order3 模块后,浏览器访问:127.0.0.1/consumer/payment/ok/997,会发现调用的是服务降级处理的实现类方法。</p>]]></content>
<summary type="html"><h2 id="Hystrix(续一)"><a href="#Hystrix(续一)" class="headerlink" title="Hystrix(续一)"></a>Hystrix(续一)</h2><h3 id="服务降级(服务生产者)"><a href="#服务降级(服务生产者)" class="headerlink" title="服务降级(服务生产者)"></a>服务降级(服务生产者)</h3><p>服务生产者超时或宕机了,服务消费者不能一直卡死等待,服务生产者就必须要有服务降级。</p>
<h4 id="Controller-层"><a href="#Controller-层" class="headerlink" title="Controller 层"></a>Controller 层</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.Controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.netflix.hystrix.contrib.javanica.<span class="keyword">annotation</span>.HystrixCommand;</span><br><span class="line"><span class="keyword">import</span> com.netflix.hystrix.contrib.javanica.<span class="keyword">annotation</span>.HystrixProperty;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PaymentController</span> </span>&#123;</span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">&quot;/payment/ok/&#123;id&#125;&quot;</span>)</span></span><br><span class="line"> <span class="keyword">public</span> String paymentOK(<span class="meta">@PathVariable(<span class="meta-string">&quot;id&quot;</span>)</span> Integer id) &#123;</span><br><span class="line"> String s = <span class="string">&quot;当前线程:&quot;</span> + Thread.currentThread().getName() + <span class="string">&quot; paymentOK id:&quot;</span> + id;</span><br><span class="line"> log.info(<span class="string">&quot;result:&quot;</span> + s);</span><br><span class="line"> <span class="keyword">return</span> s;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">&quot;/payment/timeout/&#123;id&#125;&quot;</span>)</span></span><br><span class="line"> <span class="meta">@HystrixCommand(fallbackMethod = <span class="meta-string">&quot;paymentTimeOutHandler&quot;</span>, commandProperties = &#123;</span></span><br><span class="line"><span class="meta"> @HystrixProperty(name = <span class="meta-string">&quot;execution.isolation.thread.timeoutInMilliseconds&quot;</span>, value = <span class="meta-string">&quot;2000&quot;</span>)</span> <span class="comment">//超时2秒将调用 fallbackMethod</span></span><br><span class="line"> &#125;)</span><br><span class="line"> <span class="keyword">public</span> String paymentTimeOut(<span class="meta">@PathVariable(<span class="meta-string">&quot;id&quot;</span>)</span> Integer id) &#123;</span><br><span class="line"> String s = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> TimeUnit.MILLISECONDS.sleep(<span class="number">3000</span>);</span><br><span class="line"> s = <span class="string">&quot;当前线程:&quot;</span> + Thread.currentThread().getName() + <span class="string">&quot; paymentTimeOut id:&quot;</span> + id + <span class="string">&quot; 耗时3秒&quot;</span>;</span><br><span class="line"> &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> &#125;</span><br><span class="line"> log.info(<span class="string">&quot;result:&quot;</span> + s);</span><br><span class="line"> <span class="keyword">return</span> s;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> String paymentTimeOutHandler(Integer id) &#123; <span class="comment">//fallback 方法一定要与原方法参数一致</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">&quot;当前线程:&quot;</span> + Thread.currentThread().getName() + <span class="string">&quot; 系统繁忙或者运行报错,请稍后再试。&quot;</span>;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>SpringCloud 详解(八)</title>
<link href="http://guest997.tk/2022/04/18/springcloud-expound08/"/>
<id>http://guest997.tk/2022/04/18/springcloud-expound08/</id>
<published>2022-04-18T02:00:48.000Z</published>
<updated>2022-07-28T14:58:31.676Z</updated>
<content type="html"><![CDATA[<h2 id="Hystrix"><a href="#Hystrix" class="headerlink" title="Hystrix"></a>Hystrix</h2><p>一个用于处理分布式系统的<strong>延迟</strong>和<strong>容错</strong>的开源库。在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix 能够保证在一个依赖出问题的情况下,<strong>不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性</strong>。</p><p>“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(<strong>类似熔断保险丝</strong>),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。</p><h3 id="服务降级"><a href="#服务降级" class="headerlink" title="服务降级"></a>服务降级</h3><p>系统将某些不重要的业务或接口的功能降低,可以只提供部分功能,也可以完全停止所有所有不重要的功能。服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示。降级的思想是丢车保帅。</p><p>哪些情况会触发降级:</p><ul><li> 程序运行导常</li><li> 超时</li><li> 服务熔断触发服务降级</li><li> 线程池或信号量打满</li></ul><p>常见降级方式:</p><ul><li> 系统后门降级:系统预留后门用于降级,比如提供一个降级 URL,访问 URL 时就执行降级指令。缺点:如果服务器数量多,需要一台一台去操作,效率低。</li><li> 独立系统降级:将降级操作独立到一个单独的系统中,可以实现复杂的权限管理、批量操作等功能。</li></ul><h3 id="服务熔断"><a href="#服务熔断" class="headerlink" title="服务熔断"></a>服务熔断</h3><p>降级是应对系统自身的故障,而熔断的目的是应对外部系统的故障。类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示。<strong>当检测到该节点微服务调用响应正常后,恢复调用链路</strong>。实现思路:需要系统有一个统一的 API 调用层,由 API 来进行采样或者统计。</p><h3 id="服务限流"><a href="#服务限流" class="headerlink" title="服务限流"></a>服务限流</h3><p>只允许系统能够承受的访问量进来,超出的会被丢弃。降级从系统功能优先级角度考虑如何应对故障,而限流则从用户访问压力的角度来考虑如何应对故障。</p><p>常见限流方式:</p><ul><li> 基于请求限流:指从外部请求的角度考虑限流。</li><li> 基于资源限流:指从系统内部考虑,找到影响性能的关键资源,对其使用上限限制。</li></ul><h3 id="支付模块"><a href="#支付模块" class="headerlink" title="支付模块"></a>支付模块</h3><h4 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h4><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight dust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="tag"><<span class="name">dependencies</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-hystrix<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>2.2.10.RELEASE<span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-client<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>ml.guest997<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>Commons<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{project.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"><span class="tag"></<span class="name">dependencies</span>></span></span></span><br></pre></td></tr></table></figure><h4 id="编写配置文件"><a href="#编写配置文件" class="headerlink" title="编写配置文件"></a>编写配置文件</h4><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8005</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">payment</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka</span></span><br></pre></td></tr></table></figure><h4 id="主启动类"><a href="#主启动类" class="headerlink" title="主启动类"></a>主启动类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.eureka.EnableEurekaClient;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Payment5</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Payment5.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="Controller-层"><a href="#Controller-层" class="headerlink" title="Controller 层"></a>Controller 层</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.Controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.<span class="keyword">annotation</span>.Value;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PaymentController</span> </span>{</span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/payment/ok/{id}"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> String paymentOK(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> Integer id) {</span><br><span class="line"> String s = <span class="string">"当前线程:"</span> + Thread.currentThread().getName() + <span class="string">" paymentOK id:"</span> + id;</span><br><span class="line"> log.info(<span class="string">"result:"</span> + s);</span><br><span class="line"> <span class="keyword">return</span> s;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/payment//timeout/{id}"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> String paymentTimeOut(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> Integer id) {</span><br><span class="line"> String s = <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> TimeUnit.MILLISECONDS.sleep(<span class="number">3000</span>);</span><br><span class="line"> s = <span class="string">"当前线程:"</span> + Thread.currentThread().getName() + <span class="string">" paymentTimeOut id:"</span> + id + <span class="string">" 耗时3秒"</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> log.info(<span class="string">"result:"</span> + s);</span><br><span class="line"> <span class="keyword">return</span> s;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server 和 Payment5 模块后,浏览器访问:127.0.0.1:8005/payment/ok/997 和 127.0.0.1:8005/payment/timeout/997,能够正常返回数据,控制台也能正常打印信息。</p><h4 id="JMeter-高并发压测"><a href="#JMeter-高并发压测" class="headerlink" title="JMeter 高并发压测"></a>JMeter 高并发压测</h4><p>设置20000个并发请求,然后再在浏览器测试,访问之前的两个网址,会发现响应时间都有所增加甚至出现卡顿。这是因为 Tomcat 默认的工作线程数被打满了,没有多余的线程来分担压力和处理。</p><p><img data-src="/images/springcloud-expound08.md-0.png"></p><p><img data-src="/images/springcloud-expound08.md-1.png"></p><p><img data-src="/images/springcloud-expound08.md-2.png"></p><p><img data-src="/images/springcloud-expound08.md-3.png"></p><h3 id="订单模块"><a href="#订单模块" class="headerlink" title="订单模块"></a>订单模块</h3><h4 id="准备工作-1"><a href="#准备工作-1" class="headerlink" title="准备工作"></a>准备工作</h4><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight dust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="tag"><<span class="name">dependencies</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-hystrix<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>2.2.10.RELEASE<span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-client<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>ml.guest997<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>Commons<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{project.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"><span class="tag"></<span class="name">dependencies</span>></span></span></span><br></pre></td></tr></table></figure><h4 id="编写配置文件-1"><a href="#编写配置文件-1" class="headerlink" title="编写配置文件"></a>编写配置文件</h4><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka/</span></span><br></pre></td></tr></table></figure><h4 id="主启动类-1"><a href="#主启动类-1" class="headerlink" title="主启动类"></a>主启动类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.hystrix.EnableHystrix;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.openfeign.EnableFeignClients;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableFeignClients</span></span><br><span class="line"><span class="meta">@EnableHystrix</span> <span class="comment">//启动 Hystrix</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Order3</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Order3.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="Service-层"><a href="#Service-层" class="headerlink" title="Service 层"></a>Service 层</h4><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">package</span> <span class="selector-tag">ml</span><span class="selector-class">.guest997</span><span class="selector-class">.service</span>;</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">import</span> <span class="selector-tag">org</span><span class="selector-class">.springframework</span><span class="selector-class">.cloud</span><span class="selector-class">.openfeign</span><span class="selector-class">.FeignClient</span>;</span><br><span class="line"><span class="selector-tag">import</span> <span class="selector-tag">org</span><span class="selector-class">.springframework</span><span class="selector-class">.stereotype</span><span class="selector-class">.Component</span>;</span><br><span class="line"><span class="selector-tag">import</span> <span class="selector-tag">org</span><span class="selector-class">.springframework</span><span class="selector-class">.web</span><span class="selector-class">.bind</span><span class="selector-class">.annotation</span><span class="selector-class">.GetMapping</span>;</span><br><span class="line"><span class="selector-tag">import</span> <span class="selector-tag">org</span><span class="selector-class">.springframework</span><span class="selector-class">.web</span><span class="selector-class">.bind</span><span class="selector-class">.annotation</span><span class="selector-class">.PathVariable</span>;</span><br><span class="line"></span><br><span class="line">@<span class="selector-tag">Component</span></span><br><span class="line">@<span class="selector-tag">FeignClient</span>(<span class="string">"PAYMENT"</span>)</span><br><span class="line"><span class="selector-tag">public</span> <span class="selector-tag">interface</span> <span class="selector-tag">PaymentService</span> {</span><br><span class="line"> <span class="variable">@GetMapping</span>(<span class="string">"/payment/ok/{id}"</span>)</span><br><span class="line"> String paymentOK(<span class="variable">@PathVariable</span>(<span class="string">"id"</span>) Integer id);</span><br><span class="line"></span><br><span class="line"> <span class="variable">@GetMapping</span>(<span class="string">"/payment/timeout/{id}"</span>)</span><br><span class="line"> String paymentTimeOut(<span class="variable">@PathVariable</span>(<span class="string">"id"</span>) Integer id);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="Controller-层-1"><a href="#Controller-层-1" class="headerlink" title="Controller 层"></a>Controller 层</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.service.PaymentService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.<span class="keyword">annotation</span>.Resource;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OrderController</span> </span>{</span><br><span class="line"> <span class="meta">@Resource</span></span><br><span class="line"> <span class="keyword">private</span> PaymentService paymentService;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/consumer/payment/ok/{id}"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> String paymentOK(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> Integer id) {</span><br><span class="line"> <span class="keyword">return</span> paymentService.paymentOK(id);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/consumer/payment/timeout/{id}"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> String paymentTimeOut(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> Integer id) {</span><br><span class="line"> <span class="keyword">return</span> paymentService.paymentTimeOut(id);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试-1"><a href="#测试-1" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment5 和 Order3 模块后,浏览器访问:127.0.0.1/consumer/payment/ok/997,能够正常返回数据而且响应很快。</p><h4 id="JMeter-高并发压测-1"><a href="#JMeter-高并发压测-1" class="headerlink" title="JMeter 高并发压测"></a>JMeter 高并发压测</h4><p>使用上面同样的方面设置20000个并发请求,然后再在浏览器测试,会发现响应也是会被拖慢的。</p>]]></content>
<summary type="html"><h2 id="Hystrix"><a href="#Hystrix" class="headerlink" title="Hystrix"></a>Hystrix</h2><p>一个用于处理分布式系统的<strong>延迟</strong>和<strong>容错</strong>的开源库。在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix 能够保证在一个依赖出问题的情况下,<strong>不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性</strong>。</p>
<p>“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(<strong>类似熔断保险丝</strong>),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。</p>
<h3 id="服务降级"><a href="#服务降级" class="headerlink" title="服务降级"></a>服务降级</h3><p>系统将某些不重要的业务或接口的功能降低,可以只提供部分功能,也可以完全停止所有所有不重要的功能。服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示。降级的思想是丢车保帅。</p></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>SpringCloud 详解(七)</title>
<link href="http://guest997.tk/2022/04/17/springcloud-expound07/"/>
<id>http://guest997.tk/2022/04/17/springcloud-expound07/</id>
<published>2022-04-17T03:33:56.000Z</published>
<updated>2022-07-28T14:58:19.395Z</updated>
<content type="html"><![CDATA[<h2 id="OpenFeign"><a href="#OpenFeign" class="headerlink" title="OpenFeign"></a>OpenFeign</h2><p><strong>Feign</strong> 是 SpringCloud 组件中的一个轻量级 RESTful 的 HTTP 服务客户端。Feign 内置了 Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign 的使用方式是:使用 Feign 的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。</p><p><strong>OpenFeign</strong> 是 SpringCloud 在 Feign 的基础上支持了 SpringMVC 的注解,如 @RequesMapping。OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,在实现类中做负载均衡并调用其它服务。</p><h3 id="服务调用"><a href="#服务调用" class="headerlink" title="服务调用"></a>服务调用</h3><h4 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h4><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight dust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="tag"><<span class="name">dependencies</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-openfeign<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-client<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>ml.guest997<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>Commons<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{project.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"><span class="tag"></<span class="name">dependencies</span>></span></span></span><br></pre></td></tr></table></figure><p>在 resources 文件夹下创建 application.yaml 配置文件,并加入下面的配置。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">order</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka/,</span> <span class="string">http://eureka7002.com:7002/eureka/</span></span><br></pre></td></tr></table></figure><h4 id="主启动类"><a href="#主启动类" class="headerlink" title="主启动类"></a>主启动类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.openfeign.EnableFeignClients;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableFeignClients</span> <span class="comment">//启动 Feign Clients</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Order2</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Order2.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="Service-层"><a href="#Service-层" class="headerlink" title="Service 层"></a>Service 层</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.CommonResult;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.Payment;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.openfeign.FeignClient;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@FeignClient(<span class="meta-string">"PAYMENT"</span>)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">PaymentService</span> </span>{</span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/payment/add"</span>)</span></span><br><span class="line"> CommonResult add(Payment payment); <span class="comment">//跟支付模块 controller 中定义的方式一样,不需要自己写实现类,通过动态代理实现。</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="Controller-层"><a href="#Controller-层" class="headerlink" title="Controller 层"></a>Controller 层</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.CommonResult;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.Payment;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.service.PaymentService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.<span class="keyword">annotation</span>.Resource;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OrderController</span> </span>{</span><br><span class="line"> <span class="meta">@Resource</span></span><br><span class="line"> <span class="keyword">private</span> PaymentService paymentService;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/consumer/payment/add"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> CommonResult add(Payment payment) {</span><br><span class="line"> <span class="keyword">return</span> paymentService.add(payment);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment、Payment2 和 Order2 模块后,浏览器多次访问:127.0.0.1/consumer/payment/add?serial=Guest006,会发现端口是互相切换的,就说明 OpenFeign 内部已经实现了负载均衡。</p><h3 id="超时控制"><a href="#超时控制" class="headerlink" title="超时控制"></a>超时控制</h3><p><strong>OpenFeign 调用远程服务时,一定时间内没有建立起请求或没有响应,就会报错。</strong></p><h4 id="添加支付-Controller"><a href="#添加支付-Controller" class="headerlink" title="添加支付 Controller"></a>添加支付 Controller</h4><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping</span>(<span class="string">"/payment/timeout"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">paymentTimeout</span>(<span class="params"></span>)</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> TimeUnit.MINUTES.sleep(<span class="number">1</span>); <span class="comment">//休眠1分钟</span></span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> serverPort;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="添加订单接口"><a href="#添加订单接口" class="headerlink" title="添加订单接口"></a>添加订单接口</h4><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">@<span class="built_in">GetMapping</span>(<span class="string">"/payment/timeout"</span>)</span><br><span class="line"><span class="function"><span class="keyword">String</span> <span class="title">paymentTimeout</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure><h4 id="添加订单-Controller"><a href="#添加订单-Controller" class="headerlink" title="添加订单 Controller"></a>添加订单 Controller</h4><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping</span>(<span class="string">"/consumer/payment/timeout"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">paymentFeignTimeout</span>(<span class="params"></span>)</span> {</span><br><span class="line"> <span class="keyword">return</span> paymentService.paymentTimeout();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试-1"><a href="#测试-1" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment、Payment2 和 Order2 模块后,浏览器访问:127.0.0.1/consumer/payment/timeout,过了一段时间后就会发现页面报错了。</p><h4 id="添加配置"><a href="#添加配置" class="headerlink" title="添加配置"></a>添加配置</h4><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">feign:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">config:</span></span><br><span class="line"> <span class="attr">default:</span></span><br><span class="line"> <span class="attr">connectTimeout:</span> <span class="number">3000</span> <span class="comment">#指的是建立连接所用的时间</span></span><br><span class="line"> <span class="attr">readTimeout:</span> <span class="number">80000</span> <span class="comment">#指的是建立连接后收到响应所用的时间</span></span><br></pre></td></tr></table></figure><h3 id="日志增强"><a href="#日志增强" class="headerlink" title="日志增强"></a>日志增强</h3><p>通过配置来调整日志级别,从而了解请求中的细节。</p><p>日志级别</p><ul><li> NONE:默认的,不显示任何日志。</li><li> BASIC:仅记录请求方法、URL、响应状态码及执行时间。</li><li> HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息。</li><li> FULL:除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据。</li></ul><h4 id="配置类"><a href="#配置类" class="headerlink" title="配置类"></a>配置类</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> feign.Logger;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.<span class="keyword">annotation</span>.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.<span class="keyword">annotation</span>.Configuration;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FeignConfig</span> </span>{</span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> Logger.Level feignLoggerLevel() {</span><br><span class="line"> <span class="keyword">return</span> Logger.Level.FULL;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="添加配置-1"><a href="#添加配置-1" class="headerlink" title="添加配置"></a>添加配置</h4><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">logging:</span></span><br><span class="line"> <span class="attr">level:</span></span><br><span class="line"> <span class="attr">ml.guest997.service.PaymentService:</span> <span class="string">debug</span> <span class="comment">#指定特定的接口的日志级别(会被上面的配置覆盖)</span></span><br></pre></td></tr></table></figure><h4 id="测试-2"><a href="#测试-2" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment、Payment2 和 Order2 模块后,浏览器访问:127.0.0.1/consumer/payment/add?serial=Guest007,会发现控制台的输出内容如下图所示。</p><p><img data-src="/images/springcloud-expound07.md-0.png"></p>]]></content>
<summary type="html"><h2 id="OpenFeign"><a href="#OpenFeign" class="headerlink" title="OpenFeign"></a>OpenFeign</h2><p><strong>Feign</strong> 是 SpringCloud 组件中的一个轻量级 RESTful 的 HTTP 服务客户端。Feign 内置了 Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign 的使用方式是:使用 Feign 的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。</p>
<p><strong>OpenFeign</strong> 是 SpringCloud 在 Feign 的基础上支持了 SpringMVC 的注解,如 @RequesMapping。OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,在实现类中做负载均衡并调用其它服务。</p>
<h3 id="服务调用"><a href="#服务调用" class="headerlink" title="服务调用"></a>服务调用</h3><h4 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h4></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>SpringCloud 详解(六)</title>
<link href="http://guest997.tk/2022/04/16/springcloud-expound06/"/>
<id>http://guest997.tk/2022/04/16/springcloud-expound06/</id>
<published>2022-04-16T04:48:21.000Z</published>
<updated>2022-07-28T14:58:17.289Z</updated>
<content type="html"><![CDATA[<h2 id="Ribbon"><a href="#Ribbon" class="headerlink" title="Ribbon"></a>Ribbon</h2><p>基于 Netflix Ribbon 实现的一套<strong>客户端负载均衡的工具</strong>。负载均衡(Load Balance - LB)就是将用户请求通过特定策略分配到多个服务上,从而达到系统的高可用(HA)。</p><h3 id="与-Nginx-的不同之处"><a href="#与-Nginx-的不同之处" class="headerlink" title="与 Nginx 的不同之处"></a>与 Nginx 的不同之处</h3><p>Nginx 是服务器负载均衡,客户端所有请求都会交给 Nginx,然后由 Nginx 实现请求转发。即负载均衡是由服务端实现的。<br>Ribbon 则是本地负载均衡,在调用微服务接口时,会在注册中心上获取注册信息服务列表,然后缓存到本地 JVM,从而在本地实现远程服务调用。</p><h3 id="集中式-LB"><a href="#集中式-LB" class="headerlink" title="集中式 LB"></a>集中式 LB</h3><p>即在服务的消费方和提供方之间使用独立的 LB 设施(可以是硬件,如 F5;也可以是软件,如 Nginx),由该设施负责把请求通过某种策略转发至服务的提供方。</p><h3 id="进程内-LB"><a href="#进程内-LB" class="headerlink" title="进程内 LB"></a>进程内 LB</h3><p>将 LB 逻辑集成到消费方,消费方从服务注册中心获知哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。</p><p><strong>Ribbon 就属于进程内 LB</strong>,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。</p><h3 id="RestTemplate-请求方法"><a href="#RestTemplate-请求方法" class="headerlink" title="RestTemplate 请求方法"></a>RestTemplate 请求方法</h3><ul><li> getForObject() / getForEntity():GET 请求</li><li> postForObject() / postForEntity():POST 请求</li></ul><p>ForObject 和 ForEntity 的区别在于</p><ul><li> ForObject():返回对象为响应体中数据转化成的对象,可以理解为 json。</li><li> ForEntity():返回对象为 ResponseEntity 对象,包含了响应中的一些重要信息,比如响应头、响应状态码、响应体等。</li></ul><h3 id="自带的负载策略"><a href="#自带的负载策略" class="headerlink" title="自带的负载策略"></a>自带的负载策略</h3><ul><li> RoundRobinRule:轮询</li><li> RandomRule:随机</li><li> RetryRule:先按照轮询的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务。</li><li> WeightedResponseTimeRule:对轮询的扩展,响应速度越快的实例选择权重越大,越容易被选择。</li><li> BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。</li><li> AvailabilityFilteringRule:先过滤掉故障实例,再选择并发量较小的实例。</li><li> ZoneAvoidanceRule:复合判断 server 所在区域的性能和 server 的可用性选择服务器。</li></ul><h3 id="负载策略替换(订单模块)"><a href="#负载策略替换(订单模块)" class="headerlink" title="负载策略替换(订单模块)"></a>负载策略替换(订单模块)</h3><h4 id="自定义负载均衡器"><a href="#自定义负载均衡器" class="headerlink" title="自定义负载均衡器"></a>自定义负载均衡器</h4><figure class="highlight qml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.ServiceInstance;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.env.Environment;</span><br><span class="line"></span><br><span class="line">public class <span class="title">CustomLoadBalancerConfiguration</span> {</span><br><span class="line"> @Bean</span><br><span class="line"> ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {</span><br><span class="line"> <span class="built_in">String</span> <span class="keyword">property</span><span class="string"> </span>= environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);</span><br><span class="line"> <span class="comment">//返回随机负载均衡器</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(<span class="keyword">property</span><span class="string"></span>, ServiceInstanceListSupplier.class), <span class="keyword">property</span><span class="string">)</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="修改配置类"><a href="#修改配置类" class="headerlink" title="修改配置类"></a>修改配置类</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.loadbalancer.LoadBalanced;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.loadbalancer.<span class="keyword">annotation</span>.LoadBalancerClient;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.<span class="keyword">annotation</span>.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.<span class="keyword">annotation</span>.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@LoadBalancerClient(name = <span class="meta-string">"PAYMENT"</span>,configuration = CustomLoadBalancerConfiguration.class)</span> <span class="comment">//配置自定义负载均衡器</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ApplicationContextConfig</span> </span>{</span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="meta">@LoadBalanced</span> <span class="comment">//配置负载均衡</span></span><br><span class="line"> <span class="keyword">public</span> RestTemplate getRestTemplate() {</span><br><span class="line"> <span class="keyword">return</span> new RestTemplate();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment、Payment2 和 Order 模块后,浏览器多次访问:127.0.0.1/consumer/payment/add?serial=Guest005,会发现端口已经不再是互相切换,而是随机的。</p><h3 id="默认的轮询策略原理"><a href="#默认的轮询策略原理" class="headerlink" title="默认的轮询策略原理"></a>默认的轮询策略原理</h3><p><strong>接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标,每次服务重启后接口计数从头开始</strong>。</p><figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//源码</span></span><br><span class="line"><span class="keyword">private</span> Response<ServiceInstance> get<span class="constructor">InstanceResponse(List<ServiceInstance> <span class="params">instances</span>)</span> {</span><br><span class="line"> <span class="keyword">if</span> (instances.is<span class="constructor">Empty()</span>) { <span class="comment">//没有实例返回空响应对象</span></span><br><span class="line"> <span class="keyword">if</span> (log.is<span class="constructor">WarnEnabled()</span>) {</span><br><span class="line"> log.warn(<span class="string">"No servers available for service: "</span> + serviceId);</span><br><span class="line"> }</span><br><span class="line"> return <span class="keyword">new</span> <span class="constructor">EmptyResponse()</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// <span class="doctag">TODO:</span> enforce order?</span></span><br><span class="line"> <span class="built_in">int</span> pos = <span class="module-access"><span class="module"><span class="identifier">Math</span>.</span></span>abs(this.position.increment<span class="constructor">AndGet()</span>); <span class="comment">//参数表示的是 position + 1,获取绝对值就是接口第几次请求数。incrementAndGet 方法的具体实现在下面。</span></span><br><span class="line"> ServiceInstance instance = instances.get(pos % instances.size<span class="literal">()</span>); <span class="comment">//就是通过上面的公式获取实例下标</span></span><br><span class="line"> return <span class="keyword">new</span> <span class="constructor">DefaultResponse(<span class="params">instance</span>)</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//主要是为了确保并发安全</span></span><br><span class="line">public final <span class="built_in">int</span> increment<span class="constructor">AndGet()</span> {</span><br><span class="line"> return unsafe.get<span class="constructor">AndAddInt(<span class="params">this</span>, <span class="params">valueOffset</span>, 1)</span> + <span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line">public final <span class="built_in">int</span> get<span class="constructor">AndAddInt(Object <span class="params">var1</span>, <span class="params">long</span> <span class="params">var2</span>, <span class="params">int</span> <span class="params">var4</span>)</span> {</span><br><span class="line"> <span class="built_in">int</span> var5;</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> var5 = this.get<span class="constructor">IntVolatile(<span class="params">var1</span>, <span class="params">var2</span>)</span>; <span class="comment">//这个方法是系统实现的</span></span><br><span class="line"> } <span class="keyword">while</span>(!this.compare<span class="constructor">AndSwapInt(<span class="params">var1</span>, <span class="params">var2</span>, <span class="params">var5</span>, <span class="params">var5</span> + <span class="params">var4</span>)</span>); <span class="comment">//这个方法也是系统实现的</span></span><br><span class="line"> return var5;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="手动实现轮询策略"><a href="#手动实现轮询策略" class="headerlink" title="手动实现轮询策略"></a>手动实现轮询策略</h3><h4 id="注释掉原先的策略"><a href="#注释掉原先的策略" class="headerlink" title="注释掉原先的策略"></a>注释掉原先的策略</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.loadbalancer.LoadBalanced;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.loadbalancer.<span class="keyword">annotation</span>.LoadBalancerClient;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.<span class="keyword">annotation</span>.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.<span class="keyword">annotation</span>.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="comment">//@LoadBalancerClient(name = "PAYMENT",configuration = CustomLoadBalancerConfiguration.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ApplicationContextConfig</span> </span>{</span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"><span class="comment">// @LoadBalanced //配置负载均衡</span></span><br><span class="line"> <span class="keyword">public</span> RestTemplate getRestTemplate() {</span><br><span class="line"> <span class="keyword">return</span> new RestTemplate();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="实现轮询策略"><a href="#实现轮询策略" class="headerlink" title="实现轮询策略"></a>实现轮询策略</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.ServiceInstance;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">LoadBalancer</span> </span>{</span><br><span class="line"> <span class="function">ServiceInstance <span class="title">getInstance</span><span class="params">(List<ServiceInstance> serviceInstances)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.ServiceInstance;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicInteger;</span><br><span class="line"></span><br><span class="line">@Component</span><br><span class="line"><span class="built_in">public</span> <span class="keyword">class</span> MyLB implements LoadBalancer {</span><br><span class="line"> private AtomicInteger atomicInteger = <span class="built_in">new</span> AtomicInteger(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">public</span> final <span class="type">int</span> getAndIncrement() {</span><br><span class="line"> <span class="type">int</span> <span class="keyword">before</span>, <span class="keyword">current</span>;</span><br><span class="line"> <span class="keyword">do</span> {</span><br><span class="line"> <span class="keyword">before</span> = atomicInteger.<span class="keyword">get</span>(); //获取之前的访问次数,如果是第一次进行访问,就是<span class="number">0</span>。</span><br><span class="line"> <span class="keyword">current</span> = <span class="keyword">before</span> >= <span class="number">2147483647</span> ? <span class="number">0</span> : <span class="keyword">before</span> + <span class="number">1</span>; //这个数字是 <span class="type">Integer</span> 的最大值,如果将要超出这个数值就重置为<span class="number">0</span>,否则+<span class="number">1</span>。</span><br><span class="line"> } <span class="keyword">while</span> (!atomicInteger.compareAndSet(<span class="keyword">before</span>, <span class="keyword">current</span>)); //为了并发安全,调用这个方法。将 <span class="keyword">before</span> 在内存中偏移量为 x 位置的值与期望值 <span class="keyword">current</span> 作比较,相等就把 <span class="keyword">current</span> 赋值给偏移量为 x 位置的值并返回 <span class="keyword">true</span>。</span><br><span class="line"> <span class="keyword">System</span>.<span class="keyword">out</span>.println("当前是第几次访问:" + <span class="keyword">current</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">current</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> <span class="built_in">public</span> ServiceInstance getInstance(List<ServiceInstance> serviceInstances) {</span><br><span class="line"> <span class="type">int</span> <span class="keyword">index</span> = getAndIncrement() % serviceInstances.size(); //取余得到下标</span><br><span class="line"> <span class="keyword">return</span> serviceInstances.<span class="keyword">get</span>(<span class="keyword">index</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="添加支付-Controller"><a href="#添加支付-Controller" class="headerlink" title="添加支付 Controller"></a>添加支付 Controller</h4><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping</span>(value = <span class="string">"/payment/lb"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="built_in">String</span> <span class="function"><span class="title">getPaymentLB</span>(<span class="params"></span>)</span> {</span><br><span class="line"> <span class="keyword">return</span> serverPort;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="添加订单-Controller"><a href="#添加订单-Controller" class="headerlink" title="添加订单 Controller"></a>添加订单 Controller</h4><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Resource</span></span><br><span class="line"><span class="keyword">private</span> LoadBalancer loadBalancer;</span><br><span class="line"><span class="meta">@Resource</span></span><br><span class="line"><span class="keyword">private</span> DiscoveryClient discoveryClient;</span><br><span class="line"></span><br><span class="line"><span class="meta">@GetMapping(value = <span class="meta-string">"/consumer/payment/lb"</span>)</span></span><br><span class="line"><span class="keyword">public</span> String getPaymentLB() {</span><br><span class="line"> List<ServiceInstance> instances = discoveryClient.getInstances(<span class="string">"PAYMENT"</span>); <span class="comment">//获取 id 为 PAYMENT 的全部服务实例</span></span><br><span class="line"> <span class="keyword">if</span> (instances == <span class="literal">null</span> instances.size() <= <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"> ServiceInstance serviceInstance = loadBalancer.getInstance(instances); <span class="comment">//通过调用自定义的负载均衡器方法获取具体的服务实例对象</span></span><br><span class="line"> URI uri = serviceInstance.getUri();</span><br><span class="line"> <span class="keyword">return</span> restTemplate.getForObject(uri + <span class="string">"/payment/lb"</span>, String.<span class="keyword">class</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试-1"><a href="#测试-1" class="headerlink" title="测试"></a>测试</h4><p>分别启动 Eureka-Server、Payment、Payment2 和 Order 模块后,浏览器多次访问:127.0.0.1/consumer/payment/lb,会发现端口又变回互相切换的了。</p><p>Order 模块下的控制台也会输出当前的访问次数。</p>]]></content>
<summary type="html"><h2 id="Ribbon"><a href="#Ribbon" class="headerlink" title="Ribbon"></a>Ribbon</h2><p>基于 Netflix Ribbon 实现的一套<strong>客户端负载均衡的工具</strong>。负载均衡(Load Balance - LB)就是将用户请求通过特定策略分配到多个服务上,从而达到系统的高可用(HA)。</p>
<h3 id="与-Nginx-的不同之处"><a href="#与-Nginx-的不同之处" class="headerlink" title="与 Nginx 的不同之处"></a>与 Nginx 的不同之处</h3><p>Nginx 是服务器负载均衡,客户端所有请求都会交给 Nginx,然后由 Nginx 实现请求转发。即负载均衡是由服务端实现的。<br>Ribbon 则是本地负载均衡,在调用微服务接口时,会在注册中心上获取注册信息服务列表,然后缓存到本地 JVM,从而在本地实现远程服务调用。</p>
<h3 id="集中式-LB"><a href="#集中式-LB" class="headerlink" title="集中式 LB"></a>集中式 LB</h3></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>SpringCloud 详解(五)</title>
<link href="http://guest997.tk/2022/04/15/springcloud-expound05/"/>
<id>http://guest997.tk/2022/04/15/springcloud-expound05/</id>
<published>2022-04-15T02:42:06.000Z</published>
<updated>2022-07-28T14:58:17.285Z</updated>
<content type="html"><![CDATA[<h2 id="Consul"><a href="#Consul" class="headerlink" title="Consul"></a>Consul</h2><p>一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,总之 Consul 提供了一种完整的服务网格解决方案。</p><h3 id="运行"><a href="#运行" class="headerlink" title="运行"></a>运行</h3><p>官方下载地址:<a href="https://www.consul.io/downloads">https://www.consul.io/downloads</a>,下载完之后解压,并在解压目录下运行下面的命令以开发者模式启动 Consul。</p><figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">consul agent -dev</span></span><br></pre></td></tr></table></figure><p>浏览器访问:127.0.0.1:8500,就能看见其 Web 界面。</p><p><img data-src="/images/springcloud-expound05.md-0.png"></p><h3 id="注册服务"><a href="#注册服务" class="headerlink" title="注册服务"></a>注册服务</h3><h4 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h4><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight dust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="tag"><<span class="name">dependencies</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>ml.guest997<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>Commons<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{project.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-consul-discovery<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"><span class="tag"></<span class="name">dependencies</span>></span></span></span><br></pre></td></tr></table></figure><h4 id="编写配置文件"><a href="#编写配置文件" class="headerlink" title="编写配置文件"></a>编写配置文件</h4><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8004</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">payment</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line"> <span class="attr">consul:</span></span><br><span class="line"> <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8500</span></span><br><span class="line"> <span class="attr">discovery:</span></span><br><span class="line"> <span class="attr">service-name:</span> <span class="string">${spring.application.name}</span></span><br></pre></td></tr></table></figure><h4 id="主启动类"><a href="#主启动类" class="headerlink" title="主启动类"></a>主启动类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.discovery.EnableDiscoveryClient;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableDiscoveryClient</span> <span class="comment">//启动 Discovery Client</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Payment4</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Payment4.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4><p>启动该模块后,浏览器访问:127.0.0.1:8500,就能看见多了一个名为 payment 的服务。</p><h4 id="备注:"><a href="#备注:" class="headerlink" title="备注:"></a>备注:</h4><p>上面是支付模块的注册,订单模块的注册其实是差不多的,就不再赘述了。</p><h2 id="三个注册中心异同点"><a href="#三个注册中心异同点" class="headerlink" title="三个注册中心异同点"></a>三个注册中心异同点</h2><p>组件名</p><p>语言</p><p>CAP</p><p>服务健康检查</p><p>对外暴露接口</p><p>Eureka</p><p>Java</p><p>AP</p><p>可配支持</p><p>HTTP</p><p>Consul</p><p>Go</p><p>CP</p><p>支持</p><p>HTTP/DNS</p><p>Zookeeper</p><p>Java</p><p>CP</p><p>支持</p><p>客户端</p><h3 id="CAP"><a href="#CAP" class="headerlink" title="CAP"></a>CAP</h3><ul><li> C:Consistency(强一致性)</li><li> A:Availability(可用性)</li><li> P:Partition tolerance(分区容忍性)</li></ul><p><strong>CAP 理论核心是:一个分布式系统不可能同时很好的满足一致性、可用性和分区容忍性这三个需求。最多只能同时较好地满足其中两个。</strong></p><p>因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 或 CP 或 AP 原则的三大类:</p><ul><li> CA:单点集群,满足—致性和可用性的系统,通常在可扩展性上不太强。</li><li> CP:满足一致性和分区容忍性的系统,通常性能不是特别高。</li><li> AP:满足可用性和分区容忍性的系统,通常对一致性要求低一些。</li></ul><p><img data-src="/images/springcloud-expound05.md-1.png"></p><h3 id="AP-架构图例"><a href="#AP-架构图例" class="headerlink" title="AP 架构图例"></a>AP 架构图例</h3><p><img data-src="/images/springcloud-expound05.md-2.png"></p><h3 id="CP-架构图例"><a href="#CP-架构图例" class="headerlink" title="CP 架构图例"></a>CP 架构图例</h3><p><img data-src="/images/springcloud-expound05.md-3.png"></p>]]></content>
<summary type="html"><h2 id="Consul"><a href="#Consul" class="headerlink" title="Consul"></a>Consul</h2><p>一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,总之 Consul 提供了一种完整的服务网格解决方案。</p>
<h3 id="运行"><a href="#运行" class="headerlink" title="运行"></a>运行</h3><p>官方下载地址:<a href="https://www.consul.io/downloads">https://www.consul.io/downloads</a>,下载完之后解压,并在解压目录下运行下面的命令以开发者模式启动 Consul。</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">consul agent -dev</span></span><br></pre></td></tr></table></figure></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>SpringCloud 详解(四)</title>
<link href="http://guest997.tk/2022/04/14/springcloud-expound04/"/>
<id>http://guest997.tk/2022/04/14/springcloud-expound04/</id>
<published>2022-04-14T01:38:53.000Z</published>
<updated>2022-07-28T14:58:04.503Z</updated>
<content type="html"><![CDATA[<h2 id="服务信息显示优化"><a href="#服务信息显示优化" class="headerlink" title="服务信息显示优化"></a>服务信息显示优化</h2><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment">#是否从 Eureka Server 抓取已有的注册信息,默认为 true。单节点无所谓,集群必须设置为 true 才能配合 ribbon 使用负载均衡。</span></span><br><span class="line"> <span class="attr">fetchRegistry:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka,</span> <span class="string">http://eureka7002.com:7002/eureka</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">instance-id:</span> <span class="string">payment8001</span> <span class="comment">#前缀一般会是公司缩写或项目名称</span></span><br><span class="line"> <span class="attr">prefer-ip-address:</span> <span class="literal">true</span> <span class="comment">#鼠标移动到 eureka 页面下的服务时会在浏览器左下角出现 ip 地址</span></span><br></pre></td></tr></table></figure><p><img data-src="/images/springcloud-expound04.md-0.png"></p><h2 id="服务发现-Discovery"><a href="#服务发现-Discovery" class="headerlink" title="服务发现 Discovery"></a>服务发现 Discovery</h2><p>注册进 eureka 的微服务,可以通过服务发现来获得服务的信息。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.discovery.EnableDiscoveryClient;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.eureka.EnableEurekaClient;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span> <span class="comment">//启动 Eureka Client</span></span><br><span class="line"><span class="meta">@EnableDiscoveryClient</span> <span class="comment">//启动 Discovery Client</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Payment</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Payment.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Resource</span></span><br><span class="line"><span class="keyword">private</span> DiscoveryClient discoveryClient;</span><br><span class="line"></span><br><span class="line"><span class="meta">@GetMapping</span>(value = <span class="string">"/payment/discovery"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="built_in">Object</span> <span class="function"><span class="title">discovery</span>(<span class="params"></span>)</span> {</span><br><span class="line"> List<<span class="built_in">String</span>> services = discoveryClient.getServices(); <span class="comment">//注册进 eureka 的所有服务</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="built_in">String</span> element : services) {</span><br><span class="line"> log.info(<span class="string">"服务:"</span> + element);</span><br><span class="line"> }</span><br><span class="line"> List<ServiceInstance> instances = discoveryClient.getInstances(<span class="string">"PAYMENT"</span>); <span class="comment">//通过服务 id 获取全部实例</span></span><br><span class="line"> <span class="keyword">for</span> (ServiceInstance instance : instances) {</span><br><span class="line"> log.info(instance.getServiceId() + <span class="string">"\t"</span> + instance.getHost() + <span class="string">"\t"</span> + instance.getPort() + <span class="string">"\t"</span> + instance.getUri());</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">this</span>.discoveryClient;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>浏览器访问 127.0.0.1:8001/payment/discovery,页面和浏览器都会打印出服务信息。</p><h2 id="Eureka-自我保护机制"><a href="#Eureka-自我保护机制" class="headerlink" title="Eureka 自我保护机制"></a>Eureka 自我保护机制</h2><p>默认情况下,如果 Eureka Server 在一定时间内没有接收到某个服务实例的心跳,Eureka Server 将会注销该实例(默认90秒)。但是当网络分区故障发生时,服务与 Eureka Server 之间无法正常通信,以上行为可能变得非常危险了,因为服务本身其实是健康的,此时本不应该注销这个服务。Eureka 通过自我保护机制来解决这个问题。当 Eureka Server 节点在短时间内丢失过多客户端时,那么这个节点就会进入自我保护模式。在自我保护模式中,Eureka Server 会保护服务注册表中的信息,不再注销任何服务实例。</p><p>关闭自我保护机制:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">server:</span></span><br><span class="line"> <span class="attr">enable-self-preservation:</span> <span class="literal">false</span></span><br></pre></td></tr></table></figure><p>更改自我保护配置:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="comment">#心跳检测与续约时间</span></span><br><span class="line"> <span class="comment">#开发时没置小些,保证服务关闭后注册中心能即使剔除服务</span></span><br><span class="line"> <span class="comment">#Eureka 客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)</span></span><br><span class="line"> <span class="attr">lease-renewal-interval-in-seconds:</span> <span class="number">1</span></span><br><span class="line"> <span class="comment">#Eureka 服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务。</span></span><br><span class="line"> <span class="attr">lease-expiration-duration-in-seconds:</span> <span class="number">2</span></span><br></pre></td></tr></table></figure><h2 id="服务注册-Zookeeper"><a href="#服务注册-Zookeeper" class="headerlink" title="服务注册 Zookeeper"></a>服务注册 Zookeeper</h2><p>Zookeeper 的安装就不赘述了。</p><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight dust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="tag"><<span class="name">dependencies</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>ml.guest997<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>Commons<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{project.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-zookeeper-discovery<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"><span class="tag"></<span class="name">dependencies</span>></span></span></span><br></pre></td></tr></table></figure><h3 id="编写配置文件"><a href="#编写配置文件" class="headerlink" title="编写配置文件"></a>编写配置文件</h3><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8003</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">payment</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line"> <span class="attr">zookeeper:</span></span><br><span class="line"> <span class="attr">connect-string:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:2181</span> <span class="comment">#zookeeper 地址</span></span><br></pre></td></tr></table></figure><h3 id="主启动类"><a href="#主启动类" class="headerlink" title="主启动类"></a>主启动类</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.discovery.EnableDiscoveryClient;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableDiscoveryClient</span> <span class="comment">//启动 Discovery Client</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Payment3</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Payment3.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h3><p>启动该模块后,通过 zkCli 获取服务信息。</p><p><img data-src="/images/springcloud-expound04.md-1.png"></p><p><strong>注意:Zookeeper 的服务节点是临时节点,一段时间检测不到服务发来的心跳,就会将其剔除。</strong></p><h3 id="备注:"><a href="#备注:" class="headerlink" title="备注:"></a>备注:</h3><p>上面是支付模块的注册,订单模块的注册其实是差不多的,就不再赘述了。</p>]]></content>
<summary type="html"><h2 id="服务信息显示优化"><a href="#服务信息显示优化" class="headerlink" title="服务信息显示优化"></a>服务信息显示优化</h2><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment">#是否从 Eureka Server 抓取已有的注册信息,默认为 true。单节点无所谓,集群必须设置为 true 才能配合 ribbon 使用负载均衡。</span></span><br><span class="line"> <span class="attr">fetchRegistry:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka,</span> <span class="string">http://eureka7002.com:7002/eureka</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">instance-id:</span> <span class="string">payment8001</span> <span class="comment">#前缀一般会是公司缩写或项目名称</span></span><br><span class="line"> <span class="attr">prefer-ip-address:</span> <span class="literal">true</span> <span class="comment">#鼠标移动到 eureka 页面下的服务时会在浏览器左下角出现 ip 地址</span></span><br></pre></td></tr></table></figure>
<p><img data-src="/images/springcloud-expound04.md-0.png"></p>
<h2 id="服务发现-Discovery"><a href="#服务发现-Discovery" class="headerlink" title="服务发现 Discovery"></a>服务发现 Discovery</h2><p>注册进 eureka 的微服务,可以通过服务发现来获得服务的信息。</p></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>SpringCloud 详解(三)</title>
<link href="http://guest997.tk/2022/04/13/springcloud-expound03/"/>
<id>http://guest997.tk/2022/04/13/springcloud-expound03/</id>
<published>2022-04-13T03:24:01.000Z</published>
<updated>2022-07-28T14:57:58.915Z</updated>
<content type="html"><![CDATA[<h2 id="Eureka"><a href="#Eureka" class="headerlink" title="Eureka"></a>Eureka</h2><p>在传统的 RPC 远程调用框架中,管理每个服务之间的依赖关系比较复杂,管理也就比较复杂,所以需要使用服务治理,管理服务之间的依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。</p><p>在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前服务器的信息,比如服务地址和通讯地址以别名方式注册到注册中心上。消费者以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地 RPC 调用。</p><p>Eureka 采用了 CS 的设计架构,Eureka Sever 作为服务注册功能的服务器,它是服务注册中心。而系统中的其它微服务,使用 Eureka Client 连接到 Eureka Server 并维持心跳连接。这样就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。</p><h2 id="搭建-Eureka-Server"><a href="#搭建-Eureka-Server" class="headerlink" title="搭建 Eureka Server"></a>搭建 Eureka Server</h2><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight dust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="tag"><<span class="name">dependencies</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-server<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>ml.guest997<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>Commons<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{project.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.junit.jupiter<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>junit-jupiter-api<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"><span class="tag"></<span class="name">dependencies</span>></span></span></span><br></pre></td></tr></table></figure><p>创建主启动类。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaServer</span> <span class="comment">//启动 Eureka Server</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">EurekaServer</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(EurekaServer.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="编写配置文件"><a href="#编写配置文件" class="headerlink" title="编写配置文件"></a>编写配置文件</h3><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">7001</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">localhost</span> <span class="comment">#eureka server 的实例名称</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="comment">#false 表示不向注册中心注册自己。</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span></span><br><span class="line"> <span class="comment">#false 表示自己就是注册中心,我的职责就是维护服务实例,并不需要去检索服务。</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="comment">#设置 eureka server 交互的地址,查询和注册服务都需要依赖这个地址。</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://${eureka.instance.hostname}:${server.port}/eureka/</span></span><br></pre></td></tr></table></figure><h3 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h3><p>运行模块之后,浏览器访问 127.0.0.1:7001,出现如下页面就算成功。</p><p><img data-src="/images/springcloud-expound03.md-0.png"></p><h2 id="注册服务"><a href="#注册服务" class="headerlink" title="注册服务"></a>注册服务</h2><h3 id="导入依赖"><a href="#导入依赖" class="headerlink" title="导入依赖"></a>导入依赖</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-client<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><h3 id="编写配置文件-1"><a href="#编写配置文件-1" class="headerlink" title="编写配置文件"></a>编写配置文件</h3><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">order</span> <span class="comment">#一定要配置名字,要不然服务注册中心会找不到服务。</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment">#是否从 Eureka Server 抓取已有的注册信息,默认为 true。单节点无所谓,集群必须设置为 true 才能配合 ribbon 使用负载均衡。</span></span><br><span class="line"> <span class="attr">fetchRegistry:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://localhost:7001/eureka</span></span><br></pre></td></tr></table></figure><h3 id="启动-Client"><a href="#启动-Client" class="headerlink" title="启动 Client"></a>启动 Client</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.netflix.eureka.EnableEurekaClient;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span> <span class="comment">//启动 Eureka Client</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Order</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Order.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="测试-1"><a href="#测试-1" class="headerlink" title="测试"></a>测试</h3><p>在将之前的两个模块都按照上面的步骤进行服务注册之后,启动所有的模块,浏览器访问 127.0.0.1:7001,就会发现之前的两个模块都注册进去了。</p><p><img data-src="/images/springcloud-expound03.md-1.png"></p><h2 id="搭建-Eureka-集群(相互注册)"><a href="#搭建-Eureka-集群(相互注册)" class="headerlink" title="搭建 Eureka 集群(相互注册)"></a>搭建 Eureka 集群(相互注册)</h2><h3 id="模拟多个-Eureka-Server-地址"><a href="#模拟多个-Eureka-Server-地址" class="headerlink" title="模拟多个 Eureka Server 地址"></a>模拟多个 Eureka Server 地址</h3><p>修改 hosts 文件。</p><figure class="highlight accesslog"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">127.0.0.1</span> eureka7001.com</span><br><span class="line"><span class="number">127.0.0.1</span> eureka7002.com</span><br></pre></td></tr></table></figure><h3 id="搭建另一个-Eureka-Server"><a href="#搭建另一个-Eureka-Server" class="headerlink" title="搭建另一个 Eureka Server"></a>搭建另一个 Eureka Server</h3><p>跟上面的步骤是一样的,就不再赘述了。</p><h3 id="更改配置文件"><a href="#更改配置文件" class="headerlink" title="更改配置文件"></a>更改配置文件</h3><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">7001</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">eureka7001.com</span> <span class="comment">#eureka server 的实例名称</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="comment">#false 表示不向注册中心注册自己。</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span></span><br><span class="line"> <span class="comment">#false 表示自己就是注册中心,我的职责就是维护服务实例,并不需要去检索服务。</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="comment">#设置 eureka server 交互的地址,查询和注册服务都需要依赖这个地址。</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7002.com:7002/eureka/</span></span><br></pre></td></tr></table></figure><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">7002</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">eureka7002.com</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="comment">#指向其它 eureka server,如果有多个,用逗号隔开。</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka/</span></span><br></pre></td></tr></table></figure><h3 id="测试-2"><a href="#测试-2" class="headerlink" title="测试"></a>测试</h3><p>浏览器分别访问:eureka7001.com:7001 和 eureka7002.com:7002 会发现,在 DS Replicas 项下各自都多了一个相互的域名地址。</p><h2 id="注册服务2"><a href="#注册服务2" class="headerlink" title="注册服务2"></a>注册服务2</h2><p>要想将之前的模块注册进 Eureka 集群中,只需要改下配置文件,将 defaultZone 设置为多个即可。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">80</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">order</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">true</span></span><br><span class="line"> <span class="comment">#是否从 Eureka Server 抓取已有的注册信息,默认为 true。单节点无所谓,集群必须设置为 true 才能配合 ribbon 使用负载均衡。</span></span><br><span class="line"> <span class="attr">fetchRegistry:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka7001.com:7001/eureka,</span> <span class="string">http://eureka7002.com:7002/eureka</span></span><br></pre></td></tr></table></figure><h2 id="支付模块集群配置"><a href="#支付模块集群配置" class="headerlink" title="支付模块集群配置"></a>支付模块集群配置</h2><p>需要新建一个支付模块,也是更之前一样的步骤,就不再赘述了。<strong>注意:记得修改新模块的端口。</strong></p><h3 id="修改订单模块的-Config"><a href="#修改订单模块的-Config" class="headerlink" title="修改订单模块的 Config"></a>修改订单模块的 Config</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.client.loadbalancer.LoadBalanced;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ApplicationContextConfig</span> </span>{</span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="meta">@LoadBalanced</span> <span class="comment">//配置负载均衡</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> RestTemplate <span class="title">getRestTemplate</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> RestTemplate();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="修改订单模块的-Controller"><a href="#修改订单模块的-Controller" class="headerlink" title="修改订单模块的 Controller"></a>修改订单模块的 Controller</h3><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.CommonResult;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.Payment;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.RestController;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.<span class="keyword">annotation</span>.Resource;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OrderController</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> static <span class="keyword">final</span> String PAYMENT_URL = <span class="string">"http://PAYMENT"</span>; <span class="comment">//不再是固定地址,而是 eureka 的服务名地址。</span></span><br><span class="line"></span><br><span class="line"> <span class="meta">@Resource</span></span><br><span class="line"> <span class="keyword">private</span> RestTemplate restTemplate;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/consumer/payment/add"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> CommonResult add(Payment payment) {</span><br><span class="line"> <span class="keyword">return</span> restTemplate.postForObject(PAYMENT_URL + <span class="string">"/payment/add"</span>, payment, CommonResult.<span class="keyword">class</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/consumer/payment/get/{id}"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> CommonResult<Payment> getPayment(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> <span class="built_in">Long</span> id) {</span><br><span class="line"> <span class="keyword">return</span> restTemplate.getForObject(PAYMENT_URL + <span class="string">"/payment/get/"</span> + id, CommonResult.<span class="keyword">class</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="修改支付模块的-Controller"><a href="#修改支付模块的-Controller" class="headerlink" title="修改支付模块的 Controller"></a>修改支付模块的 Controller</h3><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.CommonResult;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.Payment;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.service.PaymentService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.<span class="keyword">annotation</span>.Value;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.<span class="keyword">annotation</span>.Resource;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PaymentController</span> </span>{</span><br><span class="line"> <span class="meta">@Resource</span></span><br><span class="line"> <span class="keyword">private</span> PaymentService paymentService;</span><br><span class="line"> <span class="meta">@Value(<span class="meta-string">"<span class="subst">${server.port}</span>"</span>)</span></span><br><span class="line"> <span class="keyword">private</span> String serverPort; <span class="comment">//为了方便显示负载均衡是否成功</span></span><br><span class="line"></span><br><span class="line"> <span class="meta">@PostMapping(<span class="meta-string">"/payment/add"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> CommonResult add(<span class="meta">@RequestBody</span> Payment payment) {</span><br><span class="line"> int res = paymentService.add(payment);</span><br><span class="line"> log.info(<span class="string">"插入结果:"</span> + res);</span><br><span class="line"> <span class="keyword">if</span> (res > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> new CommonResult(<span class="number">200</span>, <span class="string">"插入数据库成功,支付服务端口为:"</span> + serverPort, res);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> new CommonResult(<span class="number">400</span>, <span class="string">"插入数据库失败"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(value = <span class="meta-string">"/payment/get/{id}"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> CommonResult<Payment> getPaymentById(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> <span class="built_in">Long</span> id) {</span><br><span class="line"> Payment payment = paymentService.getPaymentById(id);</span><br><span class="line"> <span class="keyword">if</span> (payment != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> new CommonResult(<span class="number">200</span>, <span class="string">"查询成功"</span>, payment);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> new CommonResult(<span class="number">404</span>, <span class="string">"没有对应记录,查询 id 为:"</span> + id);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="测试-3"><a href="#测试-3" class="headerlink" title="测试"></a>测试</h3><p>启动所有的模块,浏览器访问 127.0.0.1/consumer/payment/add?serial=Guest004,会发现页面显示的端口在来回切换,就说明负载均衡功能生效了。</p>]]></content>
<summary type="html"><h2 id="Eureka"><a href="#Eureka" class="headerlink" title="Eureka"></a>Eureka</h2><p>在传统的 RPC 远程调用框架中,管理每个服务之间的依赖关系比较复杂,管理也就比较复杂,所以需要使用服务治理,管理服务之间的依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。</p>
<p>在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前服务器的信息,比如服务地址和通讯地址以别名方式注册到注册中心上。消费者以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地 RPC 调用。</p>
<p>Eureka 采用了 CS 的设计架构,Eureka Sever 作为服务注册功能的服务器,它是服务注册中心。而系统中的其它微服务,使用 Eureka Client 连接到 Eureka Server 并维持心跳连接。这样就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。</p>
<h2 id="搭建-Eureka-Server"><a href="#搭建-Eureka-Server" class="headerlink" title="搭建 Eureka Server"></a>搭建 Eureka Server</h2></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>SpringCloud 详解(二)</title>
<link href="http://guest997.tk/2022/04/12/springcloud-expound02/"/>
<id>http://guest997.tk/2022/04/12/springcloud-expound02/</id>
<published>2022-04-12T05:01:37.000Z</published>
<updated>2022-07-28T14:57:53.265Z</updated>
<content type="html"><![CDATA[<h2 id="支付模块(服务生产者)"><a href="#支付模块(服务生产者)" class="headerlink" title="支付模块(服务生产者)"></a>支付模块(服务生产者)</h2><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.mybatis.spring.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>mybatis-spring-boot-starter<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.alibaba<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>druid-spring-boot-starter<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>mysql<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>mysql-connector-java<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-jdbc<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependencies</span>></span></span><br></pre></td></tr></table></figure><p>在 resources 文件夹下创建 application.yaml 配置文件,并加入下面的配置。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8001</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">payment</span></span><br><span class="line"> <span class="attr">datasource:</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">com.alibaba.druid.pool.DruidDataSource</span></span><br><span class="line"> <span class="attr">driver-class-name:</span> <span class="string">com.mysql.cj.jdbc.Driver</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false</span></span><br><span class="line"> <span class="attr">username:</span> <span class="string">root</span></span><br><span class="line"> <span class="attr">password:</span> <span class="string">root</span></span><br><span class="line"></span><br><span class="line"><span class="attr">mybatis:</span></span><br><span class="line"> <span class="attr">mapperLocations:</span> <span class="string">classpath:mapper/*.xml</span></span><br><span class="line"> <span class="attr">type-aliases-package:</span> <span class="string">ml.guest997.pojo</span></span><br></pre></td></tr></table></figure><p>创建主启动类。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Payment</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Payment.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>运行下面的 sql 语句创建数据库和表。</p><figure class="highlight n1ql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">DATABASE</span> <span class="symbol">`springcloud`</span>;</span><br><span class="line">USE `springcloud`;</span><br><span class="line"><span class="keyword">CREATE</span> TABLE <span class="symbol">`payment`</span>(</span><br><span class="line"> <span class="symbol">`id`</span> bigint(<span class="number">20</span>) <span class="keyword">NOT</span> <span class="literal">NULL</span> AUTO_INCREMENT COMMENT <span class="string">'ID'</span>,</span><br><span class="line"> <span class="symbol">`serial`</span> varchar(<span class="number">200</span>) DEFAULT <span class="string">''</span>,</span><br><span class="line"> <span class="keyword">PRIMARY</span> <span class="keyword">KEY</span> (id)</span><br><span class="line">)ENGINE=InnoDB AUTO_INCREMENT=<span class="number">1</span> DEFAULT CHARSET=utf8mb4</span><br></pre></td></tr></table></figure><h3 id="POJO-层"><a href="#POJO-层" class="headerlink" title="POJO 层"></a>POJO 层</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.pojo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.AllArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"><span class="keyword">import</span> lombok.NoArgsConstructor;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="meta">@NoArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Payment</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = -<span class="number">3231455795280061701L</span>;</span><br><span class="line"> <span class="keyword">private</span> Long id;</span><br><span class="line"> <span class="keyword">private</span> String serial;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.pojo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.AllArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"><span class="keyword">import</span> lombok.NoArgsConstructor;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="meta">@NoArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CommonResult</span><<span class="type">T</span>> </span>{</span><br><span class="line"> <span class="keyword">private</span> Integer code;</span><br><span class="line"> <span class="keyword">private</span> String message;</span><br><span class="line"> <span class="keyword">private</span> T <span class="keyword">data</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> CommonResult(Integer code, String message) {</span><br><span class="line"> <span class="keyword">this</span>.code = code;</span><br><span class="line"> <span class="keyword">this</span>.message = message;</span><br><span class="line"> <span class="keyword">this</span>.<span class="keyword">data</span> = <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Dao-层"><a href="#Dao-层" class="headerlink" title="Dao 层"></a>Dao 层</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.dao;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.Payment;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.annotations.Mapper;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.annotations.Param;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Mapper</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">PaymentDao</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">add</span><span class="params">(Payment payment)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="function">Payment <span class="title">getPaymentById</span><span class="params">(<span class="meta">@Param("id")</span> Long id)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight dust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="meta"><?xml version="1.0" encoding="UTF-8" ?></span></span></span><br><span class="line"><span class="xml"><span class="meta"><!DOCTYPE <span class="meta-keyword">mapper</span> <span class="meta-keyword">PUBLIC</span> <span class="meta-string">"-//mybatis.org//DTD Mapper 3.0//EN"</span> <span class="meta-string">"http://mybatis.org/dtd/mybatis-3-mapper.dtd"</span> ></span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml"><span class="tag"><<span class="name">mapper</span> <span class="attr">namespace</span>=<span class="string">"ml.guest997.dao.PaymentDao"</span>></span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">insert</span> <span class="attr">id</span>=<span class="string">"add"</span> <span class="attr">parameterType</span>=<span class="string">"Payment"</span> <span class="attr">useGeneratedKeys</span>=<span class="string">"true"</span> <span class="attr">keyProperty</span>=<span class="string">"id"</span>></span></span></span><br><span class="line"><span class="xml"> insert into payment(serial)</span></span><br><span class="line"><span class="xml"> values (#</span><span class="template-variable">{serial}</span><span class="xml">);</span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">insert</span>></span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">resultMap</span> <span class="attr">id</span>=<span class="string">"BaseResultMap"</span> <span class="attr">type</span>=<span class="string">"Payment"</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">id</span> <span class="attr">column</span>=<span class="string">"id"</span> <span class="attr">property</span>=<span class="string">"id"</span> <span class="attr">jdbcType</span>=<span class="string">"BIGINT"</span>/></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">id</span> <span class="attr">column</span>=<span class="string">"serial"</span> <span class="attr">property</span>=<span class="string">"serial"</span> <span class="attr">jdbcType</span>=<span class="string">"VARCHAR"</span>/></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">resultMap</span>></span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">select</span> <span class="attr">id</span>=<span class="string">"getPaymentById"</span> <span class="attr">parameterType</span>=<span class="string">"Long"</span> <span class="attr">resultMap</span>=<span class="string">"BaseResultMap"</span>></span></span></span><br><span class="line"><span class="xml"> select *</span></span><br><span class="line"><span class="xml"> from payment</span></span><br><span class="line"><span class="xml"> where id = #</span><span class="template-variable">{id}</span><span class="xml">;</span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">select</span>></span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml"><span class="tag"></<span class="name">mapper</span>></span></span></span><br></pre></td></tr></table></figure><h3 id="Service-层"><a href="#Service-层" class="headerlink" title="Service 层"></a>Service 层</h3><figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">package</span> <span class="selector-tag">ml</span><span class="selector-class">.guest997</span><span class="selector-class">.service</span>;</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">import</span> <span class="selector-tag">ml</span><span class="selector-class">.guest997</span><span class="selector-class">.pojo</span><span class="selector-class">.Payment</span>;</span><br><span class="line"><span class="selector-tag">import</span> <span class="selector-tag">org</span><span class="selector-class">.apache</span><span class="selector-class">.ibatis</span><span class="selector-class">.annotations</span><span class="selector-class">.Param</span>;</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">public</span> <span class="selector-tag">interface</span> <span class="selector-tag">PaymentService</span> {</span><br><span class="line"> <span class="selector-tag">int</span> <span class="selector-tag">add</span>(Payment payment);</span><br><span class="line"></span><br><span class="line"> <span class="selector-tag">Payment</span> <span class="selector-tag">getPaymentById</span>(<span class="variable">@Param</span>(<span class="string">"id"</span>) Long id);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.service.impl;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> ml.guest997.dao.PaymentDao;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.Payment;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.service.PaymentService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.annotation.Resource;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PaymentServiceImpl</span> <span class="keyword">implements</span> <span class="title">PaymentService</span> </span>{</span><br><span class="line"> <span class="meta">@Resource</span></span><br><span class="line"> <span class="keyword">private</span> PaymentDao paymentDao;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function"><span class="keyword">int</span> <span class="title">add</span><span class="params">(Payment payment)</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">return</span> paymentDao.<span class="title">add</span><span class="params">(payment)</span></span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="function">Payment <span class="title">getPaymentById</span><span class="params">(Long id)</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">return</span> paymentDao.<span class="title">getPaymentById</span><span class="params">(id)</span></span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Controller-层"><a href="#Controller-层" class="headerlink" title="Controller 层"></a>Controller 层</h3><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.CommonResult;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.Payment;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.service.PaymentService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.<span class="keyword">annotation</span>.Resource;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PaymentController</span> </span>{</span><br><span class="line"> <span class="meta">@Resource</span></span><br><span class="line"> <span class="keyword">private</span> PaymentService paymentService;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@PostMapping(<span class="meta-string">"/payment/add"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> CommonResult add(<span class="meta">@RequestBody</span> Payment payment) {</span><br><span class="line"> int res = paymentService.add(payment);</span><br><span class="line"> log.info(<span class="string">"插入结果:"</span> + res);</span><br><span class="line"> <span class="keyword">if</span> (res > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> new CommonResult(<span class="number">200</span>, <span class="string">"插入数据库成功"</span>, res);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> new CommonResult(<span class="number">400</span>, <span class="string">"插入数据库失败"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(value = <span class="meta-string">"/payment/get/{id}"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> CommonResult<Payment> getPaymentById(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> <span class="built_in">Long</span> id) {</span><br><span class="line"> Payment payment = paymentService.getPaymentById(id);</span><br><span class="line"> <span class="keyword">if</span> (payment != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> new CommonResult(<span class="number">200</span>, <span class="string">"查询成功"</span>, payment);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> new CommonResult(<span class="number">404</span>, <span class="string">"没有对应记录,查询 id 为:"</span> + id);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h3><p>启动模块后,使用 Postman 发送请求,(因为浏览器不能够通过 url 直接发送 Post 请求)分别是 Post 请求:127.0.0.1:8001/payment/add?serial=Guest001 和 Get 请求: 127.0.0.1:8001/payment/get/1,能够正常返回数据即可。</p><h2 id="热部署(开发时使用,生产环境必须关闭)"><a href="#热部署(开发时使用,生产环境必须关闭)" class="headerlink" title="热部署(开发时使用,生产环境必须关闭)"></a>热部署(开发时使用,生产环境必须关闭)</h2><p>导入下面的依赖。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><p>开启自动构建。</p><p><img data-src="/images/springcloud-expound02.md-0.png"></p><p><img data-src="/images/springcloud-expound02.md-1.png"></p><p>然后修改一下代码,看下控制台是否能自动构建即可。</p><h2 id="订单模块(服务消费者)"><a href="#订单模块(服务消费者)" class="headerlink" title="订单模块(服务消费者)"></a>订单模块(服务消费者)</h2><h3 id="准备工作-1"><a href="#准备工作-1" class="headerlink" title="准备工作"></a>准备工作</h3><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependencies</span>></span></span><br></pre></td></tr></table></figure><p>在 resources 文件夹下创建 application.yaml 配置文件,并加入下面的配置。</p><figure class="highlight dts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="symbol">server:</span></span><br><span class="line"><span class="symbol"> port:</span> <span class="number">80</span></span><br><span class="line"><span class="symbol"></span></span><br><span class="line"><span class="symbol">spring:</span></span><br><span class="line"><span class="symbol"> application:</span></span><br><span class="line"><span class="symbol"> name:</span> order</span><br></pre></td></tr></table></figure><p>创建主启动类。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Order</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(Order.class, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="POJO-层-1"><a href="#POJO-层-1" class="headerlink" title="POJO 层"></a>POJO 层</h3><p>就是上面的支付模块的代码,就不再赘述了。</p><h3 id="Config-层"><a href="#Config-层" class="headerlink" title="Config 层"></a>Config 层</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.config;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ApplicationContextConfig</span> </span>{</span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> RestTemplate <span class="title">getRestTemplate</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> RestTemplate();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Controller-层-1"><a href="#Controller-层-1" class="headerlink" title="Controller 层"></a>Controller 层</h3><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.CommonResult;</span><br><span class="line"><span class="keyword">import</span> ml.guest997.pojo.Payment;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.<span class="keyword">annotation</span>.RestController;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.client.RestTemplate;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.<span class="keyword">annotation</span>.Resource;</span><br><span class="line"></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OrderController</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> static <span class="keyword">final</span> String PAYMENT_URL = <span class="string">"http://localhost:8001"</span>;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Resource</span></span><br><span class="line"> <span class="keyword">private</span> RestTemplate restTemplate;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/consumer/payment/add"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> CommonResult add(Payment payment) {</span><br><span class="line"> <span class="comment">//三个参数分别表示请求地址、请求参数和响应被转换成的对象类型。</span></span><br><span class="line"> <span class="keyword">return</span> restTemplate.postForObject(PAYMENT_URL + <span class="string">"/payment/add"</span>, payment, CommonResult.<span class="keyword">class</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping(<span class="meta-string">"/consumer/payment/get/{id}"</span>)</span></span><br><span class="line"> <span class="keyword">public</span> CommonResult<Payment> getPayment(<span class="meta">@PathVariable(<span class="meta-string">"id"</span>)</span> <span class="built_in">Long</span> id) {</span><br><span class="line"> <span class="keyword">return</span> restTemplate.getForObject(PAYMENT_URL + <span class="string">"/payment/get/"</span> + id, CommonResult.<span class="keyword">class</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>RestTemplate 提供了多种便捷访问远程 http 服务的方法,是一种简单便捷的访问 restful 服务模板类,是 Spring 提供的用于访问 Rest 服务的客户端模板工具集。</p><h3 id="测试-1"><a href="#测试-1" class="headerlink" title="测试"></a>测试</h3><p>将两个模块都启动后,浏览器访问地址:127.0.0.1//consumer/payment/add?serial=Guest002 和 127.0.0.1//consumer/payment/get/2,能够正常返回数据即可。</p><h2 id="IDEA-开启-Services"><a href="#IDEA-开启-Services" class="headerlink" title="IDEA 开启 Services"></a>IDEA 开启 Services</h2><p>为了方便管理多个微服务,可以通过 IDEA 开启 Services 进行统一管理。</p><p><img data-src="/images/springcloud-expound02.md-2.png"></p><p><img data-src="/images/springcloud-expound02.md-3.png"></p><h2 id="工程重构"><a href="#工程重构" class="headerlink" title="工程重构"></a>工程重构</h2><p>从上面的两个模块就能看出来,POJO 层的代码是冗余的,可能以后每写一个模块,就需要把这些代码都复制一份,十分的麻烦。我们可以通过新建个 Commons 模块,将这些冗余的代码放进去,在需要的模块下引入这个模块就能实现简单的复用了。</p><h3 id="准备工作-2"><a href="#准备工作-2" class="headerlink" title="准备工作"></a>准备工作</h3><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>cn.hutool<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>hutool-all<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>5.7.22<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependencies</span>></span></span><br></pre></td></tr></table></figure><h3 id="POJO-层-2"><a href="#POJO-层-2" class="headerlink" title="POJO 层"></a>POJO 层</h3><p>就是上面两个模块中冗余的 POJO 层代码。然后将另两个模块的 POJO 层删除。</p><h3 id="编译打包"><a href="#编译打包" class="headerlink" title="编译打包"></a>编译打包</h3><p>通过 IDEA 右侧栏中的 Maven 工具栏,将 Commons 模块编译打包以供其它模块使用。(先 clean 后 install)</p><p><img data-src="/images/springcloud-expound02.md-4.png"></p><h3 id="引入依赖"><a href="#引入依赖" class="headerlink" title="引入依赖"></a>引入依赖</h3><p>在其它模块的 pom 配置文件中引入下面的依赖。</p><figure class="highlight dust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>ml.guest997<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>Commons<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{project.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"><span class="tag"></<span class="name">dependency</span>></span></span></span><br></pre></td></tr></table></figure><h3 id="测试-2"><a href="#测试-2" class="headerlink" title="测试"></a>测试</h3><p>将两个模块都启动后,通过浏览器访问地址:127.0.0.1//consumer/payment/add?serial=Guest003 和 127.0.0.1//consumer/payment/get/3,能够正常返回数据即可。</p>]]></content>
<summary type="html"><h2 id="支付模块(服务生产者)"><a href="#支付模块(服务生产者)" class="headerlink" title="支付模块(服务生产者)"></a>支付模块(服务生产者)</h2><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><p>创建一个 Module,一个空的 Maven 项目。并导入下面的依赖。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-actuator<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.mybatis.spring.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mybatis-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>druid-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>mysql<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mysql-connector-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-jdbc<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.projectlombok<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>lombok<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="name">optional</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>在 resources 文件夹下创建 application.yaml 配置文件,并加入下面的配置。</p></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>SpringCloud 详解(一)</title>
<link href="http://guest997.tk/2022/04/11/springcloud-expound01/"/>
<id>http://guest997.tk/2022/04/11/springcloud-expound01/</id>
<published>2022-04-11T01:28:33.000Z</published>
<updated>2022-07-28T14:57:40.471Z</updated>
<content type="html"><![CDATA[<p><strong>SpringCloud = 分布式微服务架构的一站式解决方案,是多种微服务架构技术的集合体,俗称微服务全家桶。</strong></p><p>SpringCloud Alibaba 和 SpringCloud 和 SpringBoot 的版本以及各组件版本兼容性选择请查看下面的版本说明:<a href="https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E">https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明</a></p><h2 id="组件说明"><a href="#组件说明" class="headerlink" title="组件说明"></a>组件说明</h2><p>SpringCloud 的组件有很多,在学习的时候需要抓住重点,并不是所有组件在一个项目中都会用到,很多时候我们需要的只是其中必要的部分,有了这些必要的东西就能完成所需要的功能。</p><p>Netflix 在 SpringCloud 项目中占着重要的地位,Netflix 公司提供了包括 Eureka、Hystrix、Zuul 等在内的很多组件,在微服务架构中至关重要,而 Spring 在 Netflix 的基础上,进一步封装了这些组件。但是因为一些原因,Netflix 提供的很多组件已不再维护,但并不是不能用了,所以还是需要学习其中的思想,而替代它们的新组件也要进行学习。</p><p>具体哪些常用的组件已不维护,替代它们的又有哪些,可以查看下面的列表。</p><ul><li>服务注册中心<ul><li> × Eureka</li><li> √ Zookeeper</li><li> √ Consul</li><li> √ Nacos</li></ul></li><li>服务调用<ul><li> √ Ribbon</li><li> √ LoadBalancer</li><li> × Feign</li><li> √ OpenFeign</li></ul></li><li>服务降级<ul><li> × Hystrix</li><li> √ resilience4j</li><li> √ sentienl</li></ul></li><li>服务网关<ul><li> × Zuul</li><li> ! Zuul2</li><li> √ gateway</li></ul></li><li>服务配置<ul><li>× Config</li><li> √ Nacos</li></ul></li><li>服务总线<ul><li> × Bus</li><li> √ Nacos</li></ul></li></ul><h2 id="父工程搭建"><a href="#父工程搭建" class="headerlink" title="父工程搭建"></a>父工程搭建</h2><p>创建一个 Maven 工程,模板选择:maven-archetype-site。删除 src 文件夹。下面是 pom 配置文件。</p><figure class="highlight dust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="meta"><?xml version="1.0" encoding="UTF-8"?></span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml"><span class="tag"><<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span></span><br><span class="line"><span class="tag"><span class="xml"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">modelVersion</span>></span>4.0.0<span class="tag"></<span class="name">modelVersion</span>></span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>ml.guest997<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>SpringCloud<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>1.0-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">packaging</span>></span>pom<span class="tag"></<span class="name">packaging</span>></span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">properties</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">project.build.sourceEncoding</span>></span>UTF-8<span class="tag"></<span class="name">project.build.sourceEncoding</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">maven.compiler.source</span>></span>1.8<span class="tag"></<span class="name">maven.compiler.source</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">maven.compiler.target</span>></span>1.8<span class="tag"></<span class="name">maven.compiler.target</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">junit.version</span>></span>5.8.2<span class="tag"></<span class="name">junit.version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">log4j.version</span>></span>2.17.2<span class="tag"></<span class="name">log4j.version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">lombok.version</span>></span>1.18.22<span class="tag"></<span class="name">lombok.version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">mysql.version</span>></span>8.0.28<span class="tag"></<span class="name">mysql.version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">druid.spring.boot.version</span>></span>1.2.8<span class="tag"></<span class="name">druid.spring.boot.version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">mybatis.spring.boot.version</span>></span>2.2.2<span class="tag"></<span class="name">mybatis.spring.boot.version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">properties</span>></span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependencyManagement</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependencies</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-dependencies<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>2.6.3<span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">type</span>></span>pom<span class="tag"></<span class="name">type</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>import<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-dependencies<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>2021.0.1<span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">type</span>></span>pom<span class="tag"></<span class="name">type</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>import<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>com.alibaba.cloud<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-alibaba-dependencies<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>2021.0.1.0<span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">type</span>></span>pom<span class="tag"></<span class="name">type</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">scope</span>></span>import<span class="tag"></<span class="name">scope</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>mysql<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>mysql-connector-java<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{mysql.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>com.alibaba<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>druid-spring-boot-starter<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{druid.spring.boot.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.mybatis.spring.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>mybatis-spring-boot-starter<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{mybatis.spring.boot.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.junit.jupiter<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>junit-jupiter-api<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{junit.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.logging.log4j<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>log4j-core<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{log4j.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">version</span>></span>$</span><span class="template-variable">{lombok.version}</span><span class="xml"><span class="tag"></<span class="name">version</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependency</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependencies</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dependencyManagement</span>></span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">build</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">plugins</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">plugin</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-maven-plugin<span class="tag"></<span class="name">artifactId</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">configuration</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">fork</span>></span>true<span class="tag"></<span class="name">fork</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"><<span class="name">addResources</span>></span>true<span class="tag"></<span class="name">addResources</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">configuration</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">plugin</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">plugins</span>></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">build</span>></span></span></span><br><span class="line"><span class="xml"></span></span><br><span class="line"><span class="xml"><span class="tag"></<span class="name">project</span>></span></span></span><br></pre></td></tr></table></figure><p>packing 标签只是为了聚合工程或传递依赖用的。</p><p>dependencyManagement 标签提供了一种管理依赖版本号的方式。通常会在项目的最顶层的父 pom 中看到。这样做的好处就是:如果有多个子项目都引用同一样依赖,则可以避免在每个使用的子项目里都声明一个版本号,这样当想升级或切换到另一个版本时,只需要在父 pom 中进行修改,而不需要一个个的子项目中进行修改;另外如果某个子项目需要另外的一个版本,只需要在其 pom 中声明其它版本即可。<strong>dependencyManagement 只是声明依赖,并不实现引入,因此子项目需要显式地声明需要用的依赖。</strong></p>]]></content>
<summary type="html"><p><strong>SpringCloud = 分布式微服务架构的一站式解决方案,是多种微服务架构技术的集合体,俗称微服务全家桶。</strong></p>
<p>SpringCloud Alibaba 和 SpringCloud 和 SpringBoot 的版本以及各组件版本兼容性选择请查看下面的版本说明:<a href="https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E">https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明</a></p>
<h2 id="组件说明"><a href="#组件说明" class="headerlink" title="组件说明"></a>组件说明</h2><p>SpringCloud 的组件有很多,在学习的时候需要抓住重点,并不是所有组件在一个项目中都会用到,很多时候我们需要的只是其中必要的部分,有了这些必要的东西就能完成所需要的功能。</p>
<p>Netflix 在 SpringCloud 项目中占着重要的地位,Netflix 公司提供了包括 Eureka、Hystrix、Zuul 等在内的很多组件,在微服务架构中至关重要,而 Spring 在 Netflix 的基础上,进一步封装了这些组件。但是因为一些原因,Netflix 提供的很多组件已不再维护,但并不是不能用了,所以还是需要学习其中的思想,而替代它们的新组件也要进行学习。</p></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="springcloud" scheme="http://guest997.tk/tags/springcloud/"/>
</entry>
<entry>
<title>JavaSE 进阶(二十二)</title>
<link href="http://guest997.tk/2022/04/04/javase-advanced22/"/>
<id>http://guest997.tk/2022/04/04/javase-advanced22/</id>
<published>2022-04-04T02:47:24.000Z</published>
<updated>2022-07-28T14:57:40.467Z</updated>
<content type="html"><![CDATA[<h2 id="TCP-连接测试"><a href="#TCP-连接测试" class="headerlink" title="TCP 连接测试"></a>TCP 连接测试</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.OutputStream;</span><br><span class="line"><span class="keyword">import</span> java.net.InetAddress;</span><br><span class="line"><span class="keyword">import</span> java.net.Socket;</span><br><span class="line"><span class="keyword">import</span> java.nio.charset.StandardCharsets;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TCPClient</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> Socket socket = <span class="keyword">null</span>;</span><br><span class="line"> OutputStream outputStream = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//发送信息</span></span><br><span class="line"> socket = <span class="keyword">new</span> Socket(InetAddress.getByName(<span class="string">"localhost"</span>), <span class="number">9999</span>);</span><br><span class="line"> outputStream = socket.getOutputStream();</span><br><span class="line"> outputStream.write(<span class="string">"客户端发送信息..."</span>.getBytes(StandardCharsets.UTF_8));</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">if</span> (outputStream != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> outputStream.close();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (socket != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> socket.close();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.net.ServerSocket;</span><br><span class="line"><span class="keyword">import</span> java.net.Socket;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TCPServer</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> ServerSocket serverSocket = <span class="keyword">null</span>;</span><br><span class="line"> Socket accept = <span class="keyword">null</span>;</span><br><span class="line"> InputStream inputStream = <span class="keyword">null</span>;</span><br><span class="line"> ByteArrayOutputStream byteArrayOutputStream = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//创建连接</span></span><br><span class="line"> serverSocket = <span class="keyword">new</span> ServerSocket(<span class="number">9999</span>);</span><br><span class="line"> <span class="comment">//等待客户端请求</span></span><br><span class="line"> accept = serverSocket.accept();</span><br><span class="line"> <span class="comment">//读取用户信息</span></span><br><span class="line"> inputStream = accept.getInputStream();</span><br><span class="line"> <span class="comment">//管道流接收和打印</span></span><br><span class="line"> byteArrayOutputStream = <span class="keyword">new</span> ByteArrayOutputStream();</span><br><span class="line"> <span class="keyword">byte</span>[] bytes = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">int</span> len = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> ((len = inputStream.read(bytes)) != -<span class="number">1</span>) {</span><br><span class="line"> byteArrayOutputStream.write(bytes, <span class="number">0</span>, len);</span><br><span class="line"> }</span><br><span class="line"> System.out.println(byteArrayOutputStream);</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">if</span> (byteArrayOutputStream != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> byteArrayOutputStream.close();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (inputStream != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> inputStream.close();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (accept != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> accept.close();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (serverSocket != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> serverSocket.close();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="TCP-文件上传"><a href="#TCP-文件上传" class="headerlink" title="TCP 文件上传"></a>TCP 文件上传</h2><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.net.InetAddress;</span><br><span class="line"><span class="keyword">import</span> java.net.Socket;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FileClient</span> {</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Socket socket = <span class="keyword">new</span> <span class="built_in">Socket</span>(InetAddress.<span class="built_in">getByName</span>(<span class="string">"localhost"</span>), <span class="number">9999</span>);</span><br><span class="line"> OutputStream outputStream = socket.<span class="built_in">getOutputStream</span>();</span><br><span class="line"> FileInputStream fileInputStream = <span class="keyword">new</span> <span class="built_in">FileInputStream</span>(<span class="string">"pc.png"</span>);</span><br><span class="line"> <span class="keyword">byte</span>[] buffer = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">int</span> len;</span><br><span class="line"> <span class="keyword">while</span> ((len = fileInputStream.<span class="built_in">read</span>(buffer)) != <span class="number">-1</span>) {</span><br><span class="line"> outputStream.<span class="built_in">write</span>(buffer, <span class="number">0</span>, len);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//通知服务器文件已发送完毕</span></span><br><span class="line"> socket.<span class="built_in">shutdownOutput</span>();</span><br><span class="line"> <span class="comment">//确定服务端接收完毕,才断开连接。</span></span><br><span class="line"> InputStream inputStream = socket.<span class="built_in">getInputStream</span>();</span><br><span class="line"> <span class="keyword">byte</span>[] buffer2 = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">int</span> len2;</span><br><span class="line"> ByteArrayOutputStream byteArrayOutputStream = <span class="keyword">new</span> <span class="built_in">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="keyword">while</span> ((len2 = inputStream.<span class="built_in">read</span>(buffer2)) != <span class="number">-1</span>) {</span><br><span class="line"> byteArrayOutputStream.<span class="built_in">write</span>(buffer2, <span class="number">0</span>, len2);</span><br><span class="line"> }</span><br><span class="line"> System.out.<span class="built_in">println</span>(byteArrayOutputStream);</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"客户端断开连接..."</span>);</span><br><span class="line"> byteArrayOutputStream.<span class="built_in">close</span>();</span><br><span class="line"> inputStream.<span class="built_in">close</span>();</span><br><span class="line"> outputStream.<span class="built_in">close</span>();</span><br><span class="line"> fileInputStream.<span class="built_in">close</span>();</span><br><span class="line"> socket.<span class="built_in">close</span>();</span><br><span class="line"> } <span class="built_in"><span class="keyword">catch</span></span> (IOException e) {</span><br><span class="line"> e.<span class="built_in">printStackTrace</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.net.ServerSocket;</span><br><span class="line"><span class="keyword">import</span> java.net.Socket;</span><br><span class="line"><span class="keyword">import</span> java.nio.charset.StandardCharsets;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FileServer</span> {</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> ServerSocket serverSocket = <span class="keyword">new</span> <span class="built_in">ServerSocket</span>(<span class="number">9999</span>);</span><br><span class="line"> Socket accept = serverSocket.<span class="built_in">accept</span>();</span><br><span class="line"> InputStream inputStream = accept.<span class="built_in">getInputStream</span>();</span><br><span class="line"> FileOutputStream fileOutputStream = <span class="keyword">new</span> <span class="built_in">FileOutputStream</span>(<span class="string">"receive.png"</span>);</span><br><span class="line"> <span class="keyword">byte</span>[] buffer = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">int</span> len;</span><br><span class="line"> <span class="keyword">while</span> ((len = inputStream.<span class="built_in">read</span>(buffer)) != <span class="number">-1</span>) {</span><br><span class="line"> fileOutputStream.<span class="built_in">write</span>(buffer, <span class="number">0</span>, len);</span><br><span class="line"> }</span><br><span class="line"> OutputStream outputStream = accept.<span class="built_in">getOutputStream</span>();</span><br><span class="line"> outputStream.<span class="built_in">write</span>(<span class="string">"服务端接收成功..."</span>.<span class="built_in">getBytes</span>(StandardCharsets.UTF_8));</span><br><span class="line"> outputStream.<span class="built_in">close</span>();</span><br><span class="line"> fileOutputStream.<span class="built_in">close</span>();</span><br><span class="line"> inputStream.<span class="built_in">close</span>();</span><br><span class="line"> accept.<span class="built_in">close</span>();</span><br><span class="line"> serverSocket.<span class="built_in">close</span>();</span><br><span class="line"> } <span class="built_in"><span class="keyword">catch</span></span> (IOException e) {</span><br><span class="line"> e.<span class="built_in">printStackTrace</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="UDP-发送消息"><a href="#UDP-发送消息" class="headerlink" title="UDP 发送消息"></a>UDP 发送消息</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.net.*;</span><br><span class="line"><span class="keyword">import</span> java.nio.charset.StandardCharsets;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UDPSend</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> DatagramSocket datagramSocket = <span class="keyword">new</span> DatagramSocket();</span><br><span class="line"> String msg = <span class="string">"发送消息..."</span>;</span><br><span class="line"> DatagramPacket datagramPacket = <span class="keyword">new</span> DatagramPacket(msg.getBytes(StandardCharsets.UTF_8), <span class="number">0</span>, msg.getBytes(StandardCharsets.UTF_8).length, InetAddress.getByName(<span class="string">"127.0.0.1"</span>), <span class="number">9999</span>);</span><br><span class="line"> datagramSocket.send(datagramPacket);</span><br><span class="line"> datagramSocket.close();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.net.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UDPReceive</span> {</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> DatagramSocket datagramSocket = <span class="keyword">new</span> <span class="built_in">DatagramSocket</span>(<span class="number">9999</span>, InetAddress.<span class="built_in">getByName</span>(<span class="string">"127.0.0.1"</span>));</span><br><span class="line"> <span class="keyword">byte</span>[] buffer = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> DatagramPacket datagramPacket = <span class="keyword">new</span> <span class="built_in">DatagramPacket</span>(buffer, <span class="number">0</span>, buffer.length);</span><br><span class="line"> datagramSocket.<span class="built_in">receive</span>(datagramPacket);</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="keyword">new</span> <span class="built_in"><span class="keyword">String</span></span>(buffer, <span class="number">0</span>, datagramPacket.<span class="built_in">getLength</span>())); <span class="comment">//不能直接使用 datagramPacket.getData(),因为未赋值的位数全是0。</span></span><br><span class="line"> } <span class="built_in"><span class="keyword">catch</span></span> (IOException e) {</span><br><span class="line"> e.<span class="built_in">printStackTrace</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="UDP-实现聊天"><a href="#UDP-实现聊天" class="headerlink" title="UDP 实现聊天"></a>UDP 实现聊天</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.BufferedReader;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStreamReader;</span><br><span class="line"><span class="keyword">import</span> java.net.*;</span><br><span class="line"><span class="keyword">import</span> java.nio.charset.StandardCharsets;</span><br><span class="line"></span><br><span class="line"><span class="comment">//发送消息</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ChatSend</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"> DatagramSocket datagramSocket;</span><br><span class="line"> BufferedReader reader;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> fromPort;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> toPort;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">ChatSend</span><span class="params">(<span class="keyword">int</span> fromPort, <span class="keyword">int</span> toPort)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.fromPort = fromPort;</span><br><span class="line"> <span class="keyword">this</span>.toPort = toPort;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">this</span>.datagramSocket = <span class="keyword">new</span> DatagramSocket(fromPort);</span><br><span class="line"> reader = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(System.in));</span><br><span class="line"> } <span class="keyword">catch</span> (SocketException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> String s = reader.readLine();</span><br><span class="line"> <span class="keyword">byte</span>[] data = s.getBytes(StandardCharsets.UTF_8);</span><br><span class="line"> DatagramPacket datagramPacket = <span class="keyword">new</span> DatagramPacket(data, <span class="number">0</span>, data.length, <span class="keyword">new</span> InetSocketAddress(<span class="string">"localhost"</span>, <span class="keyword">this</span>.toPort));</span><br><span class="line"> datagramSocket.send(datagramPacket);</span><br><span class="line"> <span class="keyword">if</span> (<span class="string">"bye"</span>.equals(s)) {</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.net.DatagramPacket;</span><br><span class="line"><span class="keyword">import</span> java.net.DatagramSocket;</span><br><span class="line"><span class="keyword">import</span> java.net.SocketException;</span><br><span class="line"></span><br><span class="line"><span class="comment">//接收消息</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ChatReceive</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"> DatagramSocket datagramSocket;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> String from;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> port;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">ChatReceive</span><span class="params">(String from, <span class="keyword">int</span> port)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.from = from;</span><br><span class="line"> <span class="keyword">this</span>.port = port;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">this</span>.datagramSocket = <span class="keyword">new</span> DatagramSocket(port);</span><br><span class="line"> } <span class="keyword">catch</span> (SocketException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">byte</span>[] cache = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> DatagramPacket datagramPacket = <span class="keyword">new</span> DatagramPacket(cache, <span class="number">0</span>, cache.length);</span><br><span class="line"> datagramSocket.receive(datagramPacket);</span><br><span class="line"> String receiveData = <span class="keyword">new</span> String(datagramPacket.getData(), <span class="number">0</span>, datagramPacket.getLength());</span><br><span class="line"> System.out.println(from + <span class="string">":"</span> + receiveData);</span><br><span class="line"> <span class="keyword">if</span> (<span class="string">"bye"</span>.equals(receiveData)) {</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight haxe"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ChatServer</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> void main(<span class="keyword">String</span>[] args) {</span><br><span class="line"> <span class="keyword">new</span> <span class="type">Thread</span>(<span class="keyword">new</span> <span class="type">ChatSend</span>(<span class="number">6666</span>, <span class="number">7777</span>)).start();</span><br><span class="line"> <span class="keyword">new</span> <span class="type">Thread</span>(<span class="keyword">new</span> <span class="type">ChatReceive</span>(<span class="string">"客户端"</span>, <span class="number">8888</span>)).start();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight haxe"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ChatClient</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> void main(<span class="keyword">String</span>[] args) {</span><br><span class="line"> <span class="keyword">new</span> <span class="type">Thread</span>(<span class="keyword">new</span> <span class="type">ChatSend</span>(<span class="number">9999</span>, <span class="number">8888</span>)).start();</span><br><span class="line"> <span class="keyword">new</span> <span class="type">Thread</span>(<span class="keyword">new</span> <span class="type">ChatReceive</span>(<span class="string">"服务端"</span>, <span class="number">7777</span>)).start();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="下载网络资源"><a href="#下载网络资源" class="headerlink" title="下载网络资源"></a>下载网络资源</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.FileOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.net.HttpURLConnection;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Download</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> URL url = <span class="keyword">new</span> URL(<span class="string">"https://guest997.ml/wp-content/themes/Sakurairo-2.1.1.1/homepage.mp4"</span>);</span><br><span class="line"> HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();</span><br><span class="line"> urlConnection.setRequestProperty(<span class="string">"User-Agent"</span>, <span class="string">"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"</span>);</span><br><span class="line"> InputStream inputStream = urlConnection.getInputStream();</span><br><span class="line"> FileOutputStream fos = <span class="keyword">new</span> FileOutputStream(<span class="string">"homepage.mp4"</span>);</span><br><span class="line"> <span class="keyword">byte</span>[] buffer = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">int</span> len;</span><br><span class="line"> <span class="keyword">while</span> ((len = inputStream.read(buffer)) != -<span class="number">1</span>) {</span><br><span class="line"> fos.write(buffer, <span class="number">0</span>, len);</span><br><span class="line"> }</span><br><span class="line"> fos.close();</span><br><span class="line"> inputStream.close();</span><br><span class="line"> urlConnection.disconnect();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="TCP-连接测试"><a href="#TCP-连接测试" class="headerlink" title="TCP 连接测试"></a>TCP 连接测试</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.OutputStream;</span><br><span class="line"><span class="keyword">import</span> java.net.InetAddress;</span><br><span class="line"><span class="keyword">import</span> java.net.Socket;</span><br><span class="line"><span class="keyword">import</span> java.nio.charset.StandardCharsets;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TCPClient</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"> Socket socket = <span class="keyword">null</span>;</span><br><span class="line"> OutputStream outputStream = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> <span class="comment">//发送信息</span></span><br><span class="line"> socket = <span class="keyword">new</span> Socket(InetAddress.getByName(<span class="string">&quot;localhost&quot;</span>), <span class="number">9999</span>);</span><br><span class="line"> outputStream = socket.getOutputStream();</span><br><span class="line"> outputStream.write(<span class="string">&quot;客户端发送信息...&quot;</span>.getBytes(StandardCharsets.UTF_8));</span><br><span class="line"> &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line"> <span class="keyword">if</span> (outputStream != <span class="keyword">null</span>) &#123;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> outputStream.close();</span><br><span class="line"> &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">if</span> (socket != <span class="keyword">null</span>) &#123;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> socket.close();</span><br><span class="line"> &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.net.ServerSocket;</span><br><span class="line"><span class="keyword">import</span> java.net.Socket;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TCPServer</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"> ServerSocket serverSocket = <span class="keyword">null</span>;</span><br><span class="line"> Socket accept = <span class="keyword">null</span>;</span><br><span class="line"> InputStream inputStream = <span class="keyword">null</span>;</span><br><span class="line"> ByteArrayOutputStream byteArrayOutputStream = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> <span class="comment">//创建连接</span></span><br><span class="line"> serverSocket = <span class="keyword">new</span> ServerSocket(<span class="number">9999</span>);</span><br><span class="line"> <span class="comment">//等待客户端请求</span></span><br><span class="line"> accept = serverSocket.accept();</span><br><span class="line"> <span class="comment">//读取用户信息</span></span><br><span class="line"> inputStream = accept.getInputStream();</span><br><span class="line"> <span class="comment">//管道流接收和打印</span></span><br><span class="line"> byteArrayOutputStream = <span class="keyword">new</span> ByteArrayOutputStream();</span><br><span class="line"> <span class="keyword">byte</span>[] bytes = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">int</span> len = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> ((len = inputStream.read(bytes)) != -<span class="number">1</span>) &#123;</span><br><span class="line"> byteArrayOutputStream.write(bytes, <span class="number">0</span>, len);</span><br><span class="line"> &#125;</span><br><span class="line"> System.out.println(byteArrayOutputStream);</span><br><span class="line"> &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line"> <span class="keyword">if</span> (byteArrayOutputStream != <span class="keyword">null</span>) &#123;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> byteArrayOutputStream.close();</span><br><span class="line"> &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">if</span> (inputStream != <span class="keyword">null</span>) &#123;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> inputStream.close();</span><br><span class="line"> &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">if</span> (accept != <span class="keyword">null</span>) &#123;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> accept.close();</span><br><span class="line"> &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">if</span> (serverSocket != <span class="keyword">null</span>) &#123;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> serverSocket.close();</span><br><span class="line"> &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="TCP-文件上传"><a href="#TCP-文件上传" class="headerlink" title="TCP 文件上传"></a>TCP 文件上传</h2><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.net.InetAddress;</span><br><span class="line"><span class="keyword">import</span> java.net.Socket;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FileClient</span> &#123;</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>&#123;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> Socket socket = <span class="keyword">new</span> <span class="built_in">Socket</span>(InetAddress.<span class="built_in">getByName</span>(<span class="string">&quot;localhost&quot;</span>), <span class="number">9999</span>);</span><br><span class="line"> OutputStream outputStream = socket.<span class="built_in">getOutputStream</span>();</span><br><span class="line"> FileInputStream fileInputStream = <span class="keyword">new</span> <span class="built_in">FileInputStream</span>(<span class="string">&quot;pc.png&quot;</span>);</span><br><span class="line"> <span class="keyword">byte</span>[] buffer = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">int</span> len;</span><br><span class="line"> <span class="keyword">while</span> ((len = fileInputStream.<span class="built_in">read</span>(buffer)) != <span class="number">-1</span>) &#123;</span><br><span class="line"> outputStream.<span class="built_in">write</span>(buffer, <span class="number">0</span>, len);</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="comment">//通知服务器文件已发送完毕</span></span><br><span class="line"> socket.<span class="built_in">shutdownOutput</span>();</span><br><span class="line"> <span class="comment">//确定服务端接收完毕,才断开连接。</span></span><br><span class="line"> InputStream inputStream = socket.<span class="built_in">getInputStream</span>();</span><br><span class="line"> <span class="keyword">byte</span>[] buffer2 = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">int</span> len2;</span><br><span class="line"> ByteArrayOutputStream byteArrayOutputStream = <span class="keyword">new</span> <span class="built_in">ByteArrayOutputStream</span>();</span><br><span class="line"> <span class="keyword">while</span> ((len2 = inputStream.<span class="built_in">read</span>(buffer2)) != <span class="number">-1</span>) &#123;</span><br><span class="line"> byteArrayOutputStream.<span class="built_in">write</span>(buffer2, <span class="number">0</span>, len2);</span><br><span class="line"> &#125;</span><br><span class="line"> System.out.<span class="built_in">println</span>(byteArrayOutputStream);</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">&quot;客户端断开连接...&quot;</span>);</span><br><span class="line"> byteArrayOutputStream.<span class="built_in">close</span>();</span><br><span class="line"> inputStream.<span class="built_in">close</span>();</span><br><span class="line"> outputStream.<span class="built_in">close</span>();</span><br><span class="line"> fileInputStream.<span class="built_in">close</span>();</span><br><span class="line"> socket.<span class="built_in">close</span>();</span><br><span class="line"> &#125; <span class="built_in"><span class="keyword">catch</span></span> (IOException e) &#123;</span><br><span class="line"> e.<span class="built_in">printStackTrace</span>();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="javase" scheme="http://guest997.tk/tags/javase/"/>
</entry>
<entry>
<title>JavaSE 进阶(二十一)</title>
<link href="http://guest997.tk/2022/04/03/javase-advanced21/"/>
<id>http://guest997.tk/2022/04/03/javase-advanced21/</id>
<published>2022-04-03T12:14:41.000Z</published>
<updated>2022-07-28T14:57:40.429Z</updated>
<content type="html"><![CDATA[<h2 id="计算机网络"><a href="#计算机网络" class="headerlink" title="计算机网络"></a>计算机网络</h2><p>计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备通过通信线路连接起来,在网络操作系统、网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。</p><h2 id="网络模型"><a href="#网络模型" class="headerlink" title="网络模型"></a>网络模型</h2><p><img data-src="/images/javase-advanced21.md-0.png"></p><h2 id="IP-地址"><a href="#IP-地址" class="headerlink" title="IP 地址"></a>IP 地址</h2><p>IP 地址是 IP 协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。</p><p>IPv4 地址是一个32位的二进制数,被分割为4个8位二进制数(也就是4个字节)。IPv4 地址通常用点分十进制表示成(a.b.c.d)的形式,其中,a、b、c、d 都是0~255之间的十进制整数。</p><p>IPv6 地址有128位长,IPv6 的128位地址通常写成8组,每组为四个十六进制数的形式。</p><h3 id="分类"><a href="#分类" class="headerlink" title="分类"></a>分类</h3><p>IP 地址分为五类,A 类保留给政府机构,B 类分配给中等规模的公司,C 类分配给任何需要的人,D 类用于组播,E 类用于实验,各类可容纳的地址数目不同。</p><p><img data-src="/images/javase-advanced21.md-1.jpg"></p><p>网络号用于识别主机所在的网络,主机号用于识别该网络中的主机。</p><h3 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.net.InetAddress;</span><br><span class="line"><span class="keyword">import</span> java.net.UnknownHostException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">InetAddressTest</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> UnknownHostException </span>{</span><br><span class="line"> <span class="comment">//常用方法</span></span><br><span class="line"> InetAddress address = InetAddress.getByName(<span class="string">"guest997.ml"</span>);</span><br><span class="line"> System.out.println(address.getHostAddress());</span><br><span class="line"> System.out.println(address.getHostName());</span><br><span class="line"> System.out.println(address.getCanonicalHostName());</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">104.21.84.129</span></span><br><span class="line"><span class="comment">guest997.ml</span></span><br><span class="line"><span class="comment">104.21.84.129</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h2 id="网络端口"><a href="#网络端口" class="headerlink" title="网络端口"></a>网络端口</h2><p>一般是指 TCP/IP 协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于 FTP 服务的21端口等等。在单个协议下端口号不能冲突。</p><h3 id="分类-1"><a href="#分类-1" class="headerlink" title="分类"></a>分类</h3><ul><li> 共有端口:0 - 1023</li><li> HTTP:80</li><li> HTTPS:443</li><li> FTP:21</li><li> Telent:23</li><li> 程序注册端口:1024 - 49151</li><li> Tomcat:8080</li><li> MySQL:3306</li><li> Oracle:1521</li><li> 动态或私有端口:49152 - 65535</li></ul><h2 id="通信协议"><a href="#通信协议" class="headerlink" title="通信协议"></a>通信协议</h2><p>通信协议是指双方实体完成通信或服务所必须遵循的规则和约定。交流什么、怎样交流及何时交流,都必须遵循某种互相都能接受的规则。这个规则就是通信协议。</p><ul><li> TCP:用户传输协议</li><li> UDP:用户数据报协议</li><li> IP:网络互连协议</li></ul><h3 id="TCP"><a href="#TCP" class="headerlink" title="TCP"></a>TCP</h3><h4 id="三次握手"><a href="#三次握手" class="headerlink" title="三次握手"></a>三次握手</h4><p>三次握手其实就是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上,其实就是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。</p><p><img data-src="/images/javase-advanced21.md-2.png"></p><ul><li> 第一次握手:客户端发包,服务端收到了。服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。</li><li> 第二次握手:服务端发包,客户端收到了。客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。<strong>不过此时服务器并不能确认客户端的接收能力是否正常。</strong></li><li> 第三次握手:客户端发包,服务端收到了。服务端就能得出结论:客户端的接收、发送能力正常,服务端的发送、接收能力也正常。</li></ul><h4 id="为什么需要三次握手,两次不行吗?"><a href="#为什么需要三次握手,两次不行吗?" class="headerlink" title="为什么需要三次握手,两次不行吗?"></a>为什么需要三次握手,两次不行吗?</h4><p>如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接。</p><p>客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在<strong>某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端</strong>,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,此时客户端收到服务端发来的确认,也没有数据可发送,则服务端一直等待客户端发送数据,浪费资源。</p><h4 id="四次挥手"><a href="#四次挥手" class="headerlink" title="四次挥手"></a>四次挥手</h4><p>终止一个连接要经过四次挥手。这是由于 TCP 的半关闭造成的。所谓的半关闭,其实就是 TCP 提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。TCP 连接的拆除需要发送四个包,因此称为四次挥手,客户端或服务端均可主动发起挥手动作。</p><ol><li> A 发送断开请求。(需要等待 B 的回复,不然 B 未收到消息,就单方面的断开有点不负责任。超时重传)</li><li> B 收到请求并回复 A。(B 收到请求后,很伤心,但是没有办法,只能断开连接,但是 B 是被动的接收断开,所以需要通知其应用程序做关闭准备)</li><li> B 这边准备完了,通知 A 可以断开了。</li><li> A 回复 B,我收到消息了,那就断开连接吧。</li></ol><h4 id="为什么建立连接是三次握手,而关闭连接却是四次挥手呢?"><a href="#为什么建立连接是三次握手,而关闭连接却是四次挥手呢?" class="headerlink" title="为什么建立连接是三次握手,而关闭连接却是四次挥手呢?"></a>为什么建立连接是三次握手,而关闭连接却是四次挥手呢?</h4><p>这是因为服务端在 LISTEN 状态下,收到建立连接请求的 SYN 报文后,把 ACK 和 SYN 放在一个报文里发送给客户端。其中,<strong>ACK 报文是用来应答的,SYN 报文是用来同步的</strong>。但是关闭连接时,当服务端收到 FIN 报文时,很可能并不会立即关闭 SOCKET,所以只能先回复一个 ACK 报文,告诉客户端:你发的 FIN 报文我收到了。只有等到我服务端所有的报文都发送完了,我才能发送 FIN 报文,因此不能一起发送。故需要四次挥手。</p>]]></content>
<summary type="html"><h2 id="计算机网络"><a href="#计算机网络" class="headerlink" title="计算机网络"></a>计算机网络</h2><p>计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备通过通信线路连接起来,在网络操作系统、网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。</p>
<h2 id="网络模型"><a href="#网络模型" class="headerlink" title="网络模型"></a>网络模型</h2><p><img data-src="/images/javase-advanced21.md-0.png"></p>
<h2 id="IP-地址"><a href="#IP-地址" class="headerlink" title="IP 地址"></a>IP 地址</h2></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="javase" scheme="http://guest997.tk/tags/javase/"/>
</entry>
<entry>
<title>JavaSE 进阶(二十)</title>
<link href="http://guest997.tk/2022/04/02/javase-advanced20/"/>
<id>http://guest997.tk/2022/04/02/javase-advanced20/</id>
<published>2022-04-02T03:28:36.000Z</published>
<updated>2022-07-28T14:57:32.180Z</updated>
<content type="html"><![CDATA[<h2 id="死锁"><a href="#死锁" class="headerlink" title="死锁"></a>死锁</h2><p>多个线程各自占有一些共享资源,并且互相等待别的线程占有的资源才能运行,这就出现了两个或多个线程都在等待对方释放资源,线程都停止执行的情形。</p><h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeadLock</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> Trade(<span class="number">0</span>, <span class="string">"admin "</span>)).start();</span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> Trade(<span class="number">1</span>, <span class="string">"guest "</span>)).start();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//钱</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Money</span> </span>{</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//货</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Goods</span> </span>{</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Trade</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">//用 static 来保证资源只有一份,</span></span><br><span class="line"> <span class="keyword">static</span> Money money = <span class="keyword">new</span> Money();</span><br><span class="line"> <span class="keyword">static</span> Goods goods = <span class="keyword">new</span> Goods();</span><br><span class="line"> <span class="keyword">int</span> choice; <span class="comment">//选择</span></span><br><span class="line"> String person; <span class="comment">//交易的人</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Trade</span><span class="params">(<span class="keyword">int</span> choice, String person)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.choice = choice;</span><br><span class="line"> <span class="keyword">this</span>.person = person;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (choice == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">synchronized</span> (money) {</span><br><span class="line"> System.out.println(<span class="keyword">this</span>.person + <span class="string">"获得钱"</span>);</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>); <span class="comment">//加个线程休眠是怕当前线程一下子就把两个锁都拿走了。</span></span><br><span class="line"> <span class="keyword">synchronized</span> (goods) {</span><br><span class="line"> System.out.println(<span class="keyword">this</span>.person + <span class="string">"获得货"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">synchronized</span> (goods) {</span><br><span class="line"> System.out.println(<span class="keyword">this</span>.person + <span class="string">"获得货"</span>);</span><br><span class="line"> Thread.sleep(<span class="number">2000</span>);</span><br><span class="line"> <span class="keyword">synchronized</span> (money) {</span><br><span class="line"> System.out.println(<span class="keyword">this</span>.person + <span class="string">"获得钱"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">admin 获得钱</span></span><br><span class="line"><span class="comment">guest 获得货</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>运行上面的代码后会发现程序卡住了,两个人都想要获取对方锁住的资源,然而谁都没有想要释放自己的锁,导致两个锁一直无法释放,程序自然就无法继续运行下去了。</p><h3 id="改造案例"><a href="#改造案例" class="headerlink" title="改造案例"></a>改造案例</h3><figure class="highlight d"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> run() {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">if</span> (choice == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">synchronized</span> (money) {</span><br><span class="line"> System.<span class="keyword">out</span>.println(<span class="keyword">this</span>.person + <span class="string">"获得钱"</span>);</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">synchronized</span> (goods) {</span><br><span class="line"> System.<span class="keyword">out</span>.println(<span class="keyword">this</span>.person + <span class="string">"获得货"</span>);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">synchronized</span> (goods) {</span><br><span class="line"> System.<span class="keyword">out</span>.println(<span class="keyword">this</span>.person + <span class="string">"获得货"</span>);</span><br><span class="line"> Thread.sleep(<span class="number">2000</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">synchronized</span> (money) {</span><br><span class="line"> System.<span class="keyword">out</span>.println(<span class="keyword">this</span>.person + <span class="string">"获得钱"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">admin 获得钱</span></span><br><span class="line"><span class="comment">guest 获得货</span></span><br><span class="line"><span class="comment">admin 获得货</span></span><br><span class="line"><span class="comment">guest 获得钱</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>只要不让任何一个线程同时拥有两个锁即可,当运行完自己的同步代码块后就会释放锁,这样程序就能继续运行下去了。</p><h3 id="避免方法"><a href="#避免方法" class="headerlink" title="避免方法"></a>避免方法</h3><p>产生死锁的四个必要条件:</p><ul><li> 互斥条件:一个资源每次只能被一个进程使用。</li><li> 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。</li><li> 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。</li><li> 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。</li></ul><p>只要想办法破坏其中的任意一个或多个条件,就可以避免死锁发生。</p><h2 id="Lock-锁"><a href="#Lock-锁" class="headerlink" title="Lock 锁"></a>Lock 锁</h2><p>java.util.concurrent.locks.Lock 接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对 Lock 对象加锁,线程开始访问共享资源之前应先获得 Lock 对象。<br>比较常用的是 Reentrantlock 类,它实现了 Lock 接口,拥有与 synchronized 相同的并发性和内存语义,在实现线程安全的控制中,可以显式加锁和解锁。</p><h3 id="买票案例"><a href="#买票案例" class="headerlink" title="买票案例"></a>买票案例</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LockTest</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> tickets = <span class="number">10</span>;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> ReentrantLock lock = <span class="keyword">new</span> ReentrantLock(); <span class="comment">//定义 Lock 锁,ReentrantLock 是一个可重入锁。</span></span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"> lock.lock(); <span class="comment">//加锁</span></span><br><span class="line"> <span class="keyword">if</span> (tickets > <span class="number">0</span>) {</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"拿到了第"</span> + tickets-- + <span class="string">"张票"</span>);</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>); <span class="comment">//模拟延时能够扩大问题的发生性</span></span><br><span class="line"> lock.unlock(); <span class="comment">//解锁</span></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> lock.unlock(); <span class="comment">//解锁</span></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> LockTest lockTest = <span class="keyword">new</span> LockTest();</span><br><span class="line"> <span class="keyword">new</span> Thread(lockTest, <span class="string">"01"</span>).start();</span><br><span class="line"> <span class="keyword">new</span> Thread(lockTest, <span class="string">"02"</span>).start();</span><br><span class="line"> <span class="keyword">new</span> Thread(lockTest, <span class="string">"03"</span>).start();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">01拿到了第10张票</span></span><br><span class="line"><span class="comment">01拿到了第9张票</span></span><br><span class="line"><span class="comment">01拿到了第8张票</span></span><br><span class="line"><span class="comment">01拿到了第7张票</span></span><br><span class="line"><span class="comment">01拿到了第6张票</span></span><br><span class="line"><span class="comment">02拿到了第5张票</span></span><br><span class="line"><span class="comment">02拿到了第4张票</span></span><br><span class="line"><span class="comment">02拿到了第3张票</span></span><br><span class="line"><span class="comment">02拿到了第2张票</span></span><br><span class="line"><span class="comment">03拿到了第1张票</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>使用 Lock 锁,JVM 将花费较少的时间来调度线程,性能更好,并且具有更好的扩展性(提供更多的子类)。</p><h2 id="线程通信(生产者消费者案例)"><a href="#线程通信(生产者消费者案例)" class="headerlink" title="线程通信(生产者消费者案例)"></a>线程通信(生产者消费者案例)</h2><p>对于生产者,没有生产产品之前,要通知消费者等待。而生产了产品之后,又需要马上通知消费者消费。<br>对于消费者,在消费之后,要通知生产者已经结束消费,需要生产新的产品以供消费。</p><p>这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件。</p><p>在生产者消费者问题中,仅有 synchronized 是不够的。synchronized 可阻止并发更新同一个共享资源,实现了同步。<br>但 synchronized 不能用来实现不同线程之间的消息传递(通信)。</p><h3 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h3><p>方法名</p><p>作用</p><p>wait()</p><p>表示线程一直等待,直到其它线程通知,与 sleep 不同,会释放锁。</p><p>notify()</p><p>唤醒一个处于等待状态的线程。</p><p>notifyAll()</p><p>唤醒同个对象上所有调用 wait 方法的线程,优先级别高的线程优先调度。</p><h3 id="管程法"><a href="#管程法" class="headerlink" title="管程法"></a>管程法</h3><p><img data-src="pc.png" alt="pc"></p><ul><li> 生产者:负责生产数据的模块(可能是方法、对象、线程或进程)</li><li> 消费者:负责处理数据的模块(可能是方法、对象、线程或进程)</li><li> 缓存区:消费者不能直接使用生产者的数据,生产者将生产好的数据放入缓存区,消费者从缓存区拿出数据。</li></ul><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> CommunicationTest01 {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> main(String[] args) <span class="keyword">throws</span> InterruptedException {</span><br><span class="line"> CacheArea cacheArea = <span class="keyword">new</span> CacheArea();</span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> Producer(cacheArea), <span class="string">"生产者"</span>).start();</span><br><span class="line"> Thread.sleep(<span class="number">3000</span>); <span class="comment">//配合下面生产者的循环,模拟缓存区爆满的情况。</span></span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> Consumer(cacheArea), <span class="string">"消费者"</span>).start();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Product {</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> id;</span><br><span class="line"></span><br><span class="line"> Product(<span class="keyword">int</span> id) {</span><br><span class="line"> <span class="keyword">this</span>.id = id;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">int</span> getId() {</span><br><span class="line"> <span class="keyword">return</span> id;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> setId(<span class="keyword">int</span> id) {</span><br><span class="line"> <span class="keyword">this</span>.id = id;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Producer <span class="keyword">implements</span> Runnable {</span><br><span class="line"> <span class="keyword">private</span> CacheArea cacheArea;</span><br><span class="line"></span><br><span class="line"> Producer(CacheArea cacheArea) {</span><br><span class="line"> <span class="keyword">this</span>.cacheArea = cacheArea;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> run() {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">11</span>; i++) { <span class="comment">//模拟缓存区产品爆满的情况</span></span><br><span class="line"> cacheArea.<span class="keyword">push</span>(<span class="keyword">new</span> Product(i));</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.sleep(<span class="number">100</span>); <span class="comment">//生产延时</span></span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> Consumer <span class="keyword">implements</span> Runnable {</span><br><span class="line"> <span class="keyword">private</span> CacheArea cacheArea;</span><br><span class="line"></span><br><span class="line"> Consumer(CacheArea cacheArea) {</span><br><span class="line"> <span class="keyword">this</span>.cacheArea = cacheArea;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> run() {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">11</span>; i++) { <span class="comment">//模拟缓存区产品不足的情况</span></span><br><span class="line"> cacheArea.<span class="keyword">pop</span>();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.sleep(<span class="number">100</span>); <span class="comment">//消费延时</span></span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> CacheArea {</span><br><span class="line"> <span class="comment">//容器大小</span></span><br><span class="line"> Product[] products = <span class="keyword">new</span> Product[<span class="number">10</span>];</span><br><span class="line"> <span class="comment">//容器计数器</span></span><br><span class="line"> <span class="keyword">int</span> <span class="keyword">count</span> = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//生产者放入产品</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="keyword">push</span>(Product product) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">count</span> == products.length) { <span class="comment">//如果容器满了,需要等待消费者消费。</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="string">"缓存区已经满了"</span>);</span><br><span class="line"> <span class="keyword">this</span>.wait(<span class="number">1000</span>); <span class="comment">//当前线程等待超过1秒时则被唤醒继续执行下面的代码</span></span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//缓存区产品爆满时的处理</span></span><br><span class="line"> <span class="keyword">int</span> flag = <span class="keyword">count</span> + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (flag > products.length) {</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="string">"由于指定时间内始终无消费者进行消费,等待超时,所以停止生产。"</span>);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//放入产品</span></span><br><span class="line"> products[<span class="keyword">count</span>] = product;</span><br><span class="line"> <span class="keyword">count</span>++;</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="string">"生产了第"</span> + product.getId() + <span class="string">"个产品"</span>);</span><br><span class="line"> <span class="keyword">this</span>.notifyAll(); <span class="comment">//当前线程通知消费者消费</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//消费者取出产品</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="keyword">pop</span>() {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">count</span> == <span class="number">0</span>) { <span class="comment">//如果容器空了,需要等待生产者生产。</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="string">"缓存区已经空了"</span>);</span><br><span class="line"> <span class="keyword">this</span>.wait(<span class="number">1000</span>); <span class="comment">//当前线程等待超过1秒时则被唤醒继续执行下面的代码</span></span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//缓存区产品不足时的处理</span></span><br><span class="line"> <span class="keyword">int</span> flag = <span class="keyword">count</span> - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (flag < <span class="number">0</span>) {</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="string">"由于指定时间内始终无生产者进行生产,等待超时,判断生产者已停止生产,请下次再来。"</span>);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//取出产品</span></span><br><span class="line"> <span class="keyword">count</span>--;</span><br><span class="line"> Product product = products[<span class="keyword">count</span>];</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="string">"消费了第"</span> + product.getId() + <span class="string">"个产品"</span>);</span><br><span class="line"> <span class="keyword">this</span>.notifyAll(); <span class="comment">//当前线程通知生产者生产</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">生产了第1个产品</span></span><br><span class="line"><span class="comment">生产了第2个产品</span></span><br><span class="line"><span class="comment">生产了第3个产品</span></span><br><span class="line"><span class="comment">生产了第4个产品</span></span><br><span class="line"><span class="comment">生产了第5个产品</span></span><br><span class="line"><span class="comment">生产了第6个产品</span></span><br><span class="line"><span class="comment">生产了第7个产品</span></span><br><span class="line"><span class="comment">生产了第8个产品</span></span><br><span class="line"><span class="comment">生产了第9个产品</span></span><br><span class="line"><span class="comment">生产了第10个产品</span></span><br><span class="line"><span class="comment">缓存区已经满了</span></span><br><span class="line"><span class="comment">由于指定时间内始终无消费者进行消费,等待超时,所以停止生产。</span></span><br><span class="line"><span class="comment">消费了第10个产品</span></span><br><span class="line"><span class="comment">消费了第9个产品</span></span><br><span class="line"><span class="comment">消费了第8个产品</span></span><br><span class="line"><span class="comment">消费了第7个产品</span></span><br><span class="line"><span class="comment">消费了第6个产品</span></span><br><span class="line"><span class="comment">消费了第5个产品</span></span><br><span class="line"><span class="comment">消费了第4个产品</span></span><br><span class="line"><span class="comment">消费了第3个产品</span></span><br><span class="line"><span class="comment">消费了第2个产品</span></span><br><span class="line"><span class="comment">消费了第1个产品</span></span><br><span class="line"><span class="comment">缓存区已经空了</span></span><br><span class="line"><span class="comment">由于指定时间内始终无生产者进行生产,等待超时,判断生产者已停止生产,请下次再来。</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p><strong>注意:同步方法要放在缓存区里,否则加的锁在两个线程中没有交点是不会相互唤醒的。</strong></p><h3 id="信号灯法"><a href="#信号灯法" class="headerlink" title="信号灯法"></a>信号灯法</h3><p>顾名思义,信号灯是用来在生产者与消费者之间传递信号的一个旗帜。当生产者或消费者线程完成自己的工作,等待另一个线程进行时,便会将信号值修改用以告诉另一者:我的事情做完了,该你了。而另一者获取信号的变化后便会做出对应的行为。在这个过程中,信号值一直被反复更改,直到所有线程均执行完毕。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CommunicationTest02</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> Pc pc = <span class="keyword">new</span> Pc();</span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> Pd(pc),<span class="string">"生产者"</span>).start();</span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> Cs(pc),<span class="string">"消费者"</span>).start();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//产品</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Pc</span> </span>{</span><br><span class="line"> <span class="keyword">boolean</span> flag = <span class="keyword">true</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">push</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!flag) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">this</span>.wait();</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> System.out.println(<span class="string">"产品生产出来了,可消费。"</span>);</span><br><span class="line"> flag = !flag;</span><br><span class="line"> <span class="keyword">this</span>.notifyAll();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">pop</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (flag) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">this</span>.wait();</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> System.out.println(<span class="string">"产品消费完了,请生产。"</span>);</span><br><span class="line"> flag = !flag;</span><br><span class="line"> <span class="keyword">this</span>.notifyAll();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//生产者</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Pd</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Pc pc;</span><br><span class="line"></span><br><span class="line"> Pd(Pc pc) {</span><br><span class="line"> <span class="keyword">this</span>.pc = pc;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"> pc.push();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//消费者</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cs</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Pc pc;</span><br><span class="line"></span><br><span class="line"> Cs(Pc pc) {</span><br><span class="line"> <span class="keyword">this</span>.pc = pc;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="keyword">true</span>) {</span><br><span class="line"> pc.pop();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">产品生产出来了,可消费。</span></span><br><span class="line"><span class="comment">产品消费完了,请生产。</span></span><br><span class="line"><span class="comment">产品生产出来了,可消费。</span></span><br><span class="line"><span class="comment">产品消费完了,请生产。</span></span><br><span class="line"><span class="comment">产品生产出来了,可消费。</span></span><br><span class="line"><span class="comment">产品消费完了,请生产。</span></span><br><span class="line"><span class="comment">产品生产出来了,可消费。</span></span><br><span class="line"><span class="comment">产品消费完了,请生产。</span></span><br><span class="line"><span class="comment">产品生产出来了,可消费。</span></span><br><span class="line"><span class="comment">产品消费完了,请生产。</span></span><br><span class="line"><span class="comment">...</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h2 id="线程池"><a href="#线程池" class="headerlink" title="线程池"></a>线程池</h2><p>经常创建或销毀使用量特别大的资源,比如并发情况下的线程,对性能影响很大。解决方法就是提前创建好多个线程,放入线程池中,使用时直接获取,使用完后放回池中。可以避免频繁创建和销毁线程,实现重复利用。</p><p>好处:</p><ul><li> 降低资源的消耗。线程本身是一种资源,创建和销毁线程会有 CPU 开销;创建的线程也会占用一定的内存。</li><li> 提高任务执行的响应速度。任务执行时,可以不必等到线程创建完之后再执行。</li><li> 提高线程的可管理性。线程不能无限制地创建,需要进行统一的分配、调优和监控。</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ExecutorService;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Executors;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PoolTest</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> <span class="comment">//Executors:线程池的工厂类,ExecutorService:线程池接口</span></span><br><span class="line"> ExecutorService executor = Executors.newFixedThreadPool(<span class="number">5</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++) {</span><br><span class="line"> <span class="comment">//submit() 中的参数为 Runnable 或 Callable 实例对象</span></span><br><span class="line"> executor.submit(() -> {</span><br><span class="line"> System.out.println(<span class="string">"thread id is: "</span> + Thread.currentThread().getId());</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> executor.shutdown(); <span class="comment">//关闭连接</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="死锁"><a href="#死锁" class="headerlink" title="死锁"></a>死锁</h2><p>多个线程各自占有一些共享资源,并且互相等待别的线程占有的资源才能运行,这就出现了两个或多个线程都在等待对方释放资源,线程都停止执行的情形。</p>
<h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeadLock</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> Trade(<span class="number">0</span>, <span class="string">&quot;admin &quot;</span>)).start();</span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> Trade(<span class="number">1</span>, <span class="string">&quot;guest &quot;</span>)).start();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//钱</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Money</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//货</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Goods</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Trade</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//用 static 来保证资源只有一份,</span></span><br><span class="line"> <span class="keyword">static</span> Money money = <span class="keyword">new</span> Money();</span><br><span class="line"> <span class="keyword">static</span> Goods goods = <span class="keyword">new</span> Goods();</span><br><span class="line"> <span class="keyword">int</span> choice; <span class="comment">//选择</span></span><br><span class="line"> String person; <span class="comment">//交易的人</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Trade</span><span class="params">(<span class="keyword">int</span> choice, String person)</span> </span>&#123;</span><br><span class="line"> <span class="keyword">this</span>.choice = choice;</span><br><span class="line"> <span class="keyword">this</span>.person = person;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line"> <span class="keyword">try</span> &#123;</span><br><span class="line"> <span class="keyword">if</span> (choice == <span class="number">0</span>) &#123;</span><br><span class="line"> <span class="keyword">synchronized</span> (money) &#123;</span><br><span class="line"> System.out.println(<span class="keyword">this</span>.person + <span class="string">&quot;获得钱&quot;</span>);</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>); <span class="comment">//加个线程休眠是怕当前线程一下子就把两个锁都拿走了。</span></span><br><span class="line"> <span class="keyword">synchronized</span> (goods) &#123;</span><br><span class="line"> System.out.println(<span class="keyword">this</span>.person + <span class="string">&quot;获得货&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125; <span class="keyword">else</span> &#123;</span><br><span class="line"> <span class="keyword">synchronized</span> (goods) &#123;</span><br><span class="line"> System.out.println(<span class="keyword">this</span>.person + <span class="string">&quot;获得货&quot;</span>);</span><br><span class="line"> Thread.sleep(<span class="number">2000</span>);</span><br><span class="line"> <span class="keyword">synchronized</span> (money) &#123;</span><br><span class="line"> System.out.println(<span class="keyword">this</span>.person + <span class="string">&quot;获得钱&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">admin 获得钱</span></span><br><span class="line"><span class="comment">guest 获得货</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>
<p>运行上面的代码后会发现程序卡住了,两个人都想要获取对方锁住的资源,然而谁都没有想要释放自己的锁,导致两个锁一直无法释放,程序自然就无法继续运行下去了。</p></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="javase" scheme="http://guest997.tk/tags/javase/"/>
</entry>
<entry>
<title>JavaSE 进阶(十九)</title>
<link href="http://guest997.tk/2022/04/01/javase-advanced19/"/>
<id>http://guest997.tk/2022/04/01/javase-advanced19/</id>
<published>2022-04-01T03:39:47.000Z</published>
<updated>2022-07-28T14:57:32.176Z</updated>
<content type="html"><![CDATA[<h2 id="线程同步"><a href="#线程同步" class="headerlink" title="线程同步"></a>线程同步</h2><p>并发:多个线程同时操作同一个对象。<br>线程同步:其实就是一种等待机制,多个需要同时访问此对象的线程进入这个<strong>对象的等待池</strong>形成队列,等待前面线程使用完毕,下一个线程再使用。</p><p>由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了冲突问题,为了保证数据被操作时的正确性,在操作时加入锁机制(synchronized)。当一个线程要操作一个对象时,会获得这个对象的排它锁,会独占此对象的资源,其它线程必须等待,使用完后就会释放锁。但会存在以下问题:</p><ul><li> 一个线程持有锁会导致其它所有需要此锁的线程挂起,引起性能问题。</li><li> 在多线程竟争下,加锁和释放锁会导致比较多的上下文切换和调度延时,引起性能问题。</li><li> 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题。</li></ul><h2 id="不安全案例"><a href="#不安全案例" class="headerlink" title="不安全案例"></a>不安全案例</h2><h3 id="买票案例"><a href="#买票案例" class="headerlink" title="买票案例"></a>买票案例</h3><figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line">public <span class="keyword">class</span> BuyTickets implements Runnable {</span><br><span class="line"> <span class="keyword">private</span> <span class="built_in">int</span> tickets = <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> public void run<span class="literal">()</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">while</span> (<span class="literal">true</span>) {</span><br><span class="line"> <span class="keyword">if</span> (tickets > <span class="number">0</span>) {</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(<span class="module-access"><span class="module"><span class="identifier">Thread</span>.</span></span>current<span class="constructor">Thread()</span>.get<span class="constructor">Name()</span> + <span class="string">"拿到了第"</span> + tickets-- + <span class="string">"张票"</span>);</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">Thread</span>.</span></span>sleep(<span class="number">1000</span>); <span class="comment">//模拟延时能够扩大问题的发生性</span></span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"> } catch (InterruptedException e) {</span><br><span class="line"> e.print<span class="constructor">StackTrace()</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public static void main(String<span class="literal">[]</span> args) {</span><br><span class="line"> BuyTickets buyTickets = <span class="keyword">new</span> <span class="constructor">BuyTickets()</span>;</span><br><span class="line"> <span class="keyword">new</span> <span class="constructor">Thread(<span class="params">buyTickets</span>,<span class="string">"01"</span>)</span>.start<span class="literal">()</span>;</span><br><span class="line"> <span class="keyword">new</span> <span class="constructor">Thread(<span class="params">buyTickets</span>,<span class="string">"02"</span>)</span>.start<span class="literal">()</span>;</span><br><span class="line"> <span class="keyword">new</span> <span class="constructor">Thread(<span class="params">buyTickets</span>,<span class="string">"03"</span>)</span>.start<span class="literal">()</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">01拿到了第10张票</span></span><br><span class="line"><span class="comment">02拿到了第9张票</span></span><br><span class="line"><span class="comment">03拿到了第8张票</span></span><br><span class="line"><span class="comment">01拿到了第7张票</span></span><br><span class="line"><span class="comment">03拿到了第5张票</span></span><br><span class="line"><span class="comment">02拿到了第6张票</span></span><br><span class="line"><span class="comment">02拿到了第4张票</span></span><br><span class="line"><span class="comment">03拿到了第4张票</span></span><br><span class="line"><span class="comment">01拿到了第3张票</span></span><br><span class="line"><span class="comment">03拿到了第2张票</span></span><br><span class="line"><span class="comment">02拿到了第2张票</span></span><br><span class="line"><span class="comment">01拿到了第2张票</span></span><br><span class="line"><span class="comment">02拿到了第1张票</span></span><br><span class="line"><span class="comment">01拿到了第0张票</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>可以从结果看到,有的票被重复拿到,甚至拿到了不存在的0票。</p><h3 id="取钱案例"><a href="#取钱案例" class="headerlink" title="取钱案例"></a>取钱案例</h3><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WithDraw</span> {</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>{</span><br><span class="line"> Account account = <span class="keyword">new</span> <span class="built_in">Account</span>(<span class="string">"测试账户"</span>, <span class="number">1000</span>);</span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Thread</span>(<span class="keyword">new</span> <span class="built_in">Bank</span>(account, <span class="number">500</span>, <span class="string">"guest"</span>)).<span class="built_in">start</span>();</span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Thread</span>(<span class="keyword">new</span> <span class="built_in">Bank</span>(account, <span class="number">1000</span>, <span class="string">"admin"</span>)).<span class="built_in">start</span>();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Account</span> {</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">String</span> name;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> money;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Account</span><span class="params">(<span class="keyword">String</span> name, <span class="keyword">int</span> money)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> <span class="keyword">this</span>.money = money;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">String</span> <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(<span class="keyword">String</span> name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getMoney</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> money;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMoney</span><span class="params">(<span class="keyword">int</span> money)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.money = money;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Bank</span> <span class="title">implements</span> <span class="title">Runnable</span> {</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> Account account;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> getMoney;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> nowMoney;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">String</span> username;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Bank</span><span class="params">(Account account, <span class="keyword">int</span> getMoney, <span class="keyword">String</span> name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.account = account;</span><br><span class="line"> <span class="keyword">this</span>.getMoney = getMoney;</span><br><span class="line"> <span class="keyword">this</span>.username = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @<span class="function">Override</span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (account.<span class="built_in">getMoney</span>() < getMoney) {</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"取钱失败,余额不足"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.<span class="built_in">sleep</span>(<span class="number">1000</span>);</span><br><span class="line"> nowMoney = account.<span class="built_in">getMoney</span>() - getMoney;</span><br><span class="line"> account.<span class="built_in">setMoney</span>(nowMoney);</span><br><span class="line"> System.out.<span class="built_in">println</span>(username + <span class="string">" 成功取钱:"</span> + getMoney + <span class="string">",账户余额为:"</span> + nowMoney);</span><br><span class="line"> } <span class="built_in"><span class="keyword">catch</span></span> (InterruptedException e) {</span><br><span class="line"> e.<span class="built_in">printStackTrace</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">admin 成功取钱:1000,账户余额为:0</span></span><br><span class="line"><span class="comment">guest 成功取钱:500,账户余额为:-500</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>可以从结果看到,账户余额变成了负数。</p><h3 id="集合案例"><a href="#集合案例" class="headerlink" title="集合案例"></a>集合案例</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.UUID;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ListTest</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> List<String> list = <span class="keyword">new</span> ArrayList<>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">3</span>; i++) {</span><br><span class="line"> <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="comment">//Thread.sleep(3000);</span></span><br><span class="line"> list.add(UUID.randomUUID().toString().substring(<span class="number">0</span>,<span class="number">8</span>));</span><br><span class="line"> System.out.println(list);</span><br><span class="line"> }).start();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">[null, d4743923]</span></span><br><span class="line"><span class="comment">[null, d4743923, 8cd9e495]</span></span><br><span class="line"><span class="comment">[null, d4743923]</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>正常来说,打印出来的集合元素应该分别有1、2、3个,但是出现上面的结果的原因是 CPU 切换太快了,读写的顺序乱了。如果使上面的线程休眠语句生效的话,会发现直接报错了:ConcurrentModificationException(并发修改异常),原因就是一个线程正在写入,另外一个线程抢夺执行权,导致数据不一致。</p><h2 id="同步方法"><a href="#同步方法" class="headerlink" title="同步方法"></a>同步方法</h2><p>使用 synchronized 关键字修饰的方法控制对象的操作,每个对象对应一把锁,每个 synchronized 方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行。</p><p>缺点:方法里可能有只读代码,但是只有修改代码才需要锁,因此锁得太多就会降低效率。</p><h2 id="同步块"><a href="#同步块" class="headerlink" title="同步块"></a>同步块</h2><p>同步块: synchronized (obj) { }<br>obj:同步监视器,可以是任何对象,但是推荐使用共享资源作为同步监视器。</p><p>同步方法中无需指定同步监视器,因为同步方法的同步监视器就是 this,就是这个对象本身或者是 class。</p><h2 id="改造不安全案例"><a href="#改造不安全案例" class="headerlink" title="改造不安全案例"></a>改造不安全案例</h2><h3 id="买票案例-1"><a href="#买票案例-1" class="headerlink" title="买票案例"></a>买票案例</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BuyTickets</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> tickets = <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{ <span class="comment">//不能锁 run(),因为只有当循环结束才会释放锁,所以第一个得到锁的对象会把全部票拿走。</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">while</span> (<span class="keyword">true</span>) { <span class="comment">//不能锁在 while 前,理由跟上面相同。</span></span><br><span class="line"> <span class="keyword">synchronized</span> (<span class="keyword">this</span>) {</span><br><span class="line"> <span class="keyword">if</span> (tickets > <span class="number">0</span>) {</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"拿到了第"</span> + tickets-- + <span class="string">"张票"</span>);</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>); <span class="comment">//模拟延时能够扩大问题的发生性</span></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> BuyTickets buyTickets = <span class="keyword">new</span> BuyTickets();</span><br><span class="line"> <span class="keyword">new</span> Thread(buyTickets,<span class="string">"01"</span>).start();</span><br><span class="line"> <span class="keyword">new</span> Thread(buyTickets,<span class="string">"02"</span>).start();</span><br><span class="line"> <span class="keyword">new</span> Thread(buyTickets,<span class="string">"03"</span>).start();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">01拿到了第10张票</span></span><br><span class="line"><span class="comment">03拿到了第9张票</span></span><br><span class="line"><span class="comment">03拿到了第8张票</span></span><br><span class="line"><span class="comment">02拿到了第7张票</span></span><br><span class="line"><span class="comment">03拿到了第6张票</span></span><br><span class="line"><span class="comment">01拿到了第5张票</span></span><br><span class="line"><span class="comment">01拿到了第4张票</span></span><br><span class="line"><span class="comment">03拿到了第3张票</span></span><br><span class="line"><span class="comment">02拿到了第2张票</span></span><br><span class="line"><span class="comment">02拿到了第1张票</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>多次运行之后会发现,票数一定是从10开始减到1,并且票不会被重复拿到。</p><p>每次判断是否加锁,也会有性能的消耗,进入之后再出来,哪怕什么也不做,也是消耗。其实可以在加锁的前面再加一重判断,那么之后就没必要再判断是否加锁了。</p><h3 id="取钱案例-1"><a href="#取钱案例-1" class="headerlink" title="取钱案例"></a>取钱案例</h3><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WithDraw</span> {</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>{</span><br><span class="line"> Account account = <span class="keyword">new</span> <span class="built_in">Account</span>(<span class="string">"测试账户"</span>, <span class="number">1000</span>);</span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Thread</span>(<span class="keyword">new</span> <span class="built_in">Bank</span>(account, <span class="number">500</span>, <span class="string">"guest"</span>)).<span class="built_in">start</span>();</span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Thread</span>(<span class="keyword">new</span> <span class="built_in">Bank</span>(account, <span class="number">1000</span>, <span class="string">"admin"</span>)).<span class="built_in">start</span>();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Account</span> {</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">String</span> name;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> money;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Account</span><span class="params">(<span class="keyword">String</span> name, <span class="keyword">int</span> money)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> <span class="keyword">this</span>.money = money;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">String</span> <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(<span class="keyword">String</span> name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getMoney</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> money;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMoney</span><span class="params">(<span class="keyword">int</span> money)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.money = money;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Bank</span> <span class="title">implements</span> <span class="title">Runnable</span> {</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> Account account;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> getMoney;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> nowMoney;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">String</span> username;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Bank</span><span class="params">(Account account, <span class="keyword">int</span> getMoney, <span class="keyword">String</span> name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.account = account;</span><br><span class="line"> <span class="keyword">this</span>.getMoney = getMoney;</span><br><span class="line"> <span class="keyword">this</span>.username = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @<span class="function">Override</span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (account.<span class="built_in">getMoney</span>() == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">synchronized</span> (account) {</span><br><span class="line"> <span class="keyword">if</span> (account.<span class="built_in">getMoney</span>() < getMoney) {</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"取钱失败,余额不足"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.<span class="built_in">sleep</span>(<span class="number">1000</span>);</span><br><span class="line"> nowMoney = account.<span class="built_in">getMoney</span>() - getMoney;</span><br><span class="line"> account.<span class="built_in">setMoney</span>(nowMoney);</span><br><span class="line"> System.out.<span class="built_in">println</span>(username + <span class="string">" 成功取钱:"</span> + getMoney + <span class="string">",账户余额为:"</span> + nowMoney);</span><br><span class="line"> } <span class="built_in"><span class="keyword">catch</span></span> (InterruptedException e) {</span><br><span class="line"> e.<span class="built_in">printStackTrace</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>注意:两个实例对象开启了两条线程,每条线程用的锁对象都是当前实例对象,锁对象不同是无法实现同步的。所以这里要锁的是 account 对象,因为要操作的资源就在它这,否则是没有用的。</p><h3 id="集合案例-1"><a href="#集合案例-1" class="headerlink" title="集合案例"></a>集合案例</h3><figure class="highlight livescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.UUID;</span><br><span class="line"></span><br><span class="line">public <span class="class"><span class="keyword">class</span> <span class="title">ListTest</span> {</span></span><br><span class="line"> public <span class="keyword">static</span> <span class="literal">void</span> main(<span class="built_in">String</span>[] args) {</span><br><span class="line"> List<<span class="built_in">String</span>> <span class="keyword">list</span> = <span class="keyword">new</span> ArrayList<>();</span><br><span class="line"> <span class="keyword">for</span> (int i = <span class="number">0</span>; i < <span class="number">3</span>; i++) {</span><br><span class="line"> <span class="keyword">new</span> Thread<span class="function"><span class="params">(() -> {</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">try</span> {</span></span></span><br><span class="line"><span class="params"><span class="function"> Thread.sleep(<span class="number">3000</span>);</span></span></span><br><span class="line"><span class="params"><span class="function"> } <span class="keyword">catch</span> (InterruptedException e) {</span></span></span><br><span class="line"><span class="params"><span class="function"> e.printStackTrace();</span></span></span><br><span class="line"><span class="params"><span class="function"> }</span></span></span><br><span class="line"><span class="params"><span class="function"> synchronized (<span class="keyword">list</span>) {</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">list</span>.add(UUID.randomUUID().toString().substring(<span class="number">0</span>, <span class="number">8</span>));</span></span></span><br><span class="line"><span class="params"><span class="function"> System.out.println(<span class="keyword">list</span>);</span></span></span><br><span class="line"><span class="params"><span class="function"> }</span></span></span><br><span class="line"><span class="params"><span class="function"> })</span>.<span class="title">start</span><span class="params">()</span>;</span></span><br><span class="line"><span class="function"> }</span></span><br><span class="line"><span class="function"> }</span></span><br><span class="line"><span class="function">}</span></span><br><span class="line"><span class="function">/*结果为</span></span><br><span class="line"><span class="function">[<span class="title">d551b4a4</span>]</span></span><br><span class="line"><span class="function">[<span class="title">d551b4a4</span>, 9<span class="title">c66a664</span>]</span></span><br><span class="line"><span class="function">[<span class="title">d551b4a4</span>, 9<span class="title">c66a664</span>, 6960482<span class="title">c</span>]</span></span><br><span class="line"><span class="function">*/</span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="线程同步"><a href="#线程同步" class="headerlink" title="线程同步"></a>线程同步</h2><p>并发:多个线程同时操作同一个对象。<br>线程同步:其实就是一种等待机制,多个需要同时访问此对象的线程进入这个<strong>对象的等待池</strong>形成队列,等待前面线程使用完毕,下一个线程再使用。</p>
<p>由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了冲突问题,为了保证数据被操作时的正确性,在操作时加入锁机制(synchronized)。当一个线程要操作一个对象时,会获得这个对象的排它锁,会独占此对象的资源,其它线程必须等待,使用完后就会释放锁。但会存在以下问题:</p>
<ul>
<li> 一个线程持有锁会导致其它所有需要此锁的线程挂起,引起性能问题。</li>
<li> 在多线程竟争下,加锁和释放锁会导致比较多的上下文切换和调度延时,引起性能问题。</li>
<li> 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题。</li>
</ul>
<h2 id="不安全案例"><a href="#不安全案例" class="headerlink" title="不安全案例"></a>不安全案例</h2></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="javase" scheme="http://guest997.tk/tags/javase/"/>
</entry>
<entry>
<title>JavaSE 进阶(十八)</title>
<link href="http://guest997.tk/2022/03/31/javase-advanced18/"/>
<id>http://guest997.tk/2022/03/31/javase-advanced18/</id>
<published>2022-03-31T03:22:30.000Z</published>
<updated>2022-04-05T13:54:09.986Z</updated>
<content type="html"><![CDATA[<h2 id="静态代理"><a href="#静态代理" class="headerlink" title="静态代理"></a>静态代理</h2><h3 id="结婚案例"><a href="#结婚案例" class="headerlink" title="结婚案例"></a>结婚案例</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StaticProxy</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> Company company = <span class="keyword">new</span> Company(<span class="keyword">new</span> Person()); <span class="comment">//静态代理对象的创建需要传入真实对象</span></span><br><span class="line"> company.work();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//结婚接口</span></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Marry</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">work</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//人(真实对象)实现结婚接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> <span class="keyword">implements</span> <span class="title">Marry</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">work</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"人结婚了"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//公司(代理对象)也实现结婚接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Company</span> <span class="keyword">implements</span> <span class="title">Marry</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">//代理的真实对象</span></span><br><span class="line"> <span class="keyword">private</span> Person person;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Company</span><span class="params">(Person person)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.person = person;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">work</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">//代理对象可以做很多真实对象做不了的事情,这样真实对象就能专注做自己的事。</span></span><br><span class="line"> before();</span><br><span class="line"> person.work();</span><br><span class="line"> after();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">before</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"公司处理结婚前事务"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">after</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"公司处理结婚后事务"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">公司处理结婚前事务</span></span><br><span class="line"><span class="comment">人结婚了</span></span><br><span class="line"><span class="comment">公司处理结婚后事务</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>可以看到代理对象的创建类似于线程创建时传了个实现 Runnable 接口的类对象。</p><h2 id="Lambda-表达式"><a href="#Lambda-表达式" class="headerlink" title="Lambda 表达式"></a>Lambda 表达式</h2><p>为什么要使用 Lambda 表达式?</p><ul><li> 避兔匿名内部类定义过多</li><li> 可以让代码看起来很简洁</li><li> 只留下核心的逻辑</li></ul><p>什么时候能够使用 Lambda 表达式?</p><ul><li> 创建函数式接口对象的时候。</li></ul><p>什么是函数式接口?</p><ul><li> 接口只包含唯ー一个抽象方法。</li></ul><h3 id="以前的代码实现"><a href="#以前的代码实现" class="headerlink" title="以前的代码实现"></a>以前的代码实现</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LambdaTest01</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">//静态内部类</span></span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Talk02</span> <span class="keyword">implements</span> <span class="title">ITalk</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">talk</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"talk02"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">new</span> Talk01().talk();</span><br><span class="line"> <span class="keyword">new</span> Talk02().talk();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//局部内部类</span></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">Talk03</span> <span class="keyword">implements</span> <span class="title">ITalk</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">talk</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"talk03"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">new</span> Talk03().talk();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//匿名内部类</span></span><br><span class="line"> ITalk talk04 = <span class="keyword">new</span> ITalk() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">talk</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"talk04"</span>);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> talk04.talk();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//函数式接口</span></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">ITalk</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">talk</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//实现类</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Talk01</span> <span class="keyword">implements</span> <span class="title">ITalk</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">talk</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"talk01"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">talk01</span></span><br><span class="line"><span class="comment">talk02</span></span><br><span class="line"><span class="comment">talk03</span></span><br><span class="line"><span class="comment">talk04</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>有些代码只会使用到一次,之前就能使用如上面的方法来简化代码。而 java8 之后提供了新的方式来简化代码。</p><h3 id="Lambda-简化代码"><a href="#Lambda-简化代码" class="headerlink" title="Lambda 简化代码"></a>Lambda 简化代码</h3><figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="built_in">public</span> <span class="keyword">class</span> LambdaTest02 {</span><br><span class="line"> <span class="built_in">public</span> static <span class="type">void</span> main(String[] args) {</span><br><span class="line"> //标准 Lambda 语法</span><br><span class="line"> ISay say01 = (String <span class="type">name</span>) -> {</span><br><span class="line"> <span class="keyword">System</span>.<span class="keyword">out</span>.println(<span class="type">name</span> + " say01");</span><br><span class="line"> };</span><br><span class="line"> say01.say("01");</span><br><span class="line"></span><br><span class="line"> //简化一:去掉全部参数类型</span><br><span class="line"> ISay say02 = (<span class="type">name</span>) -> {</span><br><span class="line"> <span class="keyword">System</span>.<span class="keyword">out</span>.println(<span class="type">name</span> + " say02");</span><br><span class="line"> };</span><br><span class="line"> say02.say("02");</span><br><span class="line"></span><br><span class="line"> //简化二:去掉括号(需要只有一个参数)</span><br><span class="line"> ISay say03 = <span class="type">name</span> -> {</span><br><span class="line"> <span class="keyword">System</span>.<span class="keyword">out</span>.println(<span class="type">name</span> + " say03");</span><br><span class="line"> };</span><br><span class="line"> say03.say("03");</span><br><span class="line"></span><br><span class="line"> //简化三:去掉花括号(需要代码只有一行)</span><br><span class="line"> ISay say04 = <span class="type">name</span> -> <span class="keyword">System</span>.<span class="keyword">out</span>.println(<span class="type">name</span> + " say04");</span><br><span class="line"> say04.say("04");</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">//函数式接口</span><br><span class="line">interface ISay {</span><br><span class="line"> <span class="type">void</span> say(String <span class="type">name</span>);</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">01 say01</span></span><br><span class="line"><span class="comment">02 say02</span></span><br><span class="line"><span class="comment">03 say03</span></span><br><span class="line"><span class="comment">04 say04</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>可以看到通过 Lambda 简化后的代码甚至可以短到只有一行。</p><h2 id="线程状态"><a href="#线程状态" class="headerlink" title="线程状态"></a>线程状态</h2><p><img data-src="/images/javase-advanced18.md-0.jpg"></p><p><strong>线程只能启动一次,一旦死亡就不能再次启动。</strong></p><h3 id="线程停止"><a href="#线程停止" class="headerlink" title="线程停止"></a>线程停止</h3><p>不推荐使用 JDK 提供的方法。推荐让线程自己停下来。使用一个标志位当作终止变量,如当 flag = false 时线程终止。</p><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StopTest</span> <span class="title">implements</span> <span class="title">Runnable</span> {</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">boolean</span> flag = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>{</span><br><span class="line"> StopTest stopTest = <span class="keyword">new</span> <span class="built_in">StopTest</span>();</span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">Thread</span>(stopTest).<span class="built_in">start</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">1000</span>; i++) {</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"main"</span> + i);</span><br><span class="line"> <span class="keyword">if</span> (i == <span class="number">500</span>) {</span><br><span class="line"> stopTest.<span class="built_in">stop</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @<span class="function">Override</span></span><br><span class="line"><span class="function"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (flag) {</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"running"</span> + i++);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">stop</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.flag = <span class="literal">false</span>;</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"线程停止了"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img data-src="/images/javase-advanced18.md-1.png"></p><h3 id="线程休眠"><a href="#线程休眠" class="headerlink" title="线程休眠"></a>线程休眠</h3><p>休眠可以模拟网络延时和倒计时。每一个对象都有一个锁,休眠不会释放锁。</p><figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.text.SimpleDateFormat;</span><br><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"></span><br><span class="line"><span class="built_in">public</span> <span class="keyword">class</span> SleepTest {</span><br><span class="line"> <span class="built_in">public</span> static <span class="type">void</span> main(String[] args) {</span><br><span class="line"> SleepTest sleepTest = <span class="built_in">new</span> SleepTest();</span><br><span class="line"> <span class="keyword">System</span>.<span class="keyword">out</span>.println("每隔一秒输出当前时间");</span><br><span class="line"> sleepTest.nowTime();</span><br><span class="line"> <span class="keyword">System</span>.<span class="keyword">out</span>.println("十秒倒计时");</span><br><span class="line"> sleepTest.countDown();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">public</span> <span class="type">void</span> nowTime() {</span><br><span class="line"> <span class="type">Date</span> <span class="type">date</span> = <span class="built_in">new</span> <span class="type">Date</span>(<span class="keyword">System</span>.currentTimeMillis());</span><br><span class="line"> <span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (i < <span class="number">5</span>) {</span><br><span class="line"> try {</span><br><span class="line"> <span class="keyword">System</span>.<span class="keyword">out</span>.println(<span class="built_in">new</span> SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(<span class="type">date</span>));</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> <span class="type">date</span> = <span class="built_in">new</span> <span class="type">Date</span>(<span class="keyword">System</span>.currentTimeMillis());</span><br><span class="line"> i++;</span><br><span class="line"> } catch (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">public</span> <span class="type">void</span> countDown() {</span><br><span class="line"> try {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">10</span>; i >= <span class="number">0</span>; i<span class="comment">--) {</span></span><br><span class="line"> <span class="keyword">System</span>.<span class="keyword">out</span>.println(i);</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> }</span><br><span class="line"> } catch (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">每隔一秒输出当前时间</span></span><br><span class="line"><span class="comment">2021-11-28 00:42:45</span></span><br><span class="line"><span class="comment">2021-11-28 00:42:46</span></span><br><span class="line"><span class="comment">2021-11-28 00:42:47</span></span><br><span class="line"><span class="comment">2021-11-28 00:42:48</span></span><br><span class="line"><span class="comment">2021-11-28 00:42:49</span></span><br><span class="line"><span class="comment">十秒倒计时</span></span><br><span class="line"><span class="comment">10</span></span><br><span class="line"><span class="comment">9</span></span><br><span class="line"><span class="comment">8</span></span><br><span class="line"><span class="comment">7</span></span><br><span class="line"><span class="comment">6</span></span><br><span class="line"><span class="comment">5</span></span><br><span class="line"><span class="comment">4</span></span><br><span class="line"><span class="comment">3</span></span><br><span class="line"><span class="comment">2</span></span><br><span class="line"><span class="comment">1</span></span><br><span class="line"><span class="comment">0</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h3 id="线程礼让"><a href="#线程礼让" class="headerlink" title="线程礼让"></a>线程礼让</h3><p>线程礼让就是让运行中的线程暂停,但不是进入阻塞状态,而是进入就绪状态,与其它线程回到同一起跑线。所以礼让不一定会成功,看 CPU 的调度。</p><figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line">public <span class="keyword">class</span> YieldTest implements Runnable {</span><br><span class="line"></span><br><span class="line"> public static void main(String<span class="literal">[]</span> args) {</span><br><span class="line"> YieldTest yieldTest = <span class="keyword">new</span> <span class="constructor">YieldTest()</span>;</span><br><span class="line"> <span class="keyword">new</span> <span class="constructor">Thread(<span class="params">yieldTest</span>, <span class="string">"A"</span>)</span>.start<span class="literal">()</span>;</span><br><span class="line"> <span class="keyword">new</span> <span class="constructor">Thread(<span class="params">yieldTest</span>, <span class="string">"B"</span>)</span>.start<span class="literal">()</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> public void run<span class="literal">()</span> {</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(<span class="module-access"><span class="module"><span class="identifier">Thread</span>.</span></span>current<span class="constructor">Thread()</span>.get<span class="constructor">Name()</span> + <span class="string">"线程开始"</span>);</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">Thread</span>.</span></span>yield<span class="literal">()</span>;</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(<span class="module-access"><span class="module"><span class="identifier">Thread</span>.</span></span>current<span class="constructor">Thread()</span>.get<span class="constructor">Name()</span> + <span class="string">"线程结束"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">A线程开始</span></span><br><span class="line"><span class="comment">B线程开始</span></span><br><span class="line"><span class="comment">A线程结束</span></span><br><span class="line"><span class="comment">B线程结束</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h3 id="线程合并"><a href="#线程合并" class="headerlink" title="线程合并"></a>线程合并</h3><p>线程合并可以想象为插队,只有当插队的线程运行完才能运行其它线程,其它线程会处于阻塞状态。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JoinTest</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++) {</span><br><span class="line"> System.out.println(<span class="string">"使用线程"</span> + i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> JoinTest joinTest = <span class="keyword">new</span> JoinTest();</span><br><span class="line"> Thread thread = <span class="keyword">new</span> Thread(joinTest);</span><br><span class="line"> thread.start();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++) {</span><br><span class="line"> System.out.println(<span class="string">"使用 main 线程"</span> + i);</span><br><span class="line"> <span class="keyword">if</span> (i == <span class="number">5</span>) {</span><br><span class="line"> thread.join();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">使用 main 线程0</span></span><br><span class="line"><span class="comment">使用 main 线程1</span></span><br><span class="line"><span class="comment">使用 main 线程2</span></span><br><span class="line"><span class="comment">使用 main 线程3</span></span><br><span class="line"><span class="comment">使用 main 线程4</span></span><br><span class="line"><span class="comment">使用 main 线程5</span></span><br><span class="line"><span class="comment">使用线程0</span></span><br><span class="line"><span class="comment">使用线程1</span></span><br><span class="line"><span class="comment">使用线程2</span></span><br><span class="line"><span class="comment">使用线程3</span></span><br><span class="line"><span class="comment">使用线程4</span></span><br><span class="line"><span class="comment">使用线程5</span></span><br><span class="line"><span class="comment">使用线程6</span></span><br><span class="line"><span class="comment">使用线程7</span></span><br><span class="line"><span class="comment">使用线程8</span></span><br><span class="line"><span class="comment">使用线程9</span></span><br><span class="line"><span class="comment">使用 main 线程6</span></span><br><span class="line"><span class="comment">使用 main 线程7</span></span><br><span class="line"><span class="comment">使用 main 线程8</span></span><br><span class="line"><span class="comment">使用 main 线程9</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h2 id="线程优先级"><a href="#线程优先级" class="headerlink" title="线程优先级"></a>线程优先级</h2><p>线程优先级从1到10,1最低,10最高。当线程的优先级没有指定时,所有线程都为普通优先级(5)。</p><figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line">public <span class="keyword">class</span> PriorityTest implements Runnable {</span><br><span class="line"> @Override</span><br><span class="line"> public void run<span class="literal">()</span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="built_in">int</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++) {</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(<span class="module-access"><span class="module"><span class="identifier">Thread</span>.</span></span>current<span class="constructor">Thread()</span>.get<span class="constructor">Name()</span> + i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public static void main(String<span class="literal">[]</span> args) {</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(<span class="string">"main 线程优先级:"</span> + <span class="module-access"><span class="module"><span class="identifier">Thread</span>.</span></span>current<span class="constructor">Thread()</span>.get<span class="constructor">Priority()</span>);</span><br><span class="line"> Thread t1 = <span class="keyword">new</span> <span class="constructor">Thread(<span class="params">new</span> PriorityTest()</span>, <span class="string">"one"</span>);</span><br><span class="line"> Thread t2 = <span class="keyword">new</span> <span class="constructor">Thread(<span class="params">new</span> PriorityTest()</span>, <span class="string">"two"</span>);</span><br><span class="line"> Thread t3 = <span class="keyword">new</span> <span class="constructor">Thread(<span class="params">new</span> PriorityTest()</span>, <span class="string">"three"</span>);</span><br><span class="line"> t1.set<span class="constructor">Priority(6)</span>;</span><br><span class="line"> t3.set<span class="constructor">Priority(4)</span>;</span><br><span class="line"> t1.start<span class="literal">()</span>;</span><br><span class="line"> t2.start<span class="literal">()</span>;</span><br><span class="line"> t3.start<span class="literal">()</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">main 线程优先级:5</span></span><br><span class="line"><span class="comment">one0</span></span><br><span class="line"><span class="comment">two0</span></span><br><span class="line"><span class="comment">one1</span></span><br><span class="line"><span class="comment">two1</span></span><br><span class="line"><span class="comment">one2</span></span><br><span class="line"><span class="comment">two2</span></span><br><span class="line"><span class="comment">one3</span></span><br><span class="line"><span class="comment">two3</span></span><br><span class="line"><span class="comment">one4</span></span><br><span class="line"><span class="comment">two4</span></span><br><span class="line"><span class="comment">one5</span></span><br><span class="line"><span class="comment">two5</span></span><br><span class="line"><span class="comment">one6</span></span><br><span class="line"><span class="comment">two6</span></span><br><span class="line"><span class="comment">two7</span></span><br><span class="line"><span class="comment">one7</span></span><br><span class="line"><span class="comment">two8</span></span><br><span class="line"><span class="comment">two9</span></span><br><span class="line"><span class="comment">one8</span></span><br><span class="line"><span class="comment">one9</span></span><br><span class="line"><span class="comment">three0</span></span><br><span class="line"><span class="comment">three1</span></span><br><span class="line"><span class="comment">three2</span></span><br><span class="line"><span class="comment">three3</span></span><br><span class="line"><span class="comment">three4</span></span><br><span class="line"><span class="comment">three5</span></span><br><span class="line"><span class="comment">three6</span></span><br><span class="line"><span class="comment">three7</span></span><br><span class="line"><span class="comment">three8</span></span><br><span class="line"><span class="comment">three9</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>可以从结果看出,<strong>不是高优先级的线程就一定先比低优先级的线程先运行完,而是高优先级的线程先运行的概率比低优先级的线程高。</strong></p><h2 id="守护线程"><a href="#守护线程" class="headerlink" title="守护线程"></a>守护线程</h2><p>线程分为用户线程和守护线程,<strong>虚拟机必须确保用户线程执行完毕,但是不用等待守护线程执行完毕</strong>。守护线程有如后台记录操作日志、监控内存和垃圾回收等待。</p><figure class="highlight livescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line">public <span class="class"><span class="keyword">class</span> <span class="title">DaemonTest</span> {</span></span><br><span class="line"> public <span class="keyword">static</span> <span class="literal">void</span> main(<span class="built_in">String</span>[] args) {</span><br><span class="line"> Thread daemonThread = <span class="keyword">new</span> Thread<span class="function"><span class="params">(() -> {</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">while</span> (<span class="literal">true</span>) {</span></span></span><br><span class="line"><span class="params"><span class="function"> System.out.println(<span class="string">"守护线程一直运行"</span>);</span></span></span><br><span class="line"><span class="params"><span class="function"> }</span></span></span><br><span class="line"><span class="params"><span class="function"> })</span>;</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"> <span class="title">Thread</span> <span class="title">userThread</span> = <span class="title">new</span> <span class="title">Thread</span><span class="params">(() -> {</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="keyword">for</span> (int i = <span class="number">0</span>; i < <span class="number">3</span>; i++) {</span></span></span><br><span class="line"><span class="params"><span class="function"> System.out.println(<span class="string">"用户线程运行"</span> + i);</span></span></span><br><span class="line"><span class="params"><span class="function"> }</span></span></span><br><span class="line"><span class="params"><span class="function"> })</span>;</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"> <span class="title">userThread</span>.<span class="title">setPriority</span><span class="params">(<span class="number">10</span>)</span>;</span></span><br><span class="line"><span class="function"> <span class="title">userThread</span>.<span class="title">start</span><span class="params">()</span>;</span></span><br><span class="line"><span class="function"> <span class="title">daemonThread</span>.<span class="title">setDaemon</span><span class="params">(<span class="literal">true</span>)</span>; //设置线程为守护线程</span></span><br><span class="line"><span class="function"> <span class="title">daemonThread</span>.<span class="title">start</span><span class="params">()</span>;</span></span><br><span class="line"><span class="function"> }</span></span><br><span class="line"><span class="function">}</span></span><br><span class="line"><span class="function">/*结果为</span></span><br><span class="line"><span class="function">用户线程运行0</span></span><br><span class="line"><span class="function">用户线程运行1</span></span><br><span class="line"><span class="function">用户线程运行2</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function">守护线程一直运行</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="title">Process</span> <span class="title">finished</span> <span class="title">with</span> <span class="title">exit</span> <span class="title">code</span> 0</span></span><br><span class="line"><span class="function">*/</span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="静态代理"><a href="#静态代理" class="headerlink" title="静态代理"></a>静态代理</h2><h3 id="结婚案例"><a href="#结婚案例" class="headerlink" title="结婚案例"></a>结婚案例</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StaticProxy</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"> Company company = <span class="keyword">new</span> Company(<span class="keyword">new</span> Person()); <span class="comment">//静态代理对象的创建需要传入真实对象</span></span><br><span class="line"> company.work();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//结婚接口</span></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Marry</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">work</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//人(真实对象)实现结婚接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> <span class="keyword">implements</span> <span class="title">Marry</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">work</span><span class="params">()</span> </span>&#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;人结婚了&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//公司(代理对象)也实现结婚接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Company</span> <span class="keyword">implements</span> <span class="title">Marry</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//代理的真实对象</span></span><br><span class="line"> <span class="keyword">private</span> Person person;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Company</span><span class="params">(Person person)</span> </span>&#123;</span><br><span class="line"> <span class="keyword">this</span>.person = person;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">work</span><span class="params">()</span> </span>&#123;</span><br><span class="line"> <span class="comment">//代理对象可以做很多真实对象做不了的事情,这样真实对象就能专注做自己的事。</span></span><br><span class="line"> before();</span><br><span class="line"> person.work();</span><br><span class="line"> after();</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">before</span><span class="params">()</span> </span>&#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;公司处理结婚前事务&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">after</span><span class="params">()</span> </span>&#123;</span><br><span class="line"> System.out.println(<span class="string">&quot;公司处理结婚后事务&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">公司处理结婚前事务</span></span><br><span class="line"><span class="comment">人结婚了</span></span><br><span class="line"><span class="comment">公司处理结婚后事务</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>
<p>可以看到代理对象的创建类似于线程创建时传了个实现 Runnable 接口的类对象。</p>
<h2 id="Lambda-表达式"><a href="#Lambda-表达式" class="headerlink" title="Lambda 表达式"></a>Lambda 表达式</h2></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="javase" scheme="http://guest997.tk/tags/javase/"/>
</entry>
<entry>
<title>JavaSE 进阶(十七)</title>
<link href="http://guest997.tk/2022/03/30/javase-advanced17/"/>
<id>http://guest997.tk/2022/03/30/javase-advanced17/</id>
<published>2022-03-30T03:20:02.000Z</published>
<updated>2022-04-05T13:54:02.488Z</updated>
<content type="html"><![CDATA[<h2 id="程序、进程和线程"><a href="#程序、进程和线程" class="headerlink" title="程序、进程和线程"></a>程序、进程和线程</h2><p>程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。<br>进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。<br>通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是 CPU 调度和执行的的单位。</p><h2 id="普通方法调用和多线程启动"><a href="#普通方法调用和多线程启动" class="headerlink" title="普通方法调用和多线程启动"></a>普通方法调用和多线程启动</h2><p><img data-src="/images/javase-advanced17.md-0.png"></p><p><strong>注意:很多多线程是模拟出来的,真正的多线程是指有多个 CPU(多核),如服务器。如果是模拟出来的多线程,即在一个 CPU 的情况下,在同一个时间点,CPU 只能执行一个代码,因为切换得很快,所以就有同时执行的错觉。</strong></p><h2 id="线程创建"><a href="#线程创建" class="headerlink" title="线程创建"></a>线程创建</h2><h3 id="Thread"><a href="#Thread" class="headerlink" title="Thread"></a>Thread</h3><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="comment">//继承 Thread 类</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadTest01</span> <span class="title">extends</span> <span class="title">Thread</span> {</span></span><br><span class="line"> <span class="comment">//main 方法</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(<span class="keyword">String</span>[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">new</span> <span class="built_in">ThreadTest01</span>().<span class="built_in">start</span>(); <span class="comment">//开启线程</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">1000</span>; i++) { <span class="comment">//次数不能限制的太小,否则处理得太快,结果不明显。</span></span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"使用 main 线程"</span> + i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//run 方法</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">1000</span>; i++) {</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"使用线程"</span> + i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img data-src="/images/javase-advanced17.md-1.png"></p><p>可以从图中部分结果看出两个线程是交替执行的,如果将上面代码的 start() 改成 run(),就只是普通地调用方法,而并没有开启线程,会先执行完 run(),再执行后面的代码。</p><h4 id="多线程下载图片"><a href="#多线程下载图片" class="headerlink" title="多线程下载图片"></a>多线程下载图片</h4><h5 id="添加依赖"><a href="#添加依赖" class="headerlink" title="添加依赖"></a>添加依赖</h5><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>commons-io<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>commons-io<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.11.0<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><h5 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.io.FileUtils;</span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadTest02</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> String url; <span class="comment">//图片地址</span></span><br><span class="line"> <span class="keyword">private</span> String FileName; <span class="comment">//保存的文件名</span></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">ThreadTest02</span><span class="params">(String url, String FileName)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.url = url;</span><br><span class="line"> <span class="keyword">this</span>.FileName = FileName;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">5</span>; i++) {</span><br><span class="line"> <span class="keyword">new</span> ThreadTest02(<span class="string">"https://img1.baidu.com/it/u=949092872,4035757232&fm=26&fmt=auto"</span>, <span class="string">"bg"</span> + i + <span class="string">".png"</span>).start();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> ImagesDownloader imagesDownloader = <span class="keyword">new</span> ImagesDownloader();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> imagesDownloader.downloader(url, FileName);</span><br><span class="line"> System.out.println(FileName + <span class="string">"下载完成"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//图片下载器</span></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">ImagesDownloader</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">downloader</span><span class="params">(String link, String filename)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> URL url = <span class="keyword">new</span> URL(link);</span><br><span class="line"> url.openConnection().setRequestProperty(<span class="string">"User-Agent"</span>, <span class="string">"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"</span>); <span class="comment">//如果服务器端禁止抓取,那么可以通过设置 User-Agent 来欺骗服务器.</span></span><br><span class="line"> FileUtils.copyURLToFile(url, <span class="keyword">new</span> File(filename));</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">bg0.png下载完成</span></span><br><span class="line"><span class="comment">bg3.png下载完成</span></span><br><span class="line"><span class="comment">bg1.png下载完成</span></span><br><span class="line"><span class="comment">bg4.png下载完成</span></span><br><span class="line"><span class="comment">bg2.png下载完成</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h3 id="Runnable"><a href="#Runnable" class="headerlink" title="Runnable"></a>Runnable</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="comment">//实现 Runnable 接口</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadTest03</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"> <span class="comment">//重写 run()</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">1000</span>; i++) {</span><br><span class="line"> System.out.println(<span class="string">"使用线程"</span> + i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> ThreadTest03()).start(); <span class="comment">//将 Runnable 实现类对象通过代理的方式创建线程</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">1000</span>; i++) {</span><br><span class="line"> System.out.println(<span class="string">"使用 main 线程"</span> + i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img data-src="/images/javase-advanced17.md-2.png"></p><h4 id="多线程买火车票"><a href="#多线程买火车票" class="headerlink" title="多线程买火车票"></a>多线程买火车票</h4><figure class="highlight haxe"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadTest04</span> <span class="keyword"><span class="keyword">implements</span> <span class="type">Runnable</span></span> </span>{</span><br><span class="line"> <span class="keyword">private</span> int tickets = <span class="number">100</span>;</span><br><span class="line"></span><br><span class="line"> @Override</span><br><span class="line"> <span class="keyword">public</span> void run() {</span><br><span class="line"> <span class="keyword">while</span> (<span class="literal">true</span>) {</span><br><span class="line"> <span class="keyword">if</span> (tickets > <span class="number">0</span>) {</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"拿到了第"</span> + tickets-- + <span class="string">"张票"</span>);</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> void main(<span class="keyword">String</span>[] args) {</span><br><span class="line"> ThreadTest04 threadTest04 = <span class="keyword">new</span> <span class="type">ThreadTest04</span>();</span><br><span class="line"> <span class="comment">//多个线程同时操作一个对象。注意:可能有并发问题,就是有人拿到了同一张票或者拿到了0或-1张票。</span></span><br><span class="line"> <span class="keyword">new</span> <span class="type">Thread</span>(threadTest04,<span class="string">"01"</span>).start();</span><br><span class="line"> <span class="keyword">new</span> <span class="type">Thread</span>(threadTest04,<span class="string">"02"</span>).start();</span><br><span class="line"> <span class="keyword">new</span> <span class="type">Thread</span>(threadTest04,<span class="string">"03"</span>).start();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>由于 OOP 的单继承局限性,所有推荐使用 Runnable 实现多线程,更加灵活,方便一个对象能被多个线程使用。</p><h4 id="龟兔赛跑"><a href="#龟兔赛跑" class="headerlink" title="龟兔赛跑"></a>龟兔赛跑</h4><figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line">public <span class="keyword">class</span> ThreadTest05 implements Runnable {</span><br><span class="line"> <span class="comment">//模拟赛道</span></span><br><span class="line"> <span class="keyword">private</span> <span class="built_in">int</span> race = <span class="number">50</span>;</span><br><span class="line"> <span class="comment">//胜利者</span></span><br><span class="line"> <span class="keyword">private</span> String winner;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//模拟赛跑过程</span></span><br><span class="line"> @Override</span><br><span class="line"> public void run<span class="literal">()</span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="built_in">int</span> i = <span class="number">0</span>; i <= race; i++) {</span><br><span class="line"> <span class="comment">//当兔子跑到25米时,线程休眠。</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="module-access"><span class="module"><span class="identifier">Thread</span>.</span></span>current<span class="constructor">Thread()</span>.get<span class="constructor">Name()</span>.equals(<span class="string">"兔子"</span>) & i<span class="operator"> == </span><span class="number">25</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">Thread</span>.</span></span>sleep(<span class="number">1</span>);</span><br><span class="line"> } catch (InterruptedException e) {</span><br><span class="line"> e.print<span class="constructor">StackTrace()</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> boolean gameOver = game<span class="constructor">Over(<span class="params">i</span>)</span>;</span><br><span class="line"> <span class="keyword">if</span> (gameOver) {</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(<span class="module-access"><span class="module"><span class="identifier">Thread</span>.</span></span>current<span class="constructor">Thread()</span>.get<span class="constructor">Name()</span> + <span class="string">"跑了"</span> + i + <span class="string">"米"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//检测是否存在胜利者</span></span><br><span class="line"> <span class="keyword">private</span> boolean game<span class="constructor">Over(<span class="params">int</span> <span class="params">already</span>)</span> {</span><br><span class="line"> <span class="keyword">if</span> (winner != null) {</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(<span class="string">"已经存在胜利者"</span>);</span><br><span class="line"> return <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (already >= race) {</span><br><span class="line"> winner = <span class="module-access"><span class="module"><span class="identifier">Thread</span>.</span></span>current<span class="constructor">Thread()</span>.get<span class="constructor">Name()</span>;</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(<span class="string">"胜利者是:"</span> + winner);</span><br><span class="line"> return <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> return <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public static void main(String<span class="literal">[]</span> args) {</span><br><span class="line"> ThreadTest05 threadTest05 = <span class="keyword">new</span> <span class="constructor">ThreadTest05()</span>;</span><br><span class="line"> <span class="keyword">new</span> <span class="constructor">Thread(<span class="params">threadTest05</span>,<span class="string">"兔子"</span>)</span>.start<span class="literal">()</span>;</span><br><span class="line"> <span class="keyword">new</span> <span class="constructor">Thread(<span class="params">threadTest05</span>,<span class="string">"乌龟"</span>)</span>.start<span class="literal">()</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Callable"><a href="#Callable" class="headerlink" title="Callable"></a>Callable</h3><h4 id="多线程下载图片-1"><a href="#多线程下载图片-1" class="headerlink" title="多线程下载图片"></a>多线程下载图片</h4><figure class="highlight haxe"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.io.FileUtils;</span><br><span class="line"><span class="keyword">import</span> java.io.File;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.net.URL;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.*;</span><br><span class="line"></span><br><span class="line"><span class="comment">//实现 Callable 接口,并且可以有返回值。</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ThreadTest06</span> <span class="keyword"><span class="keyword">implements</span> <span class="type">Callable</span></span><<span class="title">Boolean</span>> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">String</span> url; <span class="comment">//图片地址</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">String</span> FileName; <span class="comment">//保存的文件名</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> ThreadTest06(<span class="keyword">String</span> url, <span class="keyword">String</span> FileName) {</span><br><span class="line"> <span class="built_in">this</span>.url = url;</span><br><span class="line"> <span class="built_in">this</span>.FileName = FileName;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> void main(<span class="keyword">String</span>[] args) throws ExecutionException, InterruptedException {</span><br><span class="line"> ThreadTest06 t1 = <span class="keyword">new</span> <span class="type">ThreadTest06</span>(<span class="string">"https://img1.baidu.com/it/u=949092872,4035757232&fm=26&fmt=auto"</span>, <span class="string">"bg0.png"</span>);</span><br><span class="line"> ThreadTest06 t2 = <span class="keyword">new</span> <span class="type">ThreadTest06</span>(<span class="string">"https://img1.baidu.com/it/u=949092872,4035757232&fm=26&fmt=auto"</span>, <span class="string">"bg1.png"</span>);</span><br><span class="line"> ThreadTest06 t3 = <span class="keyword">new</span> <span class="type">ThreadTest06</span>(<span class="string">"https://img1.baidu.com/it/u=949092872,4035757232&fm=26&fmt=auto"</span>, <span class="string">"bg2.png"</span>);</span><br><span class="line"> <span class="comment">//使用 FutureTask 类包装 Callable 的实例,泛型限制要与返回结果类型一致。</span></span><br><span class="line"> FutureTask<Boolean> futureTask1 = <span class="keyword">new</span> <span class="type">FutureTask</span><>(t1);</span><br><span class="line"> FutureTask<Boolean> futureTask2 = <span class="keyword">new</span> <span class="type">FutureTask</span><>(t2);</span><br><span class="line"> FutureTask<Boolean> futureTask3 = <span class="keyword">new</span> <span class="type">FutureTask</span><>(t3);</span><br><span class="line"> <span class="comment">//将 FutureTask 的对象传给 Thread 来创建线程</span></span><br><span class="line"> <span class="keyword">new</span> <span class="type">Thread</span>(futureTask1).start();</span><br><span class="line"> <span class="keyword">new</span> <span class="type">Thread</span>(futureTask2).start();</span><br><span class="line"> <span class="keyword">new</span> <span class="type">Thread</span>(futureTask3).start();</span><br><span class="line"> <span class="comment">//获取结果</span></span><br><span class="line"> System.out.println(futureTask1.<span class="keyword">get</span>());</span><br><span class="line"> System.out.println(futureTask2.<span class="keyword">get</span>());</span><br><span class="line"> System.out.println(futureTask3.<span class="keyword">get</span>());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//重写 call()</span></span><br><span class="line"> @Override</span><br><span class="line"> <span class="keyword">public</span> Boolean call() {</span><br><span class="line"> ThreadTest06.ImagesDownloader imagesDownloader = <span class="keyword">new</span> <span class="type">ThreadTest06</span>.ImagesDownloader();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> imagesDownloader.downloader(url, FileName);</span><br><span class="line"> System.out.println(FileName + <span class="string">"下载完成"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//图片下载器</span></span><br><span class="line"> <span class="class"><span class="keyword">class</span> <span class="title">ImagesDownloader</span> </span>{</span><br><span class="line"> <span class="keyword">public</span> void downloader(<span class="keyword">String</span> link, <span class="keyword">String</span> filename) throws IOException {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> URL url = <span class="keyword">new</span> <span class="type">URL</span>(link);</span><br><span class="line"> url.openConnection().setRequestProperty(<span class="string">"User-Agent"</span>, <span class="string">"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"</span>); <span class="comment">//如果服务器端禁止抓取,那么可以通过设置 User-Agent 来欺骗服务器.</span></span><br><span class="line"> FileUtils.copyURLToFile(url, <span class="keyword">new</span> <span class="type">File</span>(filename));</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="程序、进程和线程"><a href="#程序、进程和线程" class="headerlink" title="程序、进程和线程"></a>程序、进程和线程</h2><p>程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。<br>进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。<br>通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是 CPU 调度和执行的的单位。</p>
<h2 id="普通方法调用和多线程启动"><a href="#普通方法调用和多线程启动" class="headerlink" title="普通方法调用和多线程启动"></a>普通方法调用和多线程启动</h2><p><img data-src="/images/javase-advanced17.md-0.png"></p>
<p><strong>注意:很多多线程是模拟出来的,真正的多线程是指有多个 CPU(多核),如服务器。如果是模拟出来的多线程,即在一个 CPU 的情况下,在同一个时间点,CPU 只能执行一个代码,因为切换得很快,所以就有同时执行的错觉。</strong></p></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="javase" scheme="http://guest997.tk/tags/javase/"/>
</entry>
<entry>
<title>JavaSE 进阶(十六)</title>
<link href="http://guest997.tk/2022/03/29/javase-advanced16/"/>
<id>http://guest997.tk/2022/03/29/javase-advanced16/</id>
<published>2022-03-29T03:25:22.000Z</published>
<updated>2022-04-05T13:54:02.482Z</updated>
<content type="html"><![CDATA[<h2 id="File"><a href="#File" class="headerlink" title="File"></a>File</h2><p>表示物理磁盘中的一个文件或者文件夹。</p><table><thead><tr><th>方法名</th><th>说明</th></tr></thead><tbody><tr><td>boolean CreateNewFile()</td><td>创建一个空文件。</td></tr><tr><td>boolean mkdir()</td><td>创建一个指定路径名的文件夹。</td></tr><tr><td>boolean delete()</td><td>删除一个指定的文件或文件夹,文件夹必须为空才能被删除。</td></tr><tr><td>boolean exists()</td><td>判断指定的文件或文件夹是否存在。</td></tr><tr><td>String getAbsolutePath()</td><td>返回文件或文件夹的绝对路径</td></tr><tr><td>String getName()</td><td>返回文件或文件夹的名称</td></tr><tr><td>String getParent()</td><td>返回文件/文件夹所在路径</td></tr><tr><td>boolean isDirectory()</td><td>判断是否为目录</td></tr><tr><td>boolean isFile()</td><td>判断是否为文件</td></tr><tr><td>long length()</td><td>返回文件的长度</td></tr><tr><td>File[] listFiles()</td><td>返回目录中的所有内容,一个文件数组。如果指定的路径不是一个目录就返回 null。</td></tr><tr><td>boolean renameTo(File dest)</td><td>重命名指定的文件。</td></tr></tbody></table><h3 id="文件操作"><a href="#文件操作" class="headerlink" title="文件操作"></a>文件操作</h3><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.<span class="keyword">File</span>;</span><br><span class="line"><span class="keyword">import</span> java.io.FileWriter;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> FileTest {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> main(String[] args) <span class="keyword">throws</span> IOException {</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">File</span>.separator); <span class="comment">//名称分隔符</span></span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">File</span>.pathSeparator); <span class="comment">//路径分隔符</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">File</span> <span class="keyword">file</span> = <span class="keyword">new</span> <span class="keyword">File</span>(<span class="string">"../IO/test.md"</span>); <span class="comment">//创建文件对象</span></span><br><span class="line"> <span class="keyword">if</span> (!<span class="keyword">file</span>.exists()) {</span><br><span class="line"> <span class="keyword">file</span>.createNewFile();</span><br><span class="line"> FileWriter fw = <span class="keyword">new</span> FileWriter(<span class="string">"test.md"</span>, <span class="keyword">true</span>); <span class="comment">//设置为追加内容</span></span><br><span class="line"> fw.<span class="keyword">write</span>(<span class="string">"https://guest997.ml - 一个在互联网下的小小 Coder"</span>);</span><br><span class="line"> fw.close();</span><br><span class="line"> }</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.length()); <span class="comment">//返回的是文件字节数</span></span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">new</span> Date(<span class="keyword">file</span>.lastModified()).toLocaleString()); <span class="comment">//获取文件最后修改时间</span></span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.isFile());</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.renameTo(<span class="keyword">new</span> <span class="keyword">File</span>(<span class="string">"rename.md"</span>)));</span><br><span class="line"> <span class="comment">//即使文件被重命名了,下面方法显示的文件名依旧是在创建文件对象时传入的文件名。</span></span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.getPath());</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.getAbsolutePath());</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.getName());</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.getParent()); <span class="comment">//只有在 new File 时,存在父路径,才能正常显示,否则为 null。</span></span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.<span class="keyword">delete</span>()); <span class="comment">//重命名之后会使得删除文件失败</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">\</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">58</span></span><br><span class="line"><span class="comment">2022-3-12 20:14:32</span></span><br><span class="line"><span class="comment">true</span></span><br><span class="line"><span class="comment">true</span></span><br><span class="line"><span class="comment">..\IO\test.md</span></span><br><span class="line"><span class="comment">E:\DEMO\IO\..\IO\test.md</span></span><br><span class="line"><span class="comment">test.md</span></span><br><span class="line"><span class="comment">..\IO</span></span><br><span class="line"><span class="comment">false</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h3 id="文件夹操作"><a href="#文件夹操作" class="headerlink" title="文件夹操作"></a>文件夹操作</h3><figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line">import java.io.File;</span><br><span class="line">import java.util.Arrays;</span><br><span class="line">import java.util.Date;</span><br><span class="line"></span><br><span class="line">public <span class="keyword">class</span> FolderTest {</span><br><span class="line"> public static void main(String<span class="literal">[]</span> args) {</span><br><span class="line"> File dir = <span class="keyword">new</span> <span class="constructor">File(<span class="string">"../IO/d1/d2"</span>)</span>;</span><br><span class="line"> <span class="keyword">if</span> (!dir.exists<span class="literal">()</span>) {</span><br><span class="line"> <span class="comment">//file.mkdir(); //只能创建单级目录</span></span><br><span class="line"> dir.mkdirs<span class="literal">()</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(dir.get<span class="constructor">Name()</span>);</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(dir.get<span class="constructor">Path()</span>);</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(dir.get<span class="constructor">AbsolutePath()</span>);</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(dir.get<span class="constructor">Parent()</span>);</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(<span class="keyword">new</span> <span class="constructor">Date(<span class="params">dir</span>.<span class="params">lastModified</span>()</span>).<span class="keyword">to</span><span class="constructor">LocaleString()</span>);</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(dir.is<span class="constructor">Directory()</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//遍历目录</span></span><br><span class="line"> File file = <span class="keyword">new</span> <span class="constructor">File(<span class="string">"E:/Demo/IO/target"</span>)</span>;</span><br><span class="line"> <span class="comment">//方式一</span></span><br><span class="line"> String<span class="literal">[]</span> <span class="built_in">list</span> = file.<span class="built_in">list</span><span class="literal">()</span>;</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(<span class="module-access"><span class="module"><span class="identifier">Arrays</span>.</span></span><span class="keyword">to</span><span class="constructor">String(<span class="params">list</span>)</span>);</span><br><span class="line"> <span class="comment">//方式二</span></span><br><span class="line"> File<span class="literal">[]</span> files = file.<span class="built_in">list</span><span class="constructor">Files()</span>;</span><br><span class="line"> <span class="keyword">for</span> (File f : files) {</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(f);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(dir.delete<span class="literal">()</span>); <span class="comment">//只能删除空的最后一级文件夹目录</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">d2</span></span><br><span class="line"><span class="comment">..\IO\d1\d2</span></span><br><span class="line"><span class="comment">E:\DEMO\IO\..\IO\d1\d2</span></span><br><span class="line"><span class="comment">..\IO\d1</span></span><br><span class="line"><span class="comment">2022-3-12 21:02:26</span></span><br><span class="line"><span class="comment">true</span></span><br><span class="line"><span class="comment">[classes, generated-sources]</span></span><br><span class="line"><span class="comment">E:\Demo\IO\target\classes</span></span><br><span class="line"><span class="comment">E:\Demo\IO\target\generated-sources</span></span><br><span class="line"><span class="comment">true</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h3 id="文件过滤器(FileFilter-接口)"><a href="#文件过滤器(FileFilter-接口)" class="headerlink" title="文件过滤器(FileFilter 接口)"></a>文件过滤器(FileFilter 接口)</h3><p>boolean accept(File pathname):当调用 File 类中的 listFiles 方法时,支持传入 FileFilter 接口实现类,对获取的文件进行过滤,只有满足条件的文件才可以出现在返回值中。</p><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.<span class="keyword">File</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> FF {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> main(String[] args) {</span><br><span class="line"> <span class="keyword">File</span> dir = <span class="keyword">new</span> <span class="keyword">File</span>(<span class="string">"../IO"</span>);</span><br><span class="line"> <span class="keyword">File</span>[] files = dir.listFiles(pathname -> pathname.getName().endsWith(<span class="string">".md"</span>));</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">File</span> <span class="keyword">file</span> : files) {</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//结果为 ..\IO\rename.md</span></span><br></pre></td></tr></table></figure><h3 id="递归遍历和删除文件夹"><a href="#递归遍历和删除文件夹" class="headerlink" title="递归遍历和删除文件夹"></a>递归遍历和删除文件夹</h3><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.<span class="keyword">File</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> RecursiveFolder {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> main(String[] args) {</span><br><span class="line"> traverseFolder(<span class="keyword">new</span> <span class="keyword">File</span>(<span class="string">".idea"</span>));</span><br><span class="line"> deleteFolder(<span class="keyword">new</span> <span class="keyword">File</span>(<span class="string">"target"</span>));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//递归遍历文件夹</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> traverseFolder(<span class="keyword">File</span> dir) {</span><br><span class="line"> <span class="keyword">File</span>[] files = dir.listFiles();</span><br><span class="line"> <span class="keyword">if</span> (files != <span class="keyword">null</span> && files.length > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">File</span> <span class="keyword">file</span> : files) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">file</span>.isDirectory()) {</span><br><span class="line"> traverseFolder(<span class="keyword">file</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.getAbsolutePath());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//递归删除文件夹</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> deleteFolder(<span class="keyword">File</span> dir) {</span><br><span class="line"> <span class="keyword">File</span>[] files = dir.listFiles();</span><br><span class="line"> <span class="keyword">if</span> (files != <span class="keyword">null</span> && files.length > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">File</span> <span class="keyword">file</span> : files) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">file</span>.isDirectory()) {</span><br><span class="line"> deleteFolder(<span class="keyword">file</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">file</span>.<span class="keyword">delete</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> dir.<span class="keyword">delete</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">E:\DEMO\IO\.idea\.gitignore</span></span><br><span class="line"><span class="comment">E:\DEMO\IO\.idea\compiler.xml</span></span><br><span class="line"><span class="comment">E:\DEMO\IO\.idea\encodings.xml</span></span><br><span class="line"><span class="comment">E:\DEMO\IO\.idea\inspectionProfiles\Project_Default.xml</span></span><br><span class="line"><span class="comment">E:\DEMO\IO\.idea\jarRepositories.xml</span></span><br><span class="line"><span class="comment">E:\DEMO\IO\.idea\misc.xml</span></span><br><span class="line"><span class="comment">E:\DEMO\IO\.idea\runConfigurations.xml</span></span><br><span class="line"><span class="comment">E:\DEMO\IO\.idea\workspace.xml</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h2 id="Properties"><a href="#Properties" class="headerlink" title="Properties"></a>Properties</h2><p>以键值对的形式存储属性名和属性值。属性名和属性值都是字符串类型。</p><figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line">package ml.guest997;</span><br><span class="line"></span><br><span class="line">import java.io.*;</span><br><span class="line">import java.util.Map;</span><br><span class="line">import java.util.Properties;</span><br><span class="line"></span><br><span class="line">public <span class="keyword">class</span> PropertiesTest {</span><br><span class="line"> public static void main(String<span class="literal">[]</span> args) throws IOException {</span><br><span class="line"> Properties properties = <span class="keyword">new</span> <span class="constructor">Properties()</span>;</span><br><span class="line"> <span class="comment">//设置的属性最好不要有中文</span></span><br><span class="line"> properties.set<span class="constructor">Property(<span class="string">"Blog"</span>, <span class="string">"https://guest997.ml"</span>)</span>;</span><br><span class="line"> properties.set<span class="constructor">Property(<span class="string">"Guest997"</span>, <span class="string">"一个在互联网下的小小 Coder"</span>)</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//遍历</span></span><br><span class="line"> <span class="keyword">for</span> (Object key : properties.key<span class="constructor">Set()</span>) {</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(key);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (Object value : properties.values<span class="literal">()</span>) {</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(value);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (Map.Entry<Object, Object> kv : properties.entry<span class="constructor">Set()</span>) {</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(kv.get<span class="constructor">Key()</span>);</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(kv.get<span class="constructor">Value()</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (String propertyName : properties.<span class="built_in">string</span><span class="constructor">PropertyNames()</span>) {</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(propertyName + <span class="string">":"</span> + properties.get<span class="constructor">Property(<span class="params">propertyName</span>)</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//通过流读取和写入</span></span><br><span class="line"> PrintWriter pw = <span class="keyword">new</span> <span class="constructor">PrintWriter(<span class="string">"print.md"</span>)</span>;</span><br><span class="line"> properties.<span class="built_in">list</span>(pw);</span><br><span class="line"> pw.close<span class="literal">()</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//保存</span></span><br><span class="line"> FileWriter fw = <span class="keyword">new</span> <span class="constructor">FileWriter(<span class="string">"test.properties"</span>)</span>;</span><br><span class="line"> properties.store(fw, <span class="string">"注释"</span>);</span><br><span class="line"> fw.close<span class="literal">()</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//加载</span></span><br><span class="line"> Properties properties2 = <span class="keyword">new</span> <span class="constructor">Properties()</span>;</span><br><span class="line"> FileReader fr = <span class="keyword">new</span> <span class="constructor">FileReader(<span class="string">"test.properties"</span>)</span>;</span><br><span class="line"> properties2.load(fr);</span><br><span class="line"> fr.close<span class="literal">()</span>;</span><br><span class="line"> <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(properties2);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">Guest997</span></span><br><span class="line"><span class="comment">Blog</span></span><br><span class="line"><span class="comment">一个在互联网下的小小 Coder</span></span><br><span class="line"><span class="comment">https://guest997.ml</span></span><br><span class="line"><span class="comment">Guest997</span></span><br><span class="line"><span class="comment">一个在互联网下的小小 Coder</span></span><br><span class="line"><span class="comment">Blog</span></span><br><span class="line"><span class="comment">https://guest997.ml</span></span><br><span class="line"><span class="comment">Guest997:一个在互联网下的小小 Coder</span></span><br><span class="line"><span class="comment">Blog:https://guest997.ml</span></span><br><span class="line"><span class="comment">{Guest997=一个在互联网下的小小 Coder, Blog=https://guest997.ml}</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p>print.md</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">-- listing properties --</span><br><span class="line"><span class="attribute">Guest997</span>=一个在互联网下的小小 Coder</span><br><span class="line"><span class="attribute">Blog</span>=https://guest997.ml</span><br></pre></td></tr></table></figure><p>test.properties</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#\u6CE8\u91CA</span></span><br><span class="line"><span class="comment">#Sat Mar 12 22:16:37 CST 2022</span></span><br><span class="line"><span class="attr">Guest997</span>=一个在互联网下的小小 Coder</span><br><span class="line"><span class="attr">Blog</span>=https\://guest997.ml</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="File"><a href="#File" class="headerlink" title="File"></a>File</h2><p>表示物理磁盘中的一个文件或者文件夹。</p>
<table>
<thead>
<tr>
<th>方法名</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>boolean CreateNewFile()</td>
<td>创建一个空文件。</td>
</tr>
<tr>
<td>boolean mkdir()</td>
<td>创建一个指定路径名的文件夹。</td>
</tr>
<tr>
<td>boolean delete()</td>
<td>删除一个指定的文件或文件夹,文件夹必须为空才能被删除。</td>
</tr>
<tr>
<td>boolean exists()</td>
<td>判断指定的文件或文件夹是否存在。</td>
</tr>
<tr>
<td>String getAbsolutePath()</td>
<td>返回文件或文件夹的绝对路径</td>
</tr>
<tr>
<td>String getName()</td>
<td>返回文件或文件夹的名称</td>
</tr>
<tr>
<td>String getParent()</td>
<td>返回文件/文件夹所在路径</td>
</tr>
<tr>
<td>boolean isDirectory()</td>
<td>判断是否为目录</td>
</tr>
<tr>
<td>boolean isFile()</td>
<td>判断是否为文件</td>
</tr>
<tr>
<td>long length()</td>
<td>返回文件的长度</td>
</tr>
<tr>
<td>File[] listFiles()</td>
<td>返回目录中的所有内容,一个文件数组。如果指定的路径不是一个目录就返回 null。</td>
</tr>
<tr>
<td>boolean renameTo(File dest)</td>
<td>重命名指定的文件。</td>
</tr>
</tbody></table>
<h3 id="文件操作"><a href="#文件操作" class="headerlink" title="文件操作"></a>文件操作</h3><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.<span class="keyword">File</span>;</span><br><span class="line"><span class="keyword">import</span> java.io.FileWriter;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> FileTest &#123;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> main(String[] args) <span class="keyword">throws</span> IOException &#123;</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">File</span>.separator); <span class="comment">//名称分隔符</span></span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">File</span>.pathSeparator); <span class="comment">//路径分隔符</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">File</span> <span class="keyword">file</span> = <span class="keyword">new</span> <span class="keyword">File</span>(<span class="string">&quot;../IO/test.md&quot;</span>); <span class="comment">//创建文件对象</span></span><br><span class="line"> <span class="keyword">if</span> (!<span class="keyword">file</span>.exists()) &#123;</span><br><span class="line"> <span class="keyword">file</span>.createNewFile();</span><br><span class="line"> FileWriter fw = <span class="keyword">new</span> FileWriter(<span class="string">&quot;test.md&quot;</span>, <span class="keyword">true</span>); <span class="comment">//设置为追加内容</span></span><br><span class="line"> fw.<span class="keyword">write</span>(<span class="string">&quot;https://guest997.ml - 一个在互联网下的小小 Coder&quot;</span>);</span><br><span class="line"> fw.close();</span><br><span class="line"> &#125;</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.length()); <span class="comment">//返回的是文件字节数</span></span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">new</span> Date(<span class="keyword">file</span>.lastModified()).toLocaleString()); <span class="comment">//获取文件最后修改时间</span></span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.isFile());</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.renameTo(<span class="keyword">new</span> <span class="keyword">File</span>(<span class="string">&quot;rename.md&quot;</span>)));</span><br><span class="line"> <span class="comment">//即使文件被重命名了,下面方法显示的文件名依旧是在创建文件对象时传入的文件名。</span></span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.getPath());</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.getAbsolutePath());</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.getName());</span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.getParent()); <span class="comment">//只有在 new File 时,存在父路径,才能正常显示,否则为 null。</span></span><br><span class="line"> System.out.<span class="keyword">println</span>(<span class="keyword">file</span>.<span class="keyword">delete</span>()); <span class="comment">//重命名之后会使得删除文件失败</span></span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">\</span></span><br><span class="line"><span class="comment">;</span></span><br><span class="line"><span class="comment">58</span></span><br><span class="line"><span class="comment">2022-3-12 20:14:32</span></span><br><span class="line"><span class="comment">true</span></span><br><span class="line"><span class="comment">true</span></span><br><span class="line"><span class="comment">..\IO\test.md</span></span><br><span class="line"><span class="comment">E:\DEMO\IO\..\IO\test.md</span></span><br><span class="line"><span class="comment">test.md</span></span><br><span class="line"><span class="comment">..\IO</span></span><br><span class="line"><span class="comment">false</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="javase" scheme="http://guest997.tk/tags/javase/"/>
</entry>
<entry>
<title>JavaSE 进阶(十五)</title>
<link href="http://guest997.tk/2022/03/28/javase-advanced15/"/>
<id>http://guest997.tk/2022/03/28/javase-advanced15/</id>
<published>2022-03-28T05:19:44.000Z</published>
<updated>2022-04-05T13:54:02.476Z</updated>
<content type="html"><![CDATA[<h2 id="流(续)"><a href="#流(续)" class="headerlink" title="流(续)"></a>流(续)</h2><h3 id="字符流"><a href="#字符流" class="headerlink" title="字符流"></a>字符流</h3><p><img data-src="/images/javase-advanced15.md-0.png"></p><h4 id="字符流的父类(抽象类)"><a href="#字符流的父类(抽象类)" class="headerlink" title="字符流的父类(抽象类)"></a>字符流的父类(抽象类)</h4><ul><li> Reader(字符输入流)</li><li> Writer(字符输出流)</li></ul><h4 id="字符流的子类"><a href="#字符流的子类" class="headerlink" title="字符流的子类"></a>字符流的子类</h4><h5 id="文件字符流(自带缓冲区)"><a href="#文件字符流(自带缓冲区)" class="headerlink" title="文件字符流(自带缓冲区)"></a>文件字符流(自带缓冲区)</h5><ul><li>FileReader<ul><li>int read():从输入流中读取一个字符数据。返回读到的字符数据,如果达到流末尾,返回-1。</li><li>int read(char[] c):从输入流中读取字符数组长度的字符数据存入数组中。返回实际读到的字符数,如果达到流末尾,返回-1。</li></ul></li><li>FileWriter<ul><li>void write(int n):将指定字符写入输出流,只能写入包含16位低阶字节的整型数值,16位高阶字节将会被忽略。</li><li>void write(String str):将指定字符串写入输出流。</li><li>void write(char[] cbuf):将指定字符数组写入输出流。</li></ul></li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.FileReader;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FR</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> FileReader fr = <span class="keyword">new</span> FileReader(<span class="string">"test.txt"</span>);</span><br><span class="line"> <span class="keyword">int</span> data;</span><br><span class="line"> <span class="keyword">while</span> ((data = fr.read()) != -<span class="number">1</span>) {</span><br><span class="line"> System.out.print((<span class="keyword">char</span>) data);</span><br><span class="line"> }</span><br><span class="line"> fr.close();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//结果为 123abc你好</span></span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.FileWriter;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FW</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> FileWriter fw = <span class="keyword">new</span> FileWriter(<span class="string">"out3.txt"</span>);</span><br><span class="line"> fw.write(<span class="number">110</span>);</span><br><span class="line"> fw.write(<span class="string">"Guest997"</span>);</span><br><span class="line"> fw.write(<span class="string">"你好"</span>);</span><br><span class="line"> fw.close();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//输出的文件内容为 nGuest997你好</span></span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.FileReader;</span><br><span class="line"><span class="keyword">import</span> java.io.FileWriter;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="comment">//文件复制(只能复制文本文件,因为其它文件并没有字符编码,自然就无法正常读取和写入)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CopyFile2</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> FileReader fr = <span class="keyword">new</span> FileReader(<span class="string">"test.txt"</span>);</span><br><span class="line"> FileWriter fw = <span class="keyword">new</span> FileWriter(<span class="string">"copy2.txt"</span>);</span><br><span class="line"> <span class="keyword">int</span> data;</span><br><span class="line"> <span class="keyword">while</span> ((data = fr.read()) != -<span class="number">1</span>) {</span><br><span class="line"> fw.write(data);</span><br><span class="line"> }</span><br><span class="line"> fr.close();</span><br><span class="line"> fw.close();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//输出的文件内容为 123abc你好</span></span><br></pre></td></tr></table></figure><h5 id="字符缓冲流"><a href="#字符缓冲流" class="headerlink" title="字符缓冲流"></a>字符缓冲流</h5><p>BufferedReader / BufferedWriter</p><ul><li> 高效读写</li><li> 支持换行输入符</li><li> 支持读一行或写一行</li></ul><figure class="highlight processing"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.<span class="keyword">BufferedReader</span>;</span><br><span class="line"><span class="keyword">import</span> java.io.FileReader;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> class BR {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> main(<span class="keyword">String</span>[] args) <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="comment">//方法一</span></span><br><span class="line"> FileReader fr1 = <span class="keyword">new</span> FileReader(<span class="string">"test2.txt"</span>);</span><br><span class="line"> <span class="keyword">BufferedReader</span> br1 = <span class="keyword">new</span> <span class="keyword">BufferedReader</span>(fr1); <span class="comment">//需要传入 Reader 的实现类</span></span><br><span class="line"> <span class="built_in">int</span> data;</span><br><span class="line"> <span class="keyword">while</span> ((data = br1.read()) != <span class="number">-1</span>) {</span><br><span class="line"> System.out.<span class="built_in">print</span>((<span class="built_in">char</span>) data);</span><br><span class="line"> }</span><br><span class="line"> br1.close(); <span class="comment">//只需关闭 br 即可,br 内部会关闭 fr。</span></span><br><span class="line"></span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"\n------"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//方法二</span></span><br><span class="line"> FileReader fr2 = <span class="keyword">new</span> FileReader(<span class="string">"test2.txt"</span>);</span><br><span class="line"> <span class="keyword">BufferedReader</span> br2 = <span class="keyword">new</span> <span class="keyword">BufferedReader</span>(fr2);</span><br><span class="line"> <span class="keyword">String</span> lineData;</span><br><span class="line"> <span class="keyword">while</span> ((lineData = br2.readLine()) != <span class="keyword">null</span>) { <span class="comment">//读取一行数据,读取到最后一行之后就为 null。</span></span><br><span class="line"> System.out.<span class="built_in">println</span>(lineData);</span><br><span class="line"> }</span><br><span class="line"> br2.close();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*结果为</span></span><br><span class="line"><span class="comment">456</span></span><br><span class="line"><span class="comment">def</span></span><br><span class="line"><span class="comment">世界</span></span><br><span class="line"><span class="comment">------</span></span><br><span class="line"><span class="comment">456</span></span><br><span class="line"><span class="comment">def</span></span><br><span class="line"><span class="comment">世界</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.BufferedWriter;</span><br><span class="line"><span class="keyword">import</span> java.io.FileWriter;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BW</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> FileWriter fw = <span class="keyword">new</span> FileWriter(<span class="string">"out4.txt"</span>);</span><br><span class="line"> BufferedWriter bw = <span class="keyword">new</span> BufferedWriter(fw);</span><br><span class="line"> bw.write(<span class="string">"Guest997"</span>);</span><br><span class="line"> bw.newLine(); <span class="comment">//换行</span></span><br><span class="line"> bw.write(<span class="string">"一个在互联网下的小小 Coder"</span>);</span><br><span class="line"> bw.close();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*输出的文件内容为</span></span><br><span class="line"><span class="comment">Guest997</span></span><br><span class="line"><span class="comment">一个在互联网下的小小 Coder</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h5 id="打印流"><a href="#打印流" class="headerlink" title="打印流"></a>打印流</h5><p>PrintWriter</p><ul><li> 封装了 print() 和 println()。</li><li> 支持数据原样打印。</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.FileNotFoundException;</span><br><span class="line"><span class="keyword">import</span> java.io.PrintWriter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PW</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> FileNotFoundException </span>{</span><br><span class="line"> PrintWriter pw = <span class="keyword">new</span> PrintWriter(<span class="string">"print.txt"</span>);</span><br><span class="line"> pw.println(<span class="number">110</span>);</span><br><span class="line"> pw.println(<span class="string">"你好"</span>);</span><br><span class="line"> pw.println(<span class="number">3.1415926</span>);</span><br><span class="line"> pw.println(<span class="keyword">true</span>);</span><br><span class="line"> pw.close();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*输出的文件内容为</span></span><br><span class="line"><span class="comment">110</span></span><br><span class="line"><span class="comment">你好</span></span><br><span class="line"><span class="comment">3.1415926</span></span><br><span class="line"><span class="comment">true</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h5 id="转换流"><a href="#转换流" class="headerlink" title="转换流"></a>转换流</h5><p>InputStreamReader / OutputStreamWriter</p><ul><li> 字节流和字符流互转。</li><li> 可设置字符的编码方式。</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.FileInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStreamReader;</span><br><span class="line"><span class="keyword">import</span> java.nio.charset.StandardCharsets;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ISR</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> FileInputStream fis = <span class="keyword">new</span> FileInputStream(<span class="string">"test.txt"</span>);</span><br><span class="line"> InputStreamReader isr = <span class="keyword">new</span> InputStreamReader(fis, StandardCharsets.UTF_8); <span class="comment">//需要传入 InputStream 的实现类</span></span><br><span class="line"> <span class="keyword">int</span> data;</span><br><span class="line"> <span class="keyword">while</span> ((data = isr.read()) != -<span class="number">1</span>) {</span><br><span class="line"> System.out.print((<span class="keyword">char</span>) data); <span class="comment">//之前使用 FileInputStream 读取中文时是会乱码的。</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//结果为 123abc你好</span></span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> ml.guest997;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.FileOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.OutputStreamWriter;</span><br><span class="line"><span class="keyword">import</span> java.nio.charset.StandardCharsets;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OSW</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> FileOutputStream fos = <span class="keyword">new</span> FileOutputStream(<span class="string">"out5.txt"</span>);</span><br><span class="line"> OutputStreamWriter osw = <span class="keyword">new</span> OutputStreamWriter(fos, StandardCharsets.UTF_8);</span><br><span class="line"> osw.write(<span class="number">99</span>);</span><br><span class="line"> osw.write(<span class="string">"guest"</span>); <span class="comment">//之前使用 FileOutputStream 还需要转成字节数组,中文还需要设置编码。</span></span><br><span class="line"> osw.write(<span class="string">"你好"</span>);</span><br><span class="line"> osw.close();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//输出的文件内容为 cguest你好</span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="流(续)"><a href="#流(续)" class="headerlink" title="流(续)"></a>流(续)</h2><h3 id="字符流"><a href="#字符流" class="headerlink" title="字符流"></a>字符流</h3><p><img data-src="/images/javase-advanced15.md-0.png"></p>
<h4 id="字符流的父类(抽象类)"><a href="#字符流的父类(抽象类)" class="headerlink" title="字符流的父类(抽象类)"></a>字符流的父类(抽象类)</h4><ul>
<li> Reader(字符输入流)</li>
<li> Writer(字符输出流)</li>
</ul></summary>
<category term="学习" scheme="http://guest997.tk/categories/%E5%AD%A6%E4%B9%A0/"/>
<category term="学习" scheme="http://guest997.tk/tags/%E5%AD%A6%E4%B9%A0/"/>
<category term="javase" scheme="http://guest997.tk/tags/javase/"/>
</entry>
</feed>