-
Notifications
You must be signed in to change notification settings - Fork 0
/
devops-deploy-tomcat.html
480 lines (478 loc) · 161 KB
/
devops-deploy-tomcat.html
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
<!DOCTYPE html>
<html lang="zh-CN" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>WEB开发介绍 | 广度和深度</title>
<meta name="description" content="整理和记录代码学习的笔记">
<link rel="preload stylesheet" href="/assets/style.66b7dec6.css" as="style">
<script type="module" src="/assets/app.f6aa04bd.js"></script>
<link rel="preload" href="/assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
<link rel="modulepreload" href="/assets/chunks/framework.027d2da0.js">
<link rel="modulepreload" href="/assets/chunks/theme.98d176af.js">
<link rel="modulepreload" href="/assets/devops-deploy-tomcat.md.53274c1f.lean.js">
<link rel="icon" href="./favicon.ico">
<script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"dark",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
<script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
</head>
<body>
<div id="app"><div class="Layout" data-v-8692e0c2><!--[--><!--]--><!--[--><span tabindex="-1" data-v-7da17955></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-7da17955> Skip to content </a><!--]--><!----><header class="VPNav" data-v-8692e0c2 data-v-bcf310a9><div class="VPNavBar has-sidebar" data-v-bcf310a9 data-v-7192d962><div class="container" data-v-7192d962><div class="title" data-v-7192d962><div class="VPNavBarTitle has-sidebar" data-v-7192d962 data-v-56d4391f><a class="title" href="/" data-v-56d4391f><!--[--><!--]--><!--[--><img class="VPImage logo" src="./logo.jpg" alt data-v-506001e8><!--]--><!--[-->Coder<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-7192d962><div class="curtain" data-v-7192d962></div><div class="content-body" data-v-7192d962><!--[--><!--]--><div class="VPNavBarSearch search" data-v-7192d962><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg class="DocSearch-Search-Icon" width="20" height="20" viewBox="0 0 20 20" aria-label="search icon"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-7192d962 data-v-359face2><span id="main-nav-aria-label" class="visually-hidden" data-v-359face2>Main Navigation</span><!--[--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-359face2 data-v-bb4a2dc7><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-bb4a2dc7><span class="text" data-v-bb4a2dc7><!----><span data-v-bb4a2dc7>♎语言</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-bb4a2dc7><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-bb4a2dc7><div class="VPMenu" data-v-bb4a2dc7 data-v-5d7a6046><div class="items" data-v-5d7a6046><!--[--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/lang-java.html" data-v-b6a76a69><!--[-->1️⃣ Java<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/lang-python.html" data-v-b6a76a69><!--[-->2️⃣ Python<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/lang-scala.html" data-v-b6a76a69><!--[-->3️⃣ Scala<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/lang-groovy.html" data-v-b6a76a69><!--[-->4️⃣ Groovy<!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-359face2 data-v-bb4a2dc7><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-bb4a2dc7><span class="text" data-v-bb4a2dc7><!----><span data-v-bb4a2dc7>☯️算法</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-bb4a2dc7><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-bb4a2dc7><div class="VPMenu" data-v-bb4a2dc7 data-v-5d7a6046><div class="items" data-v-5d7a6046><!--[--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>算法篇</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫代码规范<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫设计模式<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫数据结构<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫源码解读<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>并发篇</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫JVM<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫并发编程<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>设计篇</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫系统设计<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫数仓理论<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>职业篇</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫方向导航<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫职业规划<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫面试准备<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-359face2 data-v-bb4a2dc7><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-bb4a2dc7><span class="text" data-v-bb4a2dc7><!----><span data-v-bb4a2dc7>♈前端</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-bb4a2dc7><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-bb4a2dc7><div class="VPMenu" data-v-bb4a2dc7 data-v-5d7a6046><div class="items" data-v-5d7a6046><!--[--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫HTML<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫CSS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫JavaScript<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫JQuery<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫NodeJS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Vue<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫React<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫小程序<!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-359face2 data-v-bb4a2dc7><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-bb4a2dc7><span class="text" data-v-bb4a2dc7><!----><span data-v-bb4a2dc7>🔯微服务</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-bb4a2dc7><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-bb4a2dc7><div class="VPMenu" data-v-bb4a2dc7 data-v-5d7a6046><div class="items" data-v-5d7a6046><!--[--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫RPC<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Spring<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Spring MVC<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Spring Boot<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Spring Cloud<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Spring Cloud Alibaba<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Service Mesh<!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-359face2 data-v-bb4a2dc7><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-bb4a2dc7><span class="text" data-v-bb4a2dc7><!----><span data-v-bb4a2dc7>⚧️数据存储</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-bb4a2dc7><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-bb4a2dc7><div class="VPMenu" data-v-bb4a2dc7 data-v-5d7a6046><div class="items" data-v-5d7a6046><!--[--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>SQL数据库</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫MySQL<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Oracle<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>NoSQL数据库</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Redis<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫MongoDB<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>NewSQL数据库</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫TiDB<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>ORM框架</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Mybatis<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Mybatis Plus<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Spring Data JPA<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>消息中间件</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Active MQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫RabbitMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫RocketMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Kafka<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>文件存储</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫FastDFS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Ceph<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫HDFS<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>搜索引擎</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Lucene<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Solr<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫ElasticSearch<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-359face2 data-v-bb4a2dc7><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-bb4a2dc7><span class="text" data-v-bb4a2dc7><!----><span data-v-bb4a2dc7>☸️DevOps</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-bb4a2dc7><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-bb4a2dc7><div class="VPMenu" data-v-bb4a2dc7 data-v-5d7a6046><div class="items" data-v-5d7a6046><!--[--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>部署</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/devops-deploy-tomcat.html" data-v-b6a76a69><!--[-->Tomcat<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/devops-deploy-tomcat.html" data-v-b6a76a69><!--[-->🚫Linux<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/devops-deploy-shell.html" data-v-b6a76a69><!--[-->Shell<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/devops-deploy-tomcat.html" data-v-b6a76a69><!--[-->🚫Nginx<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/devops-deploy-tomcat.html" data-v-b6a76a69><!--[-->🚫Linux<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/devops-deploy-tomcat.html" data-v-b6a76a69><!--[-->🚫LVS+Keepalived<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/devops-deploy-tomcat.html" data-v-b6a76a69><!--[-->🚫OpenResty+Kong<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>容器</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Docker<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Kubernates<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>云服务器</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫IaaS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫UCloud<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>持续集成</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Jenkins<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>监控工具</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Arthas<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Zabbix<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>链路追踪</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Sleuth+Zipkin<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫Skywalking<!--]--></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-5d7a6046 data-v-2d40012a><p class="title" data-v-2d40012a>性能压测</p><!--[--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫JMeter<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2d40012a data-v-b6a76a69><a class="VPLink link" href="/#" data-v-b6a76a69><!--[-->🚫全链路压测<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-359face2 data-v-bb4a2dc7><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-bb4a2dc7><span class="text" data-v-bb4a2dc7><!----><span data-v-bb4a2dc7>✝️工具</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-bb4a2dc7><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-bb4a2dc7><div class="VPMenu" data-v-bb4a2dc7 data-v-5d7a6046><div class="items" data-v-5d7a6046><!--[--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/tools-soft.html" data-v-b6a76a69><!--[-->软性办公工具<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/tools-vcs.html" data-v-b6a76a69><!--[-->版本控制工具<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/tools-dev.html" data-v-b6a76a69><!--[-->包管理工具<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/tools-dev.html" data-v-b6a76a69><!--[-->项目构建工具<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/tools-dev.html" data-v-b6a76a69><!--[-->编程工具<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/tools-dev.html" data-v-b6a76a69><!--[-->数据库管理<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/tools-dev.html" data-v-b6a76a69><!--[-->虚拟机工具<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/tools-dev.html" data-v-b6a76a69><!--[-->SSH工具<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/tools-dev.html" data-v-b6a76a69><!--[-->调试工具<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-5d7a6046 data-v-b6a76a69><a class="VPLink link" href="/tools-dev.html" data-v-b6a76a69><!--[-->压测工具<!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-7192d962 data-v-5c7f08f3><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-5c7f08f3 data-v-f44e5024 data-v-23c4cb6c><span class="check" data-v-23c4cb6c><span class="icon" data-v-23c4cb6c><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-f44e5024><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-f44e5024><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><!----><div class="VPFlyout VPNavBarExtra extra" data-v-7192d962 data-v-4a4a2081 data-v-bb4a2dc7><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-bb4a2dc7><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-bb4a2dc7><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-bb4a2dc7><div class="VPMenu" data-v-bb4a2dc7 data-v-5d7a6046><!----><!--[--><!--[--><!----><div class="group" data-v-4a4a2081><div class="item appearance" data-v-4a4a2081><p class="label" data-v-4a4a2081>深浅模式</p><div class="appearance-action" data-v-4a4a2081><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-4a4a2081 data-v-f44e5024 data-v-23c4cb6c><span class="check" data-v-23c4cb6c><span class="icon" data-v-23c4cb6c><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-f44e5024><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-f44e5024><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><!----><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-7192d962 data-v-9cc97dbb><span class="container" data-v-9cc97dbb><span class="top" data-v-9cc97dbb></span><span class="middle" data-v-9cc97dbb></span><span class="bottom" data-v-9cc97dbb></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav reached-top" data-v-8692e0c2 data-v-a8f7ff89><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-a8f7ff89><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-a8f7ff89><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-a8f7ff89>菜单</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-a8f7ff89 data-v-a050d324><button data-v-a050d324>返回顶部</button><!----></div></div><aside class="VPSidebar" data-v-8692e0c2 data-v-cde32d1c><div class="curtain" data-v-cde32d1c></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-cde32d1c><span class="visually-hidden" id="sidebar-aria-label" data-v-cde32d1c> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-cde32d1c><section class="VPSidebarItem level-0 collapsible collapsed" data-v-cde32d1c data-v-1f85ec84><div class="item" role="button" tabindex="0" data-v-1f85ec84><div class="indicator" data-v-1f85ec84></div><h2 class="text" data-v-1f85ec84>部署</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-1f85ec84><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-1f85ec84><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-1f85ec84><!--[--><div class="VPSidebarItem level-1 is-link" data-v-1f85ec84 data-v-1f85ec84><div class="item" data-v-1f85ec84><div class="indicator" data-v-1f85ec84></div><a class="VPLink link link" href="/devops-deploy-tomcat.html" data-v-1f85ec84><!--[--><p class="text" data-v-1f85ec84>Tomcat</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1f85ec84 data-v-1f85ec84><div class="item" data-v-1f85ec84><div class="indicator" data-v-1f85ec84></div><a class="VPLink link link" href="/devops-deploy-shell.html" data-v-1f85ec84><!--[--><p class="text" data-v-1f85ec84>Shell</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1f85ec84 data-v-1f85ec84><div class="item" data-v-1f85ec84><div class="indicator" data-v-1f85ec84></div><a class="VPLink link link" href="/devops-deploy-lvs.html" data-v-1f85ec84><!--[--><p class="text" data-v-1f85ec84>LVS</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1f85ec84 data-v-1f85ec84><div class="item" data-v-1f85ec84><div class="indicator" data-v-1f85ec84></div><a class="VPLink link link" href="/devops-deploy-nginx.html" data-v-1f85ec84><!--[--><p class="text" data-v-1f85ec84>Nginx</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1f85ec84 data-v-1f85ec84><div class="item" data-v-1f85ec84><div class="indicator" data-v-1f85ec84></div><a class="VPLink link link" href="/devops-deploy-openresty.html" data-v-1f85ec84><!--[--><p class="text" data-v-1f85ec84>OpenResty</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-1f85ec84 data-v-1f85ec84><div class="item" data-v-1f85ec84><div class="indicator" data-v-1f85ec84></div><a class="VPLink link link" href="/devops-deploy-evernote.html" data-v-1f85ec84><!--[--><p class="text" data-v-1f85ec84>Evernote</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-8692e0c2 data-v-87044f80><div class="VPDoc has-sidebar has-aside" data-v-87044f80 data-v-e970bbc0><!--[--><!--]--><div class="container" data-v-e970bbc0><div class="aside" data-v-e970bbc0><div class="aside-curtain" data-v-e970bbc0></div><div class="aside-container" data-v-e970bbc0><div class="aside-content" data-v-e970bbc0><div class="VPDocAside" data-v-e970bbc0 data-v-0473afe5><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" role="navigation" data-v-0473afe5 data-v-b2f90363><div class="content" data-v-b2f90363><div class="outline-marker" data-v-b2f90363></div><div class="outline-title" role="heading" aria-level="2" data-v-b2f90363>目录</div><nav aria-labelledby="doc-outline-aria-label" data-v-b2f90363><span class="visually-hidden" id="doc-outline-aria-label" data-v-b2f90363> Table of Contents for current page </span><ul class="root" data-v-b2f90363 data-v-3d0f3048><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-0473afe5></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-e970bbc0><div class="content-container" data-v-e970bbc0><!--[--><!--]--><!----><main class="main" data-v-e970bbc0><div style="position:relative;" class="vp-doc _devops-deploy-tomcat" data-v-e970bbc0><div><h1 id="web开发介绍" tabindex="-1">WEB开发介绍 <a class="header-anchor" href="#web开发介绍" aria-label="Permalink to "WEB开发介绍""></a></h1><h2 id="web资源分类-理解" tabindex="-1">WEB资源分类(理解) <a class="header-anchor" href="#web资源分类-理解" aria-label="Permalink to "WEB资源分类(理解)""></a></h2><h3 id="什么是web" tabindex="-1">什么是web <a class="header-anchor" href="#什么是web" aria-label="Permalink to "什么是web""></a></h3><p> WEB,在英语中web即表示网页的意思,它用于<strong>表示Internet主机(服务器)上供外界访问的资源</strong></p><h3 id="web资源分类" tabindex="-1">WEB资源分类 <a class="header-anchor" href="#web资源分类" aria-label="Permalink to "WEB资源分类""></a></h3><h4 id="静态资源" tabindex="-1">静态资源 <a class="header-anchor" href="#静态资源" aria-label="Permalink to "静态资源""></a></h4><ul><li>web页面中供人们浏览的数据始终是不变 (eg: html,css,js、音视频)</li></ul><h4 id="动态资源" tabindex="-1">动态资源 <a class="header-anchor" href="#动态资源" aria-label="Permalink to "动态资源""></a></h4><ul><li>指web页面中供人们浏览的数据是由程序产生的,不同的用户或者不同时间点访问web页面看到的内容各不相同。(eg: servlet,jsp)</li></ul><h3 id="小结" tabindex="-1">小结 <a class="header-anchor" href="#小结" aria-label="Permalink to "小结""></a></h3><ol><li>什么是WEB资源:放在服务器上供客户端访问的资源</li><li>WEB资源的分类: <ol><li>静态资源:WEB页面中共用户访问的数据始终是不变的,比如说:html、css、js、图片、音视频等等</li><li>动态资源:WEB页面中供用户访问的数据是由程序产生的,是会发生变化的,比如Servlet、jsp</li></ol></li></ol><h2 id="软件架构-理解" tabindex="-1">软件架构(理解) <a class="header-anchor" href="#软件架构-理解" aria-label="Permalink to "软件架构(理解)""></a></h2><h3 id="架构类别" tabindex="-1">架构类别 <a class="header-anchor" href="#架构类别" aria-label="Permalink to "架构类别""></a></h3><h4 id="c-s架构" tabindex="-1">C/S架构 <a class="header-anchor" href="#c-s架构" aria-label="Permalink to "C/S架构""></a></h4><p> Client / Server,客户端和服务器端,<strong>用户需要安装专门客户端程序。</strong></p><h4 id="b-s架构" tabindex="-1">B/S架构 <a class="header-anchor" href="#b-s架构" aria-label="Permalink to "B/S架构""></a></h4><p> Browser / Server,浏览器和服务器端,<strong>不需要安装专门客户端程序,浏览器是操作系统内置。</strong></p><h3 id="b-s-和c-s交互模型的比较" tabindex="-1">B/S 和C/S交互模型的比较 <a class="header-anchor" href="#b-s-和c-s交互模型的比较" aria-label="Permalink to "B/S 和C/S交互模型的比较""></a></h3><ul><li><p>相同点</p><p> 都是基于请求-响应交互模型:即浏览器(客户端) 向 服务器发送 一个 请求。服务器 向 浏览器(客户端)回送 一个 响应 。</p><p> 必须先有请求 再有响应</p><p> 请求和响应成对出现</p></li><li><p>不同点</p><p> 实现C/S模型需要用户在自己的操作系统安装各种客户端软件(百度网盘、腾讯QQ等);实现B/S模型,只需要用户在操作系统中安装浏览器即可。</p></li></ul><blockquote><p>注:B/S模型可以理解为一种特殊C/S模型。</p></blockquote><h3 id="小结-1" tabindex="-1">小结 <a class="header-anchor" href="#小结-1" aria-label="Permalink to "小结""></a></h3><ol><li><p>架构类别</p><ul><li>CS: 客户端-服务器; 必须要安装指定的客户端</li><li>BS: 浏览器-服务器; 不需要安装客户端的, 通过浏览器</li></ul><blockquote><p>我们以BS架构为主.</p></blockquote></li><li><p>Java</p><ul><li>JavaSE java基础</li><li>JavaMe 移动端的,嵌入式</li><li>JavaEE 企业级应用(eg: 网站, 后台系统, 移动端提供数据....)</li></ul></li></ol><h2 id="web通信【重点】" tabindex="-1">web通信【重点】 <a class="header-anchor" href="#web通信【重点】" aria-label="Permalink to "web通信【重点】""></a></h2><p> 基于http协议,请求响应的机制</p><p> 请求一次响应一次</p><p> 先有请求后有响应</p><p><img src="/images/image-20191208091344175.png" alt="image-20191208091344175"></p><h3 id="小结-2" tabindex="-1">小结 <a class="header-anchor" href="#小结-2" aria-label="Permalink to "小结""></a></h3><ol><li>浏览器必须先请求服务器, 服务器处理请求, 给浏览器响应</li><li>一次请求, 一次响应</li><li>先有请求,再有响应</li><li>请求响应基于<strong>HTTP协议</strong></li></ol><h1 id="服务器" tabindex="-1">服务器 <a class="header-anchor" href="#服务器" aria-label="Permalink to "服务器""></a></h1><p>processon的画图软件的注册地址:</p><p><a href="https://www.processon.com/i/5f0440b81e085326375eb062" target="_blank" rel="noreferrer">https://www.processon.com/i/5f0440b81e085326375eb062</a></p><h2 id="服务器介绍" tabindex="-1">服务器介绍 <a class="header-anchor" href="#服务器介绍" aria-label="Permalink to "服务器介绍""></a></h2><h3 id="什么是服务器" tabindex="-1">什么是服务器 <a class="header-anchor" href="#什么是服务器" aria-label="Permalink to "什么是服务器""></a></h3><p> 服务器就是一个软件,任何电脑只需要安装上了服务器软件, 我们的电脑就可以当做一台服务器了.</p><p> 服务器: 硬件(电脑)+软件(mysql, tomcat,nginx)</p><h3 id="常见web服务器" tabindex="-1">常见web服务器 <a class="header-anchor" href="#常见web服务器" aria-label="Permalink to "常见web服务器""></a></h3><ul><li><p>WebLogic</p><p> Oracle公司的产品,是目前应用比较多的Web服务器,支持J2EE规范。WebLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。</p><p><img src="/images/image-20230918120229386.png" alt="image-20230918120229386"></p></li><li><p>WebSphere</p><p> IBM公司的WebSphere,支持JavaEE规范。WebSphere 是随需应变的电子商务时代的最主要的软件平台,可用于企业开发、部署和整合新一代的电子商务应用。</p><p><img src="/images/image-20230918120235595.png" alt="image-20230918120235595"></p></li><li><p>Glass Fish</p><p> 最早是Sun公司的产品,后来被Oracle收购,开源免费,中型服务器。</p></li><li><p>JBoss</p><p> JBoss公司产品,开源,支持JavaEE规范,占用内存、硬盘小,安全性和性能高。</p><p><img src="/images/image-20230918120305825.png" alt="image-20230918120305825"></p></li><li><p>Tomcat</p><p> 中小型的应用系统,免费,开源,效率特别高, 适合扩展(搭集群)支持JSP和Servlet.</p><p><img src="/images/image-20230918120314490.png" alt="image-20230918120314490"></p></li></ul><h2 id="tomcat7-快速部署" tabindex="-1">Tomcat7 快速部署 <a class="header-anchor" href="#tomcat7-快速部署" aria-label="Permalink to "Tomcat7 快速部署""></a></h2><p>1.解压 apache-tomcat-7.0.78-windows-x64.zip 到非中文无空格目录中</p><p>2.检查是否配置了 JAVA_HOME</p><p><img src="/images/image-20230918120322351.png" alt="image-20230918120322351"></p><p>3.新建环境变量 CATALINA_HOME=解压目录</p><p><img src="/images/image-20230918120327462.png" alt="image-20230918120327462"></p><p>4.在 Path 环境变量中加入 Tomcat 解压目录\bin 目录</p><p><img src="/images/image-20230918120330919.png" alt="image-20230918120330919"></p><p>5.在命令行中运行 catalina run 启动 Tomcat 服务器,在浏览器地址栏访问如下地址进行测试: <code>http://localhost:8080</code></p><p><img src="/images/image-20230918120355421.png" alt="image-20230918120355421"></p><p>6.如果启动失败,提示端口号被占用,则将默认的 8080 端口修改为其他未使用的值,例如 8989 等。</p><p>打开:<code>解压目录\\conf\\server.xml</code>,找到第一个 Connector 标签,修改 port属性</p><p>7.在 Eclipse 中创建 Tomcat 镜像</p><p><img src="/images/image-20230918120407878.png" alt="image-20230918120407878"></p><p><img src="/images/image-20230918120414572.png" alt="image-20230918120414572"></p><p><img src="/images/image-20230918120419113.png" alt="image-20230918120419113"></p><p>8.创建动态 Web 工程进行测试</p><p>[1]在 WebContent 目录下创建 index.jsp,加入如下代码</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;"><%@page import="java.util.Date"%></span></span>
<span class="line"><span style="color:#e1e4e8;"><%=new Date() %></span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;"><%@page import="java.util.Date"%></span></span>
<span class="line"><span style="color:#24292e;"><%=new Date() %></span></span></code></pre></div><p>[2]在 index.jsp 上点右键:Run as→Run on Server 查看运行结果</p><p>9.说明:关联 Tomcat 镜像时,Eclipse 会从本地 Tomcat 中复制信息及文件,之后二者的配置信息就没有关系了,其中任何一个的配置信息发生变化都不会自动同步到另外一个。</p><p><img src="/images/image-20230918120435834.png" alt="image-20230918120435834"></p><h2 id="tomcat8-安装和使用" tabindex="-1">tomcat8 安装和使用 <a class="header-anchor" href="#tomcat8-安装和使用" aria-label="Permalink to "tomcat8 安装和使用""></a></h2><h3 id="概述" tabindex="-1">概述 <a class="header-anchor" href="#概述" aria-label="Permalink to "概述""></a></h3><p> Tomcat服务器是一个免费的开放源代码的Web应用服务器。</p><p> Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。由于有了Sun的参与和支持,最新的Servlet 和JSP规范总是能在Tomcat中得到体现。</p><p> 因为Tomcat技术先进、性能稳定,而且免费,因而深受Java爱好者的喜爱并得到了部分软件开发商的认可,是目前比较流行的Web应用服务器。</p><p> Tomcat安装分为解压版和安装版,这里着重介绍解压版。当然,我们在安装Tomcat前都应该将jdk安装好且配置好环境变量。Apache Tomcat 8.5需要一个Java标准版运行时环境(JRE)版本7或更高版本。</p><h3 id="tomcat的下载" tabindex="-1">tomcat的下载 <a class="header-anchor" href="#tomcat的下载" aria-label="Permalink to "tomcat的下载""></a></h3><p>强调: 我们使用的软件版本,要和老师用的版本一致</p><p>目前阶段: jdk8、mysql5、tomcat8</p><ol><li><p>**先去官网下载:<a href="http://tomcat.apache.org/%EF%BC%8C%E9%80%89%E6%8B%A9tomcat8%E7%89%88%E6%9C%AC(%E8%B5%84%E6%96%99%E5%B7%B2%E6%8F%90%E4%BE%9B)%EF%BC%88%E7%BA%A2%E6%A1%86%E6%89%80%E7%A4%BA%EF%BC%89**%EF%BC%9A" target="_blank" rel="noreferrer">http://tomcat.apache.org/,选择tomcat8版本(资料已提供)(红框所示)**:</a></p><p><img src="/images/image-20230918120459691.png" alt="image-20230918120459691"></p></li><li><p>选择要下载的文件(红框所示):</p><p><img src="/images/image-20230918120504127.png" alt="image-20230918120504127"></p><p>tar.gz 文件 是linux操作系统下的安装版本</p><p>exe文件是window操作系统下的安装版本</p><p>zip文件是window操作系统下压缩版本(我们选择zip文件)</p></li><li><p><strong>下载完成</strong>:</p></li></ol><p><img src="/images/image-20230918120508881.png" alt="image-20230918120508881"></p><h3 id="tomcat服务器软件安装" tabindex="-1">tomcat服务器软件安装 <a class="header-anchor" href="#tomcat服务器软件安装" aria-label="Permalink to "tomcat服务器软件安装""></a></h3><ol><li><p>直接解压当前这个tomcat压缩包:(<strong>不要有中文,不要有空格</strong>)</p></li><li><p>配置环境变量:</p><p>tomcat运行依赖于java环境: <img src="/images/image-20230918120512921.png" alt="image-20230918120512921"></p></li></ol><p>也可以配置环境变量 CATALINA_HOME 和 Path</p><p> 系统变量增加: CATALINA_HOME D:\develop\tomcat\apache-tomcat-8.5.55</p><p> path增加: <code>%CATALINA_HOME%\bin</code></p><p></p><h3 id="tomcat的目录结构" tabindex="-1">tomcat的目录结构 <a class="header-anchor" href="#tomcat的目录结构" aria-label="Permalink to "tomcat的目录结构""></a></h3><p><img src="/images/image-20230918120528147.png" alt="image-20230918120528147"></p><h3 id="启动tocmat" tabindex="-1">启动Tocmat <a class="header-anchor" href="#启动tocmat" aria-label="Permalink to "启动Tocmat""></a></h3><p>通过以上安装,Tomcat启动方式就有很多种了:</p><ol><li><p>查找tomcat目录下bin目录,查找其中的startup.bat命令,双击启动服务器: <img src="/images/image-20230918120532543.png" alt="image-20230918120532543"></p><p>启动效果: <img src="/images/image-20230918120714310.png" alt="image-20230918120714310"></p></li></ol><p>2.在Tomcat解压目录中的bin文件夹下,找到tomcat8.exe并双击启动。</p><p><img src="/images/image-20230918120720822.png" alt="image-20230918120720822"></p><p>3.在Tomcat解压目录中的bin文件夹下,找到tomcat8w.exe并双击启动。</p><p><img src="/images/image-20230918120725424.png" alt="image-20230918120725424"></p><p>在图形界面中点击 Start 按钮启动。</p><p><img src="/images/image-20230918120730858.png" alt="image-20230918120730858"></p><p>4.在CMD命令行中输入startup回车启动Tomcat。</p><p><img src="/images/image-20230918120735655.png" alt="image-20230918120735655"></p><p>5.在Windows系统服务中找到Tomcat服务进行启动。</p><p><img src="/images/image-20230918120740130.png" alt="image-20230918120740130"></p><h3 id="测试tomcat" tabindex="-1">测试Tomcat <a class="header-anchor" href="#测试tomcat" aria-label="Permalink to "测试Tomcat""></a></h3><p>打开浏览器在,在浏览器的地址栏中输入:</p><p><code>http://127.0.0.1:8080或者http://localhost:8080</code></p><p><img src="/images/image-20230918120756944.png" alt="image-20230918120756944"></p><p>注: Localhost相当于127.0.0.1</p><h3 id="关闭tomcat" tabindex="-1">关闭Tomcat <a class="header-anchor" href="#关闭tomcat" aria-label="Permalink to "关闭Tomcat""></a></h3><p>查找tomcat目录下bin目录,查找其中的shutdown.bat命令,双击关闭服务器: <img src="/images/image-20230918120800875.png" alt="image-20230918120800875"></p><h3 id="常见问题" tabindex="-1">常见问题 <a class="header-anchor" href="#常见问题" aria-label="Permalink to "常见问题""></a></h3><h4 id="安装注意点" tabindex="-1">安装注意点 <a class="header-anchor" href="#安装注意点" aria-label="Permalink to "安装注意点""></a></h4><ul><li>解压到一个==没有中文和空格==目录下</li><li>使用之前, 配置java_home和path(jdk环境变量) <ul><li>java_home 不要配到bin目录,配到jdk的安装目录</li><li>path 才是配到bin目录</li></ul></li></ul><h4 id="一台服务器无法显示2个tomcat" tabindex="-1">一台服务器无法显示2个tomcat <a class="header-anchor" href="#一台服务器无法显示2个tomcat" aria-label="Permalink to "一台服务器无法显示2个tomcat""></a></h4><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">/bin/start.bat 26行,修改 start 为 run</span></span>
<span class="line"><span style="color:#e1e4e8;">因为端口占用过了</span></span>
<span class="line"><span style="color:#e1e4e8;">将server.xml 8005,8443,8080等端口修改为9005,9443,9080.</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">/bin/start.bat 26行,修改 start 为 run</span></span>
<span class="line"><span style="color:#24292e;">因为端口占用过了</span></span>
<span class="line"><span style="color:#24292e;">将server.xml 8005,8443,8080等端口修改为9005,9443,9080.</span></span></code></pre></div><h4 id="端口号冲突" tabindex="-1">端口号冲突 <a class="header-anchor" href="#端口号冲突" aria-label="Permalink to "端口号冲突""></a></h4><p> 报如下异常: java.net.BindException: Address already in use: JVM_Bind 8080</p><p> 解决办法:</p><p> 第一种:修改Tomcat的端口号</p><p> <img src="/images/image-20230918120814291.png" alt="image-20230918120814291"></p><p> 修改conf/server.xml , 第70行左右</p><p><img src="/images/image-20230918120819709.png" alt="image-20230918120819709"></p><p>第二种:查询出来哪一个进程把8080占用了, 结束掉占用8080端口后的程序</p><p> 打开命令行输入: netstat -ano</p><p> 找到占用了8080 端口的 进程的id</p><p> 去任务管理器kill掉这个id对应的程序</p><p> <img src="/images/image-20230918120824468.png" alt="image-20230918120824468"></p><p></p><h4 id="java-home没有配置" tabindex="-1">JAVA_HOME没有配置 <a class="header-anchor" href="#java-home没有配置" aria-label="Permalink to "JAVA_HOME没有配置""></a></h4><ul><li>会出现闪退 (如果java_home配置了还是闪退 忽略它了, 后面在IDEA里面进行启动, 就没有这个问题)</li></ul><h4 id="tomcat-8-5-控制台中文乱码问题" tabindex="-1">tomcat 8.5 控制台中文乱码问题 <a class="header-anchor" href="#tomcat-8-5-控制台中文乱码问题" aria-label="Permalink to "tomcat 8.5 控制台中文乱码问题""></a></h4><p>新装的,启动乱码,不影响,但是体验不好</p><p><img src="/images/image-20230918120830551.png" alt="image-20230918120830551"></p><p>本质原因就一个:<strong>字节流解码为字符串时,使用了错误的字符集(和编码所用字符集不一致)!</strong></p><p>因为windows系统中,其命令行窗口在解码字节数组时,默认使用本地字符集(对于我们就是GBK),而tomcat默认输出的启动信息是通过utf8进行编码的,这就导致编码与解码所使用字符集的不一致,从而出现了乱码情况!</p><p><img src="/images/image-20230918120841684.png" alt="image-20230918120841684"></p><h5 id="解决方案1" tabindex="-1">解决方案1 <a class="header-anchor" href="#解决方案1" aria-label="Permalink to "解决方案1""></a></h5><p>conf/logging.properties,将 UTF-8 修改为 GBK</p><p>java.util.logging.ConsoleHandler.encoding = <strong>GBK</strong></p><p><strong>要改的话,其他几个都改了</strong></p><h5 id="解决方案2" tabindex="-1">解决方案2 <a class="header-anchor" href="#解决方案2" aria-label="Permalink to "解决方案2""></a></h5><p>修改console窗口为UTF-8格式</p><p>2个我都不改...tomcat就临时用下,后面内嵌使用.懒得改了</p><h3 id="总结说明" tabindex="-1">总结说明 <a class="header-anchor" href="#总结说明" aria-label="Permalink to "总结说明""></a></h3><p>1.配置JDK环境变量名为JAVA_HOME,Tomcat会找JAVA_HOME环境变量来定位JDK。</p><p>2.同样Tomcat环境变量名为CATALINA_HOME,Tomcat启动时会找CATALINA_HOME环境变量,来调用startup.bat。</p><p>3.Tomcat配置环境变量主要是为了在CMD命令行可以直接输入Tomcat脚本命令,这样不用定位到安装目录的bin文件夹下。</p><p>4.Tomcat安装版要比解压版省事儿,一些工作安装版完成了。</p><p>5.需要注意Tomcat对java版本要求。</p><h2 id="tomcat服务注册" tabindex="-1">Tomcat服务注册 <a class="header-anchor" href="#tomcat服务注册" aria-label="Permalink to "Tomcat服务注册""></a></h2><p>由于上面配置了Tomcat的环境变量,所以现在可以在CMD命令行中直接输入bin中的命令脚本。服务器注册输入 <strong>service install</strong>回车。</p><p><img src="/images/image-20230918120928642.png" alt="image-20230918120928642"></p><p>在 服务 中我们便看到了 Apache Tomcat8.5服务,可以在其属性中设置为 自启。一般项目部署实施需要进行设置,这样服务器重启后Tomcat便可自行启动。</p><p><img src="/images/image-20230918120933702.png" alt="image-20230918120933702"></p><p>Tomcat服务移除:<strong>service remove</strong></p><p><img src="/images/image-20230918120939050.png" alt="image-20230918120939050"></p><h2 id="运用tomcat服务器部署web项目" tabindex="-1">运用Tomcat服务器部署WEB项目 <a class="header-anchor" href="#运用tomcat服务器部署web项目" aria-label="Permalink to "运用Tomcat服务器部署WEB项目""></a></h2><h3 id="标准的javaweb应用目录结构" tabindex="-1">标准的JavaWeb应用目录结构 <a class="header-anchor" href="#标准的javaweb应用目录结构" aria-label="Permalink to "标准的JavaWeb应用目录结构""></a></h3><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">WebAPP(文件夹,项目) </span></span>
<span class="line"><span style="color:#e1e4e8;"> |---静态资源: html,css,js,图片(它们可以以文件存在,也可以以文件夹存在) </span></span>
<span class="line"><span style="color:#e1e4e8;"> |---WEB-INF 固定写法。此目录下的文件不能被外部(浏览器)直接访问</span></span>
<span class="line"><span style="color:#e1e4e8;"> |---lib:jar包存放的目录</span></span>
<span class="line"><span style="color:#e1e4e8;"> |---web.xml:当前项目的配置文件(3.0规范之后可以省略)</span></span>
<span class="line"><span style="color:#e1e4e8;"> |---classes:java类编译后生成class文件存放的路径</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">WebAPP(文件夹,项目) </span></span>
<span class="line"><span style="color:#24292e;"> |---静态资源: html,css,js,图片(它们可以以文件存在,也可以以文件夹存在) </span></span>
<span class="line"><span style="color:#24292e;"> |---WEB-INF 固定写法。此目录下的文件不能被外部(浏览器)直接访问</span></span>
<span class="line"><span style="color:#24292e;"> |---lib:jar包存放的目录</span></span>
<span class="line"><span style="color:#24292e;"> |---web.xml:当前项目的配置文件(3.0规范之后可以省略)</span></span>
<span class="line"><span style="color:#24292e;"> |---classes:java类编译后生成class文件存放的路径</span></span></code></pre></div><h3 id="发布项目到tomcat" tabindex="-1">发布项目到tomcat <a class="header-anchor" href="#发布项目到tomcat" aria-label="Permalink to "发布项目到tomcat""></a></h3><h4 id="直接发布" tabindex="-1">直接发布 <a class="header-anchor" href="#直接发布" aria-label="Permalink to "直接发布""></a></h4><p> 只要将准备好的web资源直接复制到tomcat/webapps文件夹下,就可以通过浏览器使用http协议访问获取</p><h4 id="虚拟路径的方式发布项目" tabindex="-1">虚拟路径的方式发布项目 <a class="header-anchor" href="#虚拟路径的方式发布项目" aria-label="Permalink to "虚拟路径的方式发布项目""></a></h4><ol><li>第一步:在tomcat/conf目录下新建一个Catalina目录(如果已经存在无需创建)</li></ol><p><img src="/images/image-20230918120949837.png" alt="image-20230918120949837"></p><ol start="2"><li>第二步:在Catalina目录下创建localhost目录(如果已经存在无需创建)</li></ol><p><img src="/images/image-20230918120954355.png" alt="image-20230918120954355"></p><ol start="3"><li>第三步:在localhost中创建xml配置文件,名称为:随便写,比如叫做second.xml(注:这个名称是浏览器访问路径)</li></ol><p><img src="/images/image-20230918120958616.png" alt="image-20230918120958616"></p><ol start="4"><li><p>第四步:添加second.xml文件的内容为: docBase就是你需要作为虚拟路径的项目的路径</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;"><?xml version = "1.0" encoding = "utf-8"?></span></span>
<span class="line"><span style="color:#e1e4e8;"><Context docBase="C:\JavaEE_Relation\JavaEE101\itheima101_staticWeb\day24_html" /></span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;"><?xml version = "1.0" encoding = "utf-8"?></span></span>
<span class="line"><span style="color:#24292e;"><Context docBase="C:\JavaEE_Relation\JavaEE101\itheima101_staticWeb\day24_html" /></span></span></code></pre></div><p><img src="/images/image-20230918121002976.png" alt="image-20230918121002976"></p></li><li><p>第五步:直接访问(通过写配置文件的路径来访问):</p><p><code>http://localhost:8080/second/a.html</code>(second就是配置文件的名字, 映射成了myApp)</p></li></ol><h1 id="http协议" tabindex="-1">http协议 <a class="header-anchor" href="#http协议" aria-label="Permalink to "http协议""></a></h1><h2 id="http协议概述" tabindex="-1">http协议概述 <a class="header-anchor" href="#http协议概述" aria-label="Permalink to "http协议概述""></a></h2><h3 id="什么是http协议" tabindex="-1">什么是HTTP协议 <a class="header-anchor" href="#什么是http协议" aria-label="Permalink to "什么是HTTP协议""></a></h3><p> HTTP是HyperText Transfer Protocol(超文本传输协议)的简写,传输HTML文件。</p><p> HTTP是互联网上用的最多的一个协议, 所有的www开头的都是遵循这个协议的(可能是https)</p><h3 id="http协议的作用" tabindex="-1">HTTP协议的作用 <a class="header-anchor" href="#http协议的作用" aria-label="Permalink to "HTTP协议的作用""></a></h3><p> HTTP作用:用于定义WEB浏览器与WEB服务器之间<strong>交换数据的过程</strong>和数据本身的<strong>内容</strong></p><p> 浏览器和服务器交互过程: 浏览器请求, 服务请求响应</p><p> 请求(请求行,请求头,请求体)</p><p> 响应(响应行,响应头,响应体)</p><h3 id="小结-3" tabindex="-1">小结 <a class="header-anchor" href="#小结-3" aria-label="Permalink to "小结""></a></h3><ol><li><p>HTTP协议:超文本传输协议,它就定义了客户端与服务器端进行交互时候的规则</p></li><li><p>HTTP协议的作用:定义客户端与服务器端交互的过程以及传输的数据</p></li></ol><h2 id="请求部分-了解" tabindex="-1">请求部分(了解) <a class="header-anchor" href="#请求部分-了解" aria-label="Permalink to "请求部分(了解)""></a></h2><p><img src="/images/image-20230918121017000.png" alt="image-20230918121017000"></p><ul><li>get方式请求</li></ul><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">【请求行】</span></span>
<span class="line"><span style="color:#e1e4e8;">GET /myApp/success.html?username=zs&password=123456 HTTP/1.1</span></span>
<span class="line"><span style="color:#e1e4e8;"></span></span>
<span class="line"><span style="color:#e1e4e8;">【请求头】</span></span>
<span class="line"><span style="color:#e1e4e8;">Accept: text/html, application/xhtml+xml, */*</span></span>
<span class="line"><span style="color:#e1e4e8;">X-HttpWatch-RID: 41723-10011</span></span>
<span class="line"><span style="color:#e1e4e8;">Referer: http://localhost:8080/myApp/login.html</span></span>
<span class="line"><span style="color:#e1e4e8;">Accept-Language: zh-Hans-CN,zh-Hans;q=0.5</span></span>
<span class="line"><span style="color:#e1e4e8;">User-Agent: Mozilla/5.0 (MSIE 9.0; qdesk 2.4.1266.203; Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko</span></span>
<span class="line"><span style="color:#e1e4e8;">Accept-Encoding: gzip, deflate</span></span>
<span class="line"><span style="color:#e1e4e8;">Host: localhost:8080</span></span>
<span class="line"><span style="color:#e1e4e8;">Connection: Keep-Alive</span></span>
<span class="line"><span style="color:#e1e4e8;">Cookie: Idea-b77ddca6=4bc282fe-febf-4fd1-b6c9-72e9e0f381e8</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">【请求行】</span></span>
<span class="line"><span style="color:#24292e;">GET /myApp/success.html?username=zs&password=123456 HTTP/1.1</span></span>
<span class="line"><span style="color:#24292e;"></span></span>
<span class="line"><span style="color:#24292e;">【请求头】</span></span>
<span class="line"><span style="color:#24292e;">Accept: text/html, application/xhtml+xml, */*</span></span>
<span class="line"><span style="color:#24292e;">X-HttpWatch-RID: 41723-10011</span></span>
<span class="line"><span style="color:#24292e;">Referer: http://localhost:8080/myApp/login.html</span></span>
<span class="line"><span style="color:#24292e;">Accept-Language: zh-Hans-CN,zh-Hans;q=0.5</span></span>
<span class="line"><span style="color:#24292e;">User-Agent: Mozilla/5.0 (MSIE 9.0; qdesk 2.4.1266.203; Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko</span></span>
<span class="line"><span style="color:#24292e;">Accept-Encoding: gzip, deflate</span></span>
<span class="line"><span style="color:#24292e;">Host: localhost:8080</span></span>
<span class="line"><span style="color:#24292e;">Connection: Keep-Alive</span></span>
<span class="line"><span style="color:#24292e;">Cookie: Idea-b77ddca6=4bc282fe-febf-4fd1-b6c9-72e9e0f381e8</span></span></code></pre></div><ul><li>post请求</li></ul><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">【请求行】</span></span>
<span class="line"><span style="color:#e1e4e8;">POST /myApp/success.html HTTP/1.1</span></span>
<span class="line"><span style="color:#e1e4e8;"></span></span>
<span class="line"><span style="color:#e1e4e8;">【请求头】</span></span>
<span class="line"><span style="color:#e1e4e8;">Accept: text/html, application/xhtml+xml, */*</span></span>
<span class="line"><span style="color:#e1e4e8;">X-HttpWatch-RID: 37569-10012</span></span>
<span class="line"><span style="color:#e1e4e8;">Referer: http://localhost:8080/myApp/login.html</span></span>
<span class="line"><span style="color:#e1e4e8;">Accept-Language: zh-Hans-CN,zh-Hans;q=0.5</span></span>
<span class="line"><span style="color:#e1e4e8;">User-Agent: Mozilla/5.0 (MSIE 9.0; qdesk 2.4.1266.203; Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko</span></span>
<span class="line"><span style="color:#e1e4e8;">Content-Type: application/x-www-form-urlencoded</span></span>
<span class="line"><span style="color:#e1e4e8;">Accept-Encoding: gzip, deflate</span></span>
<span class="line"><span style="color:#e1e4e8;">Host: localhost:8080</span></span>
<span class="line"><span style="color:#e1e4e8;">Content-Length: 27</span></span>
<span class="line"><span style="color:#e1e4e8;">Connection: Keep-Alive</span></span>
<span class="line"><span style="color:#e1e4e8;">Cache-Control: no-cache</span></span>
<span class="line"><span style="color:#e1e4e8;"></span></span>
<span class="line"><span style="color:#e1e4e8;">【请求体】</span></span>
<span class="line"><span style="color:#e1e4e8;">username=zs&password=123456</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">【请求行】</span></span>
<span class="line"><span style="color:#24292e;">POST /myApp/success.html HTTP/1.1</span></span>
<span class="line"><span style="color:#24292e;"></span></span>
<span class="line"><span style="color:#24292e;">【请求头】</span></span>
<span class="line"><span style="color:#24292e;">Accept: text/html, application/xhtml+xml, */*</span></span>
<span class="line"><span style="color:#24292e;">X-HttpWatch-RID: 37569-10012</span></span>
<span class="line"><span style="color:#24292e;">Referer: http://localhost:8080/myApp/login.html</span></span>
<span class="line"><span style="color:#24292e;">Accept-Language: zh-Hans-CN,zh-Hans;q=0.5</span></span>
<span class="line"><span style="color:#24292e;">User-Agent: Mozilla/5.0 (MSIE 9.0; qdesk 2.4.1266.203; Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko</span></span>
<span class="line"><span style="color:#24292e;">Content-Type: application/x-www-form-urlencoded</span></span>
<span class="line"><span style="color:#24292e;">Accept-Encoding: gzip, deflate</span></span>
<span class="line"><span style="color:#24292e;">Host: localhost:8080</span></span>
<span class="line"><span style="color:#24292e;">Content-Length: 27</span></span>
<span class="line"><span style="color:#24292e;">Connection: Keep-Alive</span></span>
<span class="line"><span style="color:#24292e;">Cache-Control: no-cache</span></span>
<span class="line"><span style="color:#24292e;"></span></span>
<span class="line"><span style="color:#24292e;">【请求体】</span></span>
<span class="line"><span style="color:#24292e;">username=zs&password=123456</span></span></code></pre></div><h3 id="请求行" tabindex="-1">请求行 <a class="header-anchor" href="#请求行" aria-label="Permalink to "请求行""></a></h3><ul><li>请求行</li></ul><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">GET /myApp/success.html?username=zs&password=123456 HTTP/1.1 </span></span>
<span class="line"><span style="color:#e1e4e8;">POST /myApp/success.html HTTP/1.1</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">GET /myApp/success.html?username=zs&password=123456 HTTP/1.1 </span></span>
<span class="line"><span style="color:#24292e;">POST /myApp/success.html HTTP/1.1</span></span></code></pre></div><ul><li><p>请求方式(8种,put,delete等)</p><p> GET:明文传输, 不安全,参数跟在请求路径后面,对请求参数大小有限制,</p><p> POST: 暗文传输,安全一些,请求参数在请求体里,对请求参数大小没有有限制,</p></li><li><p>URI:统一资源标识符(即:去掉协议和IP地址部分)</p></li><li><p>协议版本:HTTP/1.1</p></li></ul><h3 id="请求头" tabindex="-1">请求头 <a class="header-anchor" href="#请求头" aria-label="Permalink to "请求头""></a></h3><p> 从第2行到空行处,都叫请求头,以键值对的形式存在,但存在一个key对应多个值的请求头.</p><p> <strong>作用:浏览器告诉服务器自己相关的设置.</strong></p><ul><li>Accept:浏览器可接受的MIME类型 ,告诉服务器客户端能接收什么样类型的文件。</li><li><strong>User-Agent</strong>:浏览器信息.(浏览器类型, 浏览器的版本....)</li><li>Accept-Charset: 浏览器通过这个头告诉服务器,它支持哪种字符集</li><li>Content-Length:表示请求参数的长度</li><li>Host:初始URL中的主机和端口</li><li><strong>Referrer</strong>:从哪里里来的(之前是哪个资源)、防盗链</li><li><strong>Content-Type</strong>:内容类型,告诉服务器,浏览器传输数据的MIME类型,文件传输的类型,application/x-www-form-urlencoded .</li><li>Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip</li><li>Connection:表示是否需要持久连接。如果服务器看到这里的值为“Keep -Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接 )</li><li><strong>Cookie</strong>:这是最重要的请求头信息之一(会话技术, 后面会有专门的时间来讲的)</li><li>Date:Date: Mon, 22Aug 2011 01:55:39 GMT请求时间GMT</li></ul><h3 id="请求体" tabindex="-1">请求体 <a class="header-anchor" href="#请求体" aria-label="Permalink to "请求体""></a></h3><p> 只有请求方式是post的时候,才有请求体. 即post请求时,请求参数(提交的数据)所在的位置</p><h3 id="小结-4" tabindex="-1">小结 <a class="header-anchor" href="#小结-4" aria-label="Permalink to "小结""></a></h3><pre><code>1. 请求行
1. 请求方式
2. 请求路径
2. 请求头: 它是由键值对构成
3. 请求体: 只有post请求才有请求体,post请求的请求体是用于携带请求参数的
</code></pre><h2 id="响应部分-了解" tabindex="-1">响应部分(了解) <a class="header-anchor" href="#响应部分-了解" aria-label="Permalink to "响应部分(了解)""></a></h2><p><img src="/images/image-20230918121635986.png" alt="image-20230918121635986"></p><ul><li><p>响应部分</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">【响应行】</span></span>
<span class="line"><span style="color:#e1e4e8;">HTTP/1.1 200 OK</span></span>
<span class="line"><span style="color:#e1e4e8;"></span></span>
<span class="line"><span style="color:#e1e4e8;">【响应头】</span></span>
<span class="line"><span style="color:#e1e4e8;">Accept-Ranges: bytes</span></span>
<span class="line"><span style="color:#e1e4e8;">ETag: W/"143-1557909081579"</span></span>
<span class="line"><span style="color:#e1e4e8;">Last-Modified: Wed, 15 May 2019 08:31:21 GMT</span></span>
<span class="line"><span style="color:#e1e4e8;">Content-Type: text/html</span></span>
<span class="line"><span style="color:#e1e4e8;">Content-Length: 143</span></span>
<span class="line"><span style="color:#e1e4e8;">Date: Sun, 08 Dec 2019 02:20:04 GMT</span></span>
<span class="line"><span style="color:#e1e4e8;"></span></span>
<span class="line"><span style="color:#e1e4e8;">【响应体】</span></span>
<span class="line"><span style="color:#e1e4e8;"><!DOCTYPE html></span></span>
<span class="line"><span style="color:#e1e4e8;"><html lang="en"></span></span>
<span class="line"><span style="color:#e1e4e8;"><head></span></span>
<span class="line"><span style="color:#e1e4e8;"> <meta charset="UTF-8"></span></span>
<span class="line"><span style="color:#e1e4e8;"> <title>Title</title></span></span>
<span class="line"><span style="color:#e1e4e8;"></head></span></span>
<span class="line"><span style="color:#e1e4e8;"><body></span></span>
<span class="line"><span style="color:#e1e4e8;"> Success</span></span>
<span class="line"><span style="color:#e1e4e8;"></body></span></span>
<span class="line"><span style="color:#e1e4e8;"></html></span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">【响应行】</span></span>
<span class="line"><span style="color:#24292e;">HTTP/1.1 200 OK</span></span>
<span class="line"><span style="color:#24292e;"></span></span>
<span class="line"><span style="color:#24292e;">【响应头】</span></span>
<span class="line"><span style="color:#24292e;">Accept-Ranges: bytes</span></span>
<span class="line"><span style="color:#24292e;">ETag: W/"143-1557909081579"</span></span>
<span class="line"><span style="color:#24292e;">Last-Modified: Wed, 15 May 2019 08:31:21 GMT</span></span>
<span class="line"><span style="color:#24292e;">Content-Type: text/html</span></span>
<span class="line"><span style="color:#24292e;">Content-Length: 143</span></span>
<span class="line"><span style="color:#24292e;">Date: Sun, 08 Dec 2019 02:20:04 GMT</span></span>
<span class="line"><span style="color:#24292e;"></span></span>
<span class="line"><span style="color:#24292e;">【响应体】</span></span>
<span class="line"><span style="color:#24292e;"><!DOCTYPE html></span></span>
<span class="line"><span style="color:#24292e;"><html lang="en"></span></span>
<span class="line"><span style="color:#24292e;"><head></span></span>
<span class="line"><span style="color:#24292e;"> <meta charset="UTF-8"></span></span>
<span class="line"><span style="color:#24292e;"> <title>Title</title></span></span>
<span class="line"><span style="color:#24292e;"></head></span></span>
<span class="line"><span style="color:#24292e;"><body></span></span>
<span class="line"><span style="color:#24292e;"> Success</span></span>
<span class="line"><span style="color:#24292e;"></body></span></span>
<span class="line"><span style="color:#24292e;"></html></span></span></code></pre></div></li></ul><h3 id="响应行" tabindex="-1">响应行 <a class="header-anchor" href="#响应行" aria-label="Permalink to "响应行""></a></h3><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">HTTP/1.1 200</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">HTTP/1.1 200</span></span></code></pre></div><ul><li><p>协议/版本</p></li><li><p><strong>响应状态码</strong> (记住-背诵下来)</p><p><img src="/images/image-20230918121642236.png" alt="image-20230918121642236"></p><p> 200:正常,跟服务器连接成功,发送请求成功</p><p> 302:重定向(跳转)</p><p> 304:读取缓存,表示客户机缓存的版本是最新的,客户机可以继续使用它,无需到服务器请求. 读取缓存</p><p> 403: forbidden 权限不够,服务器接收到了客户端的请求,但是拒绝处理</p><p> 404:服务器接收到了客户端的请求,但是我服务器里面没有你要找的资源</p><p> 500:服务器接收到了客户端的请求,也找到了具体的资源处理请求,但是处理的过程中服务器出异常了</p></li></ul><h3 id="响应头" tabindex="-1">响应头 <a class="header-anchor" href="#响应头" aria-label="Permalink to "响应头""></a></h3><p>响应头以key:vaue存在, 可能多个value情况. ==服务器指示浏览器去干什么,去配置什么.==</p><ul><li><strong>Location</strong>: <a href="http://www.it315.org/index.jsp%E6%8C%87%E7%A4%BA%E6%96%B0%E7%9A%84%E8%B5%84%E6%BA%90%E7%9A%84%E4%BD%8D%E7%BD%AE" target="_blank" rel="noreferrer">http://www.it315.org/index.jsp指示新的资源的位置</a>,通常和状态,码302一起使用,完成请求重定向</li><li><strong>Content-Type</strong>: text/html; charset=UTF-8; 设置服务器发送的内容的MIME类型,文件下载时候</li></ul><p>a.mp3 b.mp4</p><ul><li><p><strong>Refresh</strong>: 5;url=<a href="http://www.baidu.com" target="_blank" rel="noreferrer">http://www.baidu.com</a> 指示客户端刷新频率。单位是秒 eg: 告诉浏览器5s之后跳转到百度</p></li><li><p><strong>Content-Disposition</strong>: attachment; filename=a.jpg 指示客户端(浏览器)下载文件</p></li><li><p>Content-Length:80 告诉浏览器正文的长度</p></li><li><p>Server:apachetomcat 服务器的类型</p></li><li><p>Content-Encoding: gzip服务器发送的数据采用的编码类型</p></li><li><p>Set-Cookie:SS=Q0=5Lb_nQ;path=/search服务器端发送的Cookie</p></li><li><p>Cache-Control: no-cache (1.1)</p></li><li><p>Pragma: no-cache (1.0) 表示告诉客户端不要使用缓存</p></li><li><p>Connection:close/Keep-Alive</p></li><li><p>Date:Tue, 11 Jul 2000 18:23:51 GMT</p></li></ul><h3 id="响应体" tabindex="-1">响应体 <a class="header-anchor" href="#响应体" aria-label="Permalink to "响应体""></a></h3><p> 页面展示内容, 和网页右键查看的源码一样</p><h3 id="小结-5" tabindex="-1">小结 <a class="header-anchor" href="#小结-5" aria-label="Permalink to "小结""></a></h3><pre><code>1. 响应行:包含响应状态码
1. 常见的响应状态码:
1. 200 OK
2. 302 Redirect 重定向
3. 304 Cache 读取缓存
4. 400 BAD REQUEST 请求有问题(可能是请求参数等等不符合规定)
5. 403 Forbidden 拒绝处理
6. 404 NOT FOUND 找不到资源
7. 500 SERVER ERROR 服务器异常
2. 响应头: 由多个键值对构成
3. 响应体:
1. 可以用于客户端页面的展示
2. 可以用于下载
</code></pre><h1 id="tomcat架构设计-源码剖析" tabindex="-1">Tomcat架构设计&源码剖析 <a class="header-anchor" href="#tomcat架构设计-源码剖析" aria-label="Permalink to "Tomcat架构设计&源码剖析""></a></h1><ul><li><p>Tomcat功能需求分析</p></li><li><p>Tomcat套娃式架构设计(Connector层次架构、容器层次结构)</p></li><li><p>Tomcat源码构建</p></li><li><p>Tomcat源码剖析-链式初始化过程</p></li><li><p>Tomcat流程剖析-Servlet请求处理链路追踪</p></li></ul><h2 id="tomcat架构设计" tabindex="-1">Tomcat架构设计 <a class="header-anchor" href="#tomcat架构设计" aria-label="Permalink to "Tomcat架构设计""></a></h2><h3 id="tomcat的功能-需求" tabindex="-1">Tomcat的功能(需求) <a class="header-anchor" href="#tomcat的功能-需求" aria-label="Permalink to "Tomcat的功能(需求)""></a></h3><p>浏览器发给服务端的是一个 HTTP 格式的请求,HTTP 服务器收到这个请求后,需要调用服务端程序来处理,所谓的服务端程序就是你写的 Java 类,一般来说不同的请求需要由不同的 Java 类来处理。</p><p>那么问题来了,HTTP 服务器怎么知道要调用哪个 Java 类的哪个方法呢?</p><p><img src="/images/image-20220707094852453.png" alt="image-20220707094852453"></p><ul><li>HTTP 服务器直接调用具体业务类,它们是紧耦合的。</li></ul><blockquote><p>解决:HTTP 服务器不直接调用业务类,而是把请求交给容器来处理,容器通过 Servlet 接口调用业务类。因此 Servlet 接口和 Servlet 容器的出现,达到了 HTTP 服务器与业务类解耦的目的。</p></blockquote><p><img src="/images/image-20220707094943533.png" alt="image-20220707094943533"></p><p><strong>Tomcat两个非常重要的功能(身份)</strong></p><ul><li>Http服务器功能:Socket通信(TCP/IP)、解析Http报文</li><li>Servlet容器功能:有很多Servlet(自带系统级Servlet+自定义Servlet),Servlet处理具体的业务逻辑</li></ul><h3 id="tomcat的架构-设计实现" tabindex="-1">Tomcat的架构(设计实现) <a class="header-anchor" href="#tomcat的架构-设计实现" aria-label="Permalink to "Tomcat的架构(设计实现)""></a></h3><h4 id="需求" tabindex="-1">需求 <a class="header-anchor" href="#需求" aria-label="Permalink to "需求""></a></h4><p>Tomcat的需求是要实现 2 个核心功能:</p><ul><li>处理 Socket 连接,负责网络字节流与 Request 和 Response 对象的转化。=> 网络通信,协议解析</li><li>加载和管理 Servlet,以及具体处理 Request 请求。=> servlet容器</li></ul><h4 id="tomcat架构设计-1" tabindex="-1">Tomcat架构设计 <a class="header-anchor" href="#tomcat架构设计-1" aria-label="Permalink to "Tomcat架构设计""></a></h4><p>基于Tomcat需求,所以 Tomcat 设计了两个核心组件连接器(Connector)和容器(Container)来分别做这两件事情。 <strong>连接器</strong>负责对外交流,<strong>容器</strong>负责内部处理。</p><p><img src="/images/image-20220707095221858.png" alt="image-20220707095221858"></p><p>Tomcat中一个容器可能对接多个连接器,每一个连接器都对应某种协议某种IO模型,Tomcat将多个连接器和单个容器组成一个service组件,一个tomcat中可能存在多个Service组件Connector:将不同协议不同IO模型的请求转换为标准的标准的ServletRequest 对象交给容器处理。</p><ul><li>Container:Container本质上是一个Servlet容器,负责servelt的加载和管理,处理请求</li><li>ServletRequest,并返回标准的 ServletResponse 对象给连接器</li></ul><h4 id="连接器是如何设计的" tabindex="-1">连接器是如何设计的? <a class="header-anchor" href="#连接器是如何设计的" aria-label="Permalink to "连接器是如何设计的?""></a></h4><h5 id="铺垫-支持协议-io模型" tabindex="-1">铺垫:支持协议&IO模型 <a class="header-anchor" href="#铺垫-支持协议-io模型" aria-label="Permalink to "铺垫:支持协议&IO模型""></a></h5><p>铺垫:Tomcat 是支持多种 I/O 模型和应用层协议的 Tomcat 支持的 I/O 模型有:</p><ul><li>NIO:非阻塞 I/O,采用 Java NIO 类库实现</li><li>NIO.2:异步 I/O,采用 JDK 7 最新的 NIO.2 类库实现</li><li>APR:采用 Apache 可移植运行库实现,是 C/C++ 编写的本地库</li></ul><p>Tomcat 支持的应用层协议有:</p><ul><li>HTTP/1.1:这是大部分 Web 应用采用的访问协议</li><li>AJP:用于和 Web 服务器集成(如 Apache)</li><li>HTTP/2:HTTP 2.0 大幅度的提升了 Web 性能</li></ul><h5 id="连接器架构分析" tabindex="-1">连接器架构分析 <a class="header-anchor" href="#连接器架构分析" aria-label="Permalink to "连接器架构分析""></a></h5><p>Tomcat 为了实现支持多种 I/O 模型和应用层协议,一个容器可能对接多个连接器,就好比一个房间有多个门。但是单独的连接器或者容器都不能对外提供服务,需要把它们组装起来才能工作,组装后这个整体叫作 Service 组件。这里请注意,Service 本身没有做什么重要的事情,只是在连接器和容器外面多包了一层,把它们组装在一起。Tomcat 内可能有多个 Service,这样的设计也是出于灵活性的考虑。通过在 Tomcat 中配置多个 Service,可以实现通过不同的端口号来访问同一台机器上部署的不同应用。</p><p><img src="/images/image-20220707095402196.png" alt="image-20220707095402196"></p><p>从图上可以看到,最顶层是 Server,这里的 Server 指的就是一个 Tomcat 实例。一个 Server 中有一个或者多个 Service,一个 Service 中有多个连接器和一个容器。连接器与容器之间通过标准的ServletRequest 和 ServletResponse 通信。</p><h5 id="核心功能" tabindex="-1">核心功能 <a class="header-anchor" href="#核心功能" aria-label="Permalink to "核心功能""></a></h5><p>连接器对 Servlet 容器屏蔽了协议及 I/O 模型等的区别,无论是 HTTP 还是 AJP,在容器中获取到的都是一个标准的 ServletRequest 对象。我们可以把连接器的功能需求进一步细化,比如:</p><ul><li>监听网络端口。</li><li>接受网络连接请求。读取网络请求字节流。</li><li>根据具体应用层协议(HTTP/AJP)解析字节流,生成统一的 Tomcat Request 对象。</li><li>将 Tomcat Request 对象转成标准的 ServletRequest。</li><li>调用 Servlet 容器,得到 ServletResponse。 将 ServletResponse 转成 Tomcat Response 对象。</li><li>将 Tomcat Response 转成网络字节流。</li><li>将响应字节流写回给浏览器。</li></ul><h5 id="通用架构设计" tabindex="-1">通用架构设计 <a class="header-anchor" href="#通用架构设计" aria-label="Permalink to "通用架构设计""></a></h5><p>需求列清楚后,我们要考虑的下一个问题是,连接器应该有哪些子模块?优秀的模块化设计应该考虑高内聚、低耦合。</p><ul><li>高内聚是指相关度比较高的功能要尽可能集中,不要分散。</li><li>低耦合是指两个相关的模块要尽可能减少依赖的部分和降低依赖的程度,不要让两个模块产生强依赖。</li></ul><p>通过分析连接器的详细功能列表,我们发现连接器需要完成 3 个高内聚的功能:</p><ul><li>网络通信</li><li>应用层协议解析</li><li>Tomcat Request/Response 与 ServletRequest/ServletResponse 的转化</li></ul><p>因此 Tomcat 的设计者设计了 3 个组件来实现这 3 个功能,分别是 Endpoint、Processor 和 Adapter。</p><p><img src="/images/image-20220707095531409.png" alt="image-20220707095531409"></p><p>由于 I/O 模型和应用层协议可以自由组合,比如 NIO + HTTP 或者 NIO.2 + AJP。Tomcat 的设计者将网络通信和应用层协议解析放在一起考虑,设计了一个叫 ProtocolHandler 的接口来封装这两种变化点</p><p><img src="/images/image-20220707095544595.png" alt="image-20220707095544595"></p><p>通过图清晰地看到它们的继承和层次关系,这样设计的目的是尽量将稳定的部分放到抽象基类,同时每一种 I/O 模型和协议的组合都有相应的具体实现类,我们在使用时可以自由选择。</p><h5 id="protocolhandler-组件" tabindex="-1">ProtocolHandler 组件 <a class="header-anchor" href="#protocolhandler-组件" aria-label="Permalink to "ProtocolHandler 组件""></a></h5><p>现在我们知道,连接器用 ProtocolHandler 来处理网络连接和应用层协议,包含了 2 个重要部件:</p><p>Endpoint 和 Processor,下面来详细介绍它们的工作原理</p><h6 id="endpoint组件" tabindex="-1">EndPoint组件 <a class="header-anchor" href="#endpoint组件" aria-label="Permalink to "EndPoint组件""></a></h6><p>Endpoint 翻译过来是"通信端点",主要负责网络通信,这其中就包括,监听客户端连接创建于客户端连接Socket,并负责连接Socket 接收和发送处理器。因此Endpoint是对传输层的抽象,是用来实现 TCP/IP 协议的。</p><p><strong>EndPoint类结构图</strong></p><p>EndPoint用基类用抽象类AbstractEndpoint来表示,对于不同的Linux IO模型通过使用不同子类来实现。</p><p><img src="/images/image-20220707095641120.png" alt="image-20220707095641120"></p><p>Endpoint 是一个接口,对应的抽象实现类是 AbstractEndpoint,而 AbstractEndpoint 的具体子类,比如在 NioEndpoint 和 Nio2Endpoint 中,有两个重要的子组件:Acceptor 和 SocketProcessor。</p><p>其中 Acceptor 用于监听 Socket 连接请求。SocketProcessor 用于处理接收到的 Socket 请求,它实现Runnable 接口,在 run 方法里调用协议处理组件 Processor 进行处理。为了提高处理能力,SocketProcessor 被提交到线程池来执行。而这个线程池叫作执行器(Executor)</p><h6 id="processor组件" tabindex="-1">Processor组件 <a class="header-anchor" href="#processor组件" aria-label="Permalink to "Processor组件""></a></h6><p>Processor:翻译过来是"处理器",主要负责根据具体应用层协议(HTTP/AJP)读取字节流解析成Tomcat Request 和 Response,因此Processor是对应用层的抽象,是用来实现 HTTP/AJP 协议的。</p><p><strong>Processor类结构图</strong></p><p><img src="/images/image-20220707095735224.png" alt="image-20220707095735224"></p><p>Processor 是一个接口,定义了请求的处理等方法。它的抽象实现类 AbstractProcessor 对一些协议共有的属性进行封装,没有对方法进行实现。具体的实现有 AjpProcessor、Http11Processor 等,这些具体实现类实现了特定协议的解析方法和请求处理方式</p><h6 id="adapter组件" tabindex="-1"><strong>Adapter组件</strong> <a class="header-anchor" href="#adapter组件" aria-label="Permalink to "**Adapter组件**""></a></h6><p>由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat 定义了自己的 Request 类来“存放”这些请求信息。ProtocolHandler 接口负责解析请求并生成 Tomcat Request/Response类。但是这个Request/Response 对象不是标准的 ServletRequest/ServletResponse,也就意味着,不能用TomcatRequest/Response 作为参数来调用容器。</p><p>Tomcat 设计者的解决方案是引入 CoyoteAdapter,这是适配器模式的经典运用,负责将TomcatRequest/Response 与 ServletRequest/ServletResponse 的相互转化,实现连接器(Connector)和容器(Container)的解耦。</p><h6 id="protocolhandler组件" tabindex="-1"><strong>ProtocolHandler组件</strong> <a class="header-anchor" href="#protocolhandler组件" aria-label="Permalink to "**ProtocolHandler组件**""></a></h6><p>ProtocolHandler组件EndPoint组件,Processor组件合并在一起表示协议处理器。用来处理tomcat支持多种IO模型和多种协议的组件。</p><p><strong>ProtocolHandler类图</strong></p><p><img src="/images/image-20220707100309425.png" alt="image-20220707100309425"></p><h5 id="connector处理流程" tabindex="-1"><strong>Connector处理流程</strong> <a class="header-anchor" href="#connector处理流程" aria-label="Permalink to "**Connector处理流程**""></a></h5><p>我们再来看看连接器的组件图:</p><p><img src="/images/image-20220707100327036.png" alt="image-20220707100327036"></p><ul><li>Endpoint内部Acceptor组件用于监听Socket 连接请求,当发送客户端连接到服务端Acceptor组件负责与客户端建立连接创建Socket,每当连接客户端发起请求,Endpoint会创建一个SocketProcessor对象SocketProcessor 用于处理接收到的 Socket 请求,它实现 Runnable 接口,在 run 方法里调用协议处理组件 Processor 进行处理。为了提高处理能力,SocketProcessor 被提交到线程池来执行。而这个线程池叫作执行器(Executor)</li><li>Processor 接收来自 Endpoint 的 Socket,读取字节流解析成 Tomcat Request 和 Response 对象,接着会调用 Adapter 的 Service 方法。并通过 Adapter 将其提交到容器处理</li><li>连接器调用 CoyoteAdapter 的 sevice 方法,传入的是 Tomcat Request 对象,CoyoteAdapter 负责将 Tomcat Request 转成 ServletRequest,再调用容器的 service 方法。</li></ul><h5 id="容器的本质" tabindex="-1"><strong>容器的本质</strong> <a class="header-anchor" href="#容器的本质" aria-label="Permalink to "**容器的本质**""></a></h5><p>Tomcat 有两个核心组件:连接器和容器</p><p><img src="/images/image-20220707100638150.png" alt="image-20220707100638150"></p><p>容器,顾名思义就是用来装载东西的器具,在 Tomcat 里,容器就是用来装载 Servlet 的。那 Tomcat的 Servlet 容器是如何设计的呢?</p><p>Container本质上是一个Servlet容器,负责servelt的加载和管理,处理请求ServletRequest,并返回标准的 ServletResponse 对象给连接器</p><h5 id="容器工作流程" tabindex="-1"><strong>容器工作流程</strong> <a class="header-anchor" href="#容器工作流程" aria-label="Permalink to "**容器工作流程**""></a></h5><p>当客户请求某个资源时,HTTP 服务器会用一个 ServletRequest 对象把客户的请求信息封装起来,然后调用 Servlet 容器的 service 方法,Servlet 容器拿到请求后,根据请求的 URL 和 Servlet 的映射关系,找到相应的 Servlet,如果 Servlet 还没有被加载,就用反射机制创建这个 Servlet,并调用 Servlet 的init 方法来完成初始化,接着调用 Servlet 的 service 方法来处理请求,把 ServletResponse 对象返回给HTTP 服务器,HTTP 服务器会把响应发送给客户端</p><p><img src="/images/image-20220707100739382.png" alt="image-20220707100739382"></p><h5 id="容器层次结构" tabindex="-1"><strong>容器层次结构</strong> <a class="header-anchor" href="#容器层次结构" aria-label="Permalink to "**容器层次结构**""></a></h5><p>Tomcat 设计了 4 种容器组件,分别是 Engine、Host、Context 和 Wrapper。这 4 种容器不是平行关系,而是父子关系。</p><p>如图:</p><p><img src="/images/image-20220707100908090.png" alt="image-20220707100908090"></p><ul><li>Wrapper:表示一个 Servlet</li><li>Context:表示一个 Web 应用程序,一个 Web 应用程序中可能会有多个 Servlet</li><li>Host:表示的是一个虚拟主机,或者说一个站点,可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可以部署多个 Web 应用程序</li><li>Engine:表示引擎,用来管理多个虚拟站点,一个 Service 最多只能有一个 Engine。</li></ul><p>可以再通过 Tomcat 的server.xml配置文件来加深对 Tomcat 容器的理解。Tomcat 采用了组件化的设计,它的构成组件都是可配置的,其中最外层的是 Server,其他组件按照一定的格式要求配置在这个顶层容器中。</p><p><img src="/images/image-20220707100937809.png" alt="image-20220707100937809"></p><h5 id="组件类图" tabindex="-1"><strong>组件类图</strong> <a class="header-anchor" href="#组件类图" aria-label="Permalink to "**组件类图**""></a></h5><p>问题:Tomcat 是怎么管理这些容器组件?</p><p>Container容器中定义了Container 接口用来描述Container容器中所有的组件,不同的子组件分别定义了不同子接口做描述。容器组件之间具有父子关系。</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">public interface Container extends Lifecycle { </span></span>
<span class="line"><span style="color:#e1e4e8;"> public void setName(String name); </span></span>
<span class="line"><span style="color:#e1e4e8;"> public Container getParent(); </span></span>
<span class="line"><span style="color:#e1e4e8;"> public void setParent(Container container); </span></span>
<span class="line"><span style="color:#e1e4e8;"> public void addChild(Container child); </span></span>
<span class="line"><span style="color:#e1e4e8;"> public void removeChild(Container child); </span></span>
<span class="line"><span style="color:#e1e4e8;"> public Container findChild(String name); </span></span>
<span class="line"><span style="color:#e1e4e8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">public interface Container extends Lifecycle { </span></span>
<span class="line"><span style="color:#24292e;"> public void setName(String name); </span></span>
<span class="line"><span style="color:#24292e;"> public Container getParent(); </span></span>
<span class="line"><span style="color:#24292e;"> public void setParent(Container container); </span></span>
<span class="line"><span style="color:#24292e;"> public void addChild(Container child); </span></span>
<span class="line"><span style="color:#24292e;"> public void removeChild(Container child); </span></span>
<span class="line"><span style="color:#24292e;"> public Container findChild(String name); </span></span>
<span class="line"><span style="color:#24292e;">}</span></span></code></pre></div><p><img src="/images/image-20220707101535636.png" alt="image-20220707101535636"></p><p>从接口看到了 getParent、setParent、addChild 和 removeChild 等方法。可能还注意到 Container 接口扩展了 Lifecycle 接口,Lifecycle 接口用来统一管理各组件的生命周期</p><h5 id="套娃式架构设计的好处" tabindex="-1"><strong>套娃式架构设计的好处</strong> <a class="header-anchor" href="#套娃式架构设计的好处" aria-label="Permalink to "**套娃式架构设计的好处**""></a></h5><p><img src="/images/image-20220707101553907.png" alt="image-20220707101553907"></p><ul><li>一层套一层的方式,其实组件关系还是很清晰的,也便于后期组件生命周期管理</li><li>tomcat这种架构设计正好和xml配置文件中标签的包含方式对应上,那么后续在解读xml以及封装对象的过程中就容易对应</li><li>便于子容器继承父容器的一些配置</li></ul><h2 id="tomcat源码环境构建" tabindex="-1">Tomcat源码环境构建 <a class="header-anchor" href="#tomcat源码环境构建" aria-label="Permalink to "Tomcat源码环境构建""></a></h2><h3 id="apache-tomcat源码下载" tabindex="-1"><strong>Apache Tomcat源码下载</strong> <a class="header-anchor" href="#apache-tomcat源码下载" aria-label="Permalink to "**Apache Tomcat源码下载**""></a></h3><p>下载地址:<a href="https://tomcat.apache.org/download-80.cg" target="_blank" rel="noreferrer">https://tomcat.apache.org/download-80.cg</a></p><p><img src="/images/image-20220707101650332.png" alt="image-20220707101650332"></p><h3 id="解压apache-tomcat-8-5-73-src-zip" tabindex="-1">解压<code>apache-tomcat-8.5.73-src.zip</code> <a class="header-anchor" href="#解压apache-tomcat-8-5-73-src-zip" aria-label="Permalink to "解压`apache-tomcat-8.5.73-src.zip`""></a></h3><p><img src="/images/image-20220707101710136.png" alt="image-20220707101710136"></p><h3 id="apache-tomcat-8-5-73-src目录下添加pom文件" tabindex="-1"><code>apache-tomcat-8.5.73-src</code>目录下添加pom文件 <a class="header-anchor" href="#apache-tomcat-8-5-73-src目录下添加pom文件" aria-label="Permalink to "`apache-tomcat-8.5.73-src`目录下添加pom文件""></a></h3><p>因为下载下来的源码包没有pom文件,为了编译并以maven项目运行,需要手动构建一下pom文件</p><p>pom文件如下:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;"><?xml version="1.0" encoding="UTF-8"?></span></span>
<span class="line"><span style="color:#e1e4e8;"><project xmlns="http://maven.apache.org/POM/4.0.0"</span></span>
<span class="line"><span style="color:#e1e4e8;"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"</span></span>
<span class="line"><span style="color:#e1e4e8;"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0</span></span>
<span class="line"><span style="color:#e1e4e8;"> http://maven.apache.org/xsd/maven-4.0.0.xsd"></span></span>
<span class="line"><span style="color:#e1e4e8;"> <modelVersion>4.0.0</modelVersion></span></span>
<span class="line"><span style="color:#e1e4e8;"> <groupId>org.apache.tomcat</groupId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <artifactId>apache-tomcat-8.5.73-src</artifactId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <name>Tomcat8.5</name></span></span>
<span class="line"><span style="color:#e1e4e8;"> <version>8.5</version></span></span>
<span class="line"><span style="color:#e1e4e8;"> <build></span></span>
<span class="line"><span style="color:#e1e4e8;"> <!--指定源目录--></span></span>
<span class="line"><span style="color:#e1e4e8;"> <finalName>Tomcat8.5</finalName></span></span>
<span class="line"><span style="color:#e1e4e8;"> <sourceDirectory>java</sourceDirectory></span></span>
<span class="line"><span style="color:#e1e4e8;"> <resources></span></span>
<span class="line"><span style="color:#e1e4e8;"> <resource></span></span>
<span class="line"><span style="color:#e1e4e8;"> <directory>java</directory></span></span>
<span class="line"><span style="color:#e1e4e8;"> </resource></span></span>
<span class="line"><span style="color:#e1e4e8;"> </resources></span></span>
<span class="line"><span style="color:#e1e4e8;"> <plugins></span></span>
<span class="line"><span style="color:#e1e4e8;"> <!--引入编译插件--></span></span>
<span class="line"><span style="color:#e1e4e8;"> <plugin></span></span>
<span class="line"><span style="color:#e1e4e8;"> <groupId>org.apache.maven.plugins</groupId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <artifactId>maven-compiler-plugin</artifactId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <version>3.1</version></span></span>
<span class="line"><span style="color:#e1e4e8;"> <configuration></span></span>
<span class="line"><span style="color:#e1e4e8;"> <encoding>UTF-8</encoding></span></span>
<span class="line"><span style="color:#e1e4e8;"> <source>1.8</source></span></span>
<span class="line"><span style="color:#e1e4e8;"> <target>1.8</target></span></span>
<span class="line"><span style="color:#e1e4e8;"> </configuration></span></span>
<span class="line"><span style="color:#e1e4e8;"> </plugin></span></span>
<span class="line"><span style="color:#e1e4e8;"> </plugins></span></span>
<span class="line"><span style="color:#e1e4e8;"> </build></span></span>
<span class="line"><span style="color:#e1e4e8;"> <!--tomcat 依赖的基础包--></span></span>
<span class="line"><span style="color:#e1e4e8;"> <dependencies></span></span>
<span class="line"><span style="color:#e1e4e8;"> <dependency></span></span>
<span class="line"><span style="color:#e1e4e8;"> <groupId>org.easymock</groupId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <artifactId>easymock</artifactId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <version>3.4</version></span></span>
<span class="line"><span style="color:#e1e4e8;"> </dependency></span></span>
<span class="line"><span style="color:#e1e4e8;"> <dependency></span></span>
<span class="line"><span style="color:#e1e4e8;"> <groupId>ant</groupId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <artifactId>ant</artifactId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <version>1.7.0</version></span></span>
<span class="line"><span style="color:#e1e4e8;"> </dependency></span></span>
<span class="line"><span style="color:#e1e4e8;"> <dependency></span></span>
<span class="line"><span style="color:#e1e4e8;"> <groupId>wsdl4j</groupId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <artifactId>wsdl4j</artifactId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <version>1.6.2</version></span></span>
<span class="line"><span style="color:#e1e4e8;"> </dependency></span></span>
<span class="line"><span style="color:#e1e4e8;"> <dependency></span></span>
<span class="line"><span style="color:#e1e4e8;"> <groupId>javax.xml</groupId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <artifactId>jaxrpc</artifactId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <version>1.1</version></span></span>
<span class="line"><span style="color:#e1e4e8;"> </dependency></span></span>
<span class="line"><span style="color:#e1e4e8;"> <dependency></span></span>
<span class="line"><span style="color:#e1e4e8;"> <groupId>org.eclipse.jdt.core.compiler</groupId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <artifactId>ecj</artifactId></span></span>
<span class="line"><span style="color:#e1e4e8;"> <version>4.5.1</version></span></span>
<span class="line"><span style="color:#e1e4e8;"> </dependency></span></span>
<span class="line"><span style="color:#e1e4e8;"> </dependencies></span></span>
<span class="line"><span style="color:#e1e4e8;"></project></span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;"><?xml version="1.0" encoding="UTF-8"?></span></span>
<span class="line"><span style="color:#24292e;"><project xmlns="http://maven.apache.org/POM/4.0.0"</span></span>
<span class="line"><span style="color:#24292e;"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"</span></span>
<span class="line"><span style="color:#24292e;"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0</span></span>
<span class="line"><span style="color:#24292e;"> http://maven.apache.org/xsd/maven-4.0.0.xsd"></span></span>
<span class="line"><span style="color:#24292e;"> <modelVersion>4.0.0</modelVersion></span></span>
<span class="line"><span style="color:#24292e;"> <groupId>org.apache.tomcat</groupId></span></span>
<span class="line"><span style="color:#24292e;"> <artifactId>apache-tomcat-8.5.73-src</artifactId></span></span>
<span class="line"><span style="color:#24292e;"> <name>Tomcat8.5</name></span></span>
<span class="line"><span style="color:#24292e;"> <version>8.5</version></span></span>
<span class="line"><span style="color:#24292e;"> <build></span></span>
<span class="line"><span style="color:#24292e;"> <!--指定源目录--></span></span>
<span class="line"><span style="color:#24292e;"> <finalName>Tomcat8.5</finalName></span></span>
<span class="line"><span style="color:#24292e;"> <sourceDirectory>java</sourceDirectory></span></span>
<span class="line"><span style="color:#24292e;"> <resources></span></span>
<span class="line"><span style="color:#24292e;"> <resource></span></span>
<span class="line"><span style="color:#24292e;"> <directory>java</directory></span></span>
<span class="line"><span style="color:#24292e;"> </resource></span></span>
<span class="line"><span style="color:#24292e;"> </resources></span></span>
<span class="line"><span style="color:#24292e;"> <plugins></span></span>
<span class="line"><span style="color:#24292e;"> <!--引入编译插件--></span></span>
<span class="line"><span style="color:#24292e;"> <plugin></span></span>
<span class="line"><span style="color:#24292e;"> <groupId>org.apache.maven.plugins</groupId></span></span>
<span class="line"><span style="color:#24292e;"> <artifactId>maven-compiler-plugin</artifactId></span></span>
<span class="line"><span style="color:#24292e;"> <version>3.1</version></span></span>
<span class="line"><span style="color:#24292e;"> <configuration></span></span>
<span class="line"><span style="color:#24292e;"> <encoding>UTF-8</encoding></span></span>
<span class="line"><span style="color:#24292e;"> <source>1.8</source></span></span>
<span class="line"><span style="color:#24292e;"> <target>1.8</target></span></span>
<span class="line"><span style="color:#24292e;"> </configuration></span></span>
<span class="line"><span style="color:#24292e;"> </plugin></span></span>
<span class="line"><span style="color:#24292e;"> </plugins></span></span>
<span class="line"><span style="color:#24292e;"> </build></span></span>
<span class="line"><span style="color:#24292e;"> <!--tomcat 依赖的基础包--></span></span>
<span class="line"><span style="color:#24292e;"> <dependencies></span></span>
<span class="line"><span style="color:#24292e;"> <dependency></span></span>
<span class="line"><span style="color:#24292e;"> <groupId>org.easymock</groupId></span></span>
<span class="line"><span style="color:#24292e;"> <artifactId>easymock</artifactId></span></span>
<span class="line"><span style="color:#24292e;"> <version>3.4</version></span></span>
<span class="line"><span style="color:#24292e;"> </dependency></span></span>
<span class="line"><span style="color:#24292e;"> <dependency></span></span>
<span class="line"><span style="color:#24292e;"> <groupId>ant</groupId></span></span>
<span class="line"><span style="color:#24292e;"> <artifactId>ant</artifactId></span></span>
<span class="line"><span style="color:#24292e;"> <version>1.7.0</version></span></span>
<span class="line"><span style="color:#24292e;"> </dependency></span></span>
<span class="line"><span style="color:#24292e;"> <dependency></span></span>
<span class="line"><span style="color:#24292e;"> <groupId>wsdl4j</groupId></span></span>
<span class="line"><span style="color:#24292e;"> <artifactId>wsdl4j</artifactId></span></span>
<span class="line"><span style="color:#24292e;"> <version>1.6.2</version></span></span>
<span class="line"><span style="color:#24292e;"> </dependency></span></span>
<span class="line"><span style="color:#24292e;"> <dependency></span></span>
<span class="line"><span style="color:#24292e;"> <groupId>javax.xml</groupId></span></span>
<span class="line"><span style="color:#24292e;"> <artifactId>jaxrpc</artifactId></span></span>
<span class="line"><span style="color:#24292e;"> <version>1.1</version></span></span>
<span class="line"><span style="color:#24292e;"> </dependency></span></span>
<span class="line"><span style="color:#24292e;"> <dependency></span></span>
<span class="line"><span style="color:#24292e;"> <groupId>org.eclipse.jdt.core.compiler</groupId></span></span>
<span class="line"><span style="color:#24292e;"> <artifactId>ecj</artifactId></span></span>
<span class="line"><span style="color:#24292e;"> <version>4.5.1</version></span></span>
<span class="line"><span style="color:#24292e;"> </dependency></span></span>
<span class="line"><span style="color:#24292e;"> </dependencies></span></span>
<span class="line"><span style="color:#24292e;"></project></span></span></code></pre></div><h3 id="创建catalina-home目录" tabindex="-1">创建catalina-home目录 <a class="header-anchor" href="#创建catalina-home目录" aria-label="Permalink to "创建catalina-home目录""></a></h3><p><img src="/images/image-20220707101832239.png" alt="image-20220707101832239"></p><p><img src="/images/image-20220707101838069.png" alt="image-20220707101838069"></p><p>将bin、conf、webapps目录复制到catalina-home目录中:</p><p><img src="/images/image-20220707101845965.png" alt="image-20220707101845965"></p><p>其余文件夹手动进行创建:</p><p><img src="/images/image-20220707101856580.png" alt="image-20220707101856580"></p><h3 id="导入idea" tabindex="-1">导入IDEA <a class="header-anchor" href="#导入idea" aria-label="Permalink to "导入IDEA""></a></h3><p><img src="/images/image-20220707101914213.png" alt="image-20220707101914213"></p><p>新建application 设置main类和vm参数</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">Main class: org.apache.catalina.startup.Bootstrap </span></span>
<span class="line"><span style="color:#e1e4e8;">VM options: 配置自己的catalina-home目录</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">Main class: org.apache.catalina.startup.Bootstrap </span></span>
<span class="line"><span style="color:#24292e;">VM options: 配置自己的catalina-home目录</span></span></code></pre></div><p><img src="/images/image-20220707101931503.png" alt="image-20220707101931503"></p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">-Dcatalina.home=catalina-home</span></span>
<span class="line"><span style="color:#e1e4e8;">-Dcatalina.base=catalina-home</span></span>
<span class="line"><span style="color:#e1e4e8;">-Djava.io.tmpdir=catalina-home/temp</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">-Dcatalina.home=catalina-home</span></span>
<span class="line"><span style="color:#24292e;">-Dcatalina.base=catalina-home</span></span>
<span class="line"><span style="color:#24292e;">-Djava.io.tmpdir=catalina-home/temp</span></span></code></pre></div><p>打开ContextConfig 添加一行代码</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">//初始化JSP解析引擎 </span></span>
<span class="line"><span style="color:#e1e4e8;">context.addServletContainerInitializer(new JasperInitializer(),null);</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">//初始化JSP解析引擎 </span></span>
<span class="line"><span style="color:#24292e;">context.addServletContainerInitializer(new JasperInitializer(),null);</span></span></code></pre></div><p><img src="/images/image-20220707101959617.png" alt="image-20220707101959617"></p><h3 id="启动执行【常见错误解决】" tabindex="-1"><strong>启动执行【常见错误解决】</strong> <a class="header-anchor" href="#启动执行【常见错误解决】" aria-label="Permalink to "**启动执行【常见错误解决】**""></a></h3><p><img src="/images/image-20220707102011869.png" alt="image-20220707102011869"></p><p>报错</p><p><img src="/images/image-20220707102025207.png" alt="image-20220707102025207"></p><p>解决:</p><p>将JmxRemoteLifecycleListener类 全部注释,再次启动</p><p><img src="/images/image-20220707102029146.png" alt="image-20220707102029146"></p><p>启动成功:</p><p><img src="/images/image-20220707102036811.png" alt="image-20220707102036811"></p><h2 id="如何实现一键式启停" tabindex="-1">如何实现一键式启停 <a class="header-anchor" href="#如何实现一键式启停" aria-label="Permalink to "如何实现一键式启停""></a></h2><p>Tomcat里面有各种各样的组件,每个组件各司其职,组件之间又相互协作共同完成web服务器这样的工程。</p><p>组件的层次关系:</p><p><img src="/images/image-20220707102047832.png" alt="image-20220707102047832"></p><p>上面这张图描述了组件之间的静态关系,如果想让一个系统能够对外提供服务,我们需要创建、组装并启动这些组件;在服务停止的时候,我们还需要释放资源,销毁这些组件,因此这是一个动态的过程。</p><p>也就是说,Tomcat 需要动态地管理这些组件的生命周期。</p><p>组件关系:</p><p>先来看看组件之间的关系。如果你仔细分析过这些组件,可以发现它们具有两层关系。</p><ul><li>第一层关系是组件有大有小,大组件管理小组件,比如 Server 管理 Service,Service 又管理连接器和容器。</li><li>第二层关系是组件有外有内,外层组件控制内层组件,比如连接器是外层组件,负责对外交流,外层组件调用内层组件完成业务功能。也就是说,请求的处理过程是由外层组件来驱动的。</li></ul><p>这两层关系决定了系统在创建组件时应该遵循一定的顺序。</p><ul><li>第一个原则是先创建子组件,再创建父组件,子组件需要被“注入”到父组件中。</li><li>第二个原则是先创建内层组件,再创建外层组件,内层组件需要被“注入”到外层组件</li></ul><p>因此,最直观的做法就是将图上所有的组件按照先小后大、先内后外的顺序创建出来,然后组装在一起。不知道注意到没有,这个思路其实很有问题!因为这样不仅会造成代码逻辑混乱和组件遗漏,而且也不利于后期的功能扩展。为了解决这个问题,我们希望找到一种通用的、统一的方法来管理组件的生命周期,就像汽车“一键启动”那样的效果。</p><p>思考:如何统一管理组件的创建、初始化、启动、停止和销毁?</p><h4 id="一键式启停-lifecycle-接口" tabindex="-1"><strong>一键式启停:Lifecycle 接口</strong> <a class="header-anchor" href="#一键式启停-lifecycle-接口" aria-label="Permalink to "**一键式启停:Lifecycle 接口**""></a></h4><p>Lifecycle 接口里应该定义这么几个方法:init、start、stop 和 destroy,每个具体的组件去实现这些方法。</p><p>Lifecycle 接口</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">public interface Lifecycle {</span></span>
<span class="line"><span style="color:#e1e4e8;"> ....</span></span>
<span class="line"><span style="color:#e1e4e8;"> // 初始化方法</span></span>
<span class="line"><span style="color:#e1e4e8;"> public void init() throws LifecycleException;</span></span>
<span class="line"><span style="color:#e1e4e8;"> // 启动方法</span></span>
<span class="line"><span style="color:#e1e4e8;"> public void start() throws LifecycleException;</span></span>
<span class="line"><span style="color:#e1e4e8;"> // 停止方法,和start对应</span></span>
<span class="line"><span style="color:#e1e4e8;"> public void stop() throws LifecycleException;</span></span>
<span class="line"><span style="color:#e1e4e8;"> // 销毁方法,和init对应</span></span>
<span class="line"><span style="color:#e1e4e8;"> public void destroy() throws LifecycleException;</span></span>
<span class="line"><span style="color:#e1e4e8;"> // 获取生命周期状态</span></span>
<span class="line"><span style="color:#e1e4e8;"> public LifecycleState getState();</span></span>
<span class="line"><span style="color:#e1e4e8;"> // 获取字符串类型的生命周期状态</span></span>
<span class="line"><span style="color:#e1e4e8;"> public String getStateName();</span></span>
<span class="line"><span style="color:#e1e4e8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">public interface Lifecycle {</span></span>
<span class="line"><span style="color:#24292e;"> ....</span></span>
<span class="line"><span style="color:#24292e;"> // 初始化方法</span></span>
<span class="line"><span style="color:#24292e;"> public void init() throws LifecycleException;</span></span>
<span class="line"><span style="color:#24292e;"> // 启动方法</span></span>
<span class="line"><span style="color:#24292e;"> public void start() throws LifecycleException;</span></span>
<span class="line"><span style="color:#24292e;"> // 停止方法,和start对应</span></span>
<span class="line"><span style="color:#24292e;"> public void stop() throws LifecycleException;</span></span>
<span class="line"><span style="color:#24292e;"> // 销毁方法,和init对应</span></span>
<span class="line"><span style="color:#24292e;"> public void destroy() throws LifecycleException;</span></span>
<span class="line"><span style="color:#24292e;"> // 获取生命周期状态</span></span>
<span class="line"><span style="color:#24292e;"> public LifecycleState getState();</span></span>
<span class="line"><span style="color:#24292e;"> // 获取字符串类型的生命周期状态</span></span>
<span class="line"><span style="color:#24292e;"> public String getStateName();</span></span>
<span class="line"><span style="color:#24292e;">}</span></span></code></pre></div><p>在这样的设计中,在父组件的 init 方法里需要创建子组件并调用子组件的 init 方法。同样,在父组件的 start 方法里也需要调用子组件的 start 方法,因此调用者可以无差别的调用各组件的 init 方法和 start 方法,这就是组合模式的使用,并且只要调用最顶层组件,也就是 Server 组件的 init 和 start 方法,整个 Tomcat 就被启动起来了</p><h5 id="重用性-lifecyclebase-抽象基类" tabindex="-1">重用性:LifecycleBase 抽象基类 <a class="header-anchor" href="#重用性-lifecyclebase-抽象基类" aria-label="Permalink to "重用性:LifecycleBase 抽象基类""></a></h5><p>有了接口,我们就要用类去实现接口。一般来说实现类不止一个,不同的类在实现接口时往往会有一些 相同的逻辑,如果让各个子类都去实现一遍,就会有重复代码。那子类如何重用这部分逻辑呢?其实就是定义一个基类来实现共同的逻辑,然后让各个子类去继承它,就达到了重用的目的。而基类中往往会定义一些抽象方法,所谓的抽象方法就是说基类不会去实现这些方法,而是调用这些方法来实现骨架逻辑。抽象方法是留给各个子类去实现的,并且子类必须实现,否则无法实例化。</p><p><img src="/images/image-20220707102230680.png" alt="image-20220707102230680"></p><p>Tomcat 定义一个基类 LifecycleBase 来实现 Lifecycle 接口,把一些公共的逻辑放到基类中去,比如生命状态的转变与维护、生命事件的触发以及监听器的添加和删除等,而子类就负责实现自己的初始化、启动和停止等方法</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">@Override</span></span>
<span class="line"><span style="color:#e1e4e8;">public final synchronized void init() throws LifecycleException {</span></span>
<span class="line"><span style="color:#e1e4e8;"> //1. 状态检查</span></span>
<span class="line"><span style="color:#e1e4e8;"> if (!state.equals(LifecycleState.NEW)) {</span></span>
<span class="line"><span style="color:#e1e4e8;"> invalidTransition(Lifecycle.BEFORE_INIT_EVENT);</span></span>
<span class="line"><span style="color:#e1e4e8;"> }</span></span>
<span class="line"><span style="color:#e1e4e8;"> try {</span></span>
<span class="line"><span style="color:#e1e4e8;"> //2.触发INITIALIZING事件的监听器</span></span>
<span class="line"><span style="color:#e1e4e8;"> setStateInternal(LifecycleState.INITIALIZING, null, false);</span></span>
<span class="line"><span style="color:#e1e4e8;"> </span></span>
<span class="line"><span style="color:#e1e4e8;"> //3.调用具体子类的初始化方法</span></span>
<span class="line"><span style="color:#e1e4e8;"> initInternal();</span></span>
<span class="line"><span style="color:#e1e4e8;"> </span></span>
<span class="line"><span style="color:#e1e4e8;"> //4. 触发INITIALIZED事件的监听器</span></span>
<span class="line"><span style="color:#e1e4e8;"> setStateInternal(LifecycleState.INITIALIZED, null, false);</span></span>
<span class="line"><span style="color:#e1e4e8;"> } catch (Throwable t) {</span></span>
<span class="line"><span style="color:#e1e4e8;"> ...</span></span>
<span class="line"><span style="color:#e1e4e8;"> }</span></span>
<span class="line"><span style="color:#e1e4e8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">@Override</span></span>
<span class="line"><span style="color:#24292e;">public final synchronized void init() throws LifecycleException {</span></span>
<span class="line"><span style="color:#24292e;"> //1. 状态检查</span></span>
<span class="line"><span style="color:#24292e;"> if (!state.equals(LifecycleState.NEW)) {</span></span>
<span class="line"><span style="color:#24292e;"> invalidTransition(Lifecycle.BEFORE_INIT_EVENT);</span></span>
<span class="line"><span style="color:#24292e;"> }</span></span>
<span class="line"><span style="color:#24292e;"> try {</span></span>
<span class="line"><span style="color:#24292e;"> //2.触发INITIALIZING事件的监听器</span></span>
<span class="line"><span style="color:#24292e;"> setStateInternal(LifecycleState.INITIALIZING, null, false);</span></span>
<span class="line"><span style="color:#24292e;"> </span></span>
<span class="line"><span style="color:#24292e;"> //3.调用具体子类的初始化方法</span></span>
<span class="line"><span style="color:#24292e;"> initInternal();</span></span>
<span class="line"><span style="color:#24292e;"> </span></span>
<span class="line"><span style="color:#24292e;"> //4. 触发INITIALIZED事件的监听器</span></span>
<span class="line"><span style="color:#24292e;"> setStateInternal(LifecycleState.INITIALIZED, null, false);</span></span>
<span class="line"><span style="color:#24292e;"> } catch (Throwable t) {</span></span>
<span class="line"><span style="color:#24292e;"> ...</span></span>
<span class="line"><span style="color:#24292e;"> }</span></span>
<span class="line"><span style="color:#24292e;">}</span></span></code></pre></div><h2 id="源码剖析-tomcat启动流程" tabindex="-1">源码剖析-Tomcat启动流程 <a class="header-anchor" href="#源码剖析-tomcat启动流程" aria-label="Permalink to "源码剖析-Tomcat启动流程""></a></h2><h3 id="启动总流程图" tabindex="-1">启动总流程图 <a class="header-anchor" href="#启动总流程图" aria-label="Permalink to "启动总流程图""></a></h3><p>使用Tomcat时,通过 Tomcat 的/bin目录下的脚本startup.sh来启动 Tomcat,那执行了这个脚本后发生了什么呢?</p><p>流程图:</p><p><img src="/images/image-20220707102351453.png" alt="image-20220707102351453"></p><ul><li>1.Tomcat 本质上是一个 Java 程序,因此startup.sh脚本会启动一个 JVM 来运行 Tomcat 的启动类 Bootstrap</li><li>2.Bootstrap 的主要任务是初始化 Tomcat 的类加载器,并且创建 Catalina</li><li>3.Catalina 是一个启动类,它通过解析server.xml、创建相应的组件,并调用 Server 的 start 方法</li><li>4.Server 组件的职责就是管理 Service 组件,它会负责调用 Service 的 start 方法</li><li>5.Service 组件的职责就是管理连接器和顶层容器 Engine,因此它会调用连接器和 Engine 的 start 方法。</li></ul><p>这样 Tomcat 的启动就算完成了</p><h4 id="_1-启动流程细节" tabindex="-1">(1)启动流程细节 <a class="header-anchor" href="#_1-启动流程细节" aria-label="Permalink to "(1)启动流程细节""></a></h4><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">startup.sh --> catalina.sh start --> java xxxx.jar org.apache.catalina.startup.Bootstrap(main) </span></span>
<span class="line"><span style="color:#e1e4e8;">start(参数)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">startup.sh --> catalina.sh start --> java xxxx.jar org.apache.catalina.startup.Bootstrap(main) </span></span>
<span class="line"><span style="color:#24292e;">start(参数)</span></span></code></pre></div><p><img src="/images/image-20220707102444775.png" alt="image-20220707102444775"></p><p>tips:</p><ul><li>Bootstrap.init</li><li>Catalina.load</li><li>Catalina.start</li></ul><h3 id="bootstrap-init" tabindex="-1"><strong><code>Bootstrap#init();</code></strong> <a class="header-anchor" href="#bootstrap-init" aria-label="Permalink to "**`Bootstrap#init();`**""></a></h3><p>1、初始化类加载器</p><p>2、加载catalina类,并且实例化</p><p>3、反射调用Catalina的setParentClassLoader方法</p><p>4、实例 赋值</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">//1、初始化类加载器</span></span>
<span class="line"><span style="color:#e1e4e8;"> //2、加载catalina类,并且实例化</span></span>
<span class="line"><span style="color:#e1e4e8;"> //3、反射调用Catalina的setParentClassLoader方法</span></span>
<span class="line"><span style="color:#e1e4e8;"> //4、实例 赋值</span></span>
<span class="line"><span style="color:#e1e4e8;"> public void init() throws Exception {</span></span>
<span class="line"><span style="color:#e1e4e8;"> // 1. 初始化Tomcat类加载器(3个类加载器)</span></span>
<span class="line"><span style="color:#e1e4e8;"> initClassLoaders();</span></span>
<span class="line"><span style="color:#e1e4e8;"> Thread.currentThread().setContextClassLoader(catalinaLoader);</span></span>
<span class="line"><span style="color:#e1e4e8;"> SecurityClassLoad.securityClassLoad(catalinaLoader);</span></span>
<span class="line"><span style="color:#e1e4e8;"> // Load our startup class and call its process() method</span></span>
<span class="line"><span style="color:#e1e4e8;"> if (log.isDebugEnabled())</span></span>
<span class="line"><span style="color:#e1e4e8;"> log.debug("Loading startup class");</span></span>
<span class="line"><span style="color:#e1e4e8;"> // 2. 实例化Catalina实例</span></span>
<span class="line"><span style="color:#e1e4e8;"> Class<?> startupClass = </span></span>
<span class="line"><span style="color:#e1e4e8;">catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");</span></span>
<span class="line"><span style="color:#e1e4e8;"> Object startupInstance = startupClass.getConstructor().newInstance();</span></span>
<span class="line"><span style="color:#e1e4e8;"> // Set the shared extensions class loader</span></span>
<span class="line"><span style="color:#e1e4e8;"> if (log.isDebugEnabled())</span></span>
<span class="line"><span style="color:#e1e4e8;"> log.debug("Setting startup class properties");</span></span>
<span class="line"><span style="color:#e1e4e8;"> String methodName = "setParentClassLoader";</span></span>
<span class="line"><span style="color:#e1e4e8;"> Class<?> paramTypes[] = new Class[1];</span></span>
<span class="line"><span style="color:#e1e4e8;"> paramTypes[0] = Class.forName("java.lang.ClassLoader");</span></span>
<span class="line"><span style="color:#e1e4e8;"> Object paramValues[] = new Object[1];</span></span>
<span class="line"><span style="color:#e1e4e8;"> paramValues[0] = sharedLoader;</span></span>
<span class="line"><span style="color:#e1e4e8;"> // 3. 反射调用Catalina的setParentClassLoader方法,将sharedLoader设置为</span></span>
<span class="line"><span style="color:#e1e4e8;">Catalina的parentClassLoader成员变量</span></span>
<span class="line"><span style="color:#e1e4e8;"> Method method =</span></span>
<span class="line"><span style="color:#e1e4e8;"> startupInstance.getClass().getMethod(methodName, paramTypes);</span></span>
<span class="line"><span style="color:#e1e4e8;"> method.invoke(startupInstance, paramValues);</span></span>
<span class="line"><span style="color:#e1e4e8;"> //4、将catalina实例赋值</span></span>
<span class="line"><span style="color:#e1e4e8;"> catalinaDaemon = startupInstance;</span></span>
<span class="line"><span style="color:#e1e4e8;"> }</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">//1、初始化类加载器</span></span>
<span class="line"><span style="color:#24292e;"> //2、加载catalina类,并且实例化</span></span>
<span class="line"><span style="color:#24292e;"> //3、反射调用Catalina的setParentClassLoader方法</span></span>
<span class="line"><span style="color:#24292e;"> //4、实例 赋值</span></span>
<span class="line"><span style="color:#24292e;"> public void init() throws Exception {</span></span>
<span class="line"><span style="color:#24292e;"> // 1. 初始化Tomcat类加载器(3个类加载器)</span></span>
<span class="line"><span style="color:#24292e;"> initClassLoaders();</span></span>
<span class="line"><span style="color:#24292e;"> Thread.currentThread().setContextClassLoader(catalinaLoader);</span></span>
<span class="line"><span style="color:#24292e;"> SecurityClassLoad.securityClassLoad(catalinaLoader);</span></span>
<span class="line"><span style="color:#24292e;"> // Load our startup class and call its process() method</span></span>
<span class="line"><span style="color:#24292e;"> if (log.isDebugEnabled())</span></span>
<span class="line"><span style="color:#24292e;"> log.debug("Loading startup class");</span></span>
<span class="line"><span style="color:#24292e;"> // 2. 实例化Catalina实例</span></span>
<span class="line"><span style="color:#24292e;"> Class<?> startupClass = </span></span>
<span class="line"><span style="color:#24292e;">catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");</span></span>
<span class="line"><span style="color:#24292e;"> Object startupInstance = startupClass.getConstructor().newInstance();</span></span>
<span class="line"><span style="color:#24292e;"> // Set the shared extensions class loader</span></span>
<span class="line"><span style="color:#24292e;"> if (log.isDebugEnabled())</span></span>
<span class="line"><span style="color:#24292e;"> log.debug("Setting startup class properties");</span></span>
<span class="line"><span style="color:#24292e;"> String methodName = "setParentClassLoader";</span></span>
<span class="line"><span style="color:#24292e;"> Class<?> paramTypes[] = new Class[1];</span></span>
<span class="line"><span style="color:#24292e;"> paramTypes[0] = Class.forName("java.lang.ClassLoader");</span></span>
<span class="line"><span style="color:#24292e;"> Object paramValues[] = new Object[1];</span></span>
<span class="line"><span style="color:#24292e;"> paramValues[0] = sharedLoader;</span></span>
<span class="line"><span style="color:#24292e;"> // 3. 反射调用Catalina的setParentClassLoader方法,将sharedLoader设置为</span></span>
<span class="line"><span style="color:#24292e;">Catalina的parentClassLoader成员变量</span></span>
<span class="line"><span style="color:#24292e;"> Method method =</span></span>
<span class="line"><span style="color:#24292e;"> startupInstance.getClass().getMethod(methodName, paramTypes);</span></span>
<span class="line"><span style="color:#24292e;"> method.invoke(startupInstance, paramValues);</span></span>
<span class="line"><span style="color:#24292e;"> //4、将catalina实例赋值</span></span>
<span class="line"><span style="color:#24292e;"> catalinaDaemon = startupInstance;</span></span>
<span class="line"><span style="color:#24292e;"> }</span></span></code></pre></div><h3 id="catalina-load" tabindex="-1"><code>Catalina#load();</code> <a class="header-anchor" href="#catalina-load" aria-label="Permalink to "`Catalina#load();`""></a></h3><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">org.apache.catalina.startup.Bootstrap#main中的load方法调用的是catalina中的方法</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">org.apache.catalina.startup.Bootstrap#main中的load方法调用的是catalina中的方法</span></span></code></pre></div><h4 id="_1-load初始化流程" tabindex="-1">1)load初始化流程 <a class="header-anchor" href="#_1-load初始化流程" aria-label="Permalink to "1)load初始化流程""></a></h4><p>模板模式:</p><p>每个节点自己完成的任务后,会接着调用子节点(如果有的话)的同样的方法,引起链式反应。</p><p><img src="/images/image-20220707102653576.png" alt="image-20220707102653576"></p><h3 id="catalina-start" tabindex="-1"><code>Catalina#start();</code> <a class="header-anchor" href="#catalina-start" aria-label="Permalink to "`Catalina#start();`""></a></h3><p><strong>流程图</strong></p><p>与load过程很相似</p><p><img src="/images/image-20220707102718169.png" alt="image-20220707102718169"></p><h2 id="流程分析-servlet请求处理链路跟踪" tabindex="-1">流程分析-Servlet请求处理链路跟踪 <a class="header-anchor" href="#流程分析-servlet请求处理链路跟踪" aria-label="Permalink to "流程分析-Servlet请求处理链路跟踪""></a></h2><p>问题:设计了这么多层次的容器,Tomcat 是怎么确定请求是由哪个 Wrapper 容器里的 Servlet 来处理的呢?答案是,Tomcat 是用 Mapper 组件来完成这个任务的。</p><p>Mapper 组件的功能就是将用户请求的 URL 定位到一个 Servlet,它的工作原理是:Mapper 组件里保存了 Web 应用的配置信息,其实就是容器组件与访问路径的映射关系,比如 Host 容器里配置的域名、Context 容器里的 Web 应用路径,以及 Wrapper 容器里 Servlet 映射的路径,你可以想象这些配置信息就是一个多层次的 Map。</p><p>当一个请求到来时,Mapper 组件通过解析请求 URL 里的域名和路径,再到自己保存的 Map 里去查找,就能定位到一个 Servlet。请你注意,一个请求 URL 最后只会定位到一个 Wrapper 容器,也就是一个 Servlet。</p><p>例子:</p><p><img src="/images/image-20220707102749389.png" alt="image-20220707102749389"></p><p>假如有用户访问一个 URL,比如图中的<code>http://user.shopping.com:8080/order/buy</code>,Tomcat 如何将这个 URL 定位到一个 Servlet 呢?</p><p>**首先,**根据协议和端口号选定 Service 和 Engine。</p><p>我们知道 Tomcat 的每个连接器都监听不同的端口,比如 Tomcat 默认的 HTTP 连接器监听 8080 端口、默认的 AJP 连接器监听 8009 端口。上面例子中的 URL 访问的是 8080 端口,因此这个请求会被 HTTP 连接器接收,而一个连接器是属于一个 Service 组件的,这样 Service 组件就确定了。我们还知道一个 Service 组件里除了有多个连接器,还有一个容器组件,具体来说就是一个 Engine 容器,因此 Service 确定了也就意味着 Engine 也确定了。</p><p>**然后,**根据域名选定 Host。 Service 和 Engine 确定后,Mapper 组件通过 URL 中的域名去查找相应的 Host 容器,比如例子中的 URL 访问的域名是user.shopping.com,因此 Mapper 会找到 Host2 这个容器。</p><p>**之后,**根据 URL 路径找到 Context 组件。</p><p>Host 确定以后,Mapper 根据 URL 的路径来匹配相应的 Web 应用的路径,比如例子中访问的是/order,因此找到了 Context4 这个 Context 容器。</p><p>**最后,**根据 URL 路径找到 Wrapper(Servlet)。 Context 确定后,Mapper 再根据web.xml中配置的 Servlet 映射路径来找到具体的 Wrapper 和 Servlet。</p><p>我们知道容器组件最重要的功能是处理请求,最先拿到请求的是 Engine 容器,Engine 容器对请求做一些处理后,会把请求传给自己子容器 Host 继续处理,依次类推,最后这个请求会传给 Wrapper 容器,Wrapper 会调用最终的 Servlet 来处理。那么这个调用过程具体是怎么实现的呢?答案是使用 Pipeline-Valve 管道。</p><p>Pipeline-Valve 是责任链模式,责任链模式是指在一个请求处理的过程中有很多处理者依次对请求进行处理,每个处理者负责做自己相应的处理,处理完之后将再调用下一个处理者继续处理。Valve 表示一个处理点,比如权限认证和记录日志。如果还不太理解的话,可以来看看 Valve 和 Pipeline 接口中的关键方法</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">public interface Valve {</span></span>
<span class="line"><span style="color:#e1e4e8;"> public Valve getNext();</span></span>
<span class="line"><span style="color:#e1e4e8;"> public void setNext(Valve valve);</span></span>
<span class="line"><span style="color:#e1e4e8;"> public void invoke(Request request, Response response)</span></span>
<span class="line"><span style="color:#e1e4e8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">public interface Valve {</span></span>
<span class="line"><span style="color:#24292e;"> public Valve getNext();</span></span>
<span class="line"><span style="color:#24292e;"> public void setNext(Valve valve);</span></span>
<span class="line"><span style="color:#24292e;"> public void invoke(Request request, Response response)</span></span>
<span class="line"><span style="color:#24292e;">}</span></span></code></pre></div><p>由于 Valve 是一个处理点,因此 invoke 方法就是来处理请求的。注意到 Valve 中有 getNext 和 setNext 方法,因此我们大概可以猜到有一个链表将 Valve 链起来了。请你继续看 Pipeline 接口:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">public interface Pipeline extends Contained {</span></span>
<span class="line"><span style="color:#e1e4e8;"> public void addValve(Valve valve);</span></span>
<span class="line"><span style="color:#e1e4e8;"> public Valve getBasic();</span></span>
<span class="line"><span style="color:#e1e4e8;"> public void setBasic(Valve valve);</span></span>
<span class="line"><span style="color:#e1e4e8;"> public Valve getFirst();</span></span>
<span class="line"><span style="color:#e1e4e8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">public interface Pipeline extends Contained {</span></span>
<span class="line"><span style="color:#24292e;"> public void addValve(Valve valve);</span></span>
<span class="line"><span style="color:#24292e;"> public Valve getBasic();</span></span>
<span class="line"><span style="color:#24292e;"> public void setBasic(Valve valve);</span></span>
<span class="line"><span style="color:#24292e;"> public Valve getFirst();</span></span>
<span class="line"><span style="color:#24292e;">}</span></span></code></pre></div><p>没错,Pipeline 中有 addValve 方法。Pipeline 中维护了 Valve 链表,Valve 可以插入到 Pipeline 中,对请求做某些处理。我们还发现 Pipeline 中没有 invoke 方法,因为整个调用链的触发是 Valve 来完成的,Valve 完成自己的处理后,调用getNext.invoke来触发下一个 Valve 调用。</p><p>每一个容器都有一个 Pipeline 对象,只要触发这个 Pipeline 的第一个 Valve,这个容器里 Pipeline 中的 Valve 就都会被调用到。但是,不同容器的 Pipeline 是怎么链式触发的呢,比如 Engine 中 Pipeline 需要调用下层容器 Host 中的 Pipeline</p><p>这是因为 Pipeline 中还有个 getBasic 方法。这个 BasicValve 处于 Valve 链表的末端,它是 Pipeline 中必不可少的一个 Valve,负责调用下层容器的 Pipeline 里的第一个 Valve。还是通过一张图来解释</p><p><img src="/images/image-20220707102922853.png" alt="image-20220707102922853"></p><p>每一个容器组件都有一个 Pipeline,而 Pipeline 中有一个基础阀(Basic Valve),而 Engine 容器的基础阀定义如下:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">final class StandardEngineValve extends ValveBase {</span></span>
<span class="line"><span style="color:#e1e4e8;"> public final void invoke(Request request, Response response)</span></span>
<span class="line"><span style="color:#e1e4e8;"> throws IOException, ServletException {</span></span>
<span class="line"><span style="color:#e1e4e8;"> </span></span>
<span class="line"><span style="color:#e1e4e8;"> //拿到请求中的Host容器</span></span>
<span class="line"><span style="color:#e1e4e8;"> Host host = request.getHost();</span></span>
<span class="line"><span style="color:#e1e4e8;"> if (host == null) {</span></span>
<span class="line"><span style="color:#e1e4e8;"> return;</span></span>
<span class="line"><span style="color:#e1e4e8;"> }</span></span>
<span class="line"><span style="color:#e1e4e8;"> </span></span>
<span class="line"><span style="color:#e1e4e8;"> // 调用Host容器中的Pipeline中的第一个Valve</span></span>
<span class="line"><span style="color:#e1e4e8;"> host.getPipeline().getFirst().invoke(request, response);</span></span>
<span class="line"><span style="color:#e1e4e8;"> }</span></span>
<span class="line"><span style="color:#e1e4e8;"> j</span></span>
<span class="line"><span style="color:#e1e4e8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">final class StandardEngineValve extends ValveBase {</span></span>
<span class="line"><span style="color:#24292e;"> public final void invoke(Request request, Response response)</span></span>
<span class="line"><span style="color:#24292e;"> throws IOException, ServletException {</span></span>
<span class="line"><span style="color:#24292e;"> </span></span>
<span class="line"><span style="color:#24292e;"> //拿到请求中的Host容器</span></span>
<span class="line"><span style="color:#24292e;"> Host host = request.getHost();</span></span>
<span class="line"><span style="color:#24292e;"> if (host == null) {</span></span>
<span class="line"><span style="color:#24292e;"> return;</span></span>
<span class="line"><span style="color:#24292e;"> }</span></span>
<span class="line"><span style="color:#24292e;"> </span></span>
<span class="line"><span style="color:#24292e;"> // 调用Host容器中的Pipeline中的第一个Valve</span></span>
<span class="line"><span style="color:#24292e;"> host.getPipeline().getFirst().invoke(request, response);</span></span>
<span class="line"><span style="color:#24292e;"> }</span></span>
<span class="line"><span style="color:#24292e;"> j</span></span>
<span class="line"><span style="color:#24292e;">}</span></span></code></pre></div><p>这个基础阀实现非常简单,就是把请求转发到 Host 容器。问题是处理请求的 Host 容器对象是从请求中拿到的,请求对象中怎么会有 Host 容器呢?这是因为请求到达 Engine 容器中之前,Mapper 组件已经对请求进行了路由处理,Mapper 组件通过请求的 URL 定位了相应的容器,并且把容器对象保存到了请求对象中。</p></div></div></main><footer class="VPDocFooter" data-v-e970bbc0 data-v-45cfeac9><!--[--><!--]--><!----><nav class="prev-next" data-v-45cfeac9><div class="pager" data-v-45cfeac9><!----></div><div class="pager" data-v-45cfeac9><a class="pager-link next" href="/devops-deploy-tomcat.html" data-v-45cfeac9><span class="desc" data-v-45cfeac9>下一篇</span><span class="title" data-v-45cfeac9>Tomcat</span></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
<script>window.__VP_HASH_MAP__=JSON.parse("{\"lang-java.md\":\"9fff46e5\",\"api-examples.md\":\"0c7bbd41\",\"lang-java-array.md\":\"9c8e9312\",\"lang-java-base.md\":\"020e1eda\",\"tools-soft-7zip.md\":\"d1e14adf\",\"tools-soft.md\":\"9c9a88a3\",\"tools-soft-windows.md\":\"70dfbaa0\",\"tools-soft-markdown.md\":\"6c5314cd\",\"docs_05_devops_01_部署_06_linux_04_linux安装.md\":\"9068ebd9\",\"tools-soft-chrome.md\":\"785c1b29\",\"tools-soft-baidupan.md\":\"d651616f\",\"tools-soft-foxit.md\":\"6d3da41e\",\"tools-soft-cmder.md\":\"b39aed2e\",\"docs_05_devops_01_部署_06_linux_01_linux概述.md\":\"83e5c414\",\"docs_05_devops_01_部署_06_linux_02_linux常用命令.md\":\"f6f08dad\",\"tools-soft-office.md\":\"0dfaede5\",\"tools-soft-potplayer.md\":\"2344cea6\",\"tools-soft-snipaste.md\":\"b65c8145\",\"tools-soft-sublimetext.md\":\"c02c7aaf\",\"tools-soft-typora.md\":\"7c7a2879\",\"tools-soft-tizi.md\":\"70132fe0\",\"tools-soft-xmind.md\":\"165042c6\",\"tools-dev-maven.md\":\"e0a81f73\",\"tools-dev-idea.md\":\"a7daced8\",\"tools-dev-pycharm.md\":\"a24889ff\",\"tools-dev-navicat.md\":\"aad3f952\",\"tools-dev-gradle.md\":\"f91af374\",\"tools-dev-ssh.md\":\"eafa7684\",\"tools-dev-postman.md\":\"4505be9e\",\"tools-dev-jmeter.md\":\"540d7cde\",\"index.md\":\"5d013929\",\"tools-vcs-svn.md\":\"cba08751\",\"tools-vcs-git.md\":\"f375211f\",\"docs_05_devops_01_部署_06_linux_03_linux下shell篇.md\":\"5e45709e\",\"devops-deploy-tomcat.md\":\"53274c1f\",\"devops-deploy-lvs.md\":\"cf468b1a\",\"devops-deploy-nginx.md\":\"775aaeab\",\"tools-dev-vmware.md\":\"7bae1f2d\",\"markdown-examples.md\":\"6e41634c\",\"tools-vcs-gitflow.md\":\"aaed74fe\",\"tools-dev-nvm.md\":\"c458444c\",\"tools-vcs-gitee.md\":\"6c9a7eac\",\"tools-vcs-github.md\":\"632499ef\",\"tools-vcs-gitlib.md\":\"39b34382\",\"tools-soft-nodepad.md\":\"3760c1d7\",\"tools-vcs-gogs.md\":\"13159221\",\"tools-soft-evernote.md\":\"83c52166\",\"tools-vcs.md\":\"9f934182\",\"tools-soft-calibre.md\":\"70835893\",\"devops-deploy-shell.md\":\"977c5588\",\"tools-dev-vscode.md\":\"560399f9\",\"devops-deploy-openresty.md\":\"316dd579\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"zh-CN\",\"dir\":\"ltr\",\"title\":\"Coder\",\"titleTemplate\":\"广度和深度\",\"description\":\"整理和记录代码学习的笔记\",\"base\":\"/\",\"head\":[],\"appearance\":\"dark\",\"themeConfig\":{\"logo\":\"./logo.jpg\",\"siteTitle\":\"Coder\",\"outline\":[2,3],\"outlineTitle\":\"目录\",\"search\":{\"provider\":\"local\"},\"darkModeSwitchLabel\":\"深浅模式\",\"sidebarMenuLabel\":\"菜单\",\"returnToTopLabel\":\"返回顶部\",\"lastUpdatedText\":\"上次更新\",\"docFooter\":{\"prev\":\"上一篇\",\"next\":\"下一篇\"},\"nav\":[{\"text\":\"♎语言\",\"items\":[{\"text\":\"1️⃣ Java\",\"link\":\"lang-java\"},{\"text\":\"2️⃣ Python\",\"link\":\"lang-python\"},{\"text\":\"3️⃣ Scala\",\"link\":\"lang-scala\"},{\"text\":\"4️⃣ Groovy\",\"link\":\"lang-groovy\"}]},{\"text\":\"☯️算法\",\"items\":[{\"text\":\"算法篇\",\"items\":[{\"text\":\"🚫代码规范\",\"link\":\"/#\"},{\"text\":\"🚫设计模式\",\"link\":\"/#\"},{\"text\":\"🚫数据结构\",\"link\":\"/#\"},{\"text\":\"🚫源码解读\",\"link\":\"/#\"}]},{\"text\":\"并发篇\",\"items\":[{\"text\":\"🚫JVM\",\"link\":\"/#\"},{\"text\":\"🚫并发编程\",\"link\":\"/#\"}]},{\"text\":\"设计篇\",\"items\":[{\"text\":\"🚫系统设计\",\"link\":\"/#\"},{\"text\":\"🚫数仓理论\",\"link\":\"/#\"}]},{\"text\":\"职业篇\",\"items\":[{\"text\":\"🚫方向导航\",\"link\":\"/#\"},{\"text\":\"🚫职业规划\",\"link\":\"/#\"},{\"text\":\"🚫面试准备\",\"link\":\"/#\"}]}]},{\"text\":\"♈前端\",\"items\":[{\"text\":\"🚫HTML\",\"link\":\"/#\"},{\"text\":\"🚫CSS\",\"link\":\"/#\"},{\"text\":\"🚫JavaScript\",\"link\":\"/#\"},{\"text\":\"🚫JQuery\",\"link\":\"/#\"},{\"text\":\"🚫NodeJS\",\"link\":\"/#\"},{\"text\":\"🚫Vue\",\"link\":\"/#\"},{\"text\":\"🚫React\",\"link\":\"/#\"},{\"text\":\"🚫小程序\",\"link\":\"/#\"}]},{\"text\":\"🔯微服务\",\"items\":[{\"text\":\"🚫RPC\",\"link\":\"/#\"},{\"text\":\"🚫Spring\",\"link\":\"/#\"},{\"text\":\"🚫Spring MVC\",\"link\":\"/#\"},{\"text\":\"🚫Spring Boot\",\"link\":\"/#\"},{\"text\":\"🚫Spring Cloud\",\"link\":\"/#\"},{\"text\":\"🚫Spring Cloud Alibaba\",\"link\":\"/#\"},{\"text\":\"🚫Service Mesh\",\"link\":\"/#\"}]},{\"text\":\"⚧️数据存储\",\"items\":[{\"text\":\"SQL数据库\",\"items\":[{\"text\":\"🚫MySQL\",\"link\":\"/#\"},{\"text\":\"🚫Oracle\",\"link\":\"/#\"}]},{\"text\":\"NoSQL数据库\",\"items\":[{\"text\":\"🚫Redis\",\"link\":\"/#\"},{\"text\":\"🚫MongoDB\",\"link\":\"/#\"}]},{\"text\":\"NewSQL数据库\",\"items\":[{\"text\":\"🚫TiDB\",\"link\":\"/#\"}]},{\"text\":\"ORM框架\",\"items\":[{\"text\":\"🚫Mybatis\",\"link\":\"/#\"},{\"text\":\"🚫Mybatis Plus\",\"link\":\"/#\"},{\"text\":\"🚫Spring Data JPA\",\"link\":\"/#\"}]},{\"text\":\"消息中间件\",\"items\":[{\"text\":\"🚫Active MQ\",\"link\":\"/#\"},{\"text\":\"🚫RabbitMQ\",\"link\":\"/#\"},{\"text\":\"🚫RocketMQ\",\"link\":\"/#\"},{\"text\":\"🚫Kafka\",\"link\":\"/#\"}]},{\"text\":\"文件存储\",\"items\":[{\"text\":\"🚫FastDFS\",\"link\":\"/#\"},{\"text\":\"🚫Ceph\",\"link\":\"/#\"},{\"text\":\"🚫HDFS\",\"link\":\"/#\"}]},{\"text\":\"搜索引擎\",\"items\":[{\"text\":\"🚫Lucene\",\"link\":\"/#\"},{\"text\":\"🚫Solr\",\"link\":\"/#\"},{\"text\":\"🚫ElasticSearch\",\"link\":\"/#\"}]}]},{\"text\":\"☸️DevOps\",\"items\":[{\"text\":\"部署\",\"items\":[{\"text\":\"Tomcat\",\"link\":\"devops-deploy-tomcat\"},{\"text\":\"🚫Linux\",\"link\":\"devops-deploy-tomcat\"},{\"text\":\"Shell\",\"link\":\"devops-deploy-shell\"},{\"text\":\"🚫Nginx\",\"link\":\"devops-deploy-tomcat\"},{\"text\":\"🚫Linux\",\"link\":\"devops-deploy-tomcat\"},{\"text\":\"🚫LVS+Keepalived\",\"link\":\"devops-deploy-tomcat\"},{\"text\":\"🚫OpenResty+Kong\",\"link\":\"devops-deploy-tomcat\"}]},{\"text\":\"容器\",\"items\":[{\"text\":\"🚫Docker\",\"link\":\"/#\"},{\"text\":\"🚫Kubernates\",\"link\":\"/#\"}]},{\"text\":\"云服务器\",\"items\":[{\"text\":\"🚫IaaS\",\"link\":\"/#\"},{\"text\":\"🚫UCloud\",\"link\":\"/#\"}]},{\"text\":\"持续集成\",\"items\":[{\"text\":\"🚫Jenkins\",\"link\":\"/#\"}]},{\"text\":\"监控工具\",\"items\":[{\"text\":\"🚫Arthas\",\"link\":\"/#\"},{\"text\":\"🚫Zabbix\",\"link\":\"/#\"}]},{\"text\":\"链路追踪\",\"items\":[{\"text\":\"🚫Sleuth+Zipkin\",\"link\":\"/#\"},{\"text\":\"🚫Skywalking\",\"link\":\"/#\"}]},{\"text\":\"性能压测\",\"items\":[{\"text\":\"🚫JMeter\",\"link\":\"/#\"},{\"text\":\"🚫全链路压测\",\"link\":\"/#\"}]}]},{\"text\":\"✝️工具\",\"items\":[{\"text\":\"软性办公工具\",\"link\":\"tools-soft\"},{\"text\":\"版本控制工具\",\"link\":\"tools-vcs\"},{\"text\":\"包管理工具\",\"link\":\"tools-dev\"},{\"text\":\"项目构建工具\",\"link\":\"tools-dev\"},{\"text\":\"编程工具\",\"link\":\"tools-dev\"},{\"text\":\"数据库管理\",\"link\":\"tools-dev\"},{\"text\":\"虚拟机工具\",\"link\":\"tools-dev\"},{\"text\":\"SSH工具\",\"link\":\"tools-dev\"},{\"text\":\"调试工具\",\"link\":\"tools-dev\"},{\"text\":\"压测工具\",\"link\":\"tools-dev\"}]}],\"sidebar\":{\"lang-java\":[{\"text\":\"01_Java\",\"collapsed\":false,\"base\":\"lang-java-\",\"items\":[{\"text\":\"基础语法\",\"link\":\"base.md\"},{\"text\":\"数组\",\"collapsed\":true,\"items\":[{\"text\":\"数组入门\",\"link\":\"02_数组.md\"},{\"text\":\"数组进阶\",\"link\":\"02_数组.md\"},{\"text\":\"数组高级\",\"link\":\"02_数组.md\"}]}]}],\"devops\":[{\"text\":\"部署\",\"collapsed\":true,\"base\":\"devops-deploy-\",\"items\":[{\"text\":\"Tomcat\",\"link\":\"tomcat.md\"},{\"text\":\"Shell\",\"link\":\"shell.md\"},{\"text\":\"LVS\",\"link\":\"lvs.md\"},{\"text\":\"Nginx\",\"link\":\"nginx.md\"},{\"text\":\"OpenResty\",\"link\":\"openresty.md\"},{\"text\":\"Evernote\",\"link\":\"evernote.md\"}]}],\"tools\":[{\"text\":\"软性办公\",\"collapsed\":true,\"base\":\"tools-soft-\",\"items\":[{\"text\":\"百度网盘\",\"link\":\"baidupan.md\"},{\"text\":\"福昕阅读器\",\"link\":\"foxit.md\"},{\"text\":\"Calibre\",\"link\":\"calibre.md\"},{\"text\":\"Chrome\",\"link\":\"chrome.md\"},{\"text\":\"Cmder\",\"link\":\"cmder.md\"},{\"text\":\"Evernote\",\"link\":\"evernote.md\"},{\"text\":\"Nodepad\",\"link\":\"nodepad.md\"},{\"text\":\"Office\",\"link\":\"office.md\"},{\"text\":\"PotPlayer\",\"link\":\"potplayer.md\"},{\"text\":\"Snipaste\",\"link\":\"snipaste.md\"},{\"text\":\"SublimeText\",\"link\":\"sublimetext.md\"},{\"text\":\"Typora\",\"link\":\"typora.md\"},{\"text\":\"科学上网\",\"link\":\"tizi.md\"},{\"text\":\"Xmind\",\"link\":\"xmind.md\"},{\"text\":\"7zip\",\"link\":\"7zip.md\"},{\"text\":\"Windows\",\"link\":\"windows.md\"},{\"text\":\"Markdown\",\"link\":\"markdown.md\"}]},{\"text\":\"版本管理\",\"collapsed\":true,\"base\":\"tools-vcs-\",\"items\":[{\"text\":\"Git\",\"collapsed\":true,\"items\":[{\"text\":\"Git\",\"link\":\"git.md\"},{\"text\":\"Gogs\",\"link\":\"gogs.md\"},{\"text\":\"Gitee\",\"link\":\"gitee.md\"},{\"text\":\"Github\",\"link\":\"github.md\"},{\"text\":\"GitLib\",\"link\":\"gitlib.md\"},{\"text\":\"GitFlow\",\"link\":\"gitflow.md\"}]},{\"text\":\"Svn\",\"link\":\"svn.md\"}]},{\"text\":\"包管理工具\",\"collapsed\":true,\"base\":\"tools-dev-\",\"items\":[{\"text\":\"NVM\",\"link\":\"nvm.md\"}]},{\"text\":\"项目构建\",\"collapsed\":true,\"base\":\"tools-dev-\",\"items\":[{\"text\":\"Maven\",\"link\":\"maven.md\"},{\"text\":\"Gradle\",\"link\":\"gradle.md\"}]},{\"text\":\"编程工具\",\"collapsed\":true,\"base\":\"tools-dev-\",\"items\":[{\"text\":\"IDEA\",\"link\":\"idea.md\"},{\"text\":\"VsCode\",\"link\":\"vscode.md\"},{\"text\":\"PyCharm\",\"link\":\"pycharm.md\"}]},{\"text\":\"数据库管理\",\"collapsed\":true,\"base\":\"tools-dev-\",\"items\":[{\"text\":\"Navicat\",\"link\":\"navicat.md\"}]},{\"text\":\"虚拟机工具\",\"collapsed\":true,\"base\":\"tools-dev-\",\"items\":[{\"text\":\"VMware\",\"link\":\"vmware.md\"}]},{\"text\":\"SSH工具\",\"collapsed\":true,\"base\":\"tools-dev-\",\"items\":[{\"text\":\"SSH工具\",\"link\":\"ssh.md\"}]},{\"text\":\"调试工具\",\"collapsed\":true,\"base\":\"tools-dev-\",\"items\":[{\"text\":\"Postman\",\"link\":\"postman.md\"}]},{\"text\":\"压测工具\",\"collapsed\":true,\"base\":\"tools-dev-\",\"items\":[{\"text\":\"JMeter\",\"link\":\"jmeter.md\"}]}]}},\"locales\":{},\"scrollOffset\":90,\"cleanUrls\":false}");</script>
</body>
</html>