-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
1543 lines (778 loc) · 69.8 KB
/
index.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
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html class="theme-next pisces use-motion" lang="zh-Hans">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />
<link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />
<link href="/css/main.css?v=5.1.0" rel="stylesheet" type="text/css" />
<meta name="keywords" content="Hexo, NexT" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.1.0" />
<meta name="description" content="这个站有大问题">
<meta property="og:type" content="website">
<meta property="og:title" content="个人小结">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="个人小结">
<meta property="og:description" content="这个站有大问题">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="个人小结">
<meta name="twitter:description" content="这个站有大问题">
<script type="text/javascript" id="hexo.configurations">
var NexT = window.NexT || {};
var CONFIG = {
root: '/',
scheme: 'Pisces',
sidebar: {"position":"left","display":"post"},
fancybox: true,
motion: true,
duoshuo: {
userId: '0',
author: '博主'
},
algolia: {
applicationID: '',
apiKey: '',
indexName: '',
hits: {"per_page":10},
labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
}
};
</script>
<link rel="canonical" href="http://yoursite.com/"/>
<title> 个人小结 </title>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<script type="text/javascript">
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?5e30a10c9f167b5bc8ca5671d204f450";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<div class="container one-collumn sidebar-position-left
page-home
">
<div class="headband"></div>
<header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-meta ">
<div class="custom-logo-site-title">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">个人小结</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<p class="site-subtitle"></p>
</div>
<div class="site-nav-toggle">
<button>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
</button>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home">
<a href="/" rel="section">
<i class="menu-item-icon fa fa-fw fa-home"></i> <br />
首页
</a>
</li>
<li class="menu-item menu-item-categories">
<a href="/categories" rel="section">
<i class="menu-item-icon fa fa-fw fa-th"></i> <br />
分类
</a>
</li>
<li class="menu-item menu-item-about">
<a href="/about" rel="section">
<i class="menu-item-icon fa fa-fw fa-user"></i> <br />
关于
</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives" rel="section">
<i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
归档
</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/tags" rel="section">
<i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
标签
</a>
</li>
<li class="menu-item menu-item-commonweal">
<a href="/404.html" rel="section">
<i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br />
公益404
</a>
</li>
</ul>
</nav>
</div>
</header>
<main id="main" class="main">
<div class="main-inner">
<div class="content-wrap">
<div id="content" class="content">
<section id="posts" class="posts-expand">
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/05/02/spring的数据库异常体系/">
<span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="lijiwen">
<meta itemprop="description" content="">
<meta itemprop="image" content="https://avatars0.githubusercontent.com/u/6695323?v=3&u=7b09dd4f5a7c1488ab8ff262a6981116ae758c89&s=400">
</span>
<span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="个人小结">
<span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
<img style="display:none;" itemprop="url image" alt="个人小结" src="">
</span>
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/05/02/spring的数据库异常体系/" itemprop="url">
spring的数据库异常体系
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="Post created" itemprop="dateCreated datePublished" datetime="2017-05-02T23:05:57+08:00">
2017-05-02
</time>
</span>
<span class="post-category" >
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/Spring/" itemprop="url" rel="index">
<span itemprop="name">Spring</span>
</a>
</span>
</span>
<span class="post-comments-count">
<span class="post-meta-divider">|</span>
<a href="/2017/05/02/spring的数据库异常体系/#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="2017/05/02/spring的数据库异常体系/" itemprop="commentCount"></span>
</a>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>最近工作中要对spring的数据库异常做处理,自己在不了解异常层次结构的情况下写了一个判断类,妥妥的被<code>leader</code>批了,自己就打开<code>spring</code>代码研究一下异常层次结构,画了一下UML图,希望可以学习的同时帮助到大家。</p>
<h1 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h1><p><img src="springException.png" alt="spring异常层次图"></p>
<p>上图中可以看出,DataAccessException是Spring的一个基础类,其他的异常都是基于此进行扩展和延伸的。</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>多看源码,多学习,多虚心请教。</p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/04/15/OAuth2/">
<span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="lijiwen">
<meta itemprop="description" content="">
<meta itemprop="image" content="https://avatars0.githubusercontent.com/u/6695323?v=3&u=7b09dd4f5a7c1488ab8ff262a6981116ae758c89&s=400">
</span>
<span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="个人小结">
<span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
<img style="display:none;" itemprop="url image" alt="个人小结" src="">
</span>
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/04/15/OAuth2/" itemprop="url">
OAuth文档(2)——客户端注册
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="Post created" itemprop="dateCreated datePublished" datetime="2017-04-15T23:01:13+08:00">
2017-04-15
</time>
</span>
<span class="post-category" >
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/OAuth/" itemprop="url" rel="index">
<span itemprop="name">OAuth</span>
</a>
</span>
</span>
<span class="post-comments-count">
<span class="post-meta-divider">|</span>
<a href="/2017/04/15/OAuth2/#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="2017/04/15/OAuth2/" itemprop="commentCount"></span>
</a>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>这是OAuth2.0系列文档的第二章,关于OAuth系列会将官方的文档都翻译完毕,希望在自己学习的同时可以帮助有需要的同学。</p>
<h1 id="2-客户端注册"><a href="#2-客户端注册" class="headerlink" title="2.客户端注册"></a>2.客户端注册</h1><p>在启动协议之前,客户端需要注册到授权服务器。客户端注册到授权服务器的方式是超出本规范的范围的,但是涉及到终端用户和HTML注册表单的交互。</p>
<p>客户端注册不需要客户端和授权服务器之间直接交互,只要授权服务器支持,注册就可以依赖别的方式来建立可信和获取需要的客户端属性(例如,重定向URL,客户端类型)。例如,注册可以使用自分发或者第三方分发的断言来完成注册,或者通过授权服务器使用可信通道来执行客户端发现。</p>
<p>当注册一个客户端时,客户端开发者应该:</p>
<ul>
<li><p>指定客户端类型,就像第2.1章节中描述的一样。</p>
</li>
<li><p>提供客户端的重定向URL</p>
</li>
<li><p>包含其他授权服务器需要的信息(例如,程序名称,网站,描述,logo图片,接受合法条款)</p>
</li>
</ul>
<h2 id="2-1客户端类型"><a href="#2-1客户端类型" class="headerlink" title="2.1客户端类型"></a>2.1客户端类型</h2><p>OAuth定义了两种客户端类型,这种定义是建立在他们与授权服务器安全的进行身份认证的能力的基础上的(例如,保存客户端认证凭据机密性的能力)。</p>
<ul>
<li>机密的</li>
</ul>
<p>客户端能够保持他们认证凭据的机密性(例如,客户端建立在安全服务器上,安全服务器会限制对他们的认证凭据的访问),或者能够使用其他方式进行安全的客户端身份认证。</p>
<ul>
<li>公开的</li>
</ul>
<p>客户端不能够保持他们的认证凭据的机密性(例如,客户端在用户使用的设备上运行,例如:一个安装的本地应用或者一个基于浏览器的应用),并且不能使用其他任何方式来进行安全的客户端安全地身份认证。</p>
<p>客户端类型的设计是根据授权服务器对于安全身份认证的定义和它可以接受的客户端认证凭据的暴露等级来决定的。授权服务器不应该猜测客户端类型。</p>
<p>一个客户端可能分布在一个分布式的组件上,所有的客户端类型不都一样,如果授权服务器没有对这种客户端的支持,或者没有提供关于注册的指导,客户端应该分别注册每个组件作为一个单独的客户端。</p>
<p>该规范围绕以下客户端配置来设计:</p>
<ul>
<li>WEB应用</li>
</ul>
<p>一个WEB应用是运行在web服务器上的机密的客户端。资源拥有者通过使用自己设备的浏览器来访问客户端。客户端认证凭据和分发给客户端的访问令牌都存储在web服务器上,并且不会被资源拥有者接触到。</p>
<ul>
<li>基于用户代理的应用</li>
</ul>
<p>一个基于用户代理的应用是公开的客户端,客户端代码会从web服务器上下载下来,并且在用户设备上的代理(例如,浏览器)中运行。协议数据和用户认证凭据会被用户轻松获取到。因为这样的应用驻留在用户代理中,他们可以在进行请求授权的时候,完美利用用户代理的能力。</p>
<ul>
<li>本地应用</li>
</ul>
<p>本地应用是公开的客户端,他们安装并且运行在用户持有的设备上。协议数据和认证凭据可以被用户得到。假设认为程序中的客户端认证凭据都可以被提取出来。另一方面,动态分发的凭据例如访问令牌或者更新令牌可以接收一个可以接收级别的保护。最低限度,这些凭据可以被保护不受与之交互的敌对服务器的侵袭。在一些平台,这些凭据可能被保护不受在同一设备的其他应用的侵袭。</p>
<h2 id="2-2-客户端身份标识"><a href="#2-2-客户端身份标识" class="headerlink" title="2.2 客户端身份标识"></a>2.2 客户端身份标识</h2><p>授权服务器分发给注册的客户端一个身份标识——一个代表客户端注册信息的唯一的字符串。客户端身份标识不是保密的;这是暴露给资源拥有者的,并且一定不能单独用来客户端认证。对于授权服务器而言,客户端用户标识是唯一的。</p>
<p>客户端身份标识字符串长度在该规范中尚未定义。客户端应该避免对身份标识的长度做出假设。授权服务器应该记录任何它分发的标识的长度。</p>
<h2 id="2-3客户端认证"><a href="#2-3客户端认证" class="headerlink" title="2.3客户端认证"></a>2.3客户端认证</h2><p>如果客户端类型是机密类型,客户端和授权服务器建立一个满足授权服务器安全需求的客户端认证方案。授权服务器可能接受任何形式的客户端认证来满足其安全需求。</p>
<p>机密型客户端通常会被分发一系列的用于向授权服务器进行验证的客户端凭据(例如,密码,公/私钥对)。</p>
<p>授权服务器可能会建立一个和公开型客户端进行客户端认证的方法。但是授权服务器必须不能依赖公开型客户端认证来识别客户端。</p>
<p>客户端一定不能在一次请求中使用多种认证方案。</p>
<h3 id="2-3-1客户端密码"><a href="#2-3-1客户端密码" class="headerlink" title="2.3.1客户端密码"></a>2.3.1客户端密码</h3><p>拥有一个客户端密码的客户端可能会使用HTTP Basic认证模式来进行身份认证,详细参见<a href="https://tools.ietf.org/html/rfc2617" target="_blank" rel="external">RFC2617</a>。客户端身份标识使用<code>application/x-www-form-urlencoded</code>按照<a href="https://tools.ietf.org/html/rfc6749#appendix-B" target="_blank" rel="external">附录B</a>的编码算法进行编码,并且编码后的值用来作为用户名;客户端密码使用同样的算法进行编码,并且编码后作为密码。授权服务器必须支持HTTP Basic认证模式,用来对被分发密码的客户端进行认证。</p>
<p>举例如下:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3</div></pre></td></tr></table></figure>
<p>另外,授权服务器可能支持使用以下参数在请求体内包含客户端认证凭据:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">client_id</div></pre></td></tr></table></figure>
<p>必须。在注册过程中分发给客户端的客户端身份标识</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">client_secret</div></pre></td></tr></table></figure>
<p>必须,客户端密码。如果客户端面是一个空值的话,客户端可能省略该参数。</p>
<p>使用两个参数将客户端凭据封装到请求体中是不被推荐使用,并且应该限制客户端直接使用HTTP Basic认证模式(或者其他的基于密码的HTTP认证模式)。参数可以智能通过请求体进行传输,并且一定不可以放在URL中。</p>
<p>例如,一个使用请求体来请求更新访问令牌的请求:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">POST /token HTTP/1.1</div><div class="line">Host: server.example.com</div><div class="line">Content-Type: application/x-www-form-urlencoded</div><div class="line"></div><div class="line">grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA</div><div class="line">&client_id=s6BhdRkqt3&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw</div></pre></td></tr></table></figure>
<p>授权服务器在使用密码认证发送请求的时候必须需要使用TLS协议。</p>
<p>因为这个客户端认证方法涉及到一个密码,授权服务器必须保护任何终端使用它免受暴力攻击。</p>
<h3 id="2-3-2其他认证方法"><a href="#2-3-2其他认证方法" class="headerlink" title="2.3.2其他认证方法"></a>2.3.2其他认证方法</h3><p>认证服务器可能支持任何符合其安全需求的HTTP认证模式。当使用其他认证方法时,授权服务器必须定义一个客户端身份标识符和认证模式之间的映射。</p>
<h2 id="2-4未注册的客户端"><a href="#2-4未注册的客户端" class="headerlink" title="2.4未注册的客户端"></a>2.4未注册的客户端</h2><p>该规范没有包含对没注册客户端的使用。但是,对于这种客户端的时候超出了该规范的范围,并且需要额外的安全分析审视交互带来的影响。</p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/04/14/OAuth2-0-1/">
<span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="lijiwen">
<meta itemprop="description" content="">
<meta itemprop="image" content="https://avatars0.githubusercontent.com/u/6695323?v=3&u=7b09dd4f5a7c1488ab8ff262a6981116ae758c89&s=400">
</span>
<span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="个人小结">
<span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
<img style="display:none;" itemprop="url image" alt="个人小结" src="">
</span>
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/04/14/OAuth2-0-1/" itemprop="url">
OAuth2.0文档(1)——介绍
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="Post created" itemprop="dateCreated datePublished" datetime="2017-04-14T20:55:24+08:00">
2017-04-14
</time>
</span>
<span class="post-category" >
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/OAuth/" itemprop="url" rel="index">
<span itemprop="name">OAuth</span>
</a>
</span>
</span>
<span class="post-comments-count">
<span class="post-meta-divider">|</span>
<a href="/2017/04/14/OAuth2-0-1/#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="2017/04/14/OAuth2-0-1/" itemprop="commentCount"></span>
</a>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="写在前面"><a href="#写在前面" class="headerlink" title="写在前面"></a>写在前面</h1><blockquote>
<p>这是关于OAuth2.0对应文档的翻译,我会将OAuth2.0的文档在这一系列的博客中都翻译出来,希望自己学习的同时也可以给关注这方面知识的同学一些帮助。</p>
</blockquote>
<h1 id="1-介绍"><a href="#1-介绍" class="headerlink" title="1.介绍"></a>1.介绍</h1><p>在传统的客户端服务端认证模型中,客户端通过资源拥有者的可信信息来请求一个服务端受保护的资源。为了给第三方程序提供权限访问受限制的资源,资源拥有者会将自己的证书(最常见的就是用户名和密码信息)给第三方程序。这样的做法会带来一些问题和限制:</p>
<ul>
<li><p>第三方程序为了以后多次访问受限制的资源,需要存储用户的用户名密码信息。</p>
</li>
<li><p>尽管安全漏洞存在于密码中,服务端依然需要支持密码认证。</p>
</li>
<li><p>第三方程序获得了对保护资源的访问权限,使得资源拥有者无法对有限的资源子集的持续时间和访问进行限制。</p>
</li>
<li><p>资源拥有者如果不撤销所有的第三方程序的权限,就没办法撤销某一个第三方程序的访问权限,而且撤销权限的唯一做法就是更换密码。</p>
</li>
<li><p>任何第三方程序的导致损害将导致最终用户密码的损害以及所有使用该密码保护的数据也收到侵害。</p>
</li>
</ul>
<p>OAuth通过引入授权层和将客户端角色和资源拥有者分开来解决上述问题。在OAuth中,客户端请求获取用户在服务端的资源时,被分发了一系列的认证信息(不是用户的密码)。</p>
<p>不再使用用户的密码去访问受保护的资源,客户端取得了访问令牌(<code>access token</code>),访问令牌是一个制定了范围、生命周期以及其它访问属性的字符串。访问令牌是通过用户同意之后,由认证服务器分发给第三方程序的。客户端使用访问令牌去访问位于资源服务器的保护资源。</p>
<p>例如,一个用户可以授权打印服务(客户端)一个访问存储在资源服务器上的照片的权限,这个授权是不需要将自己的用户名和密码告诉打印服务的。相反的是,用户通过被照片存储服务信任的服务器直接进行认证,该服务器直接分发给客户端访问令牌。</p>
<p>这一规范使用HTTP被设计出来供大家使用,在使用OAuth使用过程中,如果不是使用HTTP协议都是超出范围的。</p>
<p>OAuth1.0协议(作为一个文档被发布出来)是小规模社区努力的结果。本标准规范建立在OAuth1.0的部署经验和更大的IETF社区提供的附加用例和扩展性需求之上。OAuth2.0协议不向后兼容OAuth1.0协议。这两个版本可能会同时存在网络上,OAuth实现可能会同时支持两个版本。但是,这个强调的意图是新的OAuth的实现要像文档强调的一样支持,OAuth1.0协议只需支持现有的部署。OAuth2.0协议的实现和OAuth1.0的实现基本没有相同的部分,新的实现必须按照文档而不是凭借对OAUth1.0的猜测。</p>
<h2 id="1-1角色"><a href="#1-1角色" class="headerlink" title="1.1角色"></a>1.1角色</h2><p>OAuth定义了四个角色:</p>
<ul>
<li><p><code>resource owner(资源拥有者,也就是用户)</code></p>
<p> 一个可以授权访问保护资源的实体,当资源拥有者是一个人的话,也就是指最终用户。</p>
</li>
<li><p><code>resource server(资源服务器)</code></p>
<p> 这个服务器存储着受保护的资源,可以使用访问令牌接受和回应对保护资源的请求。</p>
</li>
<li><p><code>client(客户端,也就是第三方程序)</code></p>
<p> 一个代表用户和使用其授权信息来请求受保护资源的程序,”client”并不实现任何的特性(无论程序是在服务器、桌面还是设备上运行)</p>
</li>
<li><p><code>authorization server(授权服务器)</code></p>
<p> 该服务器在成功认证资源拥有者和获取授权信息后会分发访问令牌给客户端。</p>
</li>
</ul>
<p>授权服务器和资源服务器之间的活动已经超越了本规范的范围。授权服务器可能和资源服务器是一台服务器,也可能是分离的。一个授权服务器可以分发多个资源服务器认可的访问令牌。</p>
<h2 id="1-2协议流"><a href="#1-2协议流" class="headerlink" title="1.2协议流"></a>1.2协议流</h2><p><img src="1.PNG" alt="协议流图片"></p>
<p>如上图所示的OAuth2.0的协议流描述了四个角色之间的活动,包括以下几个步骤:</p>
<ul>
<li><p>(A)用户打开客户端以后,客户端要求用户给予授权。</p>
</li>
<li><p>(B)客户端收到授权准许(这是代表资源拥有者授权的证明,一般来讲就是一个授权码),一般来讲是该规范定义的四种授权类型之一或者扩展的授权类型。授权类型取决于客户端使用请求授权的方法和授权服务器支持的类型。</p>
</li>
<li><p>(C)客户端通过与授权服务器认证和呈送授权准许来请求一个访问令牌。</p>
</li>
<li><p>(D)授权服务器认证客户端和验证授权准许,如果是合法的,将会分发一个访问令牌。</p>
</li>
<li><p>(E)客户端请求位于资源服务器上的保护资源,并且通过访问令牌进行认证。</p>
</li>
<li><p>(F)资源服务器验证访问令牌,如果合法,就会相应其请求。</p>
</li>
</ul>
<p>对于客户端而言,从用户获取授权最好的方法是使用授权服务器作为中介,就像第4.1章中所描述的那样。</p>
<h2 id="1-3授权准许"><a href="#1-3授权准许" class="headerlink" title="1.3授权准许"></a>1.3授权准许</h2><p>一个授权准许就是一个代表用户授权的证明(访问其保护资源的权限),客户端用来获取访问令牌。该规范定义了四种授权类型——授权码、<code>implicit</code>、用户密码证书、客户端证书,当然还存在扩展机制来定义附加的类型。</p>
<h3 id="1-3-1授权码"><a href="#1-3-1授权码" class="headerlink" title="1.3.1授权码"></a>1.3.1授权码</h3><p>授权码是通过使用授权服务器作为客户端和用户之间的中介来获取的。而不是直接从用户请求授权,客户端指导用户转向授权服务器(一般就是浏览器),在进行授权之后会将用户引导回客户端,并且带着授权码。</p>
<p>在将带着授权码的用户引导回客户端之前,授权服务器认证并取得用户的授权。因为用户和授权服务器进行了认证,用户的密码从来不会被客户端所得到的。</p>
<p>授权码带来了一些比较重要的好处,例如客户端认证的能力,访问令牌的安全传输(不用通过用户的浏览器传输,并且不会将它暴露给其他人包括用户)。</p>
<h3 id="1-3-2-Implicit"><a href="#1-3-2-Implicit" class="headerlink" title="1.3.2 Implicit"></a>1.3.2 Implicit</h3><p>隐式授权是一个简化的授权码流,对于使用JavaScript等脚本语言实现的客户端进行了优化。在隐式流中,不用分发给客户端一个授权码,客户端直接会被直接分发给一个访问令牌(就像用户授权的结果一样)。授权类型是隐式的,没有任何的中间的证书会被分发给客户端(例如授权码,直接使用访问令牌)。</p>
<p>当在隐式授权流中分发访问令牌的时候,授权服务器没有认证客户端。在一些情况下,客户端身份可以通过跳转URL(回调URL,也就是携带访问令牌返回客户端的URL)来进行验证。访问令牌可能会暴露给用户或者其他可以访问用户浏览器的程序。</p>
<p>隐式授权提高了一些客户端的响应性和效率(例如一个基于浏览器的客户端,WEBSITE),因为它减少了需要获取访问令牌的往返次数。但是,这种便捷性应该权衡使用隐式授权的安全性实现,例如就像接下来10.3和10.16中所描述的一样,尤其是可以使用授权码的时候。</p>
<h3 id="1-3-3-资源拥有者密码证书"><a href="#1-3-3-资源拥有者密码证书" class="headerlink" title="1.3.3 资源拥有者密码证书"></a>1.3.3 资源拥有者密码证书</h3><p>资源拥有者的密码证书(例如,用户名和密码)可以直接作为授权准许使用来获取访问令牌,只有当资源拥有者和客户端高度可信的时候(例如,客户端是设备操作系统的一部分或者高特权程序)并且其他授权类型不可用的时候才会被使用。</p>
<p>尽管这种授权类型需要客户端直接访问用户的证书,用户证书用来一次请求交换访问令牌。这种授权类型可以通过获取一个长时间有效的访问令牌或者更新令牌来消除客户端存储用户证书将来使用的必要。</p>
<h3 id="1-3-4客户端证书"><a href="#1-3-4客户端证书" class="headerlink" title="1.3.4客户端证书"></a>1.3.4客户端证书</h3><p>当授权范围限制在客户端控制下的受保护资源时,或者是之前部署到授权服务器的保护资源,客户端证书(或者其他形式的客户端认证信息)可以用来作为一种授权类型。客户端同时也是资源拥有者的时候,客户端证书可以作为授权准许。</p>
<h2 id="1-4访问令牌Access-Token"><a href="#1-4访问令牌Access-Token" class="headerlink" title="1.4访问令牌Access Token"></a>1.4访问令牌<code>Access Token</code></h2><p>访问令牌是用来访问受保护资源的证书,一个访问令牌就是一个代表分发给客户端授权信息的字符串。这个字符串通常对客户端是不透明的。令牌代表特定的访问范围和访问时间,由用户授权所得,并且由资源服务器和授权服务器执行。</p>
<p>令牌可能表示一个用来表示检索信息的标识符,或者可以以可验证的方式包含授权信息(例如,一个令牌字符串包含一些数据和一个签名)。超出本规范的额外认证信息可能需要客户端使用令牌。</p>
<p>访问令牌提供了一个抽象层,使用一个可以被资源服务器理解的令牌来代替不同的授权结构(例如,用户名和密码)。这种抽象使得分发访问令牌比用来获取令牌的准许更加具有限制性,与此同时资源服务器也不必了解一系列的认证方法。</p>
<p>访问令牌可以有不同的形式、结构、使用方法(例如,加解密属性,这个以资源服务器的安全性需要为基础)。访问令牌属性和用来访问受保护资源的方法是不在本规范的范围之内的。</p>
<h2 id="1-5更新令牌Refresh-Token"><a href="#1-5更新令牌Refresh-Token" class="headerlink" title="1.5更新令牌Refresh Token"></a>1.5更新令牌<code>Refresh Token</code></h2><p>更新令牌是用来获取访问令牌的认证信息,更新令牌由授权服务器分发给客户端,用来当现有的访问令牌失效或者过期的时候获取一个新的访问令牌,或者去获取一个具有相同范围或者更小范围的额外的访问令牌(和用户相比,访问令牌可能有更短或者更小的权限)。分发更新令牌在授权服务器上是可选的。如果授权服务器分发了一个更新令牌,它会包含在分发访问令牌的同时(例如图一中的D步骤)。</p>
<p>一个更新令牌是一个代表用户给客户端授权的字符串,这个字符串对于客户端也是不透明的。更新令牌表示一个用来检索授权信息的标识符。不像访问令牌一样,更新令牌是只用来在和授权服务器之间使用,并且从来不会发送给资源服务器。</p>
<p><img src="2.PNG" alt="协议流图片"></p>
<p>图2的流程图中包含了一下几个步骤:</p>
<ul>
<li><p>(A)客户端通过和授权服务器进行认证并传递给它一个授权准许(授权码)来请求一个访问令牌</p>
</li>
<li><p>(B)授权服务器认证客户端,同时验证授权准许(授权码),如果是合法的,就会分发一个访问令牌和一个更新令牌。</p>
</li>
<li><p>(C)客户端向资源服务器请求访问保护资源,同时提供一个访问令牌。</p>
</li>
<li><p>(D)资源服务器验证访问令牌,如果合法,资源服务器就会响应请求</p>
</li>
<li><p>(E)步骤C和步骤D重复执行直到访问令牌过期。如果客户端知道访问令牌过期,将会跳转到步骤G; 否则将会请求别的保护资源</p>
</li>
<li><p>(F)因为访问令牌是非法的,资源服务器返回一个非法令牌错误。</p>
</li>
<li><p>(G)客户端通过提供更新令牌请求一个新的访问密钥。客户端认证需求是以客户端类型和授权服务器政策为基础的。</p>
</li>
<li><p>(H)授权服务器认证客户端,并且验证更新令牌的合法性,如果合法,就会分发一个新的访问令牌(同时,可以选择是否返回一个新的更新令牌)</p>
</li>
</ul>
<p>步骤C、D、E和F是不在本规范的范围之内的,参见第七章。</p>
<h2 id="1-6-TLS版本"><a href="#1-6-TLS版本" class="headerlink" title="1.6 TLS版本"></a>1.6 TLS版本</h2><p>每当TLS在本规范中使用的时候,合适的版本总会过一段时间发生变化,在该文档编写的时候,TLS1.2是最新的版本,但是部署非常有限,而且在实现中基本看不到该版本。TLS1.0是最广泛部署的版本,而且提供最广泛的互操作性。</p>
<p>OAuth的实现可能支持额外的传输层安全机制,从而满足安全需求。</p>
<h2 id="1-7-HTTP重定向"><a href="#1-7-HTTP重定向" class="headerlink" title="1.7 HTTP重定向"></a>1.7 HTTP重定向</h2><p>该规范广泛使用HTTP重定向,在该规范中,客户端或者授权服务器指导用户的浏览器指向另一个地址。该规范中的例子展示了HTTP状态码302的使用,但是其它的任何可以完成重定向的方法都是被允许的,并且被认为是实现的细节。</p>
<h2 id="1-8-互用性Interoperability"><a href="#1-8-互用性Interoperability" class="headerlink" title="1.8 互用性Interoperability"></a>1.8 互用性<code>Interoperability</code></h2><p>OAuth2.0提供了一个丰富的授权框架,并且具有定义良好的安全属性。但是,作为一个有许多可选组件的丰富且高度可扩展的框架,它本身就可能产生广泛的非互操作实现。</p>
<p>除此之外,该规范留下来一些部分定义或者完全未定义的几个必需组件(例如,客户端注册,授权服务器能力,终端发现)。</p>
<p>没有这些组件,客户端必须手动并助啊们针对特定的授权服务器和资源服务器进行配置,以便进行互操作。</p>
<p>这个框架的设计很明确地表明,未来的工作将定义完成网络规模互操作性所必需的规范性配置文件和扩展。</p>
<h2 id="1-9符号约定"><a href="#1-9符号约定" class="headerlink" title="1.9符号约定"></a>1.9符号约定</h2><p>本规范中的关键字”MUST”,”MUST NOT”,”REQUIRED”,”SHALL”,”SHALL NOT”,”SHOULD”,”SHOULD NOT”,”RECOMMENDED”,”MAY”,”OPTIONAL”的解释参见<a href="https://tools.ietf.org/html/rfc2119" target="_blank" rel="external">RFC2119</a>。</p>
<p>某些安全相关的术语应该参见<a href="https://tools.ietf.org/html/rfc4949" target="_blank" rel="external">RFC4949</a>,这些术语包括但是不限于以下几种:”攻击(ATTCAK)”,”认证(authentication)”,”授权(authorization)”,”证书(certificate)”,”机密性(confidentiality)”,”凭据(credential)”,”加密(encryption)”,”身份(identity)”,”签名(sign)”,”签名(signature)”,”可信(trust)”,”验证(validate)”以及”验证(verify)”.</p>
<p>除非另有说明,所有的协议的参数名称和值都是大小写敏感的。</p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<link itemprop="mainEntityOfPage" href="http://yoursite.com/2017/04/06/log4j源码解析1/">
<span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="lijiwen">
<meta itemprop="description" content="">
<meta itemprop="image" content="https://avatars0.githubusercontent.com/u/6695323?v=3&u=7b09dd4f5a7c1488ab8ff262a6981116ae758c89&s=400">
</span>
<span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="个人小结">
<span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
<img style="display:none;" itemprop="url image" alt="个人小结" src="">
</span>
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/04/06/log4j源码解析1/" itemprop="url">
log4j体系结构
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="Post created" itemprop="dateCreated datePublished" datetime="2017-04-06T21:21:36+08:00">
2017-04-06
</time>
</span>
<span class="post-category" >
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/java/" itemprop="url" rel="index">
<span itemprop="name">java</span>
</a>
</span>
</span>
<span class="post-comments-count">
<span class="post-meta-divider">|</span>
<a href="/2017/04/06/log4j源码解析1/#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="2017/04/06/log4j源码解析1/" itemprop="commentCount"></span>
</a>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="写在前面"><a href="#写在前面" class="headerlink" title="写在前面"></a>写在前面</h2><p>最近在工作中需要对log4j进行改造,于是对log4j的内部实现进行了研究,这一系列的文章会对log4j从源码的角度进行深入的剖析。</p>
<h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>使用log4j进行获取Logger实例的时候,一般采用如下的语句进行获取,本文就会对该条语句执行的逻辑进行详细的阐述。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Logger LOGGER = Logger.getLogger(<span class="string">"x.y.z"</span>)</div></pre></td></tr></table></figure>
<p>这条语句执行的时序图如下图所示<br> <img src="/img/log4j1/getLogger.jpg" alt="log4j主要类的uml图"></p>
<p>下面首先对时序图中出现的三个<code>Object</code>进行解释 </p>
<ul>
<li><p><code>Logger</code></p>
<p> <code>Logger</code>是暴露给用户的一个类,主要是进行Logger组件的创建、日志的打印(<code>Logger.info</code>、<code>Logger.error</code>等方法),Logger继承了<code>Category</code>这个类,这个类是完成了Logger的大部分逻辑,<code>Logger</code>和<code>Category</code>类的关系以及本文涉及到的其它类的UML图如下图所示。</p>
</li>
</ul>
<p><img src="/img/log4j1/log4j2.png" alt="uml图"></p>
<p>根据上图可以很清晰的看出<code>Logger</code>继承了<code>Category</code>,<code>Category</code>实现了<code>AppenderAttachable</code>接口,并且拥有依赖<code>LoggerRepository(下面我们要说的Hierarchy就是该接口的实现)</code>。</p>
<ul>
<li><p><code>LoggerManager</code></p>
<p> <code>LoggerManager</code>顾名思义就是<code>Logger</code>的管理者,负责<code>Logger</code>的获取和存储。从上图我们可以看出:<code>LoggerManager</code>中包含一个<code>RepositorySelector</code>,该类就是负责管理<code>LoggerRepository</code>的,<code>LoggerRepository</code>也就是真正<code>Logger</code>的管理容器(主要负责配置文件中解析出来的Logger的存储以及根据LoggerName从其中获取Logger),其具体实现在上图中为<code>Hierarchy</code>,下面具体介绍该类。</p>
</li>
<li><p><code>Hierarchy</code></p>
<p> <code>Hierarchy</code>是<code>LoggerRepository</code>的具体实现,是负责<code>Logger</code>存储的真正的类,<code>Hierarchy</code>中实例化了一个<code>Hashtable</code>进行存储<code>Logger</code>,其中<code>key</code>就是根<code>LoggerName</code>生成的<code>key</code>。</p>
</li>
</ul>
<p>其中<code>LoggerRepository</code>是真正的<code>Logger</code>的管理器,<code>Hierarchy</code>是其具体实现,使用<code>Hashtable</code>存放<code>Logger</code>,每个<code>LoggerManager</code>包含一个容器选择器<code>LoggerRepositorySelector</code>负责管理日志容器。</p>
<h2 id="详细介绍"><a href="#详细介绍" class="headerlink" title="详细介绍"></a>详细介绍</h2><p>通过上述对日志实例获取流程的描述,我们可以清晰的看出来,很关键的一步是<code>LoggerManager</code>中的静态块对配置文件的解析,然后将解析的结果填充到<code>Hierarchy</code>中供用户进行获取<code>Logger</code>实例,下面我们具体来看看关于配置文件的解析流程。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div></pre></td><td class="code"><pre><div class="line"></div><div class="line">//第一步首先实例化日志实例容器,并且设置 rootLogger</div><div class="line">Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));</div><div class="line">//使用Hierarchy设置LoggerManager的容器选择器</div><div class="line">repositorySelector = new DefaultRepositorySelector(h);</div><div class="line">String override = OptionConverter.getSystemProperty(<span class="string">"log4j.defaultInitOverride"</span>, (String)null);</div><div class="line">//下面是对配置文件的查找</div><div class="line"><span class="keyword">if</span>(override != null && !<span class="string">"false"</span>.equalsIgnoreCase(override)) {</div><div class="line"> LogLog.debug(<span class="string">"Default initialization of overridden by log4j.defaultInitOverrideproperty."</span>);</div><div class="line">} <span class="keyword">else</span> {</div><div class="line"> //系统属性<span class="built_in">log</span>4j.configuration可以用来指定配置文件</div><div class="line"> String configurationOptionStr = OptionConverter.getSystemProperty(<span class="string">"log4j.configuration"</span>, (String)null);</div><div class="line"> //系统属性<span class="built_in">log</span>4j.configuratorClass可以指定配置文件解析器</div><div class="line"> String configuratorClassName = OptionConverter.getSystemProperty(<span class="string">"log4j.configuratorClass"</span>, (String)null);</div><div class="line"> URL url = null;</div><div class="line"> //如果没有设置指定的配置文件</div><div class="line"> <span class="keyword">if</span>(configurationOptionStr == null) {</div><div class="line"> //系统优先去判断有没有xml配置文件</div><div class="line"> url = Loader.getResource(<span class="string">"log4j.xml"</span>);</div><div class="line"> <span class="keyword">if</span>(url == null) {</div><div class="line"> //xml配置文件没有去判断properties文件</div><div class="line"> url = Loader.getResource(<span class="string">"log4j.properties"</span>);</div><div class="line"> }</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> //如果指定了配置文件</div><div class="line"> try {</div><div class="line"> url = new URL(configurationOptionStr);</div><div class="line"> } catch (MalformedURLException var7) {</div><div class="line"> url = Loader.getResource(configurationOptionStr);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> //url如果不是空开始进行解析</div><div class="line"> <span class="keyword">if</span>(url != null) {</div><div class="line"> LogLog.debug(<span class="string">"Using URL ["</span> + url + <span class="string">"] for automatic log4j configuration."</span>);</div><div class="line"> try {</div><div class="line"> //这个是解析的关键一步,其中url指向配置文件,configuratorClassName代表配置文件解析器类,第三个参数就是第一行实例化的Herarchy</div><div class="line"> OptionConverter.selectAndConfigure(url, configuratorClassName, getLoggerRepository());</div><div class="line"> } catch (NoClassDefFoundError var6) {</div><div class="line"> LogLog.warn(<span class="string">"Error during default initialization"</span>, var6);</div><div class="line"> }</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> LogLog.debug(<span class="string">"Could not find resource: ["</span> + configurationOptionStr + <span class="string">"]."</span>);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure>
<p>下面我们针对上面代码段中出现的<code>OptionConverter.selectAndConfigure</code>进行详细的解析,该函数主要是确定配置文件解析类用的。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"></div><div class="line">public static void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {</div><div class="line"> Object configurator = null;</div><div class="line"> String filename = url.getFile();</div><div class="line"> //如果系统没有设置解析器并且文件不为空并且文件类型为xml,我们使用DOMConfigurator来解析xml文件</div><div class="line"> <span class="keyword">if</span>(clazz == null && filename != null && filename.endsWith(<span class="string">".xml"</span>)) {</div><div class="line"> clazz = <span class="string">"org.apache.log4j.xml.DOMConfigurator"</span>;</div><div class="line"> }</div><div class="line"> //如果经历了上述逻辑,配置文件解析器已经不为空了,那么开始利用反射实例化解析器</div><div class="line"> <span class="keyword">if</span>(clazz != null) {</div><div class="line"> LogLog.debug(<span class="string">"Preferred configurator class: "</span> + clazz);</div><div class="line"> configurator = (Configurator)instantiateByClassName(clazz, Configurator.class, (Object)null);</div><div class="line"> <span class="keyword">if</span>(configurator == null) {</div><div class="line"> LogLog.error(<span class="string">"Could not instantiate configurator ["</span> + clazz + <span class="string">"]."</span>);</div><div class="line"> <span class="built_in">return</span>;</div><div class="line"> }</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> //如果配置解析器为空,那么很明显系统没有设置解析器,并且配置文件也不是xml文件,很明显配置文件是property文件,那么我们使用PropertyConfigurator进行解析</div><div class="line"> configurator = new PropertyConfigurator();</div><div class="line"> }</div><div class="line"></div><div class="line"> //使用已经获得的配置解析器进行配置文件解析,将解析结果放入Hierarchy中</div><div class="line"> ((Configurator)configurator).doConfigure(url, hierarchy);</div><div class="line">}</div></pre></td></tr></table></figure>
<p>通过上述代码我们可以清楚的看到配置解析器根据配置文件类型的不同执行不同的逻辑,但是他们都实现了<code>Configurator</code>接口,自定义解析器也要实现该接口进行逻辑的编写,下图为<code>Configurator</code>的uml图。<br><img src="/img/log4j1/log4j3.png" alt="uml图"></p>
<p>通过上图可以很明显的看到系统提供了四种配置文件解析器,基本上就可以满足我们的需求了,如果有同学在工作过程中需要自定义配置文件解析器的时候,就可以继承<code>Configurator</code>接口进行解析逻辑的编写,同时也要设置系统属性<code>log4j.configuratorClass</code>指向你自己定义的解析器类。</p>
<p>本文对不同解析器的具体实现就不在进行详细的阐述了,在接下来的文章会对xml解析器进行解析,大家可以关注一下。</p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本文主要是对Logger的获取这一流程从源码的角度进行了解析,接下来我们会对Logger打印日志进行深入的分析,希望大家可以多多关注。</p>
<p>PS:本文中的UML图是Idea画的,时序图是使用visio进行绘制的。有想尝试的小伙伴可以试试。</p>