<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[FullStack Yang]]></title><description><![CDATA[会当凌绝顶 一览众山小]]></description><link>http://www.fullstackyang.com/</link><image><url>http://www.fullstackyang.com/favicon.png</url><title>FullStack Yang</title><link>http://www.fullstackyang.com/</link></image><generator>Ghost 4.41</generator><lastBuildDate>Thu, 30 Apr 2026 12:46:55 GMT</lastBuildDate><atom:link href="http://www.fullstackyang.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Spring Security 6.x 微信公众平台OAuth2授权实战]]></title><description><![CDATA[<p>&#x4E0A;&#x4E00;&#x7BC7;&#x4ECB;&#x7ECD;&#x4E86;OAuth2&#x534F;&#x8BAE;&#x7684;&#x57FA;&#x672C;&#x539F;&#x7406;&#xFF0C;&#x4EE5;&#x53CA;Spring Security&#x6846;&#x67B6;&#x4E2D;&#x81EA;&#x5E26;&#x7684;OAuth2&#x5BA2;&#x6237;&#x7AEF;GitHub&#x7684;&#x5B9E;&#x73B0;&#x7EC6;&#x8282;&#xFF0C;&#x672C;&#x7BC7;&#x4EE5;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x53F7;&#x7F51;&#x9875;&#x6388;&#x6743;&#x767B;&#x5F55;</p>]]></description><link>http://www.fullstackyang.com/spring-security-6-x-wei-xin-gong-zhong-ping-tai-oauth2shou-quan-shi-zhan/</link><guid isPermaLink="false">665b223ddfefff0001599aa5</guid><category><![CDATA[dev]]></category><category><![CDATA[Spring Security]]></category><category><![CDATA[spring]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Sat, 01 Jun 2024 15:21:12 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2024/06/spring_security_lg-1280x720.png" medium="image"/><content:encoded><![CDATA[<img src="http://www.fullstackyang.com/content/images/2024/06/spring_security_lg-1280x720.png" alt="Spring Security 6.x &#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;OAuth2&#x6388;&#x6743;&#x5B9E;&#x6218;"><p>&#x4E0A;&#x4E00;&#x7BC7;&#x4ECB;&#x7ECD;&#x4E86;OAuth2&#x534F;&#x8BAE;&#x7684;&#x57FA;&#x672C;&#x539F;&#x7406;&#xFF0C;&#x4EE5;&#x53CA;Spring Security&#x6846;&#x67B6;&#x4E2D;&#x81EA;&#x5E26;&#x7684;OAuth2&#x5BA2;&#x6237;&#x7AEF;GitHub&#x7684;&#x5B9E;&#x73B0;&#x7EC6;&#x8282;&#xFF0C;&#x672C;&#x7BC7;&#x4EE5;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x53F7;&#x7F51;&#x9875;&#x6388;&#x6743;&#x767B;&#x5F55;&#x4E3A;&#x76EE;&#x7684;&#xFF0C;&#x4ECB;&#x7ECD;&#x5982;&#x4F55;&#x5728;&#x539F;&#x6846;&#x67B6;&#x57FA;&#x7840;&#x4E0A;&#x5B9A;&#x5236;&#x5F00;&#x53D1;OAuth2&#x5BA2;&#x6237;&#x7AEF;&#x3002;</p><h2 id="%E4%B8%80%E3%80%81%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%B9%B3%E5%8F%B0oauth2%E6%9C%8D%E5%8A%A1">&#x4E00;&#x3001;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;OAuth2&#x670D;&#x52A1;</h2><p>&#x5148;&#x7B80;&#x5355;&#x5730;&#x4ECB;&#x7ECD;&#x4E00;&#x4E0B;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;&#x7F51;&#x9875;&#x6388;&#x6743;&#x4E3B;&#x8981;&#x6D41;&#x7A0B;&#xFF0C;&#x5177;&#x4F53;&#x53EF;&#x4EE5;&#x53C2;&#x8003;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;&#x7684;&#x5B98;&#x65B9;&#x6587;&#x6863;&#xFF08;<a href="https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html">https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html</a>&#xFF09;</p><h3 id="11-%E8%AF%B7%E6%B1%82code">1.1 &#x8BF7;&#x6C42;code</h3><p>&#x5176;&#x670D;&#x52A1;&#x7AEF;&#x70B9;&#x4E3A;&#xFF1A;https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&amp;redirect_uri=REDIRECT_URI&amp;response_type=code&amp;scope=SCOPE&amp;state=STATE#wechat_redirect</p><p>&#x53C2;&#x6570;&#x90E8;&#x5206;&#x8BF4;&#x660E;&#xFF1A;</p><ul><li>appId&#xFF1A;&#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x5373;clientId&#xFF0C;&#x516C;&#x4F17;&#x53F7;&#x552F;&#x4E00;&#x6807;&#x8BC6;</li><li>redirect_uri&#xFF1A;&#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x540C;OAuth2&#x6807;&#x51C6;&#x534F;&#x8BAE;&#xFF0C;&#x8868;&#x793A;&#x670D;&#x52A1;&#x7AEF;&#x751F;&#x6210;code&#x4E4B;&#x540E;&#x91CD;&#x5B9A;&#x5411;&#x4F1A;&#x672C;&#x7CFB;&#x7EDF;&#x7684;&#x5730;&#x5740;</li><li>response_type&#xFF1A;&#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x540C;OAuth2&#x6807;&#x51C6;&#x534F;&#x8BAE;&#xFF0C;&#x9700;&#x586B;&#x5199;&quot;code&quot;</li><li>scope: &#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x540C;OAuth2&#x6807;&#x51C6;&#x534F;&#x8BAE;&#xFF0C;&#x5728;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x53F7;&#x8BBF;&#x95EE;&#x4E2D;&#x6709;&#x4E24;&#x4E2A;&#x573A;&#x666F;&#xFF0C;&#x4E00;&#x79CD;&#x53C2;&#x6570;&#x503C;&#x4E3A;&quot;snsapi_login&quot;&#xFF0C;&#x7528;&#x4E8E;&#x9759;&#x9ED8;&#x6388;&#x6743;&#x5E76;&#x81EA;&#x52A8;&#x91CD;&#x5B9A;&#x5411;&#xFF0C;&#x53EA;&#x80FD;&#x83B7;&#x53D6;&#x5230;&#x7528;&#x6237;&#x7684;openId&#xFF0C;&#x53E6;&#x4E00;&#x79CD;&#x53C2;&#x6570;&#x503C;&#x4E3A;&#x201C;snsapi_userinfo&#x201D;&#xFF0C;&#x7528;&#x4E8E;&#x5F39;&#x51FA;&#x6388;&#x6743;&#x9875;&#x9762;&#xFF0C;&#x4F9B;&#x7528;&#x6237;&#x624B;&#x52A8;&#x786E;&#x8BA4;&#x7684;&#x573A;&#x666F;&#xFF0C;&#x53EF;&#x4EE5;&#x83B7;&#x53D6;&#x6635;&#x79F0;&#x3001;&#x6027;&#x522B;&#x3001;&#x6240;&#x5728;&#x5730;&#x7B49;&#x4FE1;&#x606F;</li><li>state: &#x975E;&#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x540C;OAuth2&#x6807;&#x51C6;&#x534F;&#x8BAE;&#xFF0C;&#x53EF;&#x9632;&#x6B62;CSRF&#x653B;&#x51FB;&#xFF0C;&#x6700;&#x597D;&#x52A0;&#x4E0A;&#xFF0C;&#x53EF;&#x4F7F;&#x7528;Spring Security&#x6846;&#x63D0;&#x4F9B;&#x7684;&#x9ED8;&#x8BA4;&#x5B9E;&#x73B0;&#xFF0C;&#x4E0A;&#x4E00;&#x7BC7;&#x5DF2;&#x63D0;&#x8FC7;&#x3002;</li><li>#wechat_redirect&#xFF1A;&#x8FD9;&#x4E2A;fragment&#x4E0D;&#x80FD;&#x5C11;&#xFF0C;&#x4F46;&#x4E5F;&#x4E0D;&#x662F;OAuth2&#x6807;&#x51C6;&#x534F;&#x8BAE;&#x7684;&#x89C4;&#x8303;&#xFF0C;&#x5B98;&#x65B9;&#x4E5F;&#x672A;&#x4F5C;&#x8FC7;&#x591A;&#x8BF4;&#x660E;&#xFF0C;&#x53EF;&#x80FD;&#x662F;&#x51FA;&#x4E8E;&#x67D0;&#x79CD;&#x5B89;&#x5168;&#x8003;&#x8651;</li></ul><p>&#x53E6;&#x5916;&#x9700;&#x8981;&#x683C;&#x5916;&#x6CE8;&#x610F;&#x7684;&#x662F;&#xFF0C;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;&#x4F1A;&#x5BF9;&#x8FD9;&#x4E2A;&#x6388;&#x6743;&#x8BF7;&#x6C42;&#x7684;&#x53C2;&#x6570;&#x987A;&#x5E8F;&#x8FDB;&#x884C;&#x6821;&#x9A8C;&#xFF0C;&#x5982;&#x679C;&#x987A;&#x5E8F;&#x4E0D;&#x5BF9;&#xFF0C;&#x4E5F;&#x4F1A;&#x5BFC;&#x81F4;&#x6388;&#x6743;&#x5931;&#x8D25;&#x3002;</p><h3 id="12-%E6%9C%8D%E5%8A%A1%E7%AB%AF%E9%87%8D%E5%AE%9A%E5%90%91">1.2 &#x670D;&#x52A1;&#x7AEF;&#x91CD;&#x5B9A;&#x5411;</h3><p>&#x670D;&#x52A1;&#x7AEF;&#x5728;&#x6536;&#x5230;&#x8BF7;&#x6C42;&#x540E;&#xFF0C;&#x5C31;&#x5F39;&#x51FA;&#x7528;&#x6237;&#x6388;&#x6743;&#x9875;&#x9762;&#xFF0C;&#x7528;&#x6237;&#x540C;&#x610F;&#x6388;&#x6743;&#x540E;&#xFF08;&#x5982;&#x4F7F;&#x7528;&#x9759;&#x9ED8;&#x6388;&#x6743;&#x5219;&#x76F4;&#x63A5;&#x901A;&#x8FC7;&#xFF09;&#xFF0C;&#x53C8;&#x4F1A;&#x91CD;&#x5B9A;&#x5411;&#x5230;redirect_uri&#x7684;&#x5730;&#x5740;&#xFF0C;&#x5E76;&#x643A;&#x5E26;code&#x548C;state&#x53C2;&#x6570;&#xFF0C;&#x4F8B;&#x5982;redirect_uri?code=CODE&amp;state=STATE&#xFF0C;&#x5BA2;&#x6237;&#x7AEF;&#x5728;&#x6536;&#x5230;&#x8FD9;&#x4E2A;&#x8BF7;&#x6C42;&#x540E;&#xFF0C;&#x83B7;&#x5F97;code&#x548C;state&#x7684;&#x53C2;&#x6570;&#x503C;&#xFF0C;&#x5E76;&#x518D;&#x6B21;&#x53D1;&#x8D77;&#x8BF7;&#x6C42;&#xFF0C;&#x83B7;&#x53D6;access_token</p><h3 id="13-%E8%8E%B7%E5%8F%96accesstoken">1.3 &#x83B7;&#x53D6;access_token</h3><p>&#x5176;&#x670D;&#x52A1;&#x7AEF;&#x70B9;&#x4E3A;&#xFF1A;https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&amp;secret=SECRET&amp;code=CODE&amp;grant_type=authorization_code</p><p>&#x53C2;&#x6570;&#x90E8;&#x5206;&#x8BF4;&#x660E;&#xFF1A;</p><ul><li>appId&#xFF1A;&#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x5373;clientId&#xFF0C;&#x516C;&#x4F17;&#x53F7;&#x552F;&#x4E00;&#x6807;&#x8BC6;</li><li>secret&#xFF1A;&#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x5373;client_secret&#xFF0C;&#x53EF;&#x5728;&#x516C;&#x4F17;&#x5E73;&#x53F0;&#x5185;&#x67E5;&#x770B;</li><li>code&#xFF1A;&#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x540C;OAuth2&#x6807;&#x51C6;&#x534F;&#x8BAE;&#xFF0C;&#x5373;&#x4E0A;&#x4E00;&#x6B65;&#x83B7;&#x53D6;&#x7684;code&#x53C2;&#x6570;</li><li>grant_type&#xFF1A;&#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x540C;OAuth2&#x6807;&#x51C6;&#x534F;&#x8BAE;&#xFF0C;&#x56FA;&#x5B9A;&#x503C;&#x201C;authorization_code&#x201D;</li></ul><p>&#x8FD9;&#x4E2A;&#x7AEF;&#x70B9;&#x770B;&#x4F3C;&#x662F;&#x7528;GET&#x8BF7;&#x6C42;&#xFF0C;&#x4F46;&#x5B9E;&#x6D4B;&#x7528;POST&#x8BF7;&#x6C42;&#x4E5F;&#x662F;&#x53EF;&#x4EE5;&#x83B7;&#x53D6;&#x5230;access_token&#x3002;</p><p>&#x54CD;&#x5E94;&#x6570;&#x636E;&#x793A;&#x4F8B;&#x5982;&#x4E0B;</p><pre><code class="language-json">{
  &quot;access_token&quot;:&quot;ACCESS_TOKEN&quot;,
  &quot;expires_in&quot;:7200,
  &quot;refresh_token&quot;:&quot;REFRESH_TOKEN&quot;,
  &quot;openid&quot;:&quot;OPENID&quot;,
  &quot;scope&quot;:&quot;SCOPE&quot;,
  &quot;is_snapshotuser&quot;: 1,
  &quot;unionid&quot;: &quot;UNIONID&quot;
}</code></pre><h3 id="14-%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E7%A1%80%E4%BF%A1%E6%81%AF">1.4 &#x83B7;&#x53D6;&#x7528;&#x6237;&#x57FA;&#x7840;&#x4FE1;&#x606F;</h3><p>&#x5176;&#x670D;&#x52A1;&#x7AEF;&#x70B9;&#x4E3A;&#xFF1A;https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&amp;openid=OPENID&amp;lang=zh_CN</p><p>&#x53C2;&#x6570;&#x90E8;&#x5206;&#x8BF4;&#x660E;&#xFF1A;</p><ul><li>access_token&#xFF1A;&#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x5373;&#x4E0A;&#x4E00;&#x6B65;&#x83B7;&#x53D6;&#x5230;&#x7684;acces_token</li><li>openid&#xFF1A;&#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x5373;&#x4E0A;&#x4E00;&#x6B65;&#x83B7;&#x53D6;&#x5230;&#x7684;openid&#xFF0C;&#x7528;&#x6237;&#x552F;&#x4E00;&#x6807;&#x8BC6;</li><li>lang&#xFF1A;&#x975E;&#x5FC5;&#x586B;&#x53C2;&#x6570;&#xFF0C;&#x5373;&#x8FD4;&#x56DE;&#x6570;&#x636E;&#x7684;&#x8BED;&#x8A00;&#xFF0C;zh_CN &#x7B80;&#x4F53;&#xFF0C;zh_TW &#x7E41;&#x4F53;&#xFF0C;en &#x82F1;&#x8BED;</li></ul><p>&#x8FD9;&#x91CC;&#x6CA1;&#x6709;&#x6309;&#x7167;&#x6807;&#x51C6;&#x534F;&#x8BAE;&#x7684;&#x5EFA;&#x8BAE;&#xFF0C;&#x5C06;access_token&#x653E;&#x5728;Header&#x4E2D;&#x7684;Authorization&#x5B57;&#x6BB5;&#xFF0C;&#x800C;&#x662F;&#x4F5C;&#x4E3A;URL&#x53C2;&#x6570;&#x3002;</p><p>&#x54CD;&#x5E94;&#x6570;&#x636E;&#x793A;&#x4F8B;&#x5982;&#x4E0B;&#xFF1A;</p><pre><code class="language-json">{   
  &quot;openid&quot;: &quot;OPENID&quot;,
  &quot;nickname&quot;: NICKNAME,
  &quot;sex&quot;: 1,
  &quot;province&quot;:&quot;PROVINCE&quot;,
  &quot;city&quot;:&quot;CITY&quot;,
  &quot;country&quot;:&quot;COUNTRY&quot;,
  &quot;headimgurl&quot;:&quot;https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46&quot;,
  &quot;privilege&quot;:[ &quot;PRIVILEGE1&quot; &quot;PRIVILEGE2&quot;     ],
  &quot;unionid&quot;: &quot;o6_bmasdasdsad6_2sgVt7hMZOPfL&quot;
}</code></pre><h3 id="15-%E5%B7%AE%E5%BC%82%E5%88%86%E6%9E%90">1.5 &#x5DEE;&#x5F02;&#x5206;&#x6790;</h3><p>&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;&#x63D0;&#x4F9B;&#x7684;OAuth2&#x6388;&#x6743;&#x670D;&#x52A1;&#x6CA1;&#x6709;&#x4E25;&#x683C;&#x9075;&#x5FAA;&#x6807;&#x51C6;&#x534F;&#x8BAE;&#xFF0C;&#x6240;&#x4EE5;&#x5148;&#x68B3;&#x7406;&#x4E00;&#x4E0B;&#x54EA;&#x4E9B;&#x662F;&#x9700;&#x8981;&#x5B9A;&#x5236;&#x7684;&#x90E8;&#x5206;&#xFF0C;&#x7EFC;&#x4E0A;&#x6240;&#x8FF0;&#xFF0C;&#x4E3B;&#x8981;&#x6709;&#x4EE5;&#x4E0B;3&#x70B9;&#xFF1A;</p><ol><li>&#x5728;&#x53D1;&#x8D77;&#x6388;&#x6743;&#x8BF7;&#x6C42;&#x65F6;&#xFF0C;&#x5305;&#x62EC;&#xFF1A;</li></ol><ul><li>client-id&#x8FD9;&#x4E2A;&#x53C2;&#x6570;&#x9700;&#x91CD;&#x547D;&#x540D;&#x4E3A;appid</li><li>&#x8BF7;&#x6C42;code&#x7684;&#x53C2;&#x6570;&#x987A;&#x5E8F;&#x5FC5;&#x987B;&#x4F9D;&#x6B21;&#x4E3A;appid&#xFF0C;redirect_uri&#xFF0C;response_type&#xFF0C;scope&#xFF0C;state</li><li>&#x53C2;&#x6570;&#x6700;&#x540E;&#x5FC5;&#x987B;&#x52A0;&#x4E0A;&#x201C;#wechat_redirect&#x201D;&#x8FD9;&#x4E2A;&#x951A;&#x70B9;</li></ul><p>2. &#x5728;&#x83B7;&#x53D6;access_token&#x65F6;&#xFF0C;&#x5305;&#x62EC;&#xFF1A;</p><ul><li>client-id&#xFF0C;client-secret&#x8FD9;&#x4E24;&#x4E2A;&#x53C2;&#x6570;&#x9700;&#x91CD;&#x547D;&#x540D;&#x4E3A;appid&#x548C;secret</li><li>&#x670D;&#x52A1;&#x7AEF;&#x54CD;&#x5E94;&#x7684;MediaType&#x4E3A;text/plain&#xFF0C;&#x800C;&#x9ED8;&#x8BA4;HttpMessageConverter&#x4EC5;&#x652F;&#x6301;application/json</li><li>&#x6839;&#x636E;OAuth2&#x6807;&#x51C6;&#x534F;&#x8BAE;&#xFF0C;&#x8FD4;&#x56DE;&#x7684;&#x6570;&#x636E;&#x5B57;&#x6BB5;&#x4E2D;&#x7F3A;&#x5C11;&#x4E86;&#x4E00;&#x4E2A;&#x5FC5;&#x987B;&#x5B57;&#x6BB5;&#xFF1A;token_type&#xFF0C;&#x9700;&#x8981;&#x81EA;&#x52A8;&#x586B;&#x5145;&#x8FDB;&#x53BB;&#xFF0C;&#x5426;&#x5219;&#x53CD;&#x5E8F;&#x5217;&#x5316;&#x65F6;&#x5C31;&#x4F1A;&#x62A5;&#x9519;</li></ul><p>3. &#x5728;&#x83B7;&#x53D6;&#x7528;&#x6237;&#x4FE1;&#x606F;&#x65F6;&#xFF0C;&#x5305;&#x62EC;</p><ul><li>&#x9700;&#x8981;&#x5728;&#x8BF7;&#x6C42;&#x5730;&#x5740;&#x4E2D;&#x62FC;&#x63A5;access_token&#xFF0C;openid&#x8FD9;&#x4E24;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;&#x5E76;&#x6307;&#x5B9A;&#x4E3A;GET&#x8BF7;&#x6C42;</li><li>&#x540C;&#x4E0A;&#xFF0C;&#x9700;&#x8981;&#x517C;&#x5BB9;text/plain&#x7684;MediaType</li></ul><h2 id="%E4%BA%8C%E3%80%81%E5%BC%80%E5%8F%91%E5%AE%9E%E6%88%98">&#x4E8C;&#x3001;&#x5F00;&#x53D1;&#x5B9E;&#x6218;</h2><p>&#x4E0B;&#x9762;&#x6211;&#x4EEC;&#x9010;&#x6B65;&#x4ECB;&#x7ECD;&#x5982;&#x4F55;&#x4F18;&#x96C5;&#x5730;&#x5B9E;&#x73B0;&#x8FD9;&#x4E9B;&#x5B9A;&#x5236;&#x9700;&#x6C42;&#xFF0C;&#x8FD9;&#x91CC;&#x79C9;&#x6301;&#x4E00;&#x79CD;&#x539F;&#x5219;&#xFF0C;&#x5C3D;&#x91CF;&#x590D;&#x7528;&#x6846;&#x67B6;&#x7684;&#x4EE3;&#x7801;&#xFF0C;&#x51CF;&#x5C11;&#x91CD;&#x590D;&#x9020;&#x8F6E;&#x6240;&#x5E26;&#x6765;&#x7684;&#x6210;&#x672C;&#x3002;</p><h3 id="21-%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C">2.1 &#x51C6;&#x5907;&#x5DE5;&#x4F5C;</h3><p>&#x8FD9;&#x91CC;&#x6211;&#x4EEC;&#x4F7F;&#x7528;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;&#x63D0;&#x4F9B;&#x7684;&#x6D4B;&#x8BD5;&#x8D26;&#x53F7;&#x8FDB;&#x884C;&#x5F00;&#x53D1;&#xFF08;<a href="https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login">https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login</a>&#xFF09;&#xFF0C;&#x53EA;&#x8981;&#x626B;&#x63CF;&#x5373;&#x53EF;&#x767B;&#x5F55;&#x4F7F;&#x7528;&#x3002;&#x53E6;&#x5916;&#xFF0C;&#x4E3A;&#x4E86;&#x65B9;&#x4FBF;&#x8C03;&#x8BD5;&#xFF0C;&#x53EF;&#x4EE5;&#x4E0B;&#x8F7D;&#x5FAE;&#x4FE1;&#x5F00;&#x53D1;&#x8005;&#x5DE5;&#x5177;&#x6A21;&#x62DF;&#x5FAE;&#x4FE1;&#x5BA2;&#x6237;&#x7AEF;&#x73AF;&#x5883;&#xFF08;<a href="https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html">https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html</a>&#xFF09;</p><h3 id="22-%E5%BC%95%E5%85%A5%E4%BE%9D%E8%B5%96">2.2 &#x5F15;&#x5165;&#x4F9D;&#x8D56;</h3><p>&#x8BF4;&#x660E;&#xFF1A;&#x672C;&#x7BC7;&#x6240;&#x4F7F;&#x7528;&#x7684;Spring Boot&#x4E3A;3.3.0&#xFF0C;&#x5BF9;&#x5E94;Spring Security&#x7248;&#x672C;&#x4E3A;6.3.0&#xFF0C;&#x4F46;&#x5176;&#x4ED6;6.x&#x7248;&#x672C;&#x4E5F;&#x540C;&#x6837;&#x9002;&#x7528;&#x3002;</p><pre><code class="language-xml">&lt;properties&gt;
    &lt;maven.compiler.source&gt;17&lt;/maven.compiler.source&gt;
    &lt;maven.compiler.target&gt;17&lt;/maven.compiler.target&gt;
    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
    &lt;spring-boot.version&gt;3.3.0&lt;/spring-boot.version&gt;
&lt;/properties&gt;

&lt;dependencyManagement&gt;
    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-dependencies&lt;/artifactId&gt;
            &lt;version&gt;${spring-boot.version}&lt;/version&gt;
            &lt;type&gt;pom&lt;/type&gt;
            &lt;scope&gt;import&lt;/scope&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
&lt;/dependencyManagement&gt;

&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
        &lt;artifactId&gt;lombok&lt;/artifactId&gt;
        &lt;scope&gt;annotationProcessor&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.security&lt;/groupId&gt;
        &lt;artifactId&gt;spring-security-oauth2-client&lt;/artifactId&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;</code></pre><h3 id="23-%E9%85%8D%E7%BD%AE%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BF%A1%E6%81%AF">2.3 &#x914D;&#x7F6E;&#x5BA2;&#x6237;&#x7AEF;&#x4FE1;&#x606F;</h3><p>&#x9996;&#x5148;&#x5728;application.yml&#x6587;&#x4EF6;&#x4E2D;&#x914D;&#x7F6E;&#x5173;&#x4E8E;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;OAuth2&#x5BA2;&#x6237;&#x7AEF;&#x7684;&#x57FA;&#x7840;&#x4FE1;&#x606F;&#xFF1A;</p><pre><code class="language-yaml">spring:
  security:
    oauth2:
      client:
        registration:
          wechat:
            client-id: *********
            client-secret: *******************
            authorization-grant-type: authorization_code
            redirect-uri: &quot;{baseUrl}/{action}/oauth2/code/{registrationId}&quot;
            scope: snsapi_userinfo # &#x8BE5;scope&#x5141;&#x8BB8;&#x83B7;&#x53D6;&#x5FAE;&#x4FE1;&#x7684;&#x7528;&#x6237;&#x4FE1;&#x606F;
        provider:
          wechat:
            authorization-uri: https://open.weixin.qq.com/connect/oauth2/authorize
            token-uri: https://api.weixin.qq.com/sns/oauth2/access_token
            user-info-uri: https://api.weixin.qq.com/sns/userinfo
            user-name-attribute: nickname # &#x7528;&#x6237;&#x540D;&#x5BF9;&#x5E94;&#x7684;&#x5C5E;&#x6027;&#x540D;&#x79F0;&#xFF0C;&#x5373;&#x5FAE;&#x4FE1;&#x6635;&#x79F0;</code></pre><p>&#x5176;&#x6B21;&#x5728;HttpSecurity&#x7684;oauth2Login DSL&#x4E2D;&#xFF0C;&#x91CD;&#x70B9;&#x5173;&#x6CE8;3&#x4E2A;&#x914D;&#x7F6E;&#x9879;&#xFF1A;authorizationEndpoint&#xFF0C;tokenEndpoint&#x53CA;userInfoEndpoint&#xFF0C;&#x5206;&#x522B;&#x7528;&#x4E8E;&#x5B9A;&#x5236;&#x53D1;&#x8D77;&#x6388;&#x6743;&#x8BF7;&#x6C42;&#xFF0C;&#x83B7;&#x53D6;access_token&#xFF0C;&#x4EE5;&#x53CA;&#x83B7;&#x53D6;&#x7528;&#x6237;&#x4FE1;&#x606F;&#x8FD9;3&#x4E2A;&#x90E8;&#x5206;&#x7684;&#x4E1A;&#x52A1;&#x903B;&#x8F91;&#xFF0C;&#x4E0B;&#x9762;&#x8BE6;&#x7EC6;&#x4ECB;&#x7ECD;&#x5982;&#x4F55;&#x5229;&#x7528;&#x8FD9;&#x4E9B;&#x914D;&#x7F6E;&#x9879;&#x5C06;&#x5B9A;&#x5236;&#x903B;&#x8F91;&#x6CE8;&#x5165;&#x8FDB;&#x6765;&#xFF0C;&#x5F53;&#x7136;&#x4E5F;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x8DF3;&#x8FC7;2.4-2.6&#x5C0F;&#x8282;&#xFF0C;2.7&#x5C0F;&#x8282;&#x76F4;&#x63A5;&#x7ED9;&#x51FA;&#x4E86;&#x5B8C;&#x6574;&#x7684;&#x4EE3;&#x7801;&#x3002;</p><h3 id="24-authorizationendpoint%E9%85%8D%E7%BD%AE">2.4 authorizationEndpoint&#x914D;&#x7F6E;</h3><p>&#x8BE5;&#x914D;&#x7F6E;&#x9879;&#x5176;&#x4E2D;&#x6709;&#x4E00;&#x4E2A;authorizationRequestResolver&#x7684;&#x6269;&#x5C55;&#x70B9;&#xFF0C;&#x7528;&#x4E8E;&#x914D;&#x7F6E;&#x63A5;&#x53E3;OAuth2AuthorizationRequestResolver&#x7684;&#x5B9E;&#x4F8B;&#xFF0C;OAuth2AuthorizationRequestResolver&#x662F;&#x7528;&#x6765;&#x751F;&#x6210;&#x53D1;&#x8D77;&#x6388;&#x6743;&#x8BF7;&#x6C42;&#x5BF9;&#x8C61;OAuth2AuthorizationRequest&#xFF0C;&#x6700;&#x7EC8;&#x7528;&#x4E8E;&#x53D1;&#x8D77;&#x6388;&#x6743;&#x8BF7;&#x6C42;&#x7684;&#x5730;&#x5740;authorizationRequestUri&#x5C31;&#x662F;&#x4ECE;OAuth2AuthorizationRequest&#x5BF9;&#x8C61;&#x4E2D;&#x83B7;&#x53D6;&#x7684;&#xFF0C;&#x5176;&#x9ED8;&#x8BA4;&#x5B9E;&#x73B0;&#x7C7B;&#x662F;DefaultOAuth2AuthorizationRequestResolver&#xFF0C;&#x4E0B;&#x9762;&#x662F;&#x5176;&#x6838;&#x5FC3;&#x65B9;&#x6CD5;resolve&#xFF0C;&#x5B9E;&#x9645;&#x751F;&#x6210;&#x8FC7;&#x7A0B;&#x5176;&#x5B9E;&#x4F9D;&#x8D56;OAuth2AuthorizationRequest.Builder&#x6784;&#x9020;&#x5668;&#xFF0C;&#x8FD9;&#x91CC;&#x9884;&#x7559;&#x4E86;&#x4E00;&#x4E2A;authorizationRequestCustomizer&#x5BF9;&#x8C61;&#xFF0C;&#x53EF;&#x4EE5;&#x5B9E;&#x73B0;&#x5BF9;Builder&#x5BF9;&#x8C61;&#x7684;&#x5B9A;&#x5236;</p><pre><code class="language-Java">public final class DefaultOAuth2AuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver {
    ...
    private Consumer&lt;OAuth2AuthorizationRequest.Builder&gt; authorizationRequestCustomizer = (customizer) -&gt; {};
    ...         
    private OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId,
           String redirectUriAction) {
        if (registrationId == null) {
           return null;
        }
        ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
        if (clientRegistration == null) {
           throw new InvalidClientRegistrationIdException(&quot;Invalid Client Registration with Id: &quot; + registrationId);
        }
        OAuth2AuthorizationRequest.Builder builder = getBuilder(clientRegistration);
        ...
        this.authorizationRequestCustomizer.accept(builder); // &#x53EF;&#x5728;&#x6B64;&#x6CE8;&#x5165;&#x5B9A;&#x5236;&#x903B;&#x8F91;
        return builder.build();
    }
    ...
}</code></pre><p>&#x518D;&#x770B;&#x4E00;&#x4E0B;&#x6784;&#x9020;&#x5668;Builder&#x5185;&#x90E8;authorizationRequestUri&#x7684;&#x751F;&#x6210;&#x65B9;&#x6CD5;&#xFF0C;&#x5176;build&#x65B9;&#x6CD5;&#x6E90;&#x7801;&#x5982;&#x4E0B;&#xFF0C;&#x8FD9;&#x91CC;&#x6709;&#x4E24;&#x4E2A;&#x6269;&#x5C55;&#x70B9;&#xFF0C;&#x4E00;&#x4E2A;&#x662F;parametersConsumer&#xFF0C;&#x4E00;&#x4E2A;&#x662F;authorizationRequestUriFunction&#xFF0C;&#x524D;&#x8005;&#x53EF;&#x4EE5;&#x7528;&#x4E8E;&#x66FF;&#x6362;&#x53C2;&#x6570;&#x540D;&#x79F0;&#xFF0C;&#x4EE5;&#x53CA;&#x8C03;&#x6574;&#x53C2;&#x6570;&#x987A;&#x5E8F;&#xFF0C;&#x540E;&#x8005;&#x53EF;&#x4EE5;&#x5BF9;UriBuilder&#x4F5C;&#x8FDB;&#x4E00;&#x6B65;&#x7684;&#x5B9A;&#x5236;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x7528;&#x6765;&#x6DFB;&#x52A0;&#x201C;#wechat_redirect&#x201D;&#x3002;</p><pre><code class="language-Java">public OAuth2AuthorizationRequest build() {
    ...
    authorizationRequest.authorizationRequestUri = StringUtils.hasText(this.authorizationRequestUri)
          ? this.authorizationRequestUri : this.buildAuthorizationRequestUri(); // &#x5982;&#x679C;&#x6CA1;&#x6709;&#x989D;&#x5916;&#x8BBE;&#x7F6E;&#xFF0C;&#x6700;&#x7EC8;&#x6784;&#x9020;URL&#x7684;&#x65B9;&#x6CD5;&#x662F;buildAuthorizationRequestUri
    return authorizationRequest;
}

private String buildAuthorizationRequestUri() {
    Map&lt;String, Object&gt; parameters = getParameters(); 
    this.parametersConsumer.accept(parameters); // &#x6269;&#x5C55;&#x70B9;
    MultiValueMap&lt;String, String&gt; queryParams = new LinkedMultiValueMap&lt;&gt;();
    parameters.forEach((k, v) -&gt; queryParams.set(encodeQueryParam(k), encodeQueryParam(String.valueOf(v)))); 
    UriBuilder uriBuilder = this.uriBuilderFactory.uriString(this.authorizationUri).queryParams(queryParams);
    return this.authorizationRequestUriFunction.apply(uriBuilder).toString(); // &#x6269;&#x5C55;&#x70B9;
}</code></pre><h3 id="25-tokenendpoint%E9%85%8D%E7%BD%AE">2.5 tokenEndpoint&#x914D;&#x7F6E;</h3><p>&#x8BE5;&#x914D;&#x7F6E;&#x9879;&#x4EC5;&#x6709;&#x4E00;&#x4E2A;accessTokenResponseClient&#x7684;&#x6269;&#x5C55;&#x70B9;&#xFF0C;&#x7528;&#x4E8E;&#x914D;&#x7F6E;&#x63A5;&#x53E3;OAuth2AccessTokenResponseClient&#x7684;&#x5B9E;&#x4F8B;&#xFF0C;&#x5B83;&#x5B9A;&#x4E49;&#x4E86;&#x83B7;&#x53D6;access_token&#x7684;&#x5BA2;&#x6237;&#x7AEF;&#x64CD;&#x4F5C;&#xFF0C;&#x5176;&#x4E2D;&#x6388;&#x6743;&#x7801;&#x6A21;&#x5F0F;&#x7684;&#x5B9E;&#x73B0;&#x7C7B;&#x4E3A;DefaultAuthorizationCodeTokenResponseClient&#xFF0C;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x8FD9;&#x91CC;&#x6709;&#x4E24;&#x4E2A;&#x6269;&#x5C55;&#x70B9;&#xFF0C;&#x4E00;&#x4E2A;&#x662F;requestEntityConverter&#xFF0C;&#x53EF;&#x4EE5;&#x7528;&#x4E8E;&#x8C03;&#x6574;&#x53C2;&#x6570;&#xFF0C;&#x4E8C;&#x662F;RestOperations&#xFF0C;&#x4E3A;&#x4E86;&#x652F;&#x6301;&#x54CD;&#x5E94;&#x7684;MediaType&#xFF0C;&#x4EE5;&#x53CA;&#x9ED8;&#x8BA4;&#x586B;&#x5145;token_type&#x5B57;&#x6BB5;&#xFF0C;&#x518D;&#x5BF9;RestTemplate&#x5B9E;&#x4F8B;&#x505A;&#x8FDB;&#x4E00;&#x6B65;&#x5B9A;&#x5236;&#x3002;</p><pre><code class="language-Java">public final class DefaultAuthorizationCodeTokenResponseClient implements OAuth2AccessTokenResponseClient&lt;OAuth2AuthorizationCodeGrantRequest&gt; {
    ...
    private Converter&lt;OAuth2AuthorizationCodeGrantRequest, RequestEntity&lt;?&gt;&gt; requestEntityConverter = new ClientAuthenticationMethodValidatingRequestEntityConverter&lt;&gt;(
          new OAuth2AuthorizationCodeGrantRequestEntityConverter());

    private RestOperations restOperations;
    
    public DefaultAuthorizationCodeTokenResponseClient() {
        RestTemplate restTemplate = new RestTemplate(
              Arrays.asList(new FormHttpMessageConverter(), new OAuth2AccessTokenResponseHttpMessageConverter())); // &#x5B9A;&#x5236;OAuth2AccessTokenResponseHttpMessageConverter
        restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
        this.restOperations = restTemplate;
    }

    @Override
    public OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
       ...
       RequestEntity&lt;?&gt; request = this.requestEntityConverter.convert(authorizationCodeGrantRequest); //&#x751F;&#x6210;&#x8BF7;&#x6C42;&#x5B9E;&#x4F53;&#x5BF9;&#x8C61;&#xFF0C;&#x5229;&#x7528;&#x8FD9;&#x4E2A;converter&#x6CE8;&#x5165;&#x5B9A;&#x5236;&#x903B;&#x8F91;
       ResponseEntity&lt;OAuth2AccessTokenResponse&gt; response = getResponse(request);
       OAuth2AccessTokenResponse tokenResponse = response.getBody();
       ...
       return tokenResponse;
    }

    private ResponseEntity&lt;OAuth2AccessTokenResponse&gt; getResponse(RequestEntity&lt;?&gt; request) {
       ...
          return this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);

    }
    ...
}</code></pre><h3 id="26-userinfoendpoint%E9%85%8D%E7%BD%AE">2.6 userInfoEndpoint&#x914D;&#x7F6E;</h3><p>&#x8BE5;&#x914D;&#x7F6E;&#x9879;&#x6709;&#x4E00;&#x4E2A;userService&#x7684;&#x6269;&#x5C55;&#x70B9;&#xFF0C;&#x7528;&#x4E8E;&#x914D;&#x7F6E;&#x63A5;&#x53E3;OAuth2UserService&#x7684;&#x5B9E;&#x4F8B;&#xFF0C;&#x5B83;&#x5B9A;&#x4E49;&#x4E86;&#x53D1;&#x8D77;&#x83B7;&#x53D6;&#x7528;&#x6237;&#x4FE1;&#x606F;&#x8BF7;&#x6C42;&#x7684;&#x5BA2;&#x6237;&#x7AEF;&#x64CD;&#x4F5C;&#xFF0C;&#x9ED8;&#x8BA4;&#x5B9E;&#x73B0;&#x7C7B;&#x4E3A;DefaultOAuth2UserService&#xFF0C;&#x4E0E;&#x4E0A;&#x9762;&#x7C7B;&#x4F3C;&#xFF0C;&#x5B83;&#x4E5F;&#x6709;&#x4E24;&#x4E2A;&#x6269;&#x5C55;&#x70B9;&#xFF0C;&#x4E00;&#x4E2A;&#x662F;requestEntityConverter&#xFF0C;&#x4EE5;&#x53CA;&#x4E00;&#x4E2A;RestOperations&#xFF0C;&#x5B9A;&#x5236;&#x903B;&#x8F91;&#x4E5F;&#x57FA;&#x672C;&#x7C7B;&#x4F3C;&#x3002;</p><pre><code class="language-Java">public class DefaultOAuth2UserService implements OAuth2UserService&lt;OAuth2UserRequest, OAuth2User&gt; {
    ...
    private Converter&lt;OAuth2UserRequest, RequestEntity&lt;?&gt;&gt; requestEntityConverter = new OAuth2UserRequestEntityConverter();

    private RestOperations restOperations;

    public DefaultOAuth2UserService() {
       RestTemplate restTemplate = new RestTemplate();
       restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
       this.restOperations = restTemplate;
    }
    
    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        Assert.notNull(userRequest, &quot;userRequest cannot be null&quot;);
        String userNameAttributeName = getUserNameAttributeName(userRequest);
        RequestEntity&lt;?&gt; request = this.requestEntityConverter.convert(userRequest);
        ResponseEntity&lt;Map&lt;String, Object&gt;&gt; response = getResponse(userRequest, request);
        OAuth2AccessToken token = userRequest.getAccessToken();
        Map&lt;String, Object&gt; attributes = this.attributesConverter.convert(userRequest).convert(response.getBody());
        Collection&lt;GrantedAuthority&gt; authorities = getAuthorities(token, attributes);
        return new DefaultOAuth2User(authorities, attributes, userNameAttributeName);
    }
    ...
}</code></pre><h3 id="27-%E5%AE%9A%E5%88%B6%E5%BC%80%E5%8F%91">2<strong>.7 &#x5B9A;&#x5236;&#x5F00;&#x53D1;</strong></h3><p>&#x4E0B;&#x9762;&#x7ED9;&#x51FA;&#x5B8C;&#x6574;&#x4EE3;&#x7801;&#xFF0C;&#x4E3A;&#x4E86;&#x65B9;&#x4FBF;&#x5C55;&#x793A;&#xFF0C;&#x4E0B;&#x9762;&#x5C06;&#x6240;&#x6709;&#x7684;&#x5B9A;&#x5236;&#x5B9E;&#x73B0;&#x7C7B;&#xFF0C;&#x90FD;&#x653E;&#x5728;&#x540C;&#x4E00;&#x4E2A;Configuration&#x7C7B;&#x4E2D;&#xFF0C;&#x5B9E;&#x9645;&#x5F00;&#x53D1;&#x8FC7;&#x7A0B;&#x4E2D;&#xFF0C;&#x53EF;&#x4EE5;&#x6839;&#x636E;&#x9700;&#x8981;&#x8FDB;&#x884C;&#x62C6;&#x5206;&#x8C03;&#x6574;</p><pre><code class="language-Java">@Slf4j
@EnableWebSecurity
@Configuration
public class SpringSecurityConfiguration {

    @Resource
    private ClientRegistrationRepository clientRegistrationRepository;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.oauth2Login(oauth2 -&gt; oauth2
                .authorizationEndpoint(authorization -&gt; authorization.authorizationRequestResolver(authorizationRequestResolver(clientRegistrationRepository)))
                .tokenEndpoint(token -&gt; token.accessTokenResponseClient(accessTokenResponseClient()))
                .userInfoEndpoint(userInfo -&gt; userInfo.userService(userService()))
        );
        DefaultSecurityFilterChain filterChain = http.build();
        filterChain.getFilters().stream().map(Object::toString).forEach(log::info);
        return filterChain;
    }

    private OAuth2AuthorizationRequestResolver authorizationRequestResolver(ClientRegistrationRepository clientRegistrationRepository) {
        String authorizationRequestBaseUri = OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI;
        // &#x53C2;&#x8003;&#x6846;&#x67B6;&#x5185;&#x9ED8;&#x8BA4;&#x7684;&#x5B9E;&#x4F8B;&#x6784;&#x9020;&#x65B9;&#x6CD5;
        DefaultOAuth2AuthorizationRequestResolver resolver = new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, authorizationRequestBaseUri);
        // &#x8BBE;&#x7F6E;OAuth2AuthorizationRequest.builder&#x7684;&#x5B9A;&#x5236;&#x903B;&#x8F91;
        resolver.setAuthorizationRequestCustomizer(builder -&gt; builder.parameters(this::parametersConsumer).authorizationRequestUri(this::authorizationRequestUriFunction));
        return resolver;
    }

    private void parametersConsumer(Map&lt;String, Object&gt; parameters) {
        Object clientId = parameters.get(OAuth2ParameterNames.CLIENT_ID);
        Object redirectUri = parameters.get(OAuth2ParameterNames.REDIRECT_URI);
        Object responseType = parameters.get(OAuth2ParameterNames.RESPONSE_TYPE);
        Object scope = parameters.get(OAuth2ParameterNames.SCOPE);
        Object state = parameters.get(OAuth2ParameterNames.STATE);
        // &#x6E05;&#x9664;&#x6389;&#x539F;&#x6765;&#x6240;&#x6709;&#x7684;&#x53C2;&#x6570;
        parameters.clear();
        // &#x91CD;&#x65B0;&#x8C03;&#x6574;&#x987A;&#x5E8F;
        parameters.put(&quot;appid&quot;, clientId);// &#x4FEE;&#x6539;clientId&#x53C2;&#x6570;&#x540D;&#x79F0;&#x4E3A;appid
        parameters.put(OAuth2ParameterNames.REDIRECT_URI, redirectUri);
        parameters.put(OAuth2ParameterNames.RESPONSE_TYPE, responseType);
        parameters.put(OAuth2ParameterNames.SCOPE, scope);
        parameters.put(OAuth2ParameterNames.STATE, state);

    }

    private URI authorizationRequestUriFunction(UriBuilder builder) {
        builder.fragment(&quot;wechat_redirect&quot;);// &#x6DFB;&#x52A0;#wechat_redirect
        return builder.build();
    }
    

    private OAuth2AccessTokenResponseClient&lt;OAuth2AuthorizationCodeGrantRequest&gt; accessTokenResponseClient() {
        DefaultAuthorizationCodeTokenResponseClient client = new DefaultAuthorizationCodeTokenResponseClient();
        // &#x6CE8;&#x5165;&#x81EA;&#x5B9A;&#x4E49;WechatOAuth2AuthorizationCodeGrantRequestEntityConverter
        client.setRequestEntityConverter(new WechatOAuth2AuthorizationCodeGrantRequestEntityConverter()); 
        // &#x521B;&#x5EFA;&#x4E00;&#x4E2A;OAuth2AccessTokenResponseHttpMessageConverter&#x5BF9;&#x8C61;&#xFF0C;&#x8BBE;&#x7F6E;&#x652F;&#x6301;&#x7684;MediaType&#x4E3A;text/plain
        OAuth2AccessTokenResponseHttpMessageConverter messageConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
        messageConverter.setSupportedMediaTypes(List.of(MediaType.TEXT_PLAIN)); 
        messageConverter.setAccessTokenResponseConverter(new WechatOAuth2AccessTokenResponseConverter());
        // &#x5176;&#x4ED6;&#x914D;&#x7F6E;&#x7167;&#x642C;&#x6E90;&#x7801;
        RestTemplate restTemplate = new RestTemplate(Arrays.asList(new FormHttpMessageConverter(), messageConverter));
        restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
        client.setRestOperations(restTemplate);
        return client;
    }

    private static class WechatOAuth2AccessTokenResponseConverter implements Converter&lt;Map&lt;String, Object&gt;, OAuth2AccessTokenResponse&gt; {

        private static final DefaultMapOAuth2AccessTokenResponseConverter delegate = new DefaultMapOAuth2AccessTokenResponseConverter();
        //&#x54CD;&#x5E94;&#x4E2D;&#x7F3A;&#x5C11;token_type&#x5B57;&#x6BB5;&#xFF0C;&#x4E3A;&#x907F;&#x514D;&#x62A5;&#x9519;&#x9ED8;&#x8BA4;&#x586B;&#x5145;&#xFF0C;&#x5269;&#x4F59;&#x90E8;&#x5206;&#x4F9D;&#x7136;&#x59D4;&#x6258;&#x7ED9;&#x9ED8;&#x8BA4;&#x7684;DefaultMapOAuth2AccessTokenResponseConverter&#x5904;&#x7406;
        @Override
        public OAuth2AccessTokenResponse convert(Map&lt;String, Object&gt; source) {
            source.put(OAuth2ParameterNames.TOKEN_TYPE, OAuth2AccessToken.TokenType.BEARER.getValue()); 
            return delegate.convert(source);
        }
    }

    // &#x65E0;&#x6CD5;&#x76F4;&#x63A5;&#x5B9E;&#x73B0;&#x63A5;&#x53E3;&#xFF0C;&#x4E0D;&#x8FC7;&#x53EF;&#x4EE5;&#x7EE7;&#x627F;OAuth2AuthorizationCodeGrantRequestEntityConverter
    private static class WechatOAuth2AuthorizationCodeGrantRequestEntityConverter extends OAuth2AuthorizationCodeGrantRequestEntityConverter {
        //&#x53C2;&#x8003;&#x7236;&#x7C7B;&#x7684;&#x6E90;&#x7801;&#xFF0C;&#x4F9D;&#x846B;&#x82A6;&#x753B;&#x74E2;&#x91CD;&#x5199;createParameters&#x65B9;&#x6CD5;&#xFF0C;&#x6839;&#x636E;&#x5FAE;&#x4FE1;&#x7684;&#x6587;&#x6863;&#xFF0C;&#x4F9D;&#x6B21;&#x6DFB;&#x52A0;appid&#xFF0C;secret&#xFF0C;grant_type&#xFF0C;code&#x8FD9;&#x56DB;&#x4E2A;&#x53C2;&#x6570;
        @Override
        protected MultiValueMap&lt;String, String&gt; createParameters(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
            ClientRegistration clientRegistration = authorizationCodeGrantRequest.getClientRegistration();
            OAuth2AuthorizationExchange authorizationExchange = authorizationCodeGrantRequest.getAuthorizationExchange();
            MultiValueMap&lt;String, String&gt; parameters = new LinkedMultiValueMap&lt;&gt;();
            parameters.add(&quot;appid&quot;, clientRegistration.getClientId());
            parameters.add(&quot;secret&quot;, clientRegistration.getClientSecret());
            parameters.add(OAuth2ParameterNames.GRANT_TYPE, authorizationCodeGrantRequest.getGrantType().getValue());
            parameters.add(OAuth2ParameterNames.CODE, authorizationExchange.getAuthorizationResponse().getCode());
            return parameters;
        }
    }

    private OAuth2UserService&lt;OAuth2UserRequest, OAuth2User&gt; userService() {
        DefaultOAuth2UserService userService = new DefaultOAuth2UserService();
        // &#x6CE8;&#x5165;&#x81EA;&#x5B9A;&#x4E49;&#x7684;requestEntityConverter
        userService.setRequestEntityConverter(new WechatOAuth2UserRequestEntityConverter());
        // &#x521B;&#x5EFA;&#x4E00;&#x4E2A;MappingJackson2HttpMessageConverter&#x5BF9;&#x8C61;&#xFF0C;&#x540C;&#x6837;&#x8BBE;&#x7F6E;&#x652F;&#x6301;&#x7684;MediaType&#x4E3A;text/plain
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        messageConverter.setSupportedMediaTypes(List.of(MediaType.TEXT_PLAIN));
        RestTemplate restTemplate = new RestTemplate(List.of(messageConverter));
        restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
        userService.setRestOperations(restTemplate);
        return userService;
    }

    private static class WechatOAuth2UserRequestEntityConverter implements Converter&lt;OAuth2UserRequest, RequestEntity&lt;?&gt;&gt; {
        // &#x6839;&#x636E;&#x5FAE;&#x4FE1;&#x6587;&#x6863;&#xFF0C;&#x5728;&#x8BF7;&#x6C42;&#x5730;&#x5740;&#x4E2D;&#x62FC;&#x63A5;&#x4E0A;access_token&#x548C;openid&#x4E24;&#x4E2A;&#x53C2;&#x6570;
        @Override
        public RequestEntity&lt;?&gt; convert(OAuth2UserRequest userRequest) {
            ClientRegistration clientRegistration = userRequest.getClientRegistration();
            URI uri = UriComponentsBuilder.fromUriString(clientRegistration.getProviderDetails().getUserInfoEndpoint().getUri())
                    .queryParam(OAuth2ParameterNames.ACCESS_TOKEN, userRequest.getAccessToken().getTokenValue())
                    .queryParam(&quot;openid&quot;, userRequest.getAdditionalParameters().get(&quot;openid&quot;))
                    .build()
                    .toUri();
            return new RequestEntity&lt;&gt;(HttpMethod.GET, uri);
        }
    }
}</code></pre><h2 id="%E4%B8%89%E3%80%81%E6%B5%8B%E8%AF%95%E9%AA%8C%E8%AF%81">&#x4E09;&#x3001;&#x6D4B;&#x8BD5;&#x9A8C;&#x8BC1;</h2><p>&#x9996;&#x5148;&#x4E3A;&#x4E86;&#x65B9;&#x4FBF;&#x6D4B;&#x8BD5;&#xFF0C;&#x53EF;&#x4EE5;&#x5728;hosts&#x6587;&#x4EF6;&#x4E2D;&#x5C06;&#x672C;&#x5730;IP&quot;127.0.0.1&quot;&#x6620;&#x5C04;&#x4E3A;&#x4E00;&#x4E2A;&#x865A;&#x62DF;&#x7684;&#x57DF;&#x540D;&#xFF0C;&#x4F8B;&#x5982;www.oauth2.com&#xFF0C;&#x7136;&#x540E;&#x5728;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;&#x6D4B;&#x8BD5;&#x8D26;&#x53F7;&#x5185;&#x8BBE;&#x7F6E;&#x6388;&#x6743;&#x56DE;&#x8C03;&#x9875;&#x9762;&#x57DF;&#x540D;&#x5730;&#x5740;&#xFF0C;&#x627E;&#x5230;&#x201C;&#x7F51;&#x9875;&#x8D26;&#x53F7;&#x201D;&#x8FD9;&#x4E00;&#x9879;&#xFF0C;&#x70B9;&#x51FB;&#x4FEE;&#x6539;&#xFF0C;&#x5728;&#x5F39;&#x7A97;&#x4E2D;&#x8F93;&#x5165;&#x201C;www.oauth2.com&#x201D;&#xFF0C;&#x70B9;&#x51FB;&#x786E;&#x8BA4;&#x5373;&#x53EF;&#x3002;</p><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/06/image.png" class="kg-image" alt="Spring Security 6.x &#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;OAuth2&#x6388;&#x6743;&#x5B9E;&#x6218;" loading="lazy" width="1150" height="174" srcset="http://www.fullstackyang.com/content/images/size/w600/2024/06/image.png 600w, http://www.fullstackyang.com/content/images/size/w1000/2024/06/image.png 1000w, http://www.fullstackyang.com/content/images/2024/06/image.png 1150w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/06/image-1.png" class="kg-image" alt="Spring Security 6.x &#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;OAuth2&#x6388;&#x6743;&#x5B9E;&#x6218;" loading="lazy" width="752" height="523" srcset="http://www.fullstackyang.com/content/images/size/w600/2024/06/image-1.png 600w, http://www.fullstackyang.com/content/images/2024/06/image-1.png 752w" sizes="(min-width: 720px) 720px"></figure><p>&#x63A5;&#x7740;&#x5C31;&#x53EF;&#x4EE5;&#x542F;&#x52A8;&#x7A0B;&#x5E8F;&#x9A8C;&#x8BC1;&#x6548;&#x679C;&#x4E86;&#xFF0C;&#x6D4B;&#x8BD5;&#x65F6;&#x53EF;&#x4EE5;&#x6253;&#x5F00;spring security&#x7684;debug&#x65E5;&#x5FD7;&#xFF0C;&#x5728;&#x5FAE;&#x4FE1;&#x5F00;&#x53D1;&#x8005;&#x5DE5;&#x5177;&#x5185;&#x8BBF;&#x95EE;http://www.oauth2.com/oauth2/authorization/wechat&#xFF0C;&#x89C2;&#x5BDF;&#x65E5;&#x5FD7;&#x8F93;&#x51FA;&#xFF0C;&#x8BF7;&#x6C42;&#x88AB;&#x91CD;&#x5B9A;&#x5411;&#x5230;&#x4E86;https://open.weixin.qq.com/connect/oauth2/authorize&#x8FD9;&#x4E2A;&#x5730;&#x5740;&#xFF0C;&#x5E76;&#x4E14;&#x53C2;&#x6570;&#x90FD;&#x6309;&#x7167;&#x9884;&#x671F;&#x8BBE;&#x7F6E;&#x6210;&#x529F;&#x3002;</p><pre><code>o.s.security.web.FilterChainProxy        : Securing GET /oauth2/authorization/wechat
o.s.s.web.DefaultRedirectStrategy        : Redirecting to https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx3574913d730b2837  
&amp;redirect_uri=http://www.oauth2.com/login/oauth2/code/wechat&amp;response_type=code&amp;scope=snsapi_userinfo
&amp;state=pBpqcIj_Z_A7iiApozDIBPw1IY1XFJQw1uTHhoqvGvs%3D#wechat_redirect</code></pre><p>&#x6B64;&#x65F6;&#x5BA2;&#x6237;&#x7AEF;&#x4F1A;&#x8DF3;&#x8F6C;&#x5230;&#x5FAE;&#x4FE1;&#x6388;&#x6743;&#x9875;&#x9762;&#xFF0C;&#x5982;&#x4E0B;&#x56FE;</p><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/06/--2024-06-02-00.02.22.png" class="kg-image" alt="Spring Security 6.x &#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;OAuth2&#x6388;&#x6743;&#x5B9E;&#x6218;" loading="lazy" width="270" height="430"></figure><p>&#x70B9;&#x51FB;&#x540C;&#x610F;&#x540E;&#xFF0C;&#x670D;&#x52A1;&#x7AEF;&#x4F1A;&#x91CD;&#x5B9A;&#x5411;&#x5230;redirect_uri&#x7684;&#x5730;&#x5740;&#xFF0C;&#x5373;http://www.oauth2.com/login/oauth2/code/wechat&#xFF0C;&#x82E5;&#x8BE5;&#x5730;&#x5740;&#x540E;&#x9762;&#x643A;&#x5E26;&#x4E86;code&#x548C;state&#x8FD9;&#x4E24;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;&#x5219;&#x8868;&#x793A;code&#x83B7;&#x53D6;&#x6210;&#x529F;&#xFF0C;&#x53E6;&#x5916;&#x56DE;&#x8C03;&#x5730;&#x5740;&#x4E2D;&#x7684;state&#x548C;&#x6B64;&#x524D;&#x53D1;&#x8D77;&#x8BF7;&#x6C42;&#x65F6;&#x7684;state&#x4E24;&#x4E2A;&#x503C;&#x4E5F;&#x662F;&#x4E00;&#x6837;&#x7684;&#x3002;</p><p>&#x7136;&#x540E;&#x901A;&#x8FC7;&#x65E5;&#x5FD7;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;&#x63A5;&#x7740;&#x53C8;&#x53D1;&#x8D77;&#x4E86;&#x83B7;&#x53D6;access_token&#x7684;&#x8BF7;&#x6C42;&#xFF0C;&#x5982;&#x679C;&#x6210;&#x529F;&#x83B7;&#x53D6;&#x5230;access_token&#xFF0C;&#x968F;&#x5373;&#x5C31;&#x4F1A;&#x4F7F;&#x7528;acces_token&#x518D;&#x8BF7;&#x6C42;&#x83B7;&#x53D6;&#x7528;&#x6237;&#x4FE1;&#x606F;&#x7684;&#x63A5;&#x53E3;&#xFF0C;&#x6700;&#x540E;&#x5728;&#x5F97;&#x5230;&#x7528;&#x6237;&#x6570;&#x636E;&#x540E;&#x4F1A;&#x521B;&#x5EFA;&#x5BF9;&#x5E94;&#x7684;Authentication&#x5BF9;&#x8C61;&#xFF0C;&#x5E76;&#x4E3A;&#x5176;&#x8FDB;&#x884C;&#x6301;&#x4E45;&#x5316;&#x64CD;&#x4F5C;&#xFF0C;&#x81F3;&#x6B64;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x53F7;&#x7F51;&#x9875;&#x6388;&#x6743;&#x7684;&#x6574;&#x4E2A;&#x8FC7;&#x7A0B;&#x5C31;&#x5B8C;&#x6210;&#x4E86;&#x3002;</p><pre><code>o.s.security.web.FilterChainProxy        : Securing GET /login/oauth2/code/wechat?
code=071jlkGa1xcSxH0okrFa1ERx9y0jlkGu&amp;state=KXg4KA_6s6imMwr1Vm0DTZz7m8vn
iA2Bi4RZIjVEx2o%3D

o.s.web.client.RestTemplate              : HTTP POST https://api.weixin.qq.com/sns/oauth2/access_token
o.s.web.client.RestTemplate              : Response 200 OK

o.s.web.client.RestTemplate              : HTTP GET https://api.weixin.qq.com/sns/userinfo?
access_token=81_8wWRqWFvwAVQldmWeraiE7sNOwt7eRZJ5S5teKN2ua90TgxaCpRo97Eh
zR1Hr_3gP0eL7hpUK7zH0zYcFqZ-5Zxxs4as-6P5HJjDHiZ7Tyg&amp;openid=***
2024-06-01T16:57:34.093+08:00 DEBUG 3965 --- [p-nio-80-exec-2] 
o.s.web.client.RestTemplate              : Response 200 OK

2024-06-01T16:57:37.730+08:00 DEBUG 3965 --- [p-nio-80-exec-2] 
w.c.HttpSessionSecurityContextRepository : Stored SecurityContextImpl 
[Authentication=OAuth2AuthenticationToken [Principal=Name: [**], Granted 
Authorities: [[OAUTH2_USER, SCOPE_snsapi_userinfo]], User Attributes: 
[{openid=***, nickname=**, sex=0, language=, city=, province=, country=, 
headimgurl=https://thirdwx.qlogo.cn/mmopen/vi_32/****, privilege=[]}], 
Credentials=[PROTECTED], Authenticated=true, 
Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, 
SessionId=6D5003EC4A8EF36118C02A7138CBAAAF], Granted Authorities=
[OAUTH2_USER, SCOPE_snsapi_userinfo]]] to HttpSession 
[org.apache.catalina.session.StandardSessionFacade@50161408]
2024-06-01T16:57:37.730+08:00 DEBUG 3965 --- [p-nio-80-exec-2] 
.s.o.c.w.OAuth2LoginAuthenticationFilter : Set SecurityContextHolder to 
OAuth2AuthenticationToken [Principal=Name: [**], Granted Authorities: 
[[OAUTH2_USER, SCOPE_snsapi_userinfo]], User Attributes: [{openid=***, 
nickname=**, sex=0, language=, city=, province=, country=, 
headimgurl=https://thirdwx.qlogo.cn/mmopen/vi_32/****, privilege=[]}], 
Credentials=[PROTECTED], Authenticated=true, 
Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, 
SessionId=6D5003EC4A8EF36118C02A7138CBAAAF], Granted Authorities=
[OAUTH2_USER, SCOPE_snsapi_userinfo]]
o.s.s.web.DefaultRedirectStrategy        : Redirecting to /</code></pre><p>&#x53EF;&#x4EE5;&#x518D;&#x5199;&#x4E00;&#x4E2A;&#x7B80;&#x5355;Controller&#xFF0C;&#x67E5;&#x770B;&#x4E00;&#x4E0B;&#x5B9E;&#x9645;&#x7684;Authentication&#x5BF9;&#x8C61;</p><pre><code class="language-Java">@RestController
public class UserController {

    @GetMapping(&quot;/user&quot;)
    public String user() {
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        return &quot;Hello &quot; + username;
    }
    
}</code></pre><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/06/image-3.png" class="kg-image" alt="Spring Security 6.x &#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;OAuth2&#x6388;&#x6743;&#x5B9E;&#x6218;" loading="lazy" width="264" height="141"></figure><h2 id="%E5%9B%9B%E3%80%81%E7%BB%93%E6%9D%9F%E8%AF%AD">&#x56DB;&#x3001;&#x7ED3;&#x675F;&#x8BED;</h2><p>&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x5E73;&#x53F0;&#x63D0;&#x4F9B;&#x7684;OAuth2&#x6388;&#x6743;&#x670D;&#x52A1;&#x4E0E;&#x6807;&#x51C6;&#x534F;&#x8BAE;&#x7684;&#x89C4;&#x8303;&#x5B58;&#x5728;&#x7740;&#x8BF8;&#x591A;&#x4E0D;&#x540C;&#x4E4B;&#x5904;&#xFF0C;&#x4F46;&#x662F;&#x57FA;&#x672C;&#x6846;&#x67B6;&#x6D41;&#x7A0B;&#x90FD;&#x662F;&#x76F8;&#x540C;&#x7684;&#xFF0C;Spring Security&#x6846;&#x67B6;&#x4E5F;&#x4E3A;&#x8FD9;&#x4E9B;&#x5DEE;&#x5F02;&#x9884;&#x7559;&#x4E86;&#x76F8;&#x5E94;&#x7684;&#x6269;&#x5C55;&#x70B9;&#xFF0C;&#x6211;&#x4EEC;&#x5728;&#x5B66;&#x4E60;&#x6E90;&#x7801;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x8981;&#x5C3D;&#x91CF;&#x89C2;&#x5BDF;&#x548C;&#x601D;&#x8003;&#x8FD9;&#x4E9B;&#x6269;&#x5C55;&#x70B9;&#x7684;&#x5B9E;&#x9645;&#x7528;&#x9014;&#xFF0C;&#x8FD9;&#x6837;&#x53EF;&#x4EE5;&#x5E2E;&#x52A9;&#x6211;&#x4EEC;&#x627E;&#x5230;&#x5B9A;&#x5236;&#x5316;&#x5F00;&#x53D1;&#x7684;&#x6700;&#x4F73;&#x65B9;&#x6848;&#x3002;</p>]]></content:encoded></item><item><title><![CDATA[Spring Security 6.x OAuth2登录认证源码分析]]></title><description><![CDATA[<p>&#x4E0A;&#x4E00;&#x7BC7;&#x4ECB;&#x7ECD;&#x4E86;Spring Security&#x6846;&#x67B6;&#x4E2D;&#x8EAB;&#x4EFD;&#x8BA4;&#x8BC1;&#x7684;&#x67B6;&#x6784;&#x8BBE;&#x8BA1;&#xFF0C;&#x672C;&#x7BC7;&#x5C31;OAuth2&#x5BA2;&#x6237;&#x7AEF;&#x767B;&#x5F55;&#x8BA4;&#x8BC1;&#x7684;&#x5B9E;&#x73B0;&#x6E90;&#x7801;&#x505A;&#x4E00;&#x4E9B;&#x5206;&#x6790;&#x3002;</p><h2 id="%E4%B8%80%E3%80%81oauth2%E5%8D%8F%E8%AE%AE%E7%AE%80%E4%BB%8B">&#x4E00;&#x3001;OAuth2&#x534F;&#x8BAE;&#x7B80;&#x4ECB;</h2>]]></description><link>http://www.fullstackyang.com/spring-authorization-server/</link><guid isPermaLink="false">63fc5c4bdfefff00015997c1</guid><category><![CDATA[dev]]></category><category><![CDATA[spring]]></category><category><![CDATA[Spring Security]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Sun, 26 May 2024 13:44:25 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2024/05/spring_security_lg-1280x720-2.png" medium="image"/><content:encoded><![CDATA[<img src="http://www.fullstackyang.com/content/images/2024/05/spring_security_lg-1280x720-2.png" alt="Spring Security 6.x OAuth2&#x767B;&#x5F55;&#x8BA4;&#x8BC1;&#x6E90;&#x7801;&#x5206;&#x6790;"><p>&#x4E0A;&#x4E00;&#x7BC7;&#x4ECB;&#x7ECD;&#x4E86;Spring Security&#x6846;&#x67B6;&#x4E2D;&#x8EAB;&#x4EFD;&#x8BA4;&#x8BC1;&#x7684;&#x67B6;&#x6784;&#x8BBE;&#x8BA1;&#xFF0C;&#x672C;&#x7BC7;&#x5C31;OAuth2&#x5BA2;&#x6237;&#x7AEF;&#x767B;&#x5F55;&#x8BA4;&#x8BC1;&#x7684;&#x5B9E;&#x73B0;&#x6E90;&#x7801;&#x505A;&#x4E00;&#x4E9B;&#x5206;&#x6790;&#x3002;</p><h2 id="%E4%B8%80%E3%80%81oauth2%E5%8D%8F%E8%AE%AE%E7%AE%80%E4%BB%8B">&#x4E00;&#x3001;OAuth2&#x534F;&#x8BAE;&#x7B80;&#x4ECB;</h2><p>OAuth2&#x534F;&#x8BAE;&#xFF0C;&#x82F1;&#x6587;&#x5168;&#x79F0;Open Authorization 2.0&#xFF0C;&#x5373;&#x5F00;&#x653E;&#x6388;&#x6743;&#x534F;&#x8BAE;&#xFF0C;&#x5B83;&#x672C;&#x8EAB;&#x89E3;&#x51B3;&#x7684;&#x95EE;&#x9898;&#xFF0C;&#x5C31;&#x662F;&#x4E92;&#x8054;&#x7F51;&#x4E2D;&#x7684;&#x5B89;&#x5168;&#x4FE1;&#x4EFB;&#x95EE;&#x9898;&#xFF0C;&#x5F53;&#x7B2C;&#x4E09;&#x65B9;&#x9700;&#x8981;&#x8BBF;&#x95EE;&#x672C;&#x7CFB;&#x7EDF;&#x5185;&#x53D7;&#x4FDD;&#x62A4;&#x8D44;&#x6E90;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x5982;&#x4F55;&#x5BF9;&#x5176;&#x6388;&#x6743;&#x4EE5;&#x5B9E;&#x73B0;&#x5408;&#x6CD5;&#x5B89;&#x5168;&#x7684;&#x8BBF;&#x95EE;&#x3002;</p><p>&#x4E3E;&#x4E2A;&#x4F8B;&#x5B50;&#xFF0C;&#x53EF;&#x80FD;&#x5728;&#x7269;&#x7406;&#x4E16;&#x754C;&#x91CC;&#x9762;&#x5E76;&#x4E0D;&#x5B58;&#x5728;&#xFF0C;&#x53EA;&#x662F;&#x4E3A;&#x65B9;&#x4FBF;&#x8BF4;&#x660E;OAuth2&#x7684;&#x5DE5;&#x4F5C;&#x539F;&#x7406;&#x3002;&#x5047;&#x8BBE;&#x6709;&#x67D0;&#x4E2A;&#x5927;&#x578B;&#x5546;&#x573A;&#x63D0;&#x4F9B;&#x4E86;&#x4E00;&#x79CD;&#x65E0;&#x5361;&#x6D88;&#x8D39;&#x7684;&#x670D;&#x52A1;&#xFF0C;&#x7528;&#x6237;&#x53EA;&#x8981;&#x5728;&#x5546;&#x573A;&#x7684;&#x8D26;&#x6237;&#x4E2D;&#x5145;&#x503C;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x5728;&#x5546;&#x573A;&#x4E2D;&#x4EFB;&#x4F55;&#x4E00;&#x5BB6;&#x5E97;&#x94FA;&#x8FDB;&#x884C;&#x65E0;&#x5361;&#x6D88;&#x8D39;&#xFF0C;&#x6B64;&#x65F6;&#x5546;&#x5BB6;&#x4F5C;&#x4E3A;&#x7B2C;&#x4E09;&#x65B9;&#xFF0C;&#x9700;&#x8981;&#x8BBF;&#x95EE;&#x4F60;&#x7684;&#x65E0;&#x5361;&#x8D26;&#x6237;&#xFF0C;&#x5BF9;&#x4E8E;&#x7528;&#x6237;&#x6765;&#x8BF4;&#xFF0C;&#x65E0;&#x5361;&#x8D26;&#x6237;&#x5C31;&#x662F;&#x4E00;&#x79CD;&#x53D7;&#x4FDD;&#x62A4;&#x8D44;&#x6E90;&#xFF0C;&#x5B83;&#x5E76;&#x4E0D;&#x80FD;&#x968F;&#x610F;&#x8FDB;&#x884C;&#x8BBF;&#x95EE;&#xFF0C;&#x90A3;&#x4E48;&#x600E;&#x4E48;&#x89E3;&#x51B3;&#x4FE1;&#x4EFB;&#x95EE;&#x9898;&#x3002;</p><p>&#x9996;&#x5148;&#xFF0C;&#x80FD;&#x591F;&#x60F3;&#x5230;&#x7684;&#x662F;&#xFF0C;&#x4EFB;&#x4F55;&#x4E00;&#x5BB6;&#x7684;&#x5E97;&#x94FA;&#x60F3;&#x8981;&#x652F;&#x6301;&#x65E0;&#x5361;&#x6D88;&#x8D39;&#xFF0C;&#x5C31;&#x5FC5;&#x987B;&#x5728;&#x5546;&#x573A;&#x5185;&#x8FDB;&#x884C;&#x767B;&#x8BB0;&#x6CE8;&#x518C;&#xFF0C;&#x53EA;&#x6709;&#x5728;&#x518C;&#x7684;&#x5E97;&#x94FA;&#x624D;&#x88AB;&#x5141;&#x8BB8;&#x8BBF;&#x95EE;&#x50A8;&#x503C;&#x5361;&#x7684;&#x8D26;&#x6237;&#xFF1B;</p><p>&#x5176;&#x6B21;&#xFF0C;&#x7528;&#x6237;&#x4E0D;&#x5E94;&#x8BE5;&#x5728;&#x6BCF;&#x5BB6;&#x5E97;&#x94FA;&#x6D88;&#x8D39;&#x65F6;&#x90FD;&#x63D0;&#x4F9B;&#x7528;&#x6237;&#x540D;&#x548C;&#x5BC6;&#x7801;&#xFF0C;&#x8FD9;&#x6837;&#x5BC6;&#x7801;&#x5C31;&#x5B58;&#x5728;&#x6CC4;&#x9732;&#x7684;&#x98CE;&#x9669;&#xFF0C;&#x5546;&#x573A;&#x5E94;&#x8BE5;&#x63D0;&#x4F9B;&#x4E00;&#x79CD;&#x7528;&#x6237;&#x6388;&#x6743;&#x7684;&#x4EA4;&#x4E92;&#x65B9;&#x5F0F;&#xFF0C;&#x5728;&#x5E97;&#x94FA;&#x53D1;&#x8D77;&#x8BBF;&#x95EE;&#x65E0;&#x5361;&#x8D26;&#x6237;&#x65F6;&#xFF0C;&#x7528;&#x6237;&#x53EA;&#x9700;&#x8981;&#x6388;&#x6743;&#x5373;&#x53EF;&#xFF0C;&#x59D1;&#x4E14;&#x60F3;&#x8C61;&#x4E00;&#x4E0B;&#xFF0C;&#x5728;&#x5E97;&#x94FA;&#x4E2D;&#x652F;&#x4ED8;&#x65F6;&#xFF0C;&#x4F1A;&#x4ECE;&#x7A7A;&#x6C14;&#x4E2D;&#x5F39;&#x51FA;&#x4E00;&#x4E2A;&#x5546;&#x573A;&#x63D0;&#x4F9B;&#x7684;&#x786E;&#x8BA4;&#x6388;&#x6743;&#x9875;&#x9762;&#xFF0C;&#x5F53;&#x7136;&#x5546;&#x573A;&#x5DF2;&#x7ECF;&#x6838;&#x5BF9;&#x4E86;&#x5546;&#x6237;&#x7684;&#x6CE8;&#x518C;&#x4FE1;&#x606F;&#xFF1B;</p><p>&#x6700;&#x540E;&#xFF0C;&#x4E00;&#x65E6;&#x7528;&#x6237;&#x5BF9;&#x8BE5;&#x5E97;&#x94FA;&#x8FDB;&#x884C;&#x4E86;&#x5408;&#x6CD5;&#x7684;&#x6388;&#x6743;&#xFF0C;&#x5546;&#x573A;&#x5C31;&#x7ED9;&#x5E97;&#x94FA;&#x53D1;&#x653E;&#x4E00;&#x4E2A;&#x4EA4;&#x6613;&#x51ED;&#x8BC1;&#xFF0C;&#x5E97;&#x94FA;&#x5E26;&#x7740;&#x8FD9;&#x4E2A;&#x51ED;&#x8BC1;&#x5C31;&#x53EF;&#x4EE5;&#x8BBF;&#x95EE;&#x6211;&#x7684;&#x65E0;&#x5361;&#x8D26;&#x6237;&#xFF1B;</p><p>&#x5F53;&#x7136;&#xFF0C;&#x5546;&#x573A;&#x5E94;&#x5F53;&#x8981;&#x4FDD;&#x8BC1;&#x8FD9;&#x4E2A;&#x4EA4;&#x6613;&#x51ED;&#x8BC1;&#x7684;&#x53D1;&#x653E;&#x662F;&#x5B89;&#x5168;&#x7684;&#xFF0C;&#x4E0D;&#x80FD;&#x8F7B;&#x6613;&#x6CC4;&#x9732;&#xFF0C;&#x5426;&#x5219;&#x5C31;&#x6709;&#x76D7;&#x5237;&#x7684;&#x98CE;&#x9669;&#x3002;</p><p>&#x4EE5;&#x4E0A;&#xFF0C;OAuth2&#x7684;&#x5DE5;&#x4F5C;&#x539F;&#x7406;&#x5927;&#x81F4;&#x5982;&#x6B64;&#xFF0C;&#x7528;&#x6237;&#x4E0D;&#x7528;&#x62C5;&#x5FC3;&#x81EA;&#x5DF1;&#x7684;&#x5BC6;&#x7801;&#x66B4;&#x9732;&#x7ED9;&#x4E86;&#x7B2C;&#x4E09;&#x65B9;&#xFF0C;&#x800C;&#x53C8;&#x5B9E;&#x73B0;&#x4E86;&#x53D7;&#x4FDD;&#x62A4;&#x8D44;&#x6E90;&#x7684;&#x6388;&#x6743;&#x8BBF;&#x95EE;&#xFF0C;&#x5176;&#x4E2D;&#x5E97;&#x94FA;&#x88AB;&#x6388;&#x6743;&#x540E;&#x5F97;&#x5230;&#x51ED;&#x8BC1;&#x5C31;&#x662F;&#x6240;&#x8C13;&#x7684;&#x8BBF;&#x95EE;&#x4EE4;&#x724C;&#xFF0C;&#x5373;access_token&#x3002;OAuth2&#x534F;&#x8BAE;&#x4E2D;&#x6700;&#x4E3B;&#x8981;&#x7684;&#x4E00;&#x4E2A;&#x90E8;&#x5206;&#x5C31;&#x662F;&#x5982;&#x4F55;&#x83B7;&#x53D6;accessToken&#xFF0C;&#x5728;OAuth2&#x534F;&#x8BAE;&#x89C4;&#x8303;&#x6587;&#x6863;<a href="https://datatracker.ietf.org/doc/html/rfc6749#section-4.1">https://datatracker.ietf.org/doc/html/rfc6749</a>&#x4E2D;&#x4ECB;&#x7ECD;&#x4E86;&#x51E0;&#x79CD;&#x5E38;&#x7528;&#x7684;&#x6388;&#x6743;&#x6A21;&#x5F0F;&#xFF1A;</p><ul><li>&#x6388;&#x6743;&#x7801;&#x6A21;&#x5F0F;&#xFF08;Authorization Code Grant&#xFF09;&#xFF1A;&#x670D;&#x52A1;&#x7AEF;&#x901A;&#x8FC7;&#x91CD;&#x5B9A;&#x5411;&#x673A;&#x5236;&#xFF0C;&#x5C06;&#x4E00;&#x6B21;&#x6027;&#x7684;&#x6388;&#x6743;&#x7801;code&#x53C2;&#x6570;&#x4E0B;&#x53D1;&#x7ED9;&#x5BA2;&#x6237;&#x7AEF;&#xFF0C;&#x5BA2;&#x6237;&#x7AEF;&#x901A;&#x8FC7;code&#x83B7;&#x53D6;accessToken&#x548C;refreshToken&#xFF0C;&#x8FD9;&#x79CD;&#x6A21;&#x5F0F;&#x6BD4;&#x8F83;&#x5B8C;&#x6574;&#x5730;&#x4F53;&#x73B0;&#x4E86;OAuth2&#x534F;&#x8BAE;&#x7684;&#x539F;&#x5219;&#xFF0C;&#x6D41;&#x7A0B;&#x8F83;&#x4E3A;&#x590D;&#x6742;&#xFF0C;&#x4F46;&#x5B89;&#x5168;&#x6027;&#x6700;&#x597D;&#xFF0C;&#x56E0;&#x6B64;&#x4E5F;&#x662F;&#x6700;&#x5E38;&#x7528;&#x7684;&#x6A21;&#x5F0F;&#xFF0C;&#x5E7F;&#x6CDB;&#x8FD0;&#x7528;&#x4E8E;&#x5404;&#x7C7B;&#x4E92;&#x8054;&#x7F51;&#x5E94;&#x7528;&#x7684;&#x767B;&#x5F55;&#x8BA4;&#x8BC1;&#x573A;&#x666F;&#xFF0C;&#x4EA4;&#x4E92;&#x6D41;&#x7A0B;&#x89C1;&#x4E0B;&#x56FE;</li><li>&#x9690;&#x5F0F;&#x6A21;&#x5F0F;&#xFF08;Implicit Grant&#xFF09;&#xFF1A;&#x4E5F;&#x53EB;&#x7B80;&#x5316;&#x6A21;&#x5F0F;&#xFF0C;&#x6CA1;&#x6709;&#x91CD;&#x5B9A;&#x5411;&#x8FC7;&#x7A0B;&#xFF0C;&#x4E00;&#x6B21;&#x6388;&#x6743;&#x8BF7;&#x6C42;&#x5C31;&#x53EF;&#x4EE5;&#x83B7;&#x5F97;accessToken&#xFF0C;&#x901A;&#x5E38;&#x7528;&#x4E8E;&#x6D4F;&#x89C8;&#x5668;&#x811A;&#x672C;&#xFF0C;&#x4F8B;&#x5982;&#x5728;JavaScript&#x811A;&#x672C;&#x5185;&#x53D1;&#x8D77;&#x6388;&#x6743;&#x8BF7;&#x6C42;&#xFF0C;&#x6709;&#x4EE4;&#x724C;&#x6CC4;&#x9732;&#x7684;&#x98CE;&#x9669;&#xFF0C;&#x5B89;&#x5168;&#x6027;&#x4E00;&#x822C;&#xFF0C;&#x53E6;&#x5916;&#x4E5F;&#x4E0D;&#x652F;&#x6301;refreshToken</li><li>&#x8D44;&#x6E90;&#x5C5E;&#x4E3B;&#x5BC6;&#x7801;&#x6A21;&#x5F0F;&#xFF08;Resource Owner Password Credentials Grant&#xFF09;&#xFF1A;&#x7528;&#x6237;&#x9700;&#x8981;&#x5728;&#x7B2C;&#x4E09;&#x65B9;&#x5E94;&#x7528;&#x4E2D;&#x8F93;&#x5165;&#x7528;&#x6237;&#x540D;&#x548C;&#x5BC6;&#x7801;&#xFF0C;&#x4E0A;&#x9762;&#x63D0;&#x5230;&#x8FC7;&#xFF0C;&#x8FD9;&#x79CD;&#x6A21;&#x5F0F;&#x6709;&#x66B4;&#x9732;&#x5BC6;&#x7801;&#x7684;&#x98CE;&#x9669;&#xFF0C;&#x5B89;&#x5168;&#x6027;&#x8F83;&#x5DEE;&#xFF0C;&#x5728;OAuth2&#x5B98;&#x65B9;&#x63A8;&#x8350;&#x7684;&#x6700;&#x4F73;&#x5B9E;&#x8DF5;&#x4E2D;&#xFF0C;&#x5DF2;&#x7ECF;&#x660E;&#x786E;&#x7981;&#x6B62;&#x4F7F;&#x7528;&#x8FD9;&#x79CD;&#x6A21;&#x5F0F;&#xFF0C;&#x5E76;&#x4E14;&#x5728;Spring Security &#x9AD8;&#x7248;&#x672C;&#x4E2D;&#x4E5F;&#x5DF2;&#x7ECF;&#x5F03;&#x7528;</li><li>&#x5BA2;&#x6237;&#x7AEF;&#x51ED;&#x8BC1;&#x6A21;&#x5F0F;&#xFF08;Client Credentials Grant&#xFF09;&#xFF1A;&#x5E38;&#x7528;&#x4E8E;&#x8BBE;&#x5907;&#x6216;&#x8005;&#x53EF;&#x4FE1;&#x4EFB;&#x7684;&#x5E94;&#x7528;&#x672C;&#x8EAB;&#xFF0C;&#x901A;&#x8FC7;&#x5BA2;&#x6237;&#x7AEF;&#x51ED;&#x8BC1;&#x4E0E;OAuth2&#x76F4;&#x63A5;&#x901A;&#x4FE1;&#x8FDB;&#x884C;&#x8BA4;&#x8BC1;&#xFF0C;&#x5BF9;&#x7528;&#x6237;&#x65E0;&#x611F;</li></ul><figure class="kg-card kg-image-card"><img src="data:image/png;base64,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" class="kg-image" alt="Spring Security 6.x OAuth2&#x767B;&#x5F55;&#x8BA4;&#x8BC1;&#x6E90;&#x7801;&#x5206;&#x6790;" loading="lazy"></figure><p>OAuth2&#x672C;&#x8EAB;&#x662F;&#x4E00;&#x79CD;&#x534F;&#x8BAE;&#xFF0C;&#x5B83;&#x4E0D;&#x76F4;&#x63A5;&#x89C4;&#x5B9A;&#x5B9E;&#x73B0;&#x7EC6;&#x8282;&#xFF0C;&#x4E0B;&#x9762;&#x4E3B;&#x8981;&#x5C31;Spring Security&#x6846;&#x67B6;&#x5185;OAuth2&#x5BA2;&#x6237;&#x7AEF;&#x7684;&#x6E90;&#x7801;&#x4F5C;&#x4E00;&#x5B9A;&#x7684;&#x5206;&#x6790;&#xFF0C;&#x901A;&#x8FC7;&#x7814;&#x7A76;&#x5B83;&#x9ED8;&#x8BA4;&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x4E3A;&#x5C06;&#x6765;&#x6269;&#x5C55;&#x5BF9;&#x63A5;&#x5176;&#x4ED6;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x505A;&#x4E00;&#x5B9A;&#x53C2;&#x8003;&#x3002;</p><h2 id="%E4%BA%8C%E3%80%81oauth2%E7%99%BB%E5%BD%95%E8%AE%A4%E8%AF%81">&#x4E8C;&#x3001;OAuth2&#x767B;&#x5F55;&#x8BA4;&#x8BC1;</h2><p>Spring Security&#x96C6;&#x6210;&#x4E86;&#x56FD;&#x5916;&#x51E0;&#x4E2A;OAuth2&#x8BA4;&#x8BC1;&#x670D;&#x52A1;&#x5546;&#x7684;&#x9ED8;&#x8BA4;&#x5B9E;&#x73B0;&#xFF0C;&#x5305;&#x62EC;Google, GitHub, Facebook, &#x4EE5;&#x53CA;Okta&#xFF0C;&#x4E0B;&#x9762;&#x4EE5;Github&#x4E3A;&#x4F8B;&#xFF0C;&#x8BF4;&#x660E;OAuth2&#x767B;&#x5F55;&#x8BA4;&#x8BC1;&#xFF08;&#x6388;&#x6743;&#x7801;&#x6A21;&#x5F0F;&#xFF09;&#x7684;&#x6574;&#x4E2A;&#x4EA4;&#x4E92;&#x8FC7;&#x7A0B;&#x3002;</p><h3 id="21-oauth20%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%85%8D%E7%BD%AE">2.1 OAuth2.0&#x5BA2;&#x6237;&#x7AEF;&#x914D;&#x7F6E;</h3><p>&#x9ED8;&#x8BA4;&#x914D;&#x7F6E;&#x4E0B;&#xFF0C;&#x4EC5;&#x6DFB;&#x52A0;SecurityFilterChain&#x7684;oauth2Login&#x914D;&#x7F6E;&#x9879;&#x5373;&#x53EF;&#xFF0C;&#x5B83;&#x4E3B;&#x8981;&#x7684;&#x4F5C;&#x7528;&#x662F;&#x5411;&#x8FC7;&#x6EE4;&#x5668;&#x94FE;&#x4E2D;&#x6DFB;&#x52A0;&#x4E24;&#x4E2A;&#x8FC7;&#x6EE4;&#x5668;&#xFF1A;&#x5373;OAuth2AuthorizationRequestRedirectFilter&#x548C;OAuth2LoginAuthenticationFilter&#xFF08;&#x7B2C;2&#x5C0F;&#x8282;&#x548C;&#x7B2C;3&#x5C0F;&#x8282;&#x4F1A;&#x5206;&#x522B;&#x4ECB;&#x7ECD;&#x8FD9;&#x4E24;&#x4E2A;&#x7C7B;&#x7684;&#x5B9E;&#x73B0;&#x7EC6;&#x8282;&#xFF09;&#xFF0C;&#x4ED6;&#x4EEC;&#x5206;&#x522B;&#x8D1F;&#x8D23;&#x5904;&#x7406;&#x4E24;&#x4E2A;&#x7AEF;&#x70B9;&#xFF1A;</p><ul><li>/oauth2/authorization/{client}&#xFF0C;&#x5373;OAuth2&#x6388;&#x6743;&#x7AEF;&#x70B9;&#xFF0C;&#x7528;&#x4E8E;&#x5411;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x53D1;&#x8D77;&#x6388;&#x6743;&#x8BF7;&#x6C42;</li><li>/login/oauth2/code/{client}&#xFF0C;&#x5373;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x91CD;&#x5B9A;&#x5411;&#x7AEF;&#x70B9;&#xFF0C;&#x7528;&#x4E8E;&#x5728;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x91CD;&#x5B9A;&#x5411;&#x56DE;&#x5230;&#x672C;&#x5E94;&#x7528;&#x65F6;&#x63A5;&#x6536;code&#xFF0C;&#x4ECE;&#x800C;&#x5229;&#x7528;code&#x6362;&#x53D6;accessToken</li></ul><pre><code class="language-Java">@EnableWebSecurity
@Configuration
public class SpringSecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.oauth2Login(Customizer.withDefaults());
        return http.build();
    }
}</code></pre><p>&#x53E6;&#x5916;&#x5728;application.yaml&#x914D;&#x7F6E;&#x6587;&#x4EF6;&#x4E2D;&#x6CE8;&#x518C;Github&#x5BA2;&#x6237;&#x7AEF;&#xFF0C;&#x4E3B;&#x8981;&#x662F;&#x6307;&#x5B9A;client-id&#x548C;client-secret&#x8FD9;&#x4E24;&#x4E2A;&#x53C2;&#x6570; </p><blockquote>&#x901A;&#x5E38;&#xFF0C;client-id&#x548C;client-secret&#x7B49;&#x53C2;&#x6570;&#x90FD;&#x9700;&#x8981;&#x5728;Github&#x5B98;&#x7F51;&#x6CE8;&#x518C;&#x81EA;&#x5DF1;&#x7684;&#x5E94;&#x7528;&#x540E;&#xFF0C;&#x624D;&#x80FD;&#x62FF;&#x5230;&#x3002;&#x6CE8;&#x518C;&#x7684;&#x64CD;&#x4F5C;&#x6D41;&#x7A0B;&#x653E;&#x5728;&#x6587;&#x672B;&#x7684;&#x9644;&#x5F55;&#x4E2D;</blockquote><pre><code class="language-YAML">spring:
  security:
    oauth2:
      client:
        registration:
          github:
            client-id: *********
            client-secret: **********************</code></pre><p>&#x81F3;&#x4E8E;&#x5176;&#x4ED6;&#x53C2;&#x6570;&#xFF0C;&#x4F8B;&#x5982;authorization-uri&#xFF0C;token-uri&#x7B49;&#xFF0C;&#x5BF9;&#x4E8E;&#x4EFB;&#x4F55;&#x4E00;&#x4E2A;OAuth2&#x7684;&#x5BA2;&#x6237;&#x7AEF;&#x6765;&#x8BF4;&#x90FD;&#x662F;&#x901A;&#x7528;&#x7684;&#xFF0C;&#x6240;&#x4EE5;&#x90FD;&#x5DF2;&#x7ECF;&#x63D0;&#x524D;&#x5B9A;&#x4E49;&#x597D;&#x4E86;&#xFF0C;&#x5177;&#x4F53;&#x53EF;&#x4EE5;&#x770B;CommonOAuth2Provider&#x7684;&#x6E90;&#x7801;</p><pre><code class="language-Java">public enum CommonOAuth2Provider {
 ...
    GITHUB {

       @Override
       public Builder getBuilder(String registrationId) {
          ClientRegistration.Builder builder = getBuilder(registrationId,
                ClientAuthenticationMethod.CLIENT_SECRET_BASIC, DEFAULT_REDIRECT_URL);
          builder.scope(&quot;read:user&quot;);
          builder.authorizationUri(&quot;https://github.com/login/oauth/authorize&quot;);
          builder.tokenUri(&quot;https://github.com/login/oauth/access_token&quot;);
          builder.userInfoUri(&quot;https://api.github.com/user&quot;);
          builder.userNameAttributeName(&quot;id&quot;);
          builder.clientName(&quot;GitHub&quot;);
          return builder;
       }
...
}</code></pre><p>&#x5728;Spring Boot&#x4E2D;&#xFF0C;&#x5F53;&#x6211;&#x4EEC;&#x5728;&#x914D;&#x7F6E;&#x6587;&#x4EF6;&#x4E2D;&#x6DFB;&#x52A0;&#x4E86;spring.security.oauth2.client.registration&#x76F8;&#x5173;&#x5185;&#x5BB9;&#x65F6;&#xFF0C;&#x4F8B;&#x5982;&#x4E0A;&#x9762;&#x7684;github&#x914D;&#x7F6E;&#xFF0C;&#x5C31;&#x4F1A;&#x89E6;&#x53D1;&#x81EA;&#x52A8;&#x914D;&#x7F6E;&#x4EE5;&#x5B8C;&#x6210;&#x5BA2;&#x6237;&#x7AEF;&#x4FE1;&#x606F;&#x7684;&#x6CE8;&#x518C;&#xFF0C;&#x914D;&#x7F6E;&#x7C7B;&#x4E3A;OAuth2ClientRegistrationRepositoryConfiguration&#xFF0C;&#x5176;&#x4E2D;&#x6784;&#x5EFA;&#x8FC7;&#x7A0B;&#x4E3B;&#x8981;&#x7531;OAuth2ClientPropertiesMapper&#x8FD9;&#x4E2A;&#x7C7B;&#x5B8C;&#x6210;&#xFF0C;&#x6E90;&#x7801;&#x5982;&#x4E0B;</p><pre><code class="language-Java">@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(OAuth2ClientProperties.class)
@Conditional(ClientsConfiguredCondition.class)
class OAuth2ClientRegistrationRepositoryConfiguration {

    @Bean
    @ConditionalOnMissingBean(ClientRegistrationRepository.class)
    InMemoryClientRegistrationRepository clientRegistrationRepository(OAuth2ClientProperties properties) {
       List&lt;ClientRegistration&gt; registrations = new ArrayList&lt;&gt;(
             new OAuth2ClientPropertiesMapper(properties).asClientRegistrations().values());
       return new InMemoryClientRegistrationRepository(registrations);
    }

}

public final class OAuth2ClientPropertiesMapper {
...
    private static ClientRegistration getClientRegistration(String registrationId,
          OAuth2ClientProperties.Registration properties, Map&lt;String, Provider&gt; providers) {
       Builder builder = getBuilderFromIssuerIfPossible(registrationId, properties.getProvider(), providers);
       if (builder == null) {
          builder = getBuilder(registrationId, properties.getProvider(), providers);
       }
       PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
       map.from(properties::getClientId).to(builder::clientId);
       map.from(properties::getClientSecret).to(builder::clientSecret);
       map.from(properties::getClientAuthenticationMethod)
          .as(ClientAuthenticationMethod::new)
          .to(builder::clientAuthenticationMethod);
       map.from(properties::getAuthorizationGrantType)
          .as(AuthorizationGrantType::new)
          .to(builder::authorizationGrantType);
       map.from(properties::getRedirectUri).to(builder::redirectUri);
       map.from(properties::getScope).as(StringUtils::toStringArray).to(builder::scope);
       map.from(properties::getClientName).to(builder::clientName);
       return builder.build();
    }
...    
}</code></pre><p>OAuth2ClientPropertiesMapper#getBuilder&#x65B9;&#x6CD5;&#x4F1A;&#x6839;&#x636E;application.yml&#x914D;&#x7F6E;&#x6587;&#x4EF6;&#x4E2D;&#x914D;&#x7F6E;&#x7684;&#x5BA2;&#x6237;&#x7AEF;&#x540D;&#x79F0;&#xFF0C;&#x4ECE;CommonOAuth2Provider&#x679A;&#x4E3E;&#x7C7B;&#x4E2D;&#x5F97;&#x5230;&#x5BF9;&#x5E94;&#x679A;&#x4E3E;&#x503C;, &#x5373;&#x201C;GITHUB&#x201D;&#xFF0C;&#x5E76;&#x8C03;&#x7528;&#x5176;getBuilder&#x65B9;&#x6CD5;&#x8FD4;&#x56DE;builder&#x5BF9;&#x8C61;&#xFF0C;&#x7136;&#x540E;&#x4F7F;&#x7528;&#x914D;&#x7F6E;&#x6587;&#x4EF6;&#x4E2D;&#x7684;&#x53C2;&#x6570;&#x503C;&#x8FDB;&#x884C;&#x586B;&#x5145;&#xFF0C;&#x6700;&#x7EC8;&#x5F97;&#x5230;&#x5B8C;&#x6574;&#x7684;&#x5BA2;&#x6237;&#x7AEF;&#x6CE8;&#x518C;&#x4FE1;&#x606F;&#x3002;</p><h3 id="22-oauth2authorizationrequestredirectfilter%EF%BC%9A%E6%8F%90%E4%BA%A4%E6%8E%88%E6%9D%83%E8%AF%B7%E6%B1%82">2.2 <strong><strong><strong>OAuth2AuthorizationRequestRedirectFilter&#xFF1A;&#x63D0;&#x4EA4;&#x6388;&#x6743;&#x8BF7;&#x6C42;</strong></strong></strong></h3><p>&#x8BE5;Filter&#x7EE7;&#x627F;&#x81EA;OncePerRequestFilter&#xFF0C;&#x7528;&#x4E8E;&#x5411;OAuth2&#x534F;&#x8BAE;&#x670D;&#x52A1;&#x7AEF;&#x53D1;&#x8D77;&#x8BA4;&#x8BC1;&#x8BF7;&#x6C42;&#xFF0C;&#x6838;&#x5FC3;&#x903B;&#x8F91;&#x4E5F;&#x6BD4;&#x8F83;&#x7B80;&#x5355;&#xFF0C;&#x5176;&#x4E2D;doFilterInternal&#x6838;&#x5FC3;&#x6E90;&#x7801;&#x5982;&#x4E0B;</p><pre><code class="language-Java">@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
       throws ServletException, IOException {
    try {
       OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestResolver.resolve(request);
       if (authorizationRequest != null) {
          this.sendRedirectForAuthorization(request, response, authorizationRequest);
          return;
       }
    }
    catch (Exception ex) {
       this.unsuccessfulRedirectForAuthorization(request, response, ex);
       return;
    }
    ...
}</code></pre><p>&#x5F53;&#x8BF7;&#x6C42;&#x201C;/oauth2/authorization/{registrationId}&#x201D;&#x7AEF;&#x70B9;&#x65F6;&#xFF0C;authorizationRequestResolver&#x5C31;&#x4F1A;&#x89E3;&#x6790;&#x51FA;{registrationId}&#x5BF9;&#x5E94;&#x7684;&#x503C;&#xFF0C;&#x5982;github&#xFF0C;&#x7136;&#x540E;&#x901A;&#x8FC7;registrationId&#x67E5;&#x8BE2;&#x5230;&#x5BF9;&#x5E94;&#x5BA2;&#x6237;&#x7AEF;&#x7684;&#x6CE8;&#x518C;&#x4FE1;&#x606F;&#xFF0C;&#x5E76;&#x901A;&#x8FC7;&#x6784;&#x9020;&#x5668;OAuth2AuthorizationRequest.Builder&#xFF0C;&#x521B;&#x5EFA;&#x51FA;&#x4E00;&#x4E2A;OAuth2AuthorizationRequest&#x5B9E;&#x4F8B;&#xFF0C;&#x5B83;&#x4E3B;&#x8981;&#x4F5C;&#x7528;&#x5C31;&#x662F;&#x751F;&#x6210;&#x91CD;&#x5B9A;&#x5411;&#x5230;OAuth2.0&#x670D;&#x52A1;&#x7AEF;&#x83B7;&#x53D6;code&#x7684;&#x5730;&#x5740;&#xFF0C;&#x5BF9;&#x4E8E;github&#x6765;&#x8BF4;&#xFF0C;&#x8BE5;&#x5730;&#x5740;&#x4E3A;https://github.com/login/oauth/authorize?response_type=code&amp;client_id={client_id}&amp;scope=read:user&amp;state={state}&amp;redirect_uri={redirect_uri}&#xFF0C;&#x5176;&#x4E2D;state&#x662F;&#x7531;&#x5BA2;&#x6237;&#x7AEF;&#x751F;&#x6210;&#x7684;&#x4E00;&#x4E2A;&#x968F;&#x673A;&#x5B57;&#x7B26;&#x4E32;&#xFF0C;&#x5728;Spring Security&#x6846;&#x67B6;&#x4E2D;&#xFF0C;&#x4F7F;&#x7528;&#x4E86;32&#x4F4D;&#x957F;&#x5EA6;&#x7684;Base64&#x7F16;&#x7801;&#x751F;&#x6210;&#x7B97;&#x6CD5;&#xFF0C;&#x800C;redirect_uri&#x5219;&#x8868;&#x793A;&#x671F;&#x671B;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x5728;&#x901A;&#x8FC7;&#x9A8C;&#x8BC1;&#x540E;&#x91CD;&#x5B9A;&#x5411;&#x5230;&#x672C;&#x7CFB;&#x7EDF;&#x7684;&#x5730;&#x5740;&#xFF0C;&#x4EE5;&#x4FBF;&#x4ECE;&#x54CD;&#x5E94;&#x4E2D;&#x83B7;&#x53D6;code&#x4E4B;&#x540E;&#x53D1;&#x8D77;&#x8BA4;&#x8BC1;&#xFF0C;&#x5F53;&#x7136;&#x8FD9;&#x4E2A;redirectUri&#x9700;&#x8981;&#x4E8B;&#x5148;&#x6CE8;&#x518C;&#x5728;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x4E2D;&#xFF0C;&#x5426;&#x5219;&#x89C6;&#x4E3A;&#x975E;&#x6388;&#x6743;&#x7684;&#x8BBF;&#x95EE;&#x800C;&#x62D2;&#x7EDD;&#x3002;</p><pre><code class="language-Java">private OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId, String redirectUriAction) {
    if (registrationId == null) {
       return null;
    }
    ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
    if (clientRegistration == null) {
       throw new InvalidClientRegistrationIdException(&quot;Invalid Client Registration with Id: &quot; + registrationId);
    }
    OAuth2AuthorizationRequest.Builder builder = getBuilder(clientRegistration);

    String redirectUriStr = expandRedirectUri(request, clientRegistration, redirectUriAction);

    // @formatter:off
    builder.clientId(clientRegistration.getClientId())
          .authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
          .redirectUri(redirectUriStr)
          .scopes(clientRegistration.getScopes())
          .state(DEFAULT_STATE_GENERATOR.generateKey());
    // @formatter:on

    this.authorizationRequestCustomizer.accept(builder);

    return builder.build();
}</code></pre><p>&#x800C;&#x5728;&#x91CD;&#x5B9A;&#x5411;&#x4E4B;&#x524D;&#xFF0C;&#x4E3A;&#x4E86;&#x5728;&#x8BA4;&#x8BC1;&#x901A;&#x8FC7;&#x4E4B;&#x540E;&#x80FD;&#x591F;&#x8DF3;&#x8F6C;&#x56DE;&#x8BA4;&#x8BC1;&#x524D;&#x7684;&#x8BBF;&#x95EE;&#x8DEF;&#x5F84;&#xFF0C;&#x9700;&#x8981;&#x4FDD;&#x5B58;&#x5F53;&#x524D;&#x8BF7;&#x6C42;&#x7684;&#x5730;&#x5740;&#xFF0C;&#x5728;authorizationRequestRepository#saveAuthorizationRequest&#x65B9;&#x6CD5;&#x4E2D;&#xFF0C;&#x4F1A;&#x5C06;&#x5F53;&#x524D;&#x8BF7;&#x6C42;&#x5B58;&#x50A8;&#x5230;session&#x4E2D;&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x53EF;&#x4EE5;&#x5728;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x56DE;&#x8C03;&#x4E4B;&#x540E;&#xFF0C;&#x518D;&#x4ECE;session&#x53D6;&#x51FA;&#x3002;</p><pre><code class="language-Java">private void sendRedirectForAuthorization(HttpServletRequest request, HttpServletResponse response,
       OAuth2AuthorizationRequest authorizationRequest) throws IOException {
    if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(authorizationRequest.getGrantType())) {
       this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request, response);
    }
    this.authorizationRedirectStrategy.sendRedirect(request, response,
          authorizationRequest.getAuthorizationRequestUri());
}

public void saveAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest, HttpServletRequest request,
       HttpServletResponse response) {
    Assert.notNull(request, &quot;request cannot be null&quot;);
    Assert.notNull(response, &quot;response cannot be null&quot;);
    if (authorizationRequest == null) {
       removeAuthorizationRequest(request, response);
       return;
    }
    String state = authorizationRequest.getState();
    Assert.hasText(state, &quot;authorizationRequest.state cannot be empty&quot;);
    request.getSession().setAttribute(this.sessionAttributeName, authorizationRequest);
}</code></pre><p>OAuth2&#x670D;&#x52A1;&#x7AEF;&#x5728;&#x63A5;&#x53D7;&#x5230;&#x8BE5;&#x8BF7;&#x6C42;&#x4E4B;&#x540E;&#xFF0C;&#x5982;&#x679C;&#x4E00;&#x5207;&#x6B63;&#x5E38;&#xFF0C;&#x5219;&#x4F1A;&#x751F;&#x6210;&#x4E00;&#x4E2A;&#x4E34;&#x65F6;&#x7684;code&#xFF0C;&#x7136;&#x540E;&#x8FDE;&#x540C;&#x8BF7;&#x6C42;&#x53C2;&#x6570;&#x4E2D;state&#x4E00;&#x8D77;&#x62FC;&#x63A5;&#x5230;redirect_uri&#x7684;&#x53C2;&#x6570;&#x4E2D;&#xFF0C;&#x4F8B;&#x5982;https://{domain}/login/oauth2/code/github?code={code}&amp;state={state in request}&#xFF0C;&#x6700;&#x540E;&#x53D1;&#x8D77;&#x91CD;&#x5B9A;&#x5411;&#xFF0C;&#x6B64;&#x65F6;&#x8BF7;&#x6C42;&#x5C31;&#x4F1A;&#x8FDB;&#x5165;&#x8FC7;&#x6EE4;&#x5668;OAuth2LoginAuthenticationFilter&#x3002;</p><h3 id="23-oauth2loginauthenticationfilter%EF%BC%9A%E5%8F%91%E8%B5%B7%E8%AE%A4%E8%AF%81">2.3 OAuth2LoginAuthenticationFilter&#xFF1A;&#x53D1;&#x8D77;&#x8BA4;&#x8BC1;</h3><p>&#x8BE5;&#x8FC7;&#x6EE4;&#x5668;&#x7EE7;&#x627F;&#x81EA;AbstractAuthenticationProcessingFilter&#xFF0C;&#x663E;&#x7136;&#xFF0C;&#x5B83;&#x7684;&#x4F5C;&#x7528;&#x4E3B;&#x8981;&#x662F;&#x7528;&#x4E8E;&#x5B8C;&#x6210;OAuth2&#x7684;&#x8BA4;&#x8BC1;&#x8FC7;&#x7A0B;&#xFF0C;&#x6700;&#x7EC8;&#x751F;&#x6210;&#x8BA4;&#x8BC1;&#x5BF9;&#x8C61;&#x3002;&#x5177;&#x4F53;&#x770B;&#x4E00;&#x4E0B;attemptAuthentication&#x65B9;&#x6CD5;&#xFF0C;&#x8FD9;&#x91CC;&#x521B;&#x5EFA;&#x51FA;&#x6765;&#x7684;&#x5BF9;&#x8C61;&#x7A0D;&#x5FAE;&#x6709;&#x70B9;&#x590D;&#x6742;&#xFF0C;&#x5148;&#x68B3;&#x7406;&#x4E00;&#x4E0B;&#x5F15;&#x7528;&#x5173;&#x7CFB;&#xFF1A;</p><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/05/--2024-05-26-21.37.19.png" class="kg-image" alt="Spring Security 6.x OAuth2&#x767B;&#x5F55;&#x8BA4;&#x8BC1;&#x6E90;&#x7801;&#x5206;&#x6790;" loading="lazy" width="798" height="686" srcset="http://www.fullstackyang.com/content/images/size/w600/2024/05/--2024-05-26-21.37.19.png 600w, http://www.fullstackyang.com/content/images/2024/05/--2024-05-26-21.37.19.png 798w" sizes="(min-width: 720px) 720px"></figure><p>&#x8FD9;&#x91CC;&#xFF0C;OAuth2AuthorizationRequest&#x4EE3;&#x8868;&#x4E86;&#x6B64;&#x524D;&#x63D0;&#x4EA4;&#x6388;&#x6743;&#x7684;&#x8BF7;&#x6C42;&#xFF0C;&#x4E0A;&#x6587;&#x6709;&#x63D0;&#x5230;&#xFF0C;&#x5373;&#x4FDD;&#x5B58;&#x5728;session&#x4E2D;&#x7684;&#x8BF7;&#x6C42;&#x5BF9;&#x8C61;&#xFF0C;&#x800C;OAuth2AuthorizationResponse&#x4EE3;&#x8868;&#x4E86;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x91CD;&#x5B9A;&#x5411;&#x56DE;&#x6765;&#x7684;&#x54CD;&#x5E94;&#xFF0C;&#x5176;&#x4E2D;&#x4E5F;&#x5C01;&#x88C5;&#x4E86;&#x8BF7;&#x6C42;&#x65F6;&#x643A;&#x5E26;&#x8FC7;&#x53BB;&#x7684;state&#x53C2;&#x6570;&#xFF0C;&#x4ED6;&#x4EEC;&#x6784;&#x9020;&#x4E86;&#x4E00;&#x4E2A;OAuth2AuthorizationExchange&#x5BF9;&#x8C61;&#xFF0C;&#x5E76;&#x8FDE;&#x540C;ClientRegistration&#x4E00;&#x5E76;&#x88AB;&#x5C01;&#x88C5;&#x5230;&#x4E86;OAuth2LoginAuthenticationToken&#x5BF9;&#x8C61;&#x4E2D;&#xFF0C;&#x8BE5;&#x5BF9;&#x8C61;&#x7528;&#x4E8E;&#x5728;OAuth2LoginAuthenticationProvider&#x53D1;&#x8D77;&#x8BA4;&#x8BC1;&#x8BF7;&#x6C42;&#x65F6;&#x63D0;&#x53D6;&#x5404;&#x79CD;&#x53C2;&#x6570;&#x3002;</p><p>&#x4EE5;&#x4E0B;&#x662F;&#x6E90;&#x7801;&#x7684;&#x5B9E;&#x73B0;&#x7EC6;&#x8282;&#xFF1A;</p><pre><code class="language-Java">public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
       throws AuthenticationException {
    MultiValueMap&lt;String, String&gt; params = OAuth2AuthorizationResponseUtils.toMultiMap(request.getParameterMap());
    // &#x2460;
    if (!OAuth2AuthorizationResponseUtils.isAuthorizationResponse(params)) {
       OAuth2Error oauth2Error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST);
       throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
    }
    OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestRepository
       .removeAuthorizationRequest(request, response); // &#x2461;
    if (authorizationRequest == null) {
       OAuth2Error oauth2Error = new OAuth2Error(AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE);
       throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
    }
    String registrationId = authorizationRequest.getAttribute(OAuth2ParameterNames.REGISTRATION_ID);
    ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
    // &#x2462;
    if (clientRegistration == null) {
       OAuth2Error oauth2Error = new OAuth2Error(CLIENT_REGISTRATION_NOT_FOUND_ERROR_CODE,
             &quot;Client Registration not found with Id: &quot; + registrationId, null);
       throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
    }
    // @formatter:off
    String redirectUri = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
          .replaceQuery(null)
          .build()
          .toUriString();
    // @formatter:on
    OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponseUtils.convert(params,
          redirectUri);
    // &#x2463;      
    Object authenticationDetails = this.authenticationDetailsSource.buildDetails(request);
    OAuth2LoginAuthenticationToken authenticationRequest = new OAuth2LoginAuthenticationToken(clientRegistration,
          new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse));
    authenticationRequest.setDetails(authenticationDetails);
    // &#x2464;
    OAuth2LoginAuthenticationToken authenticationResult = (OAuth2LoginAuthenticationToken) this
       .getAuthenticationManager()
       .authenticate(authenticationRequest); // &#x2465;
    OAuth2AuthenticationToken oauth2Authentication = this.authenticationResultConverter
       .convert(authenticationResult); // &#x2466;
    Assert.notNull(oauth2Authentication, &quot;authentication result cannot be null&quot;);
    oauth2Authentication.setDetails(authenticationDetails);
    OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
          authenticationResult.getClientRegistration(), oauth2Authentication.getName(),
          authenticationResult.getAccessToken(), authenticationResult.getRefreshToken());
    // &#x2467;
    this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, oauth2Authentication, request, response);
    return oauth2Authentication;
}</code></pre><ol><li>&#x68C0;&#x67E5;URL&#x53C2;&#x6570;&#x662F;&#x5426;&#x6709;&#x6548;&#xFF0C;&#x5373;&#x662F;&#x5426;&#x5305;&#x542B;&#x4E86;code&#x548C;state</li><li>&#x901A;&#x8FC7;authorizationRequestRepository&#x67E5;&#x8BE2;&#x8BA4;&#x8BC1;&#x4E4B;&#x524D;&#x5B58;&#x50A8;&#x5728;session&#x4E2D;&#x7684;request&#x5BF9;&#x8C61;&#xFF0C;&#x5373;<strong>authorizationRequest</strong>&#xFF0C;&#x540C;&#x65F6;&#x8FD8;&#x8981;&#x5C06;&#x5176;&#x5220;&#x9664;&#xFF0C;&#x4EE5;&#x4FDD;&#x8BC1;&#x4E00;&#x4E2A;&#x5BF9;&#x5E94;&#x7684;code&#xFF0C;&#x53EA;&#x80FD;&#x88AB;&#x5904;&#x7406;&#x4E00;&#x6B21;&#xFF0C;&#x540C;&#x65F6;&#x5982;&#x679C;&#x6CA1;&#x6709;&#x67E5;&#x8BE2;&#x5230;&#x5BF9;&#x5E94;&#x7684;request&#x5BF9;&#x8C61;&#xFF0C;&#x4E5F;&#x4E0D;&#x4F1A;&#x7EE7;&#x7EED;&#x6267;&#x884C;&#xFF0C;&#x4ECE;&#x800C;&#x4E5F;&#x675C;&#x7EDD;&#x4E86;&#x5176;&#x4ED6;&#x4F2A;&#x9020;&#x7684;&#x91CD;&#x5B9A;&#x5411;&#x8BF7;&#x6C42;&#x8FDB;&#x5165;&#x7CFB;&#x7EDF;&#xFF0C;&#x8FD9;&#x4E00;&#x6B65;&#x8FD8;&#x662F;&#x6BD4;&#x8F83;&#x91CD;&#x8981;&#x7684;&#xFF0C;&#x5B83;&#x4E25;&#x683C;&#x7EA6;&#x675F;&#x4E86;&#x4E00;&#x4E2A;&#x53D1;&#x8D77;&#x6388;&#x6743;&#x8BF7;&#x6C42;&#x548C;&#x63A5;&#x53D7;&#x670D;&#x52A1;&#x7AEF;&#x54CD;&#x5E94;&#x5FC5;&#x987B;&#x6210;&#x5BF9;&#x5339;&#x914D;&#xFF0C;&#x5426;&#x5219;&#x6574;&#x4E2A;OAuth2&#x6388;&#x6743;&#x7801;&#x6D41;&#x7A0B;&#x5C31;&#x65E0;&#x6CD5;&#x6267;&#x884C;</li><li>&#x8FD9;&#x4E2A;request&#x5BF9;&#x8C61;&#x4E2D;&#x4FDD;&#x5B58;&#x4E86;&#x5BA2;&#x6237;&#x7AEF;&#x7684;registrationId&#xFF0C;&#x56E0;&#x6B64;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;clientRegistrationRepository&#x67E5;&#x8BE2;&#x5230;&#x5BF9;&#x5E94;&#x7684;&#x5BA2;&#x6237;&#x7AEF;&#x4FE1;&#x606F;&#xFF0C;&#x5373;<strong>clientRegistration</strong></li><li>&#x540C;&#x65F6;&#x518D;&#x6839;&#x636E;code&#x548C;state&#x53C2;&#x6570;&#xFF0C;&#x4EE5;&#x53CA;&#x5F53;&#x524D;request&#x8BF7;&#x6C42;&#x7684;url&#x4F5C;&#x4E3A;redirectUri&#xFF0C;&#x6784;&#x9020;&#x51FA;&#x4E00;&#x4E2A;OAuth2AuthorizationResponse&#x5BF9;&#x8C61;&#xFF0C;&#x5373;<strong>authorizationResponse</strong></li><li>&#x5728;&#x5F97;&#x5230;<strong>clientRegistration</strong>&#xFF0C;<strong>authorizationRequest</strong>&#xFF0C;<strong>authorizationResponse</strong>&#x4E09;&#x4E2A;&#x5B9E;&#x4F8B;&#x4E4B;&#x540E;&#xFF0C;&#x518D;&#x6784;&#x9020;&#x51FA;&#x4E00;&#x4E2A;<strong>OAuth2LoginAuthenticationToken</strong>&#x5B9E;&#x4F8B;&#xFF0C;&#x5B83;&#x4FBF;&#x662F;&#x7528;&#x6765;&#x53D1;&#x8D77;OAuth2&#x8BA4;&#x8BC1;&#x7684;&#x5B9E;&#x9645;&#x5BF9;&#x8C61;</li><li>OAuth2&#x8BA4;&#x8BC1;&#x8FC7;&#x7A0B;&#x4EA4;&#x7531;OAuth2LoginAuthenticationProvider&#x6267;&#x884C;&#xFF08;&#x5177;&#x4F53;&#x7EC6;&#x8282;&#x5728;&#x4E0B;&#x4E00;&#x8282;&#x4E2D;&#x4ECB;&#x7ECD;&#xFF09;</li><li>&#x8BA4;&#x8BC1;&#x901A;&#x8FC7;&#x540E;&#xFF0C;&#x7ED3;&#x679C;&#x8FD4;&#x56DE;&#x4E86;&#x4E00;&#x4E2A;OAuth2LoginAuthenticationToken&#x5BF9;&#x8C61;&#xFF0C;&#x8FD9;&#x4E2A;&#x5BF9;&#x8C61;&#x4E3B;&#x8981;&#x662F;&#x7528;&#x4E8E;&#x5C01;&#x88C5;&#x6388;&#x6743;&#x7801;&#x6A21;&#x5F0F;&#x7684;&#x8BA4;&#x8BC1;&#x7ED3;&#x679C;&#xFF0C;&#x7ECF;&#x8FC7;&#x8F6C;&#x6362;&#xFF0C;&#x5C06;&#x5176;principal&#xFF0C;authorities&#xFF0C;&#x548C;clientRegistration&#x7684;RegistrationId&#x53D6;&#x51FA;&#xFF0C;&#x6700;&#x7EC8;&#x6784;&#x9020;&#x51FA;&#x4E00;&#x4E2A;&#x6807;&#x51C6;&#x7684;OAuth2&#x8BA4;&#x8BC1;&#x5BF9;&#x8C61;&#xFF0C;&#x5373;<strong>OAuth2AuthenticationToken</strong></li></ol><h3 id="24-oauth2loginauthenticationprovider%EF%BC%9A%E8%8E%B7%E5%8F%96accesstoken">2.4 OAuth2LoginAuthenticationProvider&#xFF1A;&#x83B7;&#x53D6;AccessToken</h3><p>&#x8FD9;&#x4E2A;Provider&#x7684;&#x4F5C;&#x7528;&#x4E3B;&#x8981;&#x5305;&#x62EC;&#x4E24;&#x4E2A;&#x90E8;&#x5206;&#xFF0C;&#x4E00;&#x662F;&#x8BF7;&#x6C42;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x83B7;&#x53D6;AccessToken&#xFF0C;&#x4E8C;&#x662F;&#x83B7;&#x53D6;&#x670D;&#x52A1;&#x7AEF;&#x7528;&#x6237;&#x4FE1;&#x606F;&#xFF0C;&#x524D;&#x8005;&#x59D4;&#x6258;&#x7ED9;&#x4E86;OAuth2AuthorizationCodeAuthenticationProvider&#x6765;&#x6267;&#x884C;&#x5177;&#x4F53;&#x8BF7;&#x6C42;&#x7684;&#x903B;&#x8F91;&#xFF0C;&#x800C;&#x540E;&#x8005;&#x5219;&#x901A;&#x8FC7;UserService&#x5B9E;&#x4F8B;&#x8BF7;&#x6C42;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x7684;UserInfo&#x76F8;&#x5173;&#x7AEF;&#x70B9;&#xFF0C;&#x83B7;&#x53D6;&#x7528;&#x6237;&#x4FE1;&#x606F;&#xFF0C;&#x6700;&#x540E;&#x4E0A;&#x8FF0;AccessToken&#x76F8;&#x5173;&#x4FE1;&#x606F;&#xFF0C;&#x4EE5;&#x53CA;&#x7528;&#x6237;&#x4FE1;&#x606F;&#x88AB;&#x5C01;&#x88C5;&#x6210;OAuth2LoginAuthenticationToken&#x8BA4;&#x8BC1;&#x5BF9;&#x8C61;&#x8FD4;&#x56DE;&#x3002;</p><pre><code class="language-Java">public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    OAuth2LoginAuthenticationToken loginAuthenticationToken = (OAuth2LoginAuthenticationToken) authentication;
    ...
    OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthenticationToken;
    try {
       authorizationCodeAuthenticationToken = (OAuth2AuthorizationCodeAuthenticationToken) this.authorizationCodeAuthenticationProvider
          .authenticate(
                new OAuth2AuthorizationCodeAuthenticationToken(loginAuthenticationToken.getClientRegistration(),
                      loginAuthenticationToken.getAuthorizationExchange()));
    }
    catch (OAuth2AuthorizationException ex) {
       OAuth2Error oauth2Error = ex.getError();
       throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), ex);
    }
    OAuth2AccessToken accessToken = authorizationCodeAuthenticationToken.getAccessToken();
    Map&lt;String, Object&gt; additionalParameters = authorizationCodeAuthenticationToken.getAdditionalParameters();
    OAuth2User oauth2User = this.userService.loadUser(new OAuth2UserRequest(
          loginAuthenticationToken.getClientRegistration(), accessToken, additionalParameters));
    Collection&lt;? extends GrantedAuthority&gt; mappedAuthorities = this.authoritiesMapper
       .mapAuthorities(oauth2User.getAuthorities());
    OAuth2LoginAuthenticationToken authenticationResult = new OAuth2LoginAuthenticationToken(
          loginAuthenticationToken.getClientRegistration(), loginAuthenticationToken.getAuthorizationExchange(),
          oauth2User, mappedAuthorities, accessToken, authorizationCodeAuthenticationToken.getRefreshToken());
    authenticationResult.setDetails(loginAuthenticationToken.getDetails());
    return authenticationResult;
}
</code></pre><p>&#x4E0B;&#x9762;&#x518D;&#x770B;&#x4E00;&#x4E0B;OAuth2LoginAuthenticationProvider#authenticate&#x65B9;&#x6CD5;&#x7684;&#x6E90;&#x7801;&#xFF1A;</p><pre><code class="language-Java">public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication = (OAuth2AuthorizationCodeAuthenticationToken) authentication;
    OAuth2AuthorizationResponse authorizationResponse = authorizationCodeAuthentication.getAuthorizationExchange()
       .getAuthorizationResponse();
    if (authorizationResponse.statusError()) {
       throw new OAuth2AuthorizationException(authorizationResponse.getError());
    }
    OAuth2AuthorizationRequest authorizationRequest = authorizationCodeAuthentication.getAuthorizationExchange()
       .getAuthorizationRequest();
    if (!authorizationResponse.getState().equals(authorizationRequest.getState())) { // &#x2460;
       OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE);
       throw new OAuth2AuthorizationException(oauth2Error);
    }
    OAuth2AccessTokenResponse accessTokenResponse = this.accessTokenResponseClient.getTokenResponse(
          new OAuth2AuthorizationCodeGrantRequest(authorizationCodeAuthentication.getClientRegistration(),
                authorizationCodeAuthentication.getAuthorizationExchange())); // &#x2461;
    OAuth2AuthorizationCodeAuthenticationToken authenticationResult = new OAuth2AuthorizationCodeAuthenticationToken(
          authorizationCodeAuthentication.getClientRegistration(),
          authorizationCodeAuthentication.getAuthorizationExchange(), accessTokenResponse.getAccessToken(),
          accessTokenResponse.getRefreshToken(), accessTokenResponse.getAdditionalParameters());  // &#x2462;
    authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
    return authenticationResult;
}</code></pre><ol><li>authorizationRequest&#x4E2D;&#x5305;&#x542B;&#x4E86;&#x8BF7;&#x6C42;&#x65F6;&#x643A;&#x5E26;&#x7684;state&#xFF0C;&#x800C;authorizationResponse&#x4E2D;&#x5305;&#x542B;&#x4E86;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x91CD;&#x5B9A;&#x5411;URL&#x4E2D;&#x643A;&#x5E26;&#x7684;state&#xFF0C;&#x901A;&#x8FC7;&#x4E24;&#x4E2A;state&#x53C2;&#x6570;&#x7684;&#x6BD4;&#x8F83;&#xFF0C;&#x6821;&#x9A8C;&#x662F;&#x5426;&#x4E3A;&#x975E;&#x6CD5;&#x7684;&#x91CD;&#x5B9A;&#x5411;&#x5730;&#x5740;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x6821;&#x9A8C;state&#x662F;&#x5426;&#x4E00;&#x81F4;&#xFF0C;&#x5F53;&#x5176;&#x4ED6;&#x8D26;&#x53F7;&#x6B63;&#x5E38;&#x6388;&#x6743;&#x65F6;&#x91CD;&#x5B9A;&#x5411;&#x7684;&#x5730;&#x5740;&#x88AB;&#x53E6;&#x4E00;&#x4E2A;&#x4EBA;&#x70B9;&#x51FB;&#x4E86;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x80FD;&#x53D1;&#x751F;&#x7528;&#x6237;&#x5728;&#x6BEB;&#x65E0;&#x5BDF;&#x89C9;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#x767B;&#x5F55;&#x5176;&#x4ED6;&#x4EBA;&#x8D26;&#x53F7;&#x7684;&#x60C5;&#x51B5;&#xFF0C;&#x4ECE;&#x800C;&#x5BFC;&#x81F4;&#x4FE1;&#x606F;&#x6CC4;&#x9732;</li><li>accessTokenResponseClient&#x5411;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x53D1;&#x8D77;&#x8BA4;&#x8BC1;&#x8BF7;&#x6C42;&#xFF0C;&#x8BF7;&#x6C42;&#x5730;&#x5740;&#x5B58;&#x50A8;&#x5728;ClientRegistration&#x4E2D;&#x7684;tokenUri&#xFF0C;&#x5373;https://github.com/login/oauth/access_token&#xFF0C;&#x8BF7;&#x6C42;&#x4F53;&#x53C2;&#x6570;&#x5219;&#x5305;&#x62EC;code&#xFF0C;redirect_uri&#xFF0C;grant_type&#xFF0C;&#x53E6;&#x5916;&#x8FD8;&#x52A0;&#x5165;&#x4E86;Authorization&#x7684;&#x8BF7;&#x6C42;&#x5934;&#xFF0C;&#x5176;&#x5C5E;&#x6027;&#x503C;&#x662F;&#x7528;client_id&#x548C;client_serect&#x62FC;&#x63A5;&#x540E;&#x7F16;&#x7801;&#x51FA;&#x6765;&#x7684;&#x4E00;&#x4E2A;&#x5B57;&#x7B26;&#x4E32;&#xFF0C;&#x7528;&#x4E8E;&#x5411;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x8BC1;&#x660E;&#x5BA2;&#x6237;&#x7AEF;&#x7684;&#x771F;&#x5B9E;&#x6027;</li><li>OAuth2&#x670D;&#x52A1;&#x7AEF;&#x901A;&#x8FC7;&#x8BA4;&#x8BC1;&#x540E;&#x5C31;&#x4F1A;&#x8FD4;&#x56DE;AccessToken&#xFF0C;&#x4EE5;&#x53CA;&#x521B;&#x5EFA;&#x65F6;&#x95F4;&#xFF0C;&#x8FC7;&#x671F;&#x65F6;&#x95F4;&#x7B49;&#x4FE1;&#x606F;&#xFF0C;&#x6700;&#x540E;&#x5C01;&#x88C5;&#x6210;OAuth2AuthorizationCodeAuthenticationToken&#x8BA4;&#x8BC1;&#x5BF9;&#x8C61;&#x8FD4;&#x56DE;</li></ol><h3 id="25-oauth2userservice%EF%BC%9A%E8%AE%BF%E9%97%AE%E5%8F%97%E4%BF%9D%E6%8A%A4%E8%B5%84%E6%BA%90">2.5 OAuth2UserService&#xFF1A;&#x8BBF;&#x95EE;&#x53D7;&#x4FDD;&#x62A4;&#x8D44;&#x6E90;</h3><p>&#x4E0A;&#x6587;&#x63D0;&#x5230;&#xFF0C;&#x9700;&#x8981;&#x8BF7;&#x6C42;OAuth2&#x670D;&#x52A1;&#x7AEF;&#x83B7;&#x53D6;&#x7528;&#x6237;&#x4FE1;&#x606F;&#xFF0C;&#x7528;&#x6237;&#x4FE1;&#x606F;&#x662F;&#x670D;&#x52A1;&#x7AEF;&#x4FDD;&#x62A4;&#x7684;&#x8D44;&#x6E90;&#xFF0C;&#x5305;&#x542B;&#x4E86;&#x5728;Github&#x4E2D;&#x4E2A;&#x4EBA;&#x8D26;&#x53F7;&#x7684;&#x5404;&#x7C7B;&#x5C5E;&#x6027;&#xFF0C;&#x4F8B;&#x5982;id&#xFF0C;&#x7528;&#x6237;&#x540D;&#xFF0C;&#x5934;&#x50CF;&#xFF0C;&#x4E3B;&#x9875;&#x5730;&#x5740;&#x7B49;&#x7B49;&#xFF0C;&#x56E0;&#x6B64;&#x8FD9;&#x91CC;&#x9700;&#x8981;&#x643A;&#x5E26;AccessToken&#x624D;&#x80FD;&#x8BBF;&#x95EE;&#xFF0C;&#x4E0B;&#x9762;&#x770B;&#x4E00;&#x4E0B;&#x5177;&#x4F53;&#x7684;&#x6267;&#x884C;&#x8FC7;&#x7A0B;</p><pre><code class="language-Java">public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
 ...
    String userNameAttributeName = userRequest.getClientRegistration()
       .getProviderDetails()
       .getUserInfoEndpoint()
       .getUserNameAttributeName();
    if (!StringUtils.hasText(userNameAttributeName)) {
       OAuth2Error oauth2Error = new OAuth2Error(MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE,
             &quot;Missing required \&quot;user name\&quot; attribute name in UserInfoEndpoint for Client Registration: &quot;
                   + userRequest.getClientRegistration().getRegistrationId(),
             null);
       throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
    }
    RequestEntity&lt;?&gt; request = this.requestEntityConverter.convert(userRequest); // &#x5173;&#x952E;&#x4EE3;&#x7801;
    ResponseEntity&lt;Map&lt;String, Object&gt;&gt; response = getResponse(userRequest, request);
    Map&lt;String, Object&gt; userAttributes = response.getBody();
    Set&lt;GrantedAuthority&gt; authorities = new LinkedHashSet&lt;&gt;();
    authorities.add(new OAuth2UserAuthority(userAttributes));
    OAuth2AccessToken token = userRequest.getAccessToken();
    for (String authority : token.getScopes()) {
       authorities.add(new SimpleGrantedAuthority(&quot;SCOPE_&quot; + authority));
    }
    return new DefaultOAuth2User(authorities, userAttributes, userNameAttributeName);
}

public RequestEntity&lt;?&gt; convert(OAuth2UserRequest userRequest) {
    ClientRegistration clientRegistration = userRequest.getClientRegistration();
    HttpMethod httpMethod = getHttpMethod(clientRegistration);
    HttpHeaders headers = new HttpHeaders();
    headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
    URI uri = UriComponentsBuilder
       .fromUriString(clientRegistration.getProviderDetails().getUserInfoEndpoint().getUri())
       .build()
       .toUri();

    RequestEntity&lt;?&gt; request;
    if (HttpMethod.POST.equals(httpMethod)) {
       headers.setContentType(DEFAULT_CONTENT_TYPE);
       MultiValueMap&lt;String, String&gt; formParameters = new LinkedMultiValueMap&lt;&gt;();
       formParameters.add(OAuth2ParameterNames.ACCESS_TOKEN, userRequest.getAccessToken().getTokenValue());
       request = new RequestEntity&lt;&gt;(formParameters, headers, httpMethod, uri);
    }
    else {
       headers.setBearerAuth(userRequest.getAccessToken().getTokenValue());
       request = new RequestEntity&lt;&gt;(headers, httpMethod, uri);
    }

    return request;
}</code></pre><p>&#x5176;&#x4E2D;&#x751F;&#x6210;&#x8BF7;&#x6C42;&#x5BF9;&#x8C61;&#x7684;&#x5173;&#x952E;&#x4EE3;&#x7801;&#x5728;OAuth2UserRequestEntityConverter#convert&#x65B9;&#x6CD5;&#x4E2D;&#xFF1A;</p><ul><li>&#x7528;&#x6237;&#x4FE1;&#x606F;&#x7684;&#x7AEF;&#x70B9;&#x540C;&#x6837;&#x4E5F;&#x662F;&#x7531;clientRegistration&#x63D0;&#x4F9B;&#xFF0C;&#x5373;https://api.github.com/user</li><li>accessToken&#x4F5C;&#x4E3A;&#x53C2;&#x6570;&#xFF0C;&#x5982;&#x679C;&#x662F;GET&#x65B9;&#x6CD5;&#xFF0C;&#x5219;&#x88AB;&#x7F6E;&#x4E8E;Header&#x4E2D;&#x7684;&quot;Authorization&quot;&#x5C5E;&#x6027;&#x4E2D;&#xFF0C;&#x5E76;&#x6309;&#x7167;&#x89C4;&#x8303;&#x6DFB;&#x52A0;&quot;Bearer &quot;&#x7684;&#x524D;&#x7F00;&#xFF0C;&#x5982;&#x679C;&#x662F;POST&#xFF0C;&#x5219;&#x88AB;&#x653E;&#x5728;&#x8BF7;&#x6C42;&#x8868;&#x5355;&#x53C2;&#x6570;&quot;access_token&quot;&#x4E2D;&#xFF0C;&#x6B64;&#x5904;&#x4E3A;GET&#x65B9;&#x6CD5;&#x6709;&#x5173;</li></ul><p>&#x66F4;&#x591A;&#x8BBF;&#x95EE;&#x53D7;&#x4FDD;&#x62A4;&#x8D44;&#x6E90;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x5C06;&#x5728;&#x4E0B;&#x4E00;&#x7BC7;&#x6587;&#x7AE0;&#x4E2D;&#x4ECB;&#x7ECD;&#x3002;</p><h2 id="%E4%B8%89%E3%80%81%E9%99%84%E5%BD%95">&#x4E09;&#x3001;&#x9644;&#x5F55;</h2><h3 id="31-%E5%9C%A8github%E4%B8%AD%E6%B3%A8%E5%86%8C%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84oauth2%E5%AE%A2%E6%88%B7%E7%AB%AF">3.1 &#x5728;Github&#x4E2D;&#x6CE8;&#x518C;&#x4E00;&#x4E2A;&#x65B0;&#x7684;OAuth2&#x5BA2;&#x6237;&#x7AEF;</h3><p>&#x6CE8;&#x518C;&#x5730;&#x5740;&#x4E3A;<a href="https://github.com/settings/developers">https://github.com/settings/developers</a>&#xFF0C;&#x70B9;&#x51FB;&#x53F3;&#x4E0A;&#x65B9;&#x201C;new OAuth App&#x201D;&#xFF0C;&#x5C31;&#x4F1A;&#x8DF3;&#x8F6C;&#x5230;&#x6CE8;&#x518C;&#x9875;&#x9762;</p><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/05/image-5.png" class="kg-image" alt="Spring Security 6.x OAuth2&#x767B;&#x5F55;&#x8BA4;&#x8BC1;&#x6E90;&#x7801;&#x5206;&#x6790;" loading="lazy" width="627" height="607" srcset="http://www.fullstackyang.com/content/images/size/w600/2024/05/image-5.png 600w, http://www.fullstackyang.com/content/images/2024/05/image-5.png 627w"></figure><h3 id="32-%E5%A1%AB%E5%86%99%E8%A1%A8%E5%8D%95">3.2 &#x586B;&#x5199;&#x8868;&#x5355;</h3><p>&#x5176;&#x4E2D;&#xFF0C;&#x5FC5;&#x586B;&#x9879;&#x5305;&#x62EC;&#x201C;&#x5E94;&#x7528;&#x540D;&#x79F0;&#x201D;&#xFF0C;&#x201C;&#x4E3B;&#x9875;&#x5730;&#x5740;&#x201D;&#xFF0C;&#x201C;&#x6388;&#x6743;&#x56DE;&#x8C03;&#x5730;&#x5740;&#x201D;&#x5373;&#x4E0A;&#x6587;&#x63D0;&#x5230;&#x7684;redirect_uri&#x53C2;&#x6570;&#xFF0C;&#x6700;&#x540E;&#x70B9;&#x51FB;&#x201C;Register Application&#x201D;&#x5373;&#x53EF;&#x5B8C;&#x6210;&#x5BA2;&#x6237;&#x7AEF;&#x6CE8;&#x518C;</p><h3 id="33-%E6%9F%A5%E7%9C%8B%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BF%A1%E6%81%AF">3.3 &#x67E5;&#x770B;&#x5BA2;&#x6237;&#x7AEF;&#x4FE1;&#x606F;</h3><p>&#x6CE8;&#x518C;&#x5B8C;&#x6210;&#x4E4B;&#x540E;&#x5C31;&#x53EF;&#x4EE5;&#x8FDB;&#x5165;&#x5BA2;&#x6237;&#x7AEF;&#x4FE1;&#x606F;&#x9875;&#x9762;&#xFF0C;&#x6B64;&#x65F6;client-id&#x5DF2;&#x7ECF;&#x751F;&#x6210;&#x597D;&#x4E86;&#xFF0C;&#x8FD8;&#x9700;&#x8981;&#x751F;&#x6210;&#x4E00;&#x4E32;client-secret&#xFF0C;&#x70B9;&#x51FB;&#x201C;Generate a new client secret&#x201D;&#x5373;&#x53EF;&#x751F;&#x6210;&#xFF0C;&#x6B64;&#x65F6;&#x52A1;&#x5FC5;&#x590D;&#x5236;&#x5E76;&#x4FDD;&#x5B58;&#x8BE5;&#x5B57;&#x7B26;&#x4E32;&#xFF0C;&#x540E;&#x9762;&#x5C31;&#x65E0;&#x6CD5;&#x518D;&#x6B21;&#x67E5;&#x770B;&#x4E86;&#xFF0C;&#x53EA;&#x80FD;&#x518D;&#x751F;&#x6210;&#x4E00;&#x4E2A;&#x65B0;&#x7684;&#x3002;</p><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/05/image-6.png" class="kg-image" alt="Spring Security 6.x OAuth2&#x767B;&#x5F55;&#x8BA4;&#x8BC1;&#x6E90;&#x7801;&#x5206;&#x6790;" loading="lazy" width="770" height="449" srcset="http://www.fullstackyang.com/content/images/size/w600/2024/05/image-6.png 600w, http://www.fullstackyang.com/content/images/2024/05/image-6.png 770w" sizes="(min-width: 720px) 720px"></figure><p>&#x81F3;&#x6B64;&#xFF0C;&#x5BA2;&#x6237;&#x7AEF;&#x57FA;&#x672C;&#x4FE1;&#x606F;&#x5C31;&#x6CE8;&#x518C;&#x5B8C;&#x6210;&#x4E86;&#x3002;</p><h3 id="34-%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3">3.4 &#x5B98;&#x65B9;&#x6587;&#x6863;</h3><p>&#x5982;&#x6709;&#x5176;&#x4ED6;&#x95EE;&#x9898;&#xFF0C;&#x4E5F;&#x53EF;&#x4EE5;&#x53C2;&#x8003;&#x5176;&#x5B98;&#x65B9;&#x6587;&#x6863;</p><blockquote><a href="https://docs.github.com/zh/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps">https://docs.github.com/zh/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps</a></blockquote>]]></content:encoded></item><item><title><![CDATA[Spring Security 6.x 图解身份认证的架构设计]]></title><description><![CDATA[<h2 id="%E4%B8%80%E3%80%81%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5">&#x4E00;&#x3001;&#x57FA;&#x672C;&#x6982;&#x5FF5;</h2><p>&#x201C;Authentication(&#x8BA4;&#x8BC1;)&#x201D;&#x662F;spring security&#x6846;&#x67B6;&#x4E2D;&#x6700;&#x91CD;&#x8981;&#x7684;&#x529F;&#x80FD;&#x4E4B;&#x4E00;&#xFF0C;&#x6240;&#x8C13;&#x8BA4;&#x8BC1;&#xFF0C;&#x5C31;&#x662F;&#x5BF9;&#x5F53;&#x524D;&#x8BBF;&#x95EE;&#x7CFB;&#x7EDF;&#x7684;&#x7528;&#x6237;&#x7ED9;&#x4E88;&#x4E00;&#x4E2A;&#x5408;&#x6CD5;&#x7684;</p>]]></description><link>http://www.fullstackyang.com/spring-security-6-x-guo-lu-qi-lian-securityfilterchainshi-ru-he-gong-zuo-de/</link><guid isPermaLink="false">6644d52ddfefff00015999cf</guid><category><![CDATA[Spring Security]]></category><category><![CDATA[spring]]></category><category><![CDATA[dev]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Wed, 15 May 2024 15:47:01 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2024/05/spring_security_lg-1280x720-1.png" medium="image"/><content:encoded><![CDATA[<h2 id="%E4%B8%80%E3%80%81%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5">&#x4E00;&#x3001;&#x57FA;&#x672C;&#x6982;&#x5FF5;</h2><img src="http://www.fullstackyang.com/content/images/2024/05/spring_security_lg-1280x720-1.png" alt="Spring Security 6.x &#x56FE;&#x89E3;&#x8EAB;&#x4EFD;&#x8BA4;&#x8BC1;&#x7684;&#x67B6;&#x6784;&#x8BBE;&#x8BA1;"><p>&#x201C;Authentication(&#x8BA4;&#x8BC1;)&#x201D;&#x662F;spring security&#x6846;&#x67B6;&#x4E2D;&#x6700;&#x91CD;&#x8981;&#x7684;&#x529F;&#x80FD;&#x4E4B;&#x4E00;&#xFF0C;&#x6240;&#x8C13;&#x8BA4;&#x8BC1;&#xFF0C;&#x5C31;&#x662F;&#x5BF9;&#x5F53;&#x524D;&#x8BBF;&#x95EE;&#x7CFB;&#x7EDF;&#x7684;&#x7528;&#x6237;&#x7ED9;&#x4E88;&#x4E00;&#x4E2A;&#x5408;&#x6CD5;&#x7684;&#x8EAB;&#x4EFD;&#x6807;&#x8BC6;&#xFF0C;&#x7528;&#x6237;&#x53EA;&#x6709;&#x901A;&#x8FC7;&#x8BA4;&#x8BC1;&#x540E;&#x624D;&#x53EF;&#x4EE5;&#x8FDB;&#x5165;&#x7CFB;&#x7EDF;&#xFF0C;&#x5728;&#x7269;&#x7406;&#x4E16;&#x754C;&#x4E2D;&#xFF0C;&#x6709;&#x70B9;&#x7C7B;&#x4F3C;&#x201C;&#x62FF;&#x5DE5;&#x5361;&#x5237;&#x95E8;&#x7981;&#x201D;&#x7684;&#x573A;&#x666F;&#x3002;&#x8EAB;&#x4EFD;&#x8BA4;&#x8BC1;&#x5728;&#x5E02;&#x9762;&#x4E0A;&#x6709;&#x5F88;&#x591A;&#x79CD;&#x7684;&#x5B9E;&#x73B0;&#x534F;&#x8BAE;&#xFF0C;&#x6700;&#x5E38;&#x89C1;&#x7684;&#x5C31;&#x662F;&#x7528;&#x6237;&#x540D;&#x5BC6;&#x7801;&#x7684;&#x8BA4;&#x8BC1;&#x65B9;&#x5F0F;&#xFF0C;&#x53E6;&#x5916;&#x8FD8;&#x6709;OAuth2.0&#xFF0C;CAS&#xFF08;Central Authentication Service&#xFF09;&#xFF0C;SAML&#x7B49;&#xFF0C;&#x5176;&#x4E2D;OAuth2.0&#x662F;&#x4E00;&#x79CD;&#x6211;&#x4EEC;&#x6BD4;&#x8F83;&#x719F;&#x6089;&#x7684;&#x8BA4;&#x8BC1;&#x534F;&#x8BAE;&#xFF0C;&#x4F8B;&#x5982;&#x5FAE;&#x4FE1;&#xFF0C;&#x652F;&#x4ED8;&#x5B9D;&#x63D0;&#x4F9B;&#x7684;&#x7B2C;&#x4E09;&#x65B9;&#x767B;&#x5F55;&#x3002;&#x56DE;&#x5230;&#x8EAB;&#x4EFD;&#x8BA4;&#x8BC1;&#x7684;&#x539F;&#x672C;&#x9700;&#x6C42;&#xFF1A;</p><ul><li>&#x9996;&#x5148;&#x7CFB;&#x7EDF;&#x8981;&#x63D0;&#x4F9B;&#x5BF9;&#x5E94;&#x7684;&#x8BA4;&#x8BC1;&#x670D;&#x52A1;&#xFF0C;&#x5373;&#x9700;&#x8981;&#x5224;&#x65AD;&#x7528;&#x6237;&#x63D0;&#x4EA4;&#x7684;&#x51ED;&#x8BC1;&#x662F;&#x5426;&#x6B63;&#x786E;&#xFF0C;&#x51ED;&#x8BC1;&#x662F;&#x4E00;&#x4E2A;&#x6BD4;&#x8F83;&#x5BBD;&#x6CDB;&#x7684;&#x6982;&#x5FF5;&#xFF0C;&#x5BC6;&#x7801;&#x53EA;&#x662F;&#x5176;&#x4E2D;&#x4E00;&#x79CD;&#xFF0C;&#x8FD8;&#x5305;&#x62EC;&#x77ED;&#x4FE1;&#x9A8C;&#x8BC1;&#x7801;&#xFF0C;&#x6307;&#x7EB9;&#x7B49;&#xFF0C;&#x4E00;&#x5207;&#x53EF;&#x4EE5;&#x8BC1;&#x660E;&#x201C;&#x4F60;&#x662F;&#x4F60;&#x201D;&#x7684;&#x6750;&#x6599;&#x90FD;&#x53EF;&#x4EE5;&#x662F;&#x51ED;&#x8BC1;</li><li>&#x5728;&#x7528;&#x6237;&#x8BA4;&#x8BC1;&#x6210;&#x529F;&#x540E;&#xFF0C;&#x7CFB;&#x7EDF;&#x8FD8;&#x8981;&#x8BB0;&#x5F55;&#x8FD9;&#x4E9B;&#x8BA4;&#x8BC1;&#x4FE1;&#x606F;&#xFF0C;&#x5E76;&#x8FD4;&#x56DE;&#x5BA2;&#x6237;&#x7AEF;&#x4E00;&#x4E2A;&#x4EE4;&#x724C;&#xFF0C;&#x5BF9;&#x4E8E;&#x540E;&#x7EED;&#x7684;&#x8BF7;&#x6C42;&#xFF0C;&#x901A;&#x8FC7;&#x8FD9;&#x4E2A;&#x4EE4;&#x724C;&#x5C31;&#x53EF;&#x4EE5;&#x6821;&#x9A8C;&#x662F;&#x5426;&#x7ECF;&#x8FC7;&#x8BA4;&#x8BC1;&#xFF0C;&#x82E5;&#x5DF2;&#x7ECF;&#x5B8C;&#x6210;&#x8FC7;&#x8BA4;&#x8BC1;&#xFF0C;&#x90A3;&#x4E48;&#x5E94;&#x8BE5;&#x53D6;&#x51FA;&#x5F53;&#x65F6;&#x8BA4;&#x8BC1;&#x7684;&#x4FE1;&#x606F;&#xFF0C;&#x5305;&#x62EC;&#x7528;&#x6237;&#x540D;&#xFF0C;&#x6743;&#x9650;&#x7B49;&#xFF0C;&#x7136;&#x540E;&#x7EE7;&#x7EED;&#x6267;&#x884C;&#x540E;&#x7EED;&#x7684;&#x4E1A;&#x52A1;&#x903B;&#x8F91;&#xFF0C;&#x82E5;&#x6CA1;&#x6709;&#x8BA4;&#x8BC1;&#x4FE1;&#x606F;&#xFF0C;&#x5219;&#x62D2;&#x7EDD;&#x8BBF;&#x95EE;&#x3002;&#x8FD9;&#x6837;&#x624D;&#x80FD;&#x5BF9;&#x53D7;&#x4FDD;&#x62A4;&#x7684;&#x7CFB;&#x7EDF;&#x8D44;&#x6E90;&#x8D77;&#x5230;&#x4F5C;&#x7528;&#x3002;&#x6839;&#x636E;&#x4E0A;&#x9762;&#x7684;&#x63CF;&#x8FF0;&#xFF0C;&#x5F88;&#x81EA;&#x7136;&#x5730;&#xFF0C;&#x6211;&#x4EEC;&#x60F3;&#x5230;&#x5B9A;&#x4E49;&#x4E00;&#x4E2A;controller&#x7684;API&#x63A5;&#x53E3;&#x6765;&#x63D0;&#x4F9B;&#x8BA4;&#x8BC1;&#x670D;&#x52A1;&#xFF0C;&#x7136;&#x540E;&#x5B9A;&#x4E49;&#x4E00;&#x4E2A;&#x201C;&#x5207;&#x9762;&#x201D;&#x6765;&#x6821;&#x9A8C;&#x8BA4;&#x8BC1;&#x4FE1;&#x606F;&#xFF0C;&#x8FD9;&#x79CD;&#x65B9;&#x5F0F;&#x53EF;&#x4EE5;&#x65B9;&#x4FBF;&#x5730;&#x62E6;&#x622A;&#x5230;&#x7CFB;&#x7EDF;&#x5185;&#x5404;&#x4E2A;&#x8D44;&#x6E90;&#x7684;&#x8BBF;&#x95EE;&#x8BF7;&#x6C42;&#xFF0C;&#x4E0D;&#x4EC5;&#x53EF;&#x4EE5;&#x7075;&#x6D3B;&#x914D;&#x7F6E;&#xFF0C;&#x4E5F;&#x4E0D;&#x4F1A;&#x4FB5;&#x5165;&#x4E1A;&#x52A1;&#x4EE3;&#x7801;&#x3002;&#x5230;&#x6B64;&#xFF0C;&#x6211;&#x4EEC;&#x5BF9;&#x8BA4;&#x8BC1;&#x7684;&#x67B6;&#x6784;&#x6709;&#x4E86;&#x4E00;&#x4E2A;&#x521D;&#x6B65;&#x7684;&#x6784;&#x60F3;&#xFF0C;&#x5148;&#x753B;&#x4E00;&#x4E2A;&#x7B80;&#x5355;&#x7684;&#x8349;&#x7A3F;</li></ul><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/05/--2024-05-15-23.50.47.png" class="kg-image" alt="Spring Security 6.x &#x56FE;&#x89E3;&#x8EAB;&#x4EFD;&#x8BA4;&#x8BC1;&#x7684;&#x67B6;&#x6784;&#x8BBE;&#x8BA1;" loading="lazy" width="809" height="474" srcset="http://www.fullstackyang.com/content/images/size/w600/2024/05/--2024-05-15-23.50.47.png 600w, http://www.fullstackyang.com/content/images/2024/05/--2024-05-15-23.50.47.png 809w" sizes="(min-width: 720px) 720px"></figure><p>&#x8FD9;&#x91CC;&#x6240;&#x8C13;&#x7684;&#x201C;&#x4EE4;&#x724C;&#x201D;&#xFF0C;&#x201C;&#x51ED;&#x8BC1;&#x201D;&#xFF0C;&#x201C;&#x8BA4;&#x8BC1;&#x4FE1;&#x606F;&#x201D;&#xFF0C;&#x201C;&#x53D7;&#x4FDD;&#x62A4;&#x8D44;&#x6E90;&#x201D;&#x90FD;&#x662F;&#x62BD;&#x8C61;&#x7684;&#x6982;&#x5FF5;&#xFF0C;&#x5E76;&#x4E0D;&#x7279;&#x6307;&#x67D0;&#x4E00;&#x79CD;&#x5B9E;&#x73B0;&#xFF0C;&#x201C;&#x5207;&#x9762;&#x201D;&#x4E5F;&#x4E0D;&#x662F;Spring&#x7684;AOP&#xFF0C;&#x53EA;&#x8868;&#x793A;&#x5728;&#x6267;&#x884C;&#x6821;&#x9A8C;&#x903B;&#x8F91;&#x65F6;&#xFF0C;&#x4E0D;&#x4E0E;&#x53D7;&#x4FDD;&#x62A4;&#x8D44;&#x6E90;&#x76F8;&#x8026;&#x5408;&#xFF0C;&#x5B83;&#x5E94;&#x8BE5;&#x662F;&#x72EC;&#x7ACB;&#x8FD0;&#x4F5C;&#x7684;&#x6A21;&#x5757;&#x3002;&#x4E0B;&#x9762;&#x5177;&#x4F53;&#x770B;&#x4E00;&#x4E0B;spring security&#x4E2D;&#x7684;&#x8BA4;&#x8BC1;&#x67B6;&#x6784;&#x8BBE;&#x8BA1;&#xFF0C;&#x5BF9;&#x6BD4;&#x4E0A;&#x56FE;&#xFF0C;&#x5B66;&#x4E60;&#x4E00;&#x4E0B;spring security&#x662F;&#x5982;&#x4F55;&#x5B9E;&#x8DF5;&#x7684;&#x3002;</p><h2 id="%E4%BA%8C%E3%80%81%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1">&#x4E8C;&#x3001;&#x67B6;&#x6784;&#x8BBE;&#x8BA1;</h2><p>spring security&#x5229;&#x7528;&#x4E86;SecurityFilterChain&#x7684;&#x8FC7;&#x6EE4;&#x5668;&#x4E2D;&#x5B9E;&#x73B0;&#x4E86;&#x6821;&#x9A8C;&#x903B;&#x8F91;&#xFF0C;&#x53E6;&#x5916;&#x4E3A;&#x4E86;&#x5B9E;&#x73B0;&#x5404;&#x79CD;&#x8BA4;&#x8BC1;&#x534F;&#x8BAE;&#xFF0C;spring security&#x4E5F;&#x5185;&#x7F6E;&#x4E86;&#x5F88;&#x591A;&#x79CD;&#x8BA4;&#x8BC1;&#x5B9E;&#x73B0;&#x7C7B;&#xFF0C;&#x4F9B;&#x5F00;&#x53D1;&#x8005;&#x76F4;&#x63A5;&#x4F7F;&#x7528;&#xFF0C;&#x4E0D;&#x8FC7;&#x8FD9;&#x91CC;&#x63D0;&#x4F9B;&#x4E24;&#x79CD;&#x65B9;&#x5F0F;&#xFF0C;&#x4E00;&#x79CD;&#x4E5F;&#x662F;&#x5229;&#x7528;SecurityFilterChain&#x7684;&#x8FC7;&#x6EE4;&#x5668;&#x6765;&#x5B9E;&#x73B0;&#x8BA4;&#x8BC1;&#x670D;&#x52A1;&#xFF0C;&#x5F53;&#x7136;&#x4E5F;&#x53EF;&#x4EE5;&#x5B9E;&#x73B0;&#x81EA;&#x5B9A;&#x4E49;&#x7684;Controller&#x6765;&#x66B4;&#x9732;API&#x63A5;&#x53E3;&#x3002;&#x660E;&#x786E;&#x4E86;&#x8FD9;&#x4E24;&#x70B9;&#x4E4B;&#x540E;&#xFF0C;&#x6211;&#x4EEC;&#x518D;&#x7ED9;&#x51FA;spring security&#x5B8C;&#x6574;&#x7684;&#x8BA4;&#x8BC1;&#x67B6;&#x6784;&#xFF0C;&#x56FE;&#x4E2D;&#x5747;&#x4EE5;SecurityFilterChain&#x7684;&#x8FC7;&#x6EE4;&#x5668;&#x5B9E;&#x73B0;&#x8BA4;&#x8BC1;&#x548C;&#x6821;&#x9A8C;&#x7684;&#x903B;&#x8F91;&#xFF0C;&#x8FD9;&#x662F;&#x6BD4;&#x8F83;&#x5E38;&#x89C1;&#x60EF;&#x7528;&#x7684;&#x65B9;&#x6CD5;&#x3002; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0; &#xA0;</p><blockquote>&#x53EF;&#x4EE5;&#x53C2;&#x8003;&#x5B98;&#x65B9;&#x6587;&#x6863; <a href="https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html">https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html</a>&#xFF0C;&#x4E0D;&#x8FC7;&#x5B98;&#x65B9;&#x6587;&#x6863;&#x7684;&#x7ED3;&#x6784;&#x7EC4;&#x7EC7;&#x6BD4;&#x8F83;&#x6563;&#xFF0C;&#x8FD9;&#x91CC;&#x6211;&#x4EEC;&#x518D;&#x505A;&#x4E00;&#x6B21;&#x6574;&#x5408;&#xFF0C;&#x770B;&#x8D77;&#x6765;&#x66F4;&#x76F4;&#x89C2;&#x4E00;&#x4E9B;</blockquote><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/05/--2024-05-15-23.42.59.png" class="kg-image" alt="Spring Security 6.x &#x56FE;&#x89E3;&#x8EAB;&#x4EFD;&#x8BA4;&#x8BC1;&#x7684;&#x67B6;&#x6784;&#x8BBE;&#x8BA1;" loading="lazy" width="1696" height="1042" srcset="http://www.fullstackyang.com/content/images/size/w600/2024/05/--2024-05-15-23.42.59.png 600w, http://www.fullstackyang.com/content/images/size/w1000/2024/05/--2024-05-15-23.42.59.png 1000w, http://www.fullstackyang.com/content/images/size/w1600/2024/05/--2024-05-15-23.42.59.png 1600w, http://www.fullstackyang.com/content/images/2024/05/--2024-05-15-23.42.59.png 1696w" sizes="(min-width: 720px) 720px"></figure><p>&#x9996;&#x5148;&#x4ECB;&#x7ECD;&#x4E00;&#x4E0B;&#x76F8;&#x5173;&#x7684;&#x63A5;&#x53E3;&#x548C;&#x7C7B;&#xFF1A;</p><h3 id="%E6%8E%A5%E5%8F%A3">&#x63A5;&#x53E3;</h3><ul><li>Authentication&#xFF1A;&#x9876;&#x5C42;&#x63A5;&#x53E3;&#xFF0C;&#x7528;&#x4E8E;&#x4FDD;&#x5B58;&#x8EAB;&#x4EFD;&#x8BA4;&#x8BC1;&#x4FE1;&#x606F;&#xFF0C;&#x4E3B;&#x8981;&#x5305;&#x62EC;3&#x4E2A;&#x90E8;&#x5206;&#xFF1A;&#x7528;&#x6237;&#x6807;&#x8BC6;&#xFF08;principal&#xFF0C;&#x901A;&#x5E38;&#x4E3A;&#x7528;&#x6237;&#x540D;&#xFF09;&#xFF0C;&#x51ED;&#x8BC1;&#xFF08;credentials&#xFF0C;&#x901A;&#x5E38;&#x4E3A;&#x5BC6;&#x7801;&#xFF09;&#xFF0C;&#x6743;&#x9650;&#x4FE1;&#x606F;&#xFF08;authorities&#xFF0C;&#x901A;&#x5E38;&#x4E3A;&#x8BE5;&#x7528;&#x6237;&#x6240;&#x62E5;&#x6709;&#x7684;&#x89D2;&#x8272;&#xFF09;</li><li>SecurityContext&#xFF1A;&#x9876;&#x5C42;&#x63A5;&#x53E3;&#xFF0C;&#x76F4;&#x8BD1;&#x4E3A;&#x5B89;&#x5168;&#x4E0A;&#x4E0B;&#x6587;&#xFF0C;&#x5185;&#x90E8;&#x53EA;&#x5B9A;&#x4E49;&#x4E86;getAuthentication&#x548C;setAuthentication&#x4E24;&#x4E2A;&#x65B9;&#x6CD5;&#xFF0C;&#x6982;&#x62EC;&#x5730;&#x8BF4;&#xFF0C;SecurityContext&#x76F8;&#x5F53;&#x4E8E;&#x7528;&#x4E8E;&#x88C5;&#x8F7D;Authentication&#x5BF9;&#x8C61;&#x7684;&#x5BB9;&#x5668;&#xFF0C;&#x5728;&#x6574;&#x4E2A;SecurityFilterChain&#x4E2D;&#xFF0C;&#x4E3A;&#x4E0D;&#x540C;&#x7684;&#x8BA4;&#x8BC1;&#x673A;&#x5236;&#x64CD;&#x4F5C;Authentication&#x5BF9;&#x8C61;&#x65F6;&#x63D0;&#x4F9B;&#x670D;&#x52A1;&#x3002;</li><li>AuthenticationManager: &#x9876;&#x5C42;&#x63A5;&#x53E3;&#xFF0C;&#x5B9A;&#x4E49;&#x4E86;&#x201C;&#x8BA4;&#x8BC1;&#x201C;&#x65B9;&#x6CD5;&#xFF0C;&#x7B7E;&#x540D;&#x5982;&#x4E0B;&#xFF1A;</li></ul><pre><code class="language-Java">Authentication authenticate(Authentication authentication) throws AuthenticationException;</code></pre><ul><li>AuthenticationProvider: &#xA0;&#x9876;&#x5C42;&#x63A5;&#x53E3;&#xFF0C;&#x540C;&#x6837;&#x4E5F;&#x5B9A;&#x4E49;&#x4E86;&#x4E00;&#x4E2A;&#x7B7E;&#x540D;&#x76F8;&#x540C;&#x7684;&#x201C;&#x8BA4;&#x8BC1;&#x201D;&#x65B9;&#x6CD5;&#xFF0C;&#x4E0D;&#x540C;&#x4E8E;AuthenticationManager&#x7684;&#x8BA4;&#x8BC1;&#x65B9;&#x6CD5;&#xFF0C;&#x8FD9;&#x4E2A;&#x624D;&#x662F;&#x5404;&#x79CD;&#x8BA4;&#x8BC1;&#x534F;&#x8BAE;&#x7684;&#x5177;&#x4F53;&#x5B9E;&#x73B0;&#xFF0C;&#x5B83;&#x901A;&#x5E38;&#x63A5;&#x53D7;&#x4E00;&#x4E2A;&#x672A;&#x8BA4;&#x8BC1;&#x7684;Authentication&#x5BF9;&#x8C61;&#x7684;&#x53C2;&#x6570;&#xFF0C;&#x8BE5;&#x5BF9;&#x8C61;&#x4EC5;&#x5305;&#x542B;&#x4E86;principal&#x548C;credentials&#x7684;&#x4FE1;&#x606F;&#xFF0C;&#x5728;&#x7ECF;&#x8FC7;&#x8BA4;&#x8BC1;&#x540E;&#xFF0C;&#x4F1A;&#x628A;authorities&#x586B;&#x5145;&#x8FDB;&#x6765;&#xFF0C;&#x5E76;&#x5C06;&#x72B6;&#x6001;&#x8BBE;&#x7F6E;&#x4E3A;&#x5DF2;&#x8BA4;&#x8BC1;&#x3002;&#x5728;spring security&#x4E2D;&#x5185;&#x7F6E;&#x4E86;&#x5F88;&#x591A;&#x5B9E;&#x73B0;&#x7C7B;&#xFF0C;&#x4F8B;&#x5982;OAuth2LoginAuthenticationProvider&#xFF0C;&#x7528;&#x4E8E;&#x5B9E;&#x73B0;OAuth2.0&#x8BA4;&#x8BC1;&#x534F;&#x8BAE;&#x7B49;&#x3002;&#x5F53;&#x7136;&#x6211;&#x4EEC;&#x4E5F;&#x53EF;&#x4EE5;&#x6839;&#x636E;&#x9700;&#x8981;&#x81EA;&#x5B9A;&#x4E49;&#x5176;&#x5B9E;&#x73B0;&#x3002;</li><li>SecurityContextRepository&#xFF1A;&#x9876;&#x5C42;&#x63A5;&#x53E3;&#xFF0C;&#x5B9A;&#x4E49;&#x4E86;&#x4FDD;&#x5B58;&#x548C;&#x52A0;&#x8F7D;SecuriyContext&#x5BF9;&#x8C61;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x5E38;&#x7528;&#x7684;&#x5B9E;&#x73B0;&#x6709;HttpSessionSecurityContextRepository&#xFF0C;&#x5373;&#x901A;&#x8FC7;request&#x7684;&#x4F1A;&#x8BDD;&#x5BF9;&#x8C61;session&#xFF0C;&#x5B58;&#x53D6;SecurityContext&#x7684;&#x5B9E;&#x4F8B;&#x3002;</li><li>SecurityContextHolderStrategy&#xFF1A;&#x9876;&#x5C42;&#x63A5;&#x53E3;&#xFF0C;&#x5B9A;&#x4E49;&#x4E86;&#x5728;&#x5F53;&#x524D;&#x8BF7;&#x6C42;&#x7684;&#x7EBF;&#x7A0B;&#x4E2D;&#xFF0C;&#x83B7;&#x53D6;&#x548C;&#x8BBE;&#x7F6E;SecurityContext&#x5BF9;&#x8C61;&#x7B49;&#x65B9;&#x6CD5;&#xFF0C;&#x5728;5.8&#x7248;&#x672C;&#x4E4B;&#x540E;&#xFF0C;&#x65B0;&#x589E;&#x4E86;&#x4E24;&#x4E2A;get/set&#x201C;&#x5EF6;&#x8FDF;&#xFF08;Deferred&#xFF09;&#x201D;&#x63A5;&#x53E3;&#xFF0C;&#x4E3B;&#x8981;&#x662F;&#x4F7F;&#x7528;&#x4E86;Supplier&#x51FD;&#x6570;&#x5F0F;&#x63A5;&#x53E3;&#x5B9E;&#x73B0;&#x7684;&#x60F0;&#x6027;&#x8BA1;&#x7B97;&#xFF0C;&#x4E0D;&#x8FC7;&#x53EA;&#x662F;&#x6027;&#x80FD;&#x4E0A;&#x7684;&#x8003;&#x91CF;&#xFF0C;&#x672C;&#x8D28;&#x4E0A;&#x90FD;&#x662F;&#x7528;&#x4E8E;&#x7EF4;&#x62A4;SecurityContext&#x5BF9;&#x8C61;&#x7684;&#x65B9;&#x6CD5;</li></ul><h3 id="%E7%B1%BB">&#x7C7B;</h3><ul><li>SecurityContextHolder&#xFF1A;&#x5B83;&#x662F;spring security&#x8BA4;&#x8BC1;&#x6A21;&#x578B;&#x4E2D;&#x6700;&#x4E3A;&#x5E38;&#x7528;&#x7684;&#x4E00;&#x4E2A;&#x5DE5;&#x5177;&#x7C7B;&#xFF0C;&#x5B83;&#x91C7;&#x7528;&#x7B56;&#x7565;&#x6A21;&#x5F0F;&#x5C01;&#x88C5;&#x4E86;SecurityContextHolderStrategy&#x63A5;&#x53E3;&#x5B9E;&#x73B0;&#xFF0C;&#x9ED8;&#x8BA4;&#x7684;&#x7B56;&#x7565;&#x5B9E;&#x73B0;&#x4E3A;ThreadLocalSecurityContextHolderStrategy&#xFF0C;&#x5176;&#x5E95;&#x5C42;&#x4F7F;&#x7528;&#x4E86;ThreadLocal&#x5B9E;&#x73B0;&#x5BF9;SecurityContext&#x5BF9;&#x8C61;&#x7684;&#x5B58;&#x53D6;&#x903B;&#x8F91;&#xFF0C;&#x8FD9;&#x6837;&#x53EF;&#x4EE5;&#x4FDD;&#x8BC1;&#x5728;&#x4E00;&#x6B21;&#x8BF7;&#x6C42;&#x7684;&#x540C;&#x4E00;&#x4E2A;&#x7EBF;&#x7A0B;&#x4E2D;&#xFF0C;&#x65B9;&#x4FBF;&#x5730;&#x83B7;&#x53D6;SecurityContext&#x5BF9;&#x8C61;&#x3002;</li><li>ProviderManager: AuthenticationManager&#x7684;&#x5B9E;&#x73B0;&#x7C7B;&#xFF0C;&#x5B83;&#x5185;&#x90E8;&#x7EF4;&#x62A4;&#x4E86;&#x4E00;&#x4E2A;List&#x6210;&#x5458;&#x53D8;&#x91CF;&#xFF0C;&#x5728;&#x5B9E;&#x73B0;AuthenticationManager#authenticate&#x65B9;&#x6CD5;&#x65F6;&#xFF0C;&#x5176;&#x5B9E;&#x662F;&#x904D;&#x5386;&#x8FD9;&#x4E2A;List&#x5217;&#x8868;&#xFF0C;&#x4F9D;&#x6B21;&#x5224;&#x65AD;&#x662F;&#x5426;&#x652F;&#x6301;&#x5F53;&#x524D;Authentication&#x5BF9;&#x8C61;&#xFF08;&#x5982;OAuth2LoginAuthenticationProvider&#x652F;&#x6301;OAuth2LoginAuthenticationToken&#xFF09;&#xFF0C;&#x5982;&#x679C;&#x652F;&#x6301;&#xFF0C;&#x5219;&#x8C03;&#x7528;AuthenticationProvider#authenticate&#x65B9;&#x6CD5;&#xFF0C;&#x5B8C;&#x6210;&#x8BA4;&#x8BC1;&#x8FC7;&#x7A0B;&#x3002;</li></ul><p>&#x4ECE;&#x56FE;&#x4E2D;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;&#x6574;&#x4E2A;&#x8BA4;&#x8BC1;&#x6D41;&#x7A0B;&#x4E3B;&#x8981;&#x56F4;&#x7ED5;&#x4EE5;&#x4E0B;3&#x4E2A;Filter&#xFF1A;</p><ol><li>SecurityContextHolderFilter&#xFF1A;&#x5B83;&#x5728;&#x6574;&#x4E2A;SecurityFilterChain&#x4E2D;&#x5177;&#x6709;&#x8F83;&#x9AD8;&#x7684;&#x4F18;&#x5148;&#x7EA7;&#xFF0C;&#x56E0;&#x4E3A;&#x5F53;&#x4E00;&#x4E2A;&#x8BF7;&#x6C42;&#x8FDB;&#x5165;SecurityFilterChain&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x9700;&#x8981;&#x4ECE;SecurityContextRepository&#x52A0;&#x8F7D;SecurityContext&#x5B9E;&#x4F8B;&#x2460;&#xFF0C;&#x5E76;&#x8C03;&#x7528;SecurityContextHolder&#x5BF9;&#x5E94;&#x7684;set&#x65B9;&#x6CD5;&#x8FDB;&#x884C;&#x4FDD;&#x5B58;&#x2461;&#xFF0C;&#x4EE5;&#x4FBF;&#x540E;&#x7EED;&#x5176;&#x4ED6;&#x5730;&#x65B9;&#x83B7;&#x53D6;&#x8FD9;&#x4E2A;SecurityContext&#x5B9E;&#x4F8B;&#xFF0C;&#x5982;&#x4E0A;&#x6587;&#x6240;&#x8FF0;&#xFF0C;&#x901A;&#x5E38;&#x4F1A;&#x4FDD;&#x5B58;&#x5728;ThreadLocal&#x4E2D;</li><li>AuthorizationFilter&#xFF1A;&#x5982;&#x679C;&#x8BE5;&#x8BF7;&#x6C42;&#x6CA1;&#x6709;&#x88AB;&#x8BA4;&#x8BC1;&#x8FC7;&#xFF0C;&#x90A3;&#x4E48;&#x5728;&#x5F53;&#x524D;&#x7684;SecurityContext&#x5BF9;&#x8C61;&#x4E2D;&#x662F;&#x6CA1;&#x6709;Authentication&#x5B9E;&#x4F8B;&#x7684;&#xFF0C;&#x8FD9;&#x65F6;&#x5728;&#x6267;&#x884C;AuthorizationFilter&#x7684;&#x903B;&#x8F91;&#x65F6;&#x5C31;&#x4F1A;&#x53D1;&#x751F;&#x5F02;&#x5E38;&#xFF0C;AuthorizationFilter&#x4E3B;&#x8981;&#x662F;&#x7528;&#x6765;&#x5224;&#x65AD;&#x8BF7;&#x6C42;&#x8BBF;&#x95EE;&#x53D7;&#x4FDD;&#x62A4;&#x8D44;&#x6E90;&#x65F6;&#xFF0C;&#x662F;&#x5426;&#x7B26;&#x5408;&#x6388;&#x6743;&#x6761;&#x4EF6;&#xFF0C;&#x800C;&#x4E3A;&#x4E86;&#x83B7;&#x53D6;&#x7528;&#x6237;&#x7684;&#x6388;&#x6743;&#x4FE1;&#x606F;&#xFF0C;&#x5148;&#x901A;&#x8FC7;SecurityContext&#x5F97;&#x5230;Authentication&#x8BA4;&#x8BC1;&#x4FE1;&#x606F;&#x2460;&#xFF0C;&#x8FD9;&#x65F6;&#x5982;&#x679C;&#x83B7;&#x53D6;&#x5230;Authentication&#x5B9E;&#x4F8B;&#x4E3A;&#x7A7A;&#xFF0C;&#x5C31;&#x8868;&#x793A;&#x8BE5;&#x8BF7;&#x6C42;&#x5E76;&#x6CA1;&#x6709;&#x8BA4;&#x8BC1;&#x8FC7;&#xFF0C;&#x90A3;&#x4E48;&#x5C31;&#x4F1A;&#x629B;&#x51FA;&#x4E00;&#x4E2A;AuthenticationCredentialsNotFoundException&#x7684;&#x5F02;&#x5E38;&#x2461;&#xFF0C;&#x8FD9;&#x4E2A;&#x5F02;&#x5E38;&#x4F1A;&#x88AB;ExceptionTranslationFilter&#x6355;&#x83B7;&#xFF0C;&#x901A;&#x5E38;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x5F02;&#x5E38;&#x5904;&#x7406;&#x65B9;&#x5F0F;&#x5C31;&#x662F;&#x8DF3;&#x8F6C;&#x5230;&#x5230;&#x767B;&#x5F55;&#x9875;&#x9762;&#x2462;&#xFF0C;&#x8BA9;&#x7528;&#x6237;&#x5B8C;&#x6210;&#x767B;&#x5F55;&#x7684;&#x64CD;&#x4F5C;&#x3002;</li><li>AbstractAuthenticationProcessingFilter&#xFF1A;&#x5B83;&#x5B9A;&#x4E49;&#x4E86;&#x4E00;&#x4E2A;&#x6BD4;&#x8F83;&#x901A;&#x7528;&#x7684;&#x8BA4;&#x8BC1;&#x201C;&#x6A21;&#x677F;&#x201D;&#x65B9;&#x6CD5;&#x3002;&#x5F53;&#x7528;&#x6237;&#x53D1;&#x8D77;&#x767B;&#x5F55;&#x8BF7;&#x6C42;&#x65F6;&#xFF0C;AbstractAuthenticationProcessingFilter&#x914D;&#x7F6E;&#x7684;RequestMatcher&#x5C31;&#x5339;&#x914D;&#x5230;&#x8FD9;&#x6B21;&#x8BF7;&#x6C42;&#x7684;url&#xFF0C;&#x9ED8;&#x8BA4;&#x6267;&#x884C;&#x8BA4;&#x8BC1;&#x7684;&#x662F;UsernamePasswordAuthenticationFilter&#xFF0C;&#x5B83;&#x5339;&#x914D;&#x7684;&#x8BF7;&#x6C42;&#x7AEF;&#x70B9;&#x662F;&quot;/login&quot;&#xFF0C;&#x6B64;&#x65F6;&#x5B83;&#x4ECE;request&#x8BF7;&#x6C42;&#x53C2;&#x6570;&#x4E2D;&#x83B7;&#x53D6;&#x7528;&#x6237;&#x540D;&#x548C;&#x5BC6;&#x7801;&#xFF0C;&#x5E76;&#x5C01;&#x88C5;&#x6210;UsernamePasswordAuthenticationToken&#x2460;&#xFF0C;&#x7136;&#x540E;&#x4EA4;&#x7ED9;ProviderManager#authenticate&#x65B9;&#x6CD5;&#x5BF9;&#x5176;&#x8BA4;&#x8BC1;&#x2461;&#xFF0C;&#x5728;&#x8BA4;&#x8BC1;&#x901A;&#x8FC7;&#x4E4B;&#x540E;&#xFF0C;&#x6211;&#x4EEC;&#x5C06;AuthenticationProvider&#x8FD4;&#x56DE;&#x7684;Authentication&#x5BF9;&#x8C61;&#x2462;&#xFF0C;&#x6B64;&#x65F6;SecurityContextHolderStrategy&#x4F1A;&#x521B;&#x5EFA;&#x51FA;&#x4E00;&#x4E2A;&#x7A7A;&#x8F7D;&#x7684;SecurityContext&#x5B9E;&#x4F8B;&#x2463;&#xFF0C;&#x5E76;&#x4F20;&#x5165;&#x4E0A;&#x8FF0;Authentication&#x2464;&#xFF0C;&#x7136;&#x540E;&#x8C03;&#x7528;SecurityContextHolderStrategy&#x7684;&#x4FDD;&#x5B58;&#x65B9;&#x6CD5;&#x2464;&#xFF0C;&#x6700;&#x540E;&#x901A;&#x8FC7;SecurityContextRepository&#x8FDB;&#x884C;&#x6301;&#x4E45;&#x5316;&#x2466;&#xFF0C;&#x53EF;&#x4EE5;&#x53C2;&#x8003;&#x4EE5;&#x4E0B;&#x7684;&#x6837;&#x677F;&#x4EE3;&#x7801;&#xFF0C;&#x5BF9;&#x4E8E;&#x5404;&#x7C7B;&#x8BA4;&#x8BC1;&#x5B9E;&#x73B0;&#xFF0C;&#x57FA;&#x672C;&#x4E0A;&#x5927;&#x540C;&#x5C0F;&#x5F02;&#x3002;</li></ol><pre><code class="language-Java">try {
    Authentication authenticationToken = createAuthentication() // // &#x4F8B;&#x5982;&#x521B;&#x5EFA;UsernamePasswordAuthenticationToken,OAuth2AuthorizationCodeAuthenticationToken&#x7B49;&#x7B49;&#xFF0C;&#x5C06;&#x5F85;&#x8BA4;&#x8BC1;&#x7684;&#x4FE1;&#x606F;&#x5C01;&#x88C5;&#x8D77;&#x6765;&#xFF0C;
    Authentication authResult = this.authenticationManager.authenticate(someAuthenticationToken); // &#x4EA4;&#x7ED9;ProviderManager&#x8FDB;&#x884C;&#x8BA4;&#x8BC1;&#xFF0C;&#x901A;&#x5E38;&#x7531;&#x5B9E;&#x9645;&#x7684;AuthenticationProvider&#x5B9E;&#x73B0;&#x7C7B;&#x5B8C;&#x6210;&#x5177;&#x4F53;&#x7684;&#x8BA4;&#x8BC1;&#x903B;&#x8F91;&#xFF0C;&#x5E76;&#x5C06;&#x8BA4;&#x8BC1;&#x7ED3;&#x679C;&#x8FD4;&#x56DE;
    SecurityContext context = this.securityContextRepository.createEmptyContext(); // &#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#x7A7A;&#x8F7D;&#x7684;SecurityContext&#x5B9E;&#x4F8B;
    context.setAuthentication(authResult); // &#x4F20;&#x5165;&#x7ECF;&#x8FC7;&#x8BA4;&#x8BC1;&#x7684;Authentication&#x5BF9;&#x8C61;
    this.securityContextHolderStrategy.setContext(context); // &#x5B58;&#x50A8;SecurityContextHolder&#x4E2D;&#xFF0C;&#x65B9;&#x4FBF;&#x540C;&#x4E00;&#x4E2A;&#x7EBF;&#x7A0B;&#x6267;&#x884C;&#x8FC7;&#x7A0B;&#x4E2D;&#x7684;&#x5176;&#x4ED6;&#x5730;&#x65B9;&#x83B7;&#x53D6;
    this.securityContextRepository.saveContext(context, request, response); // &#x8FDB;&#x884C;&#x6301;&#x4E45;&#x5316;&#xFF0C;&#x65B9;&#x4FBF;&#x4E0B;&#x6B21;&#x8BF7;&#x6C42;&#x8BBF;&#x95EE;&#x65F6;&#xFF0C;&#x53EF;&#x4EE5;&#x83B7;&#x53D6;&#x5BF9;&#x5E94;SecurityContext&#xFF0C;&#x5B9E;&#x73B0;&#x767B;&#x5F55;&#x6001;&#x7684;&#x4FDD;&#x6301;
    this.successHandler.onAuthenticationSuccess(request, response, authResult); // &#x8BA4;&#x8BC1;&#x6210;&#x529F;&#x540E;&#x7684;&#x6D41;&#x7A0B;&#xFF0C;&#x4F8B;&#x5982;&#x8DF3;&#x8F6C;&#x5230;&#x7CFB;&#x7EDF;&#x9996;&#x9875;&#x7B49;
} catch (AuthenticationException ex) {
    // Authentication failed
    this.securityContextHolderStrategy.clearContext(); // &#x8BA4;&#x8BC1;&#x5931;&#x8D25;&#x65F6;&#xFF0C;&#x6E05;&#x7A7A;SecurityContext
    this.failureHandler.onAuthenticationFailure(request, response, failed); // &#x8BA4;&#x8BC1;&#x5931;&#x8D25;&#x540E;&#x7684;&#x6D41;&#x7A0B;&#xFF0C;&#x4F8B;&#x5982;&#x63D0;&#x793A;&#x9519;&#x8BEF;&#x4FE1;&#x606F;&#x7B49;
}</code></pre><p>&#x8BF4;&#x660E;&#xFF1A;spring security&#x5BF9;&#x7528;&#x6237;&#x540D;&#x548C;&#x5BC6;&#x7801;&#x7684;&#x8BA4;&#x8BC1;&#x63D0;&#x4F9B;&#x4E86;&#x9ED8;&#x8BA4;&#x5B9E;&#x73B0;DaoAuthenticationProvider&#xFF0C;&#x4F46;&#x7531;&#x4E8E;&#x9ED8;&#x8BA4;&#x5B9E;&#x73B0;&#x9650;&#x5236;&#x6BD4;&#x8F83;&#x591A;&#xFF0C;&#x4E00;&#x822C;&#x5728;&#x5B9E;&#x9645;&#x7684;&#x751F;&#x4EA7;&#x6D3B;&#x52A8;&#x4E2D;&#x4E0D;&#x4F1A;&#x91C7;&#x7528;&#xFF0C;&#x901A;&#x5E38;&#x4F1A;&#x7EE7;&#x627F;AbstractUserDetailsAuthenticationProvider&#x6765;&#x5B9A;&#x5236;&#x5F00;&#x53D1;&#xFF0C;&#x6216;&#x8005;&#x53C2;&#x8003;&#x5B83;&#x7684;&#x6E90;&#x7801;&#x81EA;&#x5B9A;&#x4E49;&#x5B9E;&#x73B0;AuthenticationProvider&#x63A5;&#x53E3;&#x3002;</p><h2 id="%E4%B8%89%E3%80%81%E6%80%BB%E7%BB%93"> &#x4E09;&#x3001;&#x603B;&#x7ED3;</h2><p>&#x6700;&#x540E;&#xFF0C;&#x6211;&#x4EEC;&#x5BF9;spring security&#x6574;&#x4E2A;&#x8BA4;&#x8BC1;&#x67B6;&#x6784;&#x4E2D;&#x7684;&#x8BA4;&#x8BC1;&#x6D41;&#x7A0B;&#x548C;&#x5B58;&#x53D6;&#x6821;&#x9A8C;&#x6D41;&#x7A0B;&#xFF0C;&#x518D;&#x505A;&#x4E00;&#x4E2A;&#x603B;&#x7ED3;&#xFF1A;</p><ul><li>&#x8BA4;&#x8BC1;&#x6D41;&#x7A0B;&#xFF1A;AuthenticationManager&#x4E3A;&#x8FD9;&#x4E2A;&#x7CFB;&#x7EDF;&#x6240;&#x652F;&#x6301;&#x7684;&#x6240;&#x6709;&#x8BA4;&#x8BC1;&#x534F;&#x8BAE;&#xFF0C;&#x7EDF;&#x4E00;&#x63D0;&#x4F9B;authenticate&#x65B9;&#x6CD5;&#xFF0C;&#x6BD4;&#x5982;&#x652F;&#x6301;&#x7528;&#x6237;&#x540D;&#x5BC6;&#x7801;&#x767B;&#x5F55;&#xFF0C;&#x4E5F;&#x652F;&#x6301;&#x77ED;&#x4FE1;&#x9A8C;&#x8BC1;&#x7801;&#xFF0C;&#x7B2C;&#x4E09;&#x65B9;&#x6388;&#x6743;&#x767B;&#x5F55;&#x7B49;&#xFF0C;&#x4E0D;&#x8BBA;&#x54EA;&#x79CD;&#x8BA4;&#x8BC1;&#x8BF7;&#x6C42;&#xFF0C;&#x6700;&#x7EC8;&#x90FD;&#x4EA4;&#x7531;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x6267;&#x884C;&#xFF0C;&#x5176;&#x5B9E;&#x73B0;&#x7C7B;ProviderManager&#x5219;&#x9AD8;&#x5EA6;&#x5C01;&#x88C5;&#x4E86;&#x8BA4;&#x8BC1;&#x8FC7;&#x7A0B;&#xFF0C;&#x5176;&#x4E2D;&#x5177;&#x4F53;&#x7684;AuthenticationProvider&#x5B9E;&#x73B0;&#x7EF4;&#x62A4;&#x5728;List&#x5217;&#x8868;&#x4E2D;&#xFF0C;&#x901A;&#x8FC7;&#x904D;&#x5386;&#x4F7F;&#x5F97;&#x4E0D;&#x540C;&#x7684;&#x8BA4;&#x8BC1;&#x534F;&#x8BAE;&#x8FDB;&#x5165;&#x4E0D;&#x540C;&#x7684;&#x8BA4;&#x8BC1;&#x5B9E;&#x73B0;&#x7C7B;&#xFF0C;&#x7136;&#x540E;&#x90FD;&#x8FD4;&#x56DE;Authentication&#x5BF9;&#x8C61;&#xFF0C;Authentication&#x5B9A;&#x4E49;&#x4E86;&#x4E00;&#x4E2A;&#x8BA4;&#x8BC1;&#x4FE1;&#x606F;&#x5E94;&#x8BE5;&#x5FC5;&#x987B;&#x5305;&#x542B;&#x7684;&#x4FE1;&#x606F;&#xFF0C;&#x5305;&#x62EC;&#x7528;&#x6237;&#x6807;&#x8BC6;principal&#xFF0C;&#x51ED;&#x8BC1;credentials&#xFF0C;&#x6743;&#x9650;authorities&#xFF0C;&#x56E0;&#x6B64;&#x6211;&#x4EEC;&#x4E5F;&#x53EF;&#x4EE5;&#x5B9E;&#x73B0;&#x81EA;&#x5B9A;&#x4E49;&#x7684;AuthenticationProvider&#xFF0C;&#x5E76;&#x6CE8;&#x518C;&#x5230;ProviderManager&#x4E2D;&#xFF0C;&#x7136;&#x540E;&#x518D;&#x5B9E;&#x73B0;&#x81EA;&#x5B9A;&#x4E49;&#x7684;&#x8BA4;&#x8BC1;Filter&#x548C;Authentication&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x5B8C;&#x6210;&#x4E86;&#x6574;&#x5408;&#x3002;</li><li>&#x5B58;&#x53D6;&#x6821;&#x9A8C;&#x6D41;&#x7A0B;&#xFF1A;&#x5728;&#x5F97;&#x5230;&#x8BA4;&#x8BC1;&#x540E;&#x7684;Authentication&#x5BF9;&#x8C61;&#xFF0C;&#x9700;&#x8981;&#x89E3;&#x51B3;&#x7684;&#x662F;&#x5982;&#x4F55;&#x83B7;&#x53D6;&#x8FD9;&#x4E2A;Authentication&#x5BF9;&#x8C61;&#xFF0C;&#x4EE5;&#x5224;&#x65AD;&#x8BE5;&#x8BF7;&#x6C42;&#x662F;&#x5426;&#x5DF2;&#x7ECF;&#x901A;&#x8FC7;&#x8BA4;&#x8BC1;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x5F15;&#x5165;&#x53E6;&#x4E00;&#x4E2A;&#x91CD;&#x8981;&#x7684;&#x7C7B;SecurityContext&#xFF0C;&#x5B83;&#x76F8;&#x5F53;&#x4E8E;&#x4E00;&#x4E2A;&#x7528;&#x4E8E;&#x88C5;&#x8F7D;Authentication&#x5BF9;&#x8C61;&#x7684;&#x5BB9;&#x5668;&#xFF0C;&#x9996;&#x5148;&#x4F9D;&#x8D56;SecurityContextRepository&#x4ECE;&#x6301;&#x4E45;&#x5316;&#x7684;&#x4ECB;&#x8D28;&#xFF08;&#x4F8B;&#x5982;session&#xFF09;&#x4E2D;&#x52A0;&#x8F7D;&#x51FA;&#x6765;SecurityContext&#x5BF9;&#x8C61;&#xFF0C;&#x5176;&#x6B21;&#x901A;&#x8FC7;SecurityContextHolder&#x5185;&#x90E8;&#x7B56;&#x7565;&#x7C7B;&#x65B9;&#x4FBF;&#x5FEB;&#x901F;&#x5730;&#x8BFB;&#x5199;SecurityContext&#x5BF9;&#x8C61;&#xFF0C;&#x8FD9;&#x91CC;&#x5F88;&#x5BB9;&#x6613;&#x5C31;&#x60F3;&#x5230;&#x4F7F;&#x7528;ThreadLocal&#x6765;&#x5B9E;&#x73B0;&#x540C;&#x4E00;&#x4E2A;&#x8BF7;&#x6C42;&#x7684;&#x7EBF;&#x7A0B;&#x4E2D;&#x5B58;&#x53D6;&#x64CD;&#x4F5C;&#xFF0C;spring security&#x4E5F;&#x662F;&#x8FD9;&#x4E48;&#x505A;&#x7684;&#xFF0C;&#x6700;&#x7EC8;&#x5728;&#x5F97;&#x5230;SecurityContext&#x540E;&#xFF0C;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;&#x5176;&#x5185;&#x90E8;&#x7684;Authentication&#x5BF9;&#x8C61;&#x5224;&#x65AD;&#x662F;&#x5426;&#x5DF2;&#x8BA4;&#x8BC1;&#x3002;</li></ul><p>&#x53EF;&#x89C1;&#xFF0C;&#x4E0A;&#x8FF0;&#x4E24;&#x4E2A;&#x6838;&#x5FC3;&#x6D41;&#x7A0B;&#x57FA;&#x672C;&#x56F4;&#x7ED5;&#x7740;Authentication&#x548C;SecurityContext&#x8FD9;&#x4E24;&#x4E2A;&#x63A5;&#x53E3;&#x6765;&#x5EFA;&#x8BBE;&#xFF0C;&#x524D;&#x8005;&#x5BF9;&#x5916;&#x63D0;&#x4F9B;&#x8BA4;&#x8BC1;&#x670D;&#x52A1;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x8FDB;&#x884C;&#x6DF1;&#x5EA6;&#x7684;&#x5B9A;&#x5236;&#x5F00;&#x53D1;&#xFF0C;&#x5305;&#x62EC;Authentication&#xFF0C;Filter&#xFF0C;AuthenticationProvider&#x90FD;&#x53EF;&#x4EE5;&#x81EA;&#x5B9A;&#x4E49;&#x5B9E;&#x73B0;&#xFF0C;&#x5E76;&#x6574;&#x5408;&#x8FDB;&#x5165;SecurityFilterChain&#xFF0C;&#x540E;&#x8005;&#x5BF9;&#x5185;&#x63D0;&#x4F9B;&#x5B58;&#x53D6;&#x670D;&#x52A1;&#xFF0C;&#x901A;&#x5E38;&#x60C5;&#x51B5;&#x4E0B;&#x6211;&#x4EEC;&#x4E5F;&#x4E0D;&#x4F1A;&#x5BF9;&#x5B58;&#x53D6;&#x6D41;&#x7A0B;&#x8FDB;&#x884C;&#x6539;&#x9020;&#xFF0C;&#x5BF9;&#x4E8E;&#x7EDD;&#x5927;&#x591A;&#x6570;&#x573A;&#x666F;&#xFF0C;&#x53EA;&#x9700;&#x8981;&#x5229;&#x7528;SecurityContextHolder&#x8FD9;&#x4E2A;&#x5DE5;&#x5177;&#x7C7B;&#x8BFB;&#x5199;SecurityContext&#x5BF9;&#x8C61;&#xFF0C;&#x8FD9;&#x57FA;&#x672C;&#x4E0A;&#x5DF2;&#x7ECF;&#x8DB3;&#x591F;&#x4E86;&#x3002;&#x8FD9;&#x6837;&#x7684;&#x8BBE;&#x8BA1;&#xFF0C;&#x5728;&#x6700;&#x5927;&#x7A0B;&#x5EA6;&#x4E0A;&#x56FA;&#x5316;&#x4E86;&#x5B58;&#x53D6;&#x6821;&#x9A8C;&#x7684;&#x903B;&#x8F91;&#xFF0C;&#x4E0D;&#x4F1A;&#x56E0;&#x4E3A;&#x8BA4;&#x8BC1;&#x673A;&#x5236;&#x548C;&#x7ED3;&#x679C;&#x7684;&#x4E0D;&#x540C;&#xFF0C;&#x800C;&#x6539;&#x53D8;&#x5B58;&#x53D6;&#x6821;&#x9A8C;&#x7684;&#x903B;&#x8F91;&#x3002;</p><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/05/--2024-05-15-23.46.24.png" class="kg-image" alt="Spring Security 6.x &#x56FE;&#x89E3;&#x8EAB;&#x4EFD;&#x8BA4;&#x8BC1;&#x7684;&#x67B6;&#x6784;&#x8BBE;&#x8BA1;" loading="lazy" width="794" height="708" srcset="http://www.fullstackyang.com/content/images/size/w600/2024/05/--2024-05-15-23.46.24.png 600w, http://www.fullstackyang.com/content/images/2024/05/--2024-05-15-23.46.24.png 794w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA[Spring Security 6.x 过滤器链SecurityFilterChain是如何工作的]]></title><description><![CDATA[<p>&#x4E0A;&#x4E00;&#x7BC7;&#x4E3B;&#x8981;&#x4ECB;&#x7ECD;&#x4E86;Spring Secuirty&#x4E2D;&#x7684;&#x8FC7;&#x6EE4;&#x5668;&#x94FE;SecurityFilterChain&#x662F;&#x5982;&#x4F55;&#x914D;&#x7F6E;&#x7684;&#xFF0C;&#x90A3;&#x4E48;&#x5728;&#x914D;&#x7F6E;&#x5B8C;&#x6210;&#x4E4B;&#x540E;&#xFF0C;SecurityFilterChain&#x662F;&#x5982;&#x4F55;&#x5728;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x4E2D;&#x8C03;&#x7528;&#x5404;&#x4E2A;Filter&#xFF0C;</p>]]></description><link>http://www.fullstackyang.com/springan-quan-kuang-jia-xi-lie-sessionguan-li/</link><guid isPermaLink="false">642bcc53dfefff00015998a1</guid><category><![CDATA[dev]]></category><category><![CDATA[Spring Security]]></category><category><![CDATA[spring]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Sun, 12 May 2024 09:09:50 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2024/05/spring_security_lg-1280x720.png" medium="image"/><content:encoded><![CDATA[<img src="http://www.fullstackyang.com/content/images/2024/05/spring_security_lg-1280x720.png" alt="Spring Security 6.x &#x8FC7;&#x6EE4;&#x5668;&#x94FE;SecurityFilterChain&#x662F;&#x5982;&#x4F55;&#x5DE5;&#x4F5C;&#x7684;"><p>&#x4E0A;&#x4E00;&#x7BC7;&#x4E3B;&#x8981;&#x4ECB;&#x7ECD;&#x4E86;Spring Secuirty&#x4E2D;&#x7684;&#x8FC7;&#x6EE4;&#x5668;&#x94FE;SecurityFilterChain&#x662F;&#x5982;&#x4F55;&#x914D;&#x7F6E;&#x7684;&#xFF0C;&#x90A3;&#x4E48;&#x5728;&#x914D;&#x7F6E;&#x5B8C;&#x6210;&#x4E4B;&#x540E;&#xFF0C;SecurityFilterChain&#x662F;&#x5982;&#x4F55;&#x5728;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x4E2D;&#x8C03;&#x7528;&#x5404;&#x4E2A;Filter&#xFF0C;&#x4ECE;&#x800C;&#x8D77;&#x5230;&#x5B89;&#x5168;&#x9632;&#x62A4;&#x7684;&#x4F5C;&#x7528;&#xFF0C;&#x672C;&#x6587;&#x4E3B;&#x8981;&#x56F4;&#x7ED5;SecurityFilterChain&#x7684;&#x5DE5;&#x4F5C;&#x539F;&#x7406;&#x505A;&#x8BE6;&#x7EC6;&#x7684;&#x4ECB;&#x7ECD;&#x3002;</p><h3 id="%E4%B8%80%E3%80%81filter%E8%83%8C%E6%99%AF%E7%9F%A5%E8%AF%86">&#x4E00;&#x3001;Filter&#x80CC;&#x666F;&#x77E5;&#x8BC6;</h3><p>&#x56E0;&#x4E3A;Spring Security&#x5E95;&#x5C42;&#x4F9D;&#x8D56;Servlet&#x7684;&#x8FC7;&#x6EE4;&#x5668;&#x6280;&#x672F;&#xFF0C;&#x6240;&#x4EE5;&#x5148;&#x7B80;&#x5355;&#x5730;&#x56DE;&#x987E;&#x4E00;&#x4E0B;&#x76F8;&#x5173;&#x80CC;&#x666F;&#x77E5;&#x8BC6;&#x3002;</p><p>&#x8FC7;&#x6EE4;&#x5668;Filter&#x662F;Servlet&#x7684;&#x6807;&#x51C6;&#x7EC4;&#x4EF6;&#xFF0C;&#x81EA;Servlet 2.3&#x7248;&#x672C;&#x5F15;&#x5165;&#xFF0C;&#x4E3B;&#x8981;&#x4F5C;&#x7528;&#x662F;&#x5728;Servlet&#x5B9E;&#x4F8B;&#x63A5;&#x53D7;&#x5230;&#x8BF7;&#x6C42;&#x4E4B;&#x524D;&#xFF0C;&#x4EE5;&#x53CA;&#x8FD4;&#x56DE;&#x54CD;&#x5E94;&#x4E4B;&#x540E;&#xFF0C;&#x8FD9;&#x4E24;&#x4E2A;&#x65B9;&#x5411;&#x4E0A;&#x8FDB;&#x884C;&#x52A8;&#x6001;&#x62E6;&#x622A;&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x53EF;&#x4EE5;&#x4E0E;Servlet&#x4E3B;&#x4E1A;&#x52A1;&#x903B;&#x8F91;&#x89E3;&#x8026;&#xFF0C;&#x4ECE;&#x800C;&#x5B9E;&#x73B0;&#x7075;&#x6D3B;&#x6027;&#x548C;&#x53EF;&#x6269;&#x5C55;&#x6027;&#xFF0C;&#x5229;&#x7528;&#x8FD9;&#x4E2A;&#x7279;&#x6027;&#x53EF;&#x4EE5;&#x5B9E;&#x73B0;&#x5F88;&#x591A;&#x529F;&#x80FD;&#xFF0C;&#x4F8B;&#x5982;&#x8EAB;&#x4EFD;&#x8BA4;&#x8BC1;&#xFF0C;&#x7EDF;&#x4E00;&#x7F16;&#x7801;&#xFF0C;&#x6570;&#x636E;&#x52A0;&#x5BC6;&#x89E3;&#x5BC6;&#xFF0C;&#x5BA1;&#x8BA1;&#x65E5;&#x5FD7;&#x7B49;&#x7B49;&#x3002;</p><p>Filter&#x63A5;&#x53E3;&#x5B9A;&#x4E49;&#x4E86;3&#x4E2A;&#x65B9;&#x6CD5;&#xFF1A;doFilter&#xFF0C;init&#x548C;destory&#xFF0C;&#x5176;&#x4E2D;doFilter&#x5C31;&#x662F;&#x8BF7;&#x6C42;&#x8FDB;&#x5165;&#x8FC7;&#x6EE4;&#x5668;&#x65F6;&#x9700;&#x8981;&#x6267;&#x884C;&#x7684;&#x903B;&#x8F91;&#xFF0C;&#x4F2A;&#x4EE3;&#x7801;&#x5B9E;&#x73B0;&#x5982;&#x4E0B;</p><pre><code class="language-Java">public class ExampleFilter implements Filter {
    &#x2026;
    public void doFilter(ServletRequest request, ServletResponse response,
                            FilterChain chain) throws IOException, ServletException {
        doSomething();
        chain.doFilter(request,response);    
    }
    &#x2026;
}</code></pre><p>&#x5176;&#x4E2D;FilterChain&#x4E2D;&#x7EF4;&#x62A4;&#x4E86;&#x4E00;&#x4E2A;&#x6240;&#x6709;&#x5DF2;&#x6CE8;&#x518C;&#x7684;&#x8FC7;&#x6EE4;&#x5668;&#x6570;&#x7EC4;&#xFF0C;&#x5B83;&#x7EC4;&#x6210;&#x4E86;&#x771F;&#x6B63;&#x7684;&#x201C;&#x8FC7;&#x6EE4;&#x5668;&#x94FE;&#x201D;&#xFF0C;&#x4E0B;&#x9762;&#x662F;FilterChain&#x7684;&#x5B9E;&#x73B0;&#x7C7B;ApplicationFilterChain&#x7684;&#x90E8;&#x5206;&#x6E90;&#x7801;&#xFF1A;&#x5F53;&#x8BF7;&#x6C42;&#x5230;&#x8FBE;Servlet&#x5BB9;&#x5668;&#x65F6;&#xFF0C;&#x5C31;&#x4F1A;&#x521B;&#x5EFA;&#x51FA;&#x4E00;&#x4E2A;FilterChain&#x5B9E;&#x4F8B;&#xFF0C;&#x7136;&#x540E;&#x8C03;&#x7528;FilterChain#doFilter&#x65B9;&#x6CD5;&#xFF0C;&#x8FD9;&#x65F6;&#x4F1A;&#x4ECE;&#x6570;&#x7EC4;&#x4E2D;&#x53D6;&#x51FA;&#x4E0B;&#x4E00;&#x4E2A;&#x8FC7;&#x6EE4;&#x5668;&#xFF0C;&#x5E76;&#x8C03;&#x7528;Filter#doFilter&#x65B9;&#x6CD5;&#xFF0C;&#x5728;&#x65B9;&#x6CD5;&#x672B;&#x5C3E;&#x53C8;&#x4F1A;&#x5C06;&#x8BF7;&#x6C42;&#x7EE7;&#x7EED;&#x4EA4;&#x7531;FilterChain&#x5904;&#x7406;&#xFF0C;&#x5982;&#x6B64;&#x5F80;&#x590D;&#xFF0C;&#x4ECE;&#x800C;&#x5B9E;&#x73B0;&#x804C;&#x8D23;&#x94FE;&#x6A21;&#x5F0F;&#x7684;&#x8C03;&#x7528;&#x65B9;&#x5F0F;&#x3002;</p><pre><code class="language-Java">private void internalDoFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {

    // Call the next filter if there is one
    if (pos &lt; n) {
        ApplicationFilterConfig filterConfig = filters[pos++];
        try {
            Filter filter = filterConfig.getFilter();
            ...
            if (Globals.IS_SECURITY_ENABLED) {
               // ...
            } else {
                filter.doFilter(request, response, this);
            }
        } catch (...) {
          ...
        }
        return;
    }

    // We fell off the end of the chain -- call the servlet instance
    try {
        ...
        // Use potentially wrapped request from this point
        if ((request instanceof HttpServletRequest) &amp;&amp; (response instanceof HttpServletResponse) &amp;&amp;
                Globals.IS_SECURITY_ENABLED) {
           ...
        } else {
            servlet.service(request, response);
        }
    } catch (...) {
       ...
    } finally {
       ...
    }
}</code></pre><p>Filter&#x5B9E;&#x4F8B;&#x53EF;&#x4EE5;&#x5728;web.xml&#x4E2D;&#x6CE8;&#x518C;&#xFF0C;&#x540C;&#x65F6;&#x8BBE;&#x7F6E;URL&#x6620;&#x5C04;&#x903B;&#x8F91;&#xFF0C;&#x5F53;URL&#x7B26;&#x5408;&#x8BBE;&#x7F6E;&#x7684;&#x89C4;&#x5219;&#x65F6;&#xFF0C;&#x4FBF;&#x4F1A;&#x8FDB;&#x5165;&#x8BE5;Filter&#xFF0C;&#x4E3E;&#x4E2A;&#x4F8B;&#x5B50;&#xFF0C;&#x5728;Spring Boot&#x95EE;&#x4E16;&#x4E4B;&#x524D;&#x5F00;&#x53D1;&#x4E00;&#x4E2A;&#x666E;&#x901A;&#x7684;Spring MVC&#x5E94;&#x7528;&#x65F6;&#xFF0C;&#x7ECF;&#x5E38;&#x4F1A;&#x914D;&#x7F6E;&#x4E00;&#x4E2A;CharacterEncodingFilter&#xFF0C;&#x7528;&#x4E8E;&#x7EDF;&#x4E00;&#x8BF7;&#x6C42;&#x548C;&#x54CD;&#x5E94;&#x7684;&#x7F16;&#x7801;&#xFF0C;&#x4EE5;&#x907F;&#x514D;&#x4E00;&#x4E9B;&#x4E2D;&#x6587;&#x4E71;&#x7801;&#x7684;&#x95EE;&#x9898;</p><pre><code class="language-XML">&lt;filter&gt;
    &lt;filter-name&gt;characterEncodingFilter&lt;/filter-name&gt;
    &lt;filter-class&gt;org.springframework.web.filter.CharacterEncodingFilter&lt;/filter-class&gt;
    &lt;init-param&gt;
        &lt;param-name&gt;encoding&lt;/param-name&gt;
        &lt;param-value&gt;UTF-8&lt;/param-value&gt;
    &lt;/init-param&gt;
    &lt;init-param&gt;
        &lt;param-name&gt;forceEncoding&lt;/param-name&gt;
        &lt;param-value&gt;true&lt;/param-value&gt;
    &lt;/init-param&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
    &lt;filter-name&gt;characterEncodingFilter&lt;/filter-name&gt;
    &lt;url-pattern&gt;/*&lt;/url-pattern&gt; &lt;!-- &#x76F8;&#x5F53;&#x4E8E;&#x62E6;&#x622A;&#x6240;&#x6709;&#x8BF7;&#x6C42; --&gt;
&lt;/filter-mapping&gt;</code></pre><h3 id="%E4%BA%8C%E3%80%81securityfilterchain%E7%9A%84%E5%BF%85%E8%A6%81%E6%80%A7">&#x4E8C;&#x3001;SecurityFilterChain&#x7684;&#x5FC5;&#x8981;&#x6027;</h3><p>&#x518D;&#x56DE;&#x5230;SecurityFilterChain&#xFF0C;&#x5148;&#x6765;&#x601D;&#x8003;&#x4E00;&#x4E2A;&#x95EE;&#x9898;&#xFF1A;&#x57FA;&#x4E8E;&#x4E0A;&#x9762;&#x6240;&#x4ECB;&#x7ECD;&#x7684;Filter&#xFF0C;&#x6211;&#x4EEC;&#x81EA;&#x7136;&#x4F1A;&#x60F3;&#x5230;&#xFF0C;&#x5B9A;&#x4E49;&#x4E00;&#x7CFB;&#x5217;&#x4E0E;&#x5B89;&#x5168;&#x76F8;&#x5173;&#x7684;Filter&#xFF0C;&#x4F8B;&#x5982;&#x6211;&#x4EEC;&#x5728;&#x4E0A;&#x4E00;&#x7BC7;&#x63D0;&#x5230;&#x7684;&#x90A3;&#x4E9B;&#x5305;&#x62EC;&#x8BA4;&#x8BC1;&#xFF0C;&#x9274;&#x6743;&#x7B49;&#x5728;&#x5185;&#x7684;Filter&#xFF0C;&#x7136;&#x540E;&#x53EA;&#x8981;&#x628A;&#x4ED6;&#x4EEC;&#x4E00;&#x4E2A;&#x4E2A;&#x6CE8;&#x518C;&#x5230;FilterChain&#x4E2D;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x5B9E;&#x73B0;&#x5404;&#x79CD;&#x5B89;&#x5168;&#x7279;&#x6027;&#xFF0C;&#x770B;&#x8D77;&#x6765;&#x4E5F;&#x5E76;&#x4E0D;&#x9700;&#x8981;Spring Security&#x63D0;&#x4F9B;&#x7684;SecuriyFilterChain&#xFF0C;&#x4E5F;&#x6B63;&#x56E0;&#x5982;&#x6B64;&#xFF0C;&#x521D;&#x5B66;&#x8005;&#x7ECF;&#x5E38;&#x4F1A;&#x6709;&#x4E00;&#x4E2A;&#x7591;&#x95EE;&#xFF0C;&#x5C31;&#x662F;&#x660E;&#x660E;&#x52A0;&#x4E00;&#x4E2A;Filter&#x5C31;&#x53EF;&#x4EE5;&#x89E3;&#x51B3;&#x7684;&#x4E8B;&#xFF0C;&#x4E3A;&#x4EC0;&#x4E48;&#x641E;&#x5F97;&#x8FD9;&#x4E48;&#x590D;&#x6742;&#xFF1F;&#x90A3;&#x4E48;SecurityFilterChain&#x7684;&#x5FC5;&#x8981;&#x6027;&#x662F;&#x4EC0;&#x4E48;&#xFF1F;&#x6211;&#x4EEC;&#x4E00;&#x5C42;&#x4E00;&#x5C42;&#x9010;&#x6B65;&#x8BF4;&#x660E;&#x8FD9;&#x4E2A;&#x95EE;&#x9898;&#xFF1A;</p><ol><li>&#x9996;&#x5148;&#x8981;&#x89E3;&#x51B3;&#x7684;&#x662F;&#x5982;&#x4F55;&#x5728;Filter&#x4E2D;&#x83B7;&#x53D6;Spring&#x5BB9;&#x5668;&#x4E2D;Bean&#x5BF9;&#x8C61;&#xFF0C;&#x56E0;&#x4E3A;&#x5728;Servlet&#x5BB9;&#x5668;&#x4E2D;&#x542F;&#x52A8;&#x65F6;&#xFF0C;&#x5404;&#x4E2A;Filter&#x7684;&#x5B9E;&#x4F8B;&#x4FBF;&#x4F1A;&#x521D;&#x59CB;&#x5316;&#x5E76;&#x5B8C;&#x6210;&#x6CE8;&#x518C;&#xFF0C;&#x6B64;&#x65F6;Spring Bean&#x5BF9;&#x8C61;&#x8FD8;&#x6CA1;&#x6709;&#x5B8C;&#x6210;&#x6574;&#x4E2A;&#x52A0;&#x8F7D;&#x8FC7;&#x7A0B;&#xFF0C;&#x4E0D;&#x80FD;&#x76F4;&#x63A5;&#x6CE8;&#x5165;&#xFF0C;&#x4E0D;&#x8FC7;&#x5F88;&#x5BB9;&#x6613;&#x60F3;&#x5230;&#xFF0C;&#x53EF;&#x4EE5;&#x7528;&#x4E00;&#x4E2A;&#x201C;&#x865A;&#x62DF;&#x201D;&#x7684;Filter&#x5728;Servlet&#x5BB9;&#x5668;&#x542F;&#x52A8;&#x65F6;&#x5148;&#x5B8C;&#x6210;&#x6CE8;&#x518C;&#xFF0C;&#x7136;&#x540E;&#x5728;&#x6267;&#x884C;doFilter&#x65F6;&#xFF0C;&#x518D;&#x83B7;&#x53D6;&#x5BF9;&#x5E94;&#x7684;Spring Bean&#x4F5C;&#x4E3A;&#x5B9E;&#x9645;&#x7684;Filter&#x5B9E;&#x4F8B;&#xFF0C;&#x6267;&#x884C;&#x5177;&#x4F53;&#x7684;doFilter&#x903B;&#x8F91;&#xFF0C;&#x8FD9;&#x662F;&#x4E00;&#x4E2A;&#x5178;&#x578B;&#x7684;&#x59D4;&#x6D3E;&#x6A21;&#x5F0F;&#xFF0C;Spring Security&#x4E3A;&#x6B64;&#x63D0;&#x4F9B;&#x4E86;&#x4E00;&#x4E2A;&#x540D;&#x4E3A;DelegatingFilterProxy&#x7684;&#x7C7B;&#xFF0C;&#x4E0B;&#x6587;&#x518D;&#x4F5C;&#x8BE6;&#x7EC6;&#x4ECB;&#x7ECD;&#x3002;</li><li>&#x89E3;&#x51B3;&#x4E86;Spring Bean&#x5BB9;&#x5668;&#x4E0E;Servlet Filter&#x6574;&#x5408;&#x7684;&#x95EE;&#x9898;&#x4E4B;&#x540E;&#xFF0C;&#x6211;&#x4EEC;&#x662F;&#x5426;&#x53EF;&#x4EE5;&#x5C06;&#x6BCF;&#x4E00;&#x4E2A;Filter&#x90FD;&#x901A;&#x8FC7;DelegatingFilterProxy&#x7684;&#x6A21;&#x5F0F;&#x6DFB;&#x52A0;&#x5230;FilterChain&#x4E2D;&#xFF1F;&#x8BD5;&#x60F3;&#x4E00;&#x4E0B;&#xFF0C;&#x5982;&#x679C;&#x6BCF;&#x4E2A;Spring Security&#x7684;Filter&#x90FD;&#x5206;&#x522B;&#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#x72EC;&#x7ACB;&#x7684;&#x59D4;&#x6D3E;&#x7C7B;&#xFF0C;&#x90A3;&#x4E48;&#x901A;&#x8FC7;ApplicationContext&#x67E5;&#x627E;bean&#x7684;&#x4EE3;&#x7801;&#x5C31;&#x4F1A;&#x53CD;&#x590D;&#x51FA;&#x73B0;&#xFF0C;&#x8FD9;&#x5728;&#x5F88;&#x5927;&#x7A0B;&#x5EA6;&#x4E0A;&#x8FDD;&#x80CC;&#x4E86;&#x4F9D;&#x8D56;&#x6CE8;&#x5165;&#x7684;&#x539F;&#x5219;&#xFF0C;&#x4E5F;&#x6781;&#x5927;&#x4E86;&#x589E;&#x52A0;&#x4E86;&#x7EF4;&#x62A4;&#x6210;&#x672C;&#x548C;&#x5F00;&#x53D1;&#x6210;&#x672C;&#xFF0C;&#x4E3A;&#x4E86;&#x89E3;&#x51B3;&#x8FD9;&#x4E2A;&#x95EE;&#x9898;&#xFF0C;&#x5728;&#x4E0A;&#x8FF0;DelegateFilterProxy&#x57FA;&#x7840;&#x4E0A;&#xFF0C;Spring Security&#x53C8;&#x5F15;&#x5165;&#x4E86;&#x4E00;&#x4E2A;&#x4EE3;&#x7406;&#x7C7B;FilterChainProxy&#xFF0C;&#x5B83;&#x53EF;&#x4EE5;&#x770B;&#x4F5C;&#x662F;Spring Security Filter&#x7684;&#x7EDF;&#x4E00;&#x5165;&#x53E3;&#xFF0C;&#x6B64;&#x65F6;&#xFF0C;&#x4ECE;Servlet&#x7684;FIlterChain&#x89D2;&#x5EA6;&#x6765;&#x770B;&#xFF0C;&#x6574;&#x4E2A;Spring Security&#x53EA;&#x5B9A;&#x4E49;&#x4E86;&#x4E00;&#x4E2A;Filter&#xFF0C;&#x5373;DelegatingFilterProxy&#xFF0C;&#x800C;&#x6267;&#x884C;doFilter&#x65F6;&#x5219;&#x59D4;&#x6D3E;&#x7ED9;&#x4E86;FilterChainProxy&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x53EF;&#x4EE5;&#x5229;&#x7528;&#x8FD9;&#x4E2A;&#x5165;&#x53E3;&#x7B80;&#x5316;&#x5F88;&#x591A;&#x5DE5;&#x4F5C;&#xFF0C;&#x4F8B;&#x5982;&#x5B98;&#x65B9;&#x6587;&#x6863;&#x4E2D;&#x63D0;&#x5230;&#xFF0C;&#x53EF;&#x4EE5;&#x5728;&#x8C03;&#x8BD5;Spring Security&#x529F;&#x80FD;&#x65F6;&#xFF0C;&#x5C06;&#x65AD;&#x70B9;&#x8BBE;&#x7F6E;&#x5728;&#x8FD9;&#x4E2A;&#x5165;&#x53E3;&#xFF0C;&#x65B9;&#x4FBF;&#x6211;&#x4EEC;&#x8DDF;&#x8E2A;&#x5B9A;&#x4F4D;&#x95EE;&#x9898;&#x7B49;&#x7B49;</li><li>FilterChainProxy&#x4F5C;&#x4E3A;&#x7EDF;&#x4E00;&#x6536;&#x53E3;&#xFF0C;&#x540C;&#x65F6;&#x4E5F;&#x8D77;&#x5230;&#x4E86;&#x6253;&#x901A;SecurityFilterChain&#x7684;&#x6865;&#x6881;&#x4F5C;&#x7528;&#xFF0C;&#x5728;&#x8C03;&#x7528;doFilter&#x65B9;&#x6CD5;&#x65F6;&#xFF0C;&#x5B9E;&#x9645;&#x4E0A;&#x90FD;&#x4EA4;&#x7ED9;&#x67D0;&#x4E2A;SecurityFilterChain&#x5B9E;&#x4F8B;&#x6267;&#x884C;&#xFF0C;&#x5230;&#x8FD9;&#x91CC;&#x8BF7;&#x6C42;&#x624D;&#x7B97;&#x662F;&#x8FDB;&#x5165;&#x4E86;&#x6211;&#x4EEC;&#x4F7F;&#x7528;HttpSecurity&#x914D;&#x7F6E;&#x7684;&#x5404;&#x4E2A;Filter&#xFF0C;&#x800C;&#x5728;&#x6267;&#x884C;SecurityFilterChain&#x7684;&#x524D;&#x540E;&#x4F4D;&#x7F6E;&#xFF0C;&#x53C8;&#x53EF;&#x4EE5;&#x7EDF;&#x4E00;&#x6DFB;&#x52A0;&#x4E00;&#x4E9B;&#x5904;&#x7406;&#xFF0C;&#x4F8B;&#x5982;&#x6DFB;&#x52A0;Spring Security&#x7684;&#x9632;&#x706B;&#x5899;HttpFirewall&#xFF0C;&#x7528;&#x4EE5;&#x9632;&#x8303;&#x67D0;&#x4E9B;&#x7279;&#x5B9A;&#x7C7B;&#x578B;&#x7684;&#x653B;&#x51FB;</li><li>&#x6700;&#x540E;&#x8FD8;&#x6709;&#x4E00;&#x70B9;&#xFF0C;Servlet Filter&#x672C;&#x8EAB;&#x4E5F;&#x5B58;&#x5728;&#x4E00;&#x5B9A;&#x7684;&#x5C40;&#x9650;&#x6027;&#xFF0C;&#x4F8B;&#x5982;&#x6620;&#x5C04;&#x914D;&#x7F6E;&#x4E0D;&#x591F;&#x7075;&#x6D3B;&#xFF0C;&#x53EA;&#x80FD;&#x6839;&#x636E;URL&#x8FDB;&#x884C;&#x5339;&#x914D;&#xFF0C;&#x800C;SecurityFilterChain&#x901A;&#x8FC7;RequestMatcher&#x63A5;&#x53E3;&#x5B9E;&#x73B0;&#x4E86;&#x4E0D;&#x540C;&#x5339;&#x914D;&#x903B;&#x8F91;&#x53CA;&#x7EC4;&#x5408;&#xFF0C;&#x5927;&#x5927;&#x4E30;&#x5BCC;&#x4E86;&#x5339;&#x914D;&#x89C4;&#x5219;&#x6620;&#x5C04;&#x7684;&#x80FD;&#x529B;</li></ol><p>&#x7EFC;&#x4E0A;&#x6240;&#x8FF0;&#xFF0C;&#x901A;&#x8FC7;DelegatingFilterProxy-&gt;FilterChainProxy-&gt;SecurityFilterChain&#x8FD9;&#x6837;&#x7684;&#x4E09;&#x5C42;&#x7ED3;&#x6784;&#x5173;&#x7CFB;&#xFF0C;&#x4F7F;&#x5F97;SecurityFilterChain&#x4E2D;&#x7684;&#x5404;&#x4E2A;Filter&#x88AB;&#x5F53;&#x6210;&#x4E86;&#x4E00;&#x4E2A;&#x6574;&#x4F53;&#xFF0C;&#x7F6E;&#x4E8E;Servlet FilterChain&#x4E4B;&#x4E2D;&#xFF0C;&#x53C8;&#x80FD;&#x548C;&#x5176;&#x4ED6;&#x7684;Filter&#x72EC;&#x7ACB;&#x5F00;&#xFF0C;&#x4E0D;&#x8BBA;&#x6211;&#x4EEC;&#x5982;&#x4F55;&#x914D;&#x7F6E;SecurityFilterChain&#xFF0C;&#x90FD;&#x4E0D;&#x4F1A;&#x5F15;&#x8D77;Servlet FilterChain&#x7684;&#x53D8;&#x66F4;&#xFF0C;&#x8FD9;&#x6837;&#x7684;&#x8BBE;&#x8BA1;&#x5F88;&#x597D;&#x5730;&#x9075;&#x5FAA;&#x4E86;&#x5F00;&#x653E;&#x5C01;&#x95ED;&#x539F;&#x5219;&#xFF0C;&#x5373;&#x5BF9;Servlet Filter&#x7684;&#x4FEE;&#x6539;&#x662F;&#x4FDD;&#x6301;&#x5C01;&#x95ED;&#x7684;&#xFF0C;&#x800C;&#x5BF9;Spring Security Filter&#x7684;&#x914D;&#x7F6E;&#x548C;&#x6269;&#x5C55;&#x662F;&#x4FDD;&#x6301;&#x5F00;&#x653E;&#x7684;&#x3002;</p><p>&#x5176;&#x5B9E;&#xFF0C;&#x6211;&#x4EEC;&#x5728;&#x5F88;&#x591A;Spring&#x7684;&#x6846;&#x67B6;&#x4E2D;&#xFF0C;&#x90FD;&#x53EF;&#x4EE5;&#x89C1;&#x5230;&#x8FD9;&#x79CD;&#x8BBE;&#x8BA1;&#xFF0C;&#x672C;&#x8D28;&#x4E0A;&#x6765;&#x8BF4;&#xFF0C;&#x5373;&#x901A;&#x8FC7;&#x6DFB;&#x52A0;&#x4E00;&#x4E2A;&#x4E2D;&#x95F4;&#x5C42;&#x6765;&#x8FBE;&#x5230;&#x89E3;&#x8026;&#x7684;&#x76EE;&#x7684;&#xFF0C;&#x6211;&#x4EEC;&#x5E94;&#x8BE5;&#x6DF1;&#x5165;&#x5730;&#x7406;&#x89E3;&#x8FD9;&#x79CD;&#x8BBE;&#x8BA1;&#xFF0C;&#x5E76;&#x5B66;&#x4EE5;&#x81F4;&#x7528;&#x3002;</p><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/05/image-4.png" class="kg-image" alt="Spring Security 6.x &#x8FC7;&#x6EE4;&#x5668;&#x94FE;SecurityFilterChain&#x662F;&#x5982;&#x4F55;&#x5DE5;&#x4F5C;&#x7684;" loading="lazy" width="765" height="1044" srcset="http://www.fullstackyang.com/content/images/size/w600/2024/05/image-4.png 600w, http://www.fullstackyang.com/content/images/2024/05/image-4.png 765w" sizes="(min-width: 720px) 720px"></figure><h3 id="%E4%B8%89%E3%80%81securiyfilterchain%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86">&#x4E09;&#x3001;SecuriyFilterChain&#x7684;&#x5DE5;&#x4F5C;&#x539F;&#x7406;</h3><p>&#x8BA8;&#x8BBA;&#x5B8C;SecurityFilterChain&#x5FC5;&#x8981;&#x6027;&#xFF0C;&#x518D;&#x6765;&#x4ECB;&#x7ECD;SecurityFilterChain&#x7684;&#x5DE5;&#x4F5C;&#x539F;&#x7406;&#x5C31;&#x4F1A;&#x53D8;&#x5F97;&#x6BD4;&#x8F83;&#x597D;&#x7406;&#x89E3;&#x4E86;&#xFF1A;</p><p>1.	&#x6CE8;&#x518C;DelegatingFilterProxy&#xFF1A;</p><p>&#x5728;&#x975E;Spring Boot&#x73AF;&#x5883;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;web.xml&#x8FDB;&#x884C;&#x6CE8;&#x518C;&#xFF0C;&#x914D;&#x7F6E;&#x5982;&#x4E0B;&#xFF1A;</p><pre><code class="language-XML">&lt;filter&gt;
    &lt;filter-name&gt;springSecurityFilterChain&lt;/filter-name&gt;
    &lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;
&lt;/filter&gt;

&lt;filter-mapping&gt;
    &lt;filter-name&gt;springSecurityFilterChain&lt;/filter-name&gt;
    &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;</code></pre><p>&#x800C;&#x5728;Spring Boot&#x73AF;&#x5883;&#x4E0B;&#xFF0C;&#x5219;&#x662F;&#x901A;&#x8FC7;RegistrationBean&#x7684;&#x65B9;&#x5F0F;&#x6CE8;&#x518C;Servlet&#x7EC4;&#x4EF6;&#xFF0C;&#x5177;&#x4F53;&#x5B9E;&#x73B0;&#x7C7B;&#x4E3A;DelegatingFilterProxyRegistrationBean&#xFF0C;&#x5B83;&#x7531;SecurityFilterAutoConfiguration&#x914D;&#x7F6E;&#x7C7B;&#x521B;&#x5EFA;&#x51FA;&#x6765;&#xFF0C;&#x5E76;&#x5728;Servlet&#x5BB9;&#x5668;&#x542F;&#x52A8;&#x7684;&#x65F6;&#x5019;&#x5B8C;&#x6210;Filter&#x7684;&#x6CE8;&#x518C;&#x3002;&#x5B8C;&#x6210;&#x6CE8;&#x518C;&#x540E;&#xFF0C;&#x5F53;Servlet&#x5BB9;&#x5668;&#x542F;&#x52A8;&#x65F6;&#xFF0C;FilterChain&#x5C31;&#x5305;&#x542B;&#x4E86;DelegatingFilterProxy&#x8FD9;&#x4E2A;Filter&#x3002;</p><p>2.	&#x59D4;&#x6D3E;FilterChainProxy&#xFF1A;</p><p>&#x4E0A;&#x6587;&#x63D0;&#x5230;&#x5728;&#x6267;&#x884C;DelegatingFilterProxy&#x7684;doFilter&#x65B9;&#x6CD5;&#x65F6;&#xFF0C;&#x5B9E;&#x9645;&#x4E0A;&#x90FD;&#x662F;&#x4EA4;&#x7ED9;FilterChainProxy&#x6765;&#x6267;&#x884C;&#xFF0C;&#x5B83;&#x662F;&#x7531;Spring&#x5BB9;&#x5668;&#x6258;&#x7BA1;&#x7684;bean&#x5BF9;&#x8C61;&#xFF0C;&#x901A;&#x8FC7;&#x4E0B;&#x9762;WebSecurityConfiguration&#x914D;&#x7F6E;&#x7C7B;&#x6E90;&#x7801;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;&#x5176;&#x4E2D;&#x5B9A;&#x4E49;&#x4E86;&#x4E00;&#x4E2A;&#x540D;&#x79F0;&#x4E3A;&#x201C;springSecurityFilterChain&#x201D;&#x7684;Bean&#xFF0C;&#x800C;&#x5176;&#x4E2D;webSecurity#build&#x65B9;&#x6CD5;&#x8FD4;&#x56DE;&#x7684;&#x5C31;&#x662F;FilerChainProxy&#x7684;&#x5B9E;&#x4F8B;&#xFF0C;&#x5176;&#x6784;&#x5EFA;&#x8FC7;&#x7A0B;&#x548C;&#x4E0A;&#x4E00;&#x7BC7;&#x4ECB;&#x7ECD;&#x7684;HttpSecurity&#x7C7B;&#x4F3C;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x4E0D;&#x518D;&#x5C55;&#x5F00;&#x3002;</p><pre><code class="language-Java">@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) // &quot;springSecurityFilterChain&quot;
public Filter springSecurityFilterChain() throws Exception {
    ...
    return this.webSecurity.build();
}</code></pre><p>&#x59D4;&#x6D3E;&#x8FC7;&#x7A0B;&#x6BD4;&#x8F83;&#x7B80;&#x5355;&#xFF0C;&#x4E0B;&#x9762;&#x662F;DelegatingFilterProxy#doFilter&#x65B9;&#x6CD5;&#x7684;&#x6E90;&#x7801;&#xFF08;&#x53EF;&#x4EE5;&#x5FFD;&#x7565;&#x5E76;&#x53D1;&#x63A7;&#x5236;&#x7684;&#x4EE3;&#x7801;&#xFF09;&#xFF0C;&#x5F53;&#x8BF7;&#x6C42;&#x8FDB;&#x5165;doFilter&#x4E4B;&#x540E;&#xFF0C;&#x9996;&#x5148;&#x8C03;&#x7528;initDelegate&#x65B9;&#x6CD5;&#xFF0C;&#x8FD9;&#x91CC;&#x5229;&#x7528;Spring&#x7684;ApplicationContext#getBean&#x65B9;&#x6CD5;&#x83B7;&#x53D6;&#x540D;&#x4E3A;&#x201C;springSecurityFilterChain&#x201C;&#x7684;bean&#x5BF9;&#x8C61;&#xFF0C;&#x5373;FilterChainProxy&#xFF0C;&#x7136;&#x540E;&#x8C03;&#x7528;&#x5176;doFilter&#x65B9;&#x6CD5;&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x5B8C;&#x6210;&#x4E86;&#x59D4;&#x6D3E;&#x8C03;&#x7528;&#x3002;</p><pre><code class="language-Java">public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
       throws ServletException, IOException {

    // Lazily initialize the delegate if necessary.
    Filter delegateToUse = this.delegate;
    if (delegateToUse == null) {
       synchronized (this.delegateMonitor) {
          delegateToUse = this.delegate;
          if (delegateToUse == null) {
             WebApplicationContext wac = findWebApplicationContext();
             if (wac == null) {
                throw new IllegalStateException(&quot;No WebApplicationContext found: &quot; +
                      &quot;no ContextLoaderListener or DispatcherServlet registered?&quot;);
             }
             delegateToUse = initDelegate(wac);
          }
          this.delegate = delegateToUse;
       }
    }

    // Let the delegate perform the actual doFilter operation.
    invokeDelegate(delegateToUse, request, response, filterChain);
}

protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
    String targetBeanName = getTargetBeanName(); // &quot;springSecurityFilterChain&quot;
    Assert.state(targetBeanName != null, &quot;No target bean name set&quot;);
    Filter delegate = wac.getBean(targetBeanName, Filter.class);
    if (isTargetFilterLifecycle()) {
       delegate.init(getFilterConfig());
    }
    return delegate;
}

protected void invokeDelegate(
       Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
       throws ServletException, IOException {

    delegate.doFilter(request, response, filterChain);
}</code></pre><p>3.	&#x6267;&#x884C;SecurityFilterChain&#x7684;&#x8FC7;&#x6EE4;&#x5668;&#x94FE;&#xFF1A;</p><p>&#x4E25;&#x683C;&#x6765;&#x8BF4;&#xFF0C;&#x6700;&#x7EC8;&#x6267;&#x884C;doFilter&#x7684;&#x5E76;&#x4E0D;&#x662F;SecuritFilterChain&#xFF0C;FilterChainProxy&#x5185;&#x90E8;&#x7EF4;&#x62A4;&#x4E86;&#x4E00;&#x4E2A;SecurityFilterChain&#x7684;List&#x5217;&#x8868;&#xFF0C;&#x5728;&#x8C03;&#x7528;doFilter&#x65B9;&#x6CD5;&#x65F6;&#xFF0C;&#x4F1A;&#x6839;&#x636E;SecurityFilterChain#match&#x65B9;&#x6CD5;&#x5339;&#x914D;&#x7684;&#x7ED3;&#x679C;&#x51B3;&#x5B9A;&#x9009;&#x62E9;&#x67D0;&#x4E00;&#x4E2A;SecurityFilterChain&#xFF0C;&#x7136;&#x540E;&#x53D6;&#x51FA;&#x8BE5;SecurityFilterChain&#x6240;&#x6709;&#x7684;Filter&#xFF0C;&#x7528;&#x5176;&#x6784;&#x9020;&#x4E00;&#x4E2A;VirtualFilterChain&#xFF0C;&#x8FD9;&#x624D;&#x662F;&#x5B9E;&#x9645;&#x610F;&#x4E49;&#x4E0A;&#x8FC7;&#x6EE4;&#x5668;&#x94FE;&#x6267;&#x884C;&#x7684;&#x5165;&#x53E3;&#x3002;</p><pre><code class="language-Java">private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
       throws IOException, ServletException {
    FirewalledRequest firewallRequest = this.firewall.getFirewalledRequest((HttpServletRequest) request);
    HttpServletResponse firewallResponse = this.firewall.getFirewalledResponse((HttpServletResponse) response);
    List&lt;Filter&gt; filters = getFilters(firewallRequest); // &#x91CD;&#x70B9;&#x5173;&#x6CE8;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#xFF0C;&#x83B7;&#x53D6;&#x5230;&#x67D0;&#x4E2A;SecurityFilterChain&#x7684;&#x6240;&#x6709;Filter
    if (filters == null || filters.size() == 0) {
        ...
       firewallRequest.reset();
       this.filterChainDecorator.decorate(chain).doFilter(firewallRequest, firewallResponse);
       return;
    }
     ...
    FilterChain reset = (req, res) -&gt; {
          ...
       // Deactivate path stripping as we exit the security filter chain
       firewallRequest.reset();
       chain.doFilter(req, res);
    };
    // &#x88C5;&#x9970;&#x5668;&#x6A21;&#x5F0F;&#xFF0C;&#x5B9E;&#x9645;&#x4E0A;&#x8FD4;&#x56DE;&#x4E86;VirtualFilterChain&#x7684;&#x5B9E;&#x4F8B;
    this.filterChainDecorator.decorate(reset, filters).doFilter(firewallRequest, firewallResponse);
}

private List&lt;Filter&gt; getFilters(HttpServletRequest request) {
    int count = 0;
    for (SecurityFilterChain chain : this.filterChains) {
         ...
       if (chain.matches(request)) {
          return chain.getFilters();
       }
    }
    return null;
}


public FilterChain decorate(FilterChain original, List&lt;Filter&gt; filters) {
    return new VirtualFilterChain(original, filters);
}</code></pre><p>VirtualFilterChain&#x7684;&#x5B9E;&#x73B0;&#x4E5F;&#x5E76;&#x4E0D;&#x590D;&#x6742;&#xFF0C;&#x5176;doFilter&#x65B9;&#x6CD5;&#x6E90;&#x7801;&#x5982;&#x4E0B;&#xFF0C;&#x539F;&#x7406;&#x548C;Servlet&#x7684;FilterChain&#x7684;&#x5B9E;&#x73B0;&#x7C7B;ApplicationFilterChain&#x57FA;&#x672C;&#x7C7B;&#x4F3C;&#xFF0C;&#x4E0D;&#x8FC7;&#x5F53;&#x6240;&#x6709;Filter&#x90FD;&#x6267;&#x884C;&#x5B8C;&#x4E4B;&#x540E;&#xFF0C;&#x5B83;&#x4F1A;&#x4EA4;&#x7ED9;originalChain&#x7EE7;&#x7EED;&#x6267;&#x884C;&#xFF0C;&#x5373;&#x56DE;&#x5230;Servlet&#x7684;FilterChain&#x3002;&#x4E0A;&#x6587;&#x63D0;&#x5230;&#xFF0C;&#x5982;&#x679C;&#x8981;&#x6253;&#x65AD;&#x70B9;debug&#xFF0C;&#x8FD9;&#x91CC;&#x662F;&#x4E00;&#x4E2A;&#x6BD4;&#x8F83;&#x597D;&#x7684;&#x4F4D;&#x7F6E;&#xFF0C;&#x53EF;&#x4EE5;&#x770B;&#x5230;Spring Security&#x4E2D;&#x5B9A;&#x4E49;&#x5404;&#x4E2A;Filter&#x6267;&#x884C;&#x7684;&#x8FC7;&#x7A0B;&#x3002;</p><pre><code class="language-Java">@Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
    if (this.currentPosition == this.size) {
       this.originalChain.doFilter(request, response);
       return;
    }
    this.currentPosition++;
    Filter nextFilter = this.additionalFilters.get(this.currentPosition - 1);
    if (logger.isTraceEnabled()) {
       String name = nextFilter.getClass().getSimpleName();
       logger.trace(LogMessage.format(&quot;Invoking %s (%d/%d)&quot;, name, this.currentPosition, this.size));
    }
    nextFilter.doFilter(request, response, this);
}</code></pre><p>&#x6700;&#x540E;&#xFF0C;&#x518D;&#x7ED3;&#x5408;Spring Security&#x5B98;&#x65B9;&#x6587;&#x6863;&#x7684;&#x56FE;&#x793A;&#xFF0C;&#x53EF;&#x4EE5;&#x66F4;&#x597D;&#x5730;&#x7406;&#x89E3;&#x6574;&#x4E2A;&#x6267;&#x884C;&#x6D41;&#x7A0B;</p><figure class="kg-card kg-image-card"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAuQAAAH7CAYAAACEzIq2AAAAAXNSR0IArs4c6QAAIABJREFUeF7snQeUFFX2xi/DMGQYYIacc84goiIGghhAWUX/YkBFMGNYVFZd14wRTAiK4CqGVcyuuqIooihIFpCc05AGGNLAwP98b3g1NTWdqrq6u7r7u+dwmOmul37vTfdXr+67t9iJEydOiEfs2JFjktH8cY/0ht0gARLwGoHstf/0WpfYHxIgARIgARIIm0AxLwryCd0bhD0wVkACJJBYBG78da1QkCfWnHI0JEACJEAC+QQoyLkSSIAE4oIABXlcTBM7SQIkQAIk4IAABbkDaCxCAiQQfQIU5NFnzhZJgARIgASiQ4CCPDqc2QoJkECYBCjIwwTI4iRAAiRAAp4lQEHu2alhx0iABMwEKMi5HkiABEiABBKVgKcE+dHDRyWzxRPCQ52Jutw4LhJwToCC3Dk7liQBEiABEvA2gagL8ry843Lw4AE5frxotMWDuw9Ii7MnUJB7e82wdyQQEwIU5DHBzkZJgARIgASiQCDqgnz//v2ydOlSOXLkiFhDoB/dkyt/u/NXCvIoTDybIIF4I0BBHm8zxv6SAAmQAAmESiDqgnzv3r2ycOFCOXz4cJE+HtuTK/9331wK8lBnj9eRQBIRoCBPosnmUEmABEggyQjERJAvWLDA5w55XvZRCvIkW4AcLgmESoCCPFRSvI4ESIAESCDeCFCQx9uMsb8kkKQEKMiTdOI5bBIgARJIAgIU5EkwyRwiCSQCAQryRJhFjoEESIAESMAXAQpyrgsSIIG4IEBBHhfTxE6SAAmQAAk4IBBVQY6oKvpQp68oK/QhdzCDHi+yce8mWbljtdHLMxp0lxLFS6jfA73n8WGxezEgQEEeA+hskgRIgARIICoEXBfkEN06nKE1rCFGtHv3blmyZInk5uYWCXtIQR6VOXfcyIbsjbJg6yLZsGej7DuSo+avUulKUrlMJelQo400q9q0SN2fLf1K3l3wH+P1cQPGqOthgd5z3EkWTFgCFOQJO7UcGAmQAAkkPQHXBfnx48eV2Mb/VsNrEOSrV6+Wo0ePUpDHyfLbeWCXvD57kizYujhgj+un15Ghp1wnjas0NK6LJ0G++9AeeXve+6rvA1qeL/Uq1Y2TGUqOblKQJ8c8c5QkQAIkkIwEXBfkeXl5KqShWZAXK1ZMsdWCfM2aNRTkcbLaNu3bIv+a9qTsO7wvpB6XKlFK/n7GHdK6esugu+DbcrIEu+7aOtZsJ6kpqSG1E4mLvvrrG/n3vPdU1feeead0rNU+Es2wTocEKMgdgmMxEiABEiABzxOgIPf8FMWug8eOH5N7//uQbNq32ehE8ZTiclbDM6Rh5QZSsXQF2bJvu/yw6kfZun+bcU3l0pXkxYueUb7i8eSWMuqbh2X17rUU5LFbcgFbpiD36MSwWyRAAiRAAmEToCAPG2HiVjBj7Ux5ZdbrxgDTS1WUe3rcIU0yGhUaNIT7q7PekF/WzzJeH9JpsPRt1iugIP9j8zz5ac0vRpnhp1wvZdPKFKo7a3+WfLNymizbsUL2HtwrKSkpUq18VelWp4uc3ehMwQ2CtpnrZsnvG/9Qv5ZLKyvDTrlOlm7/S77462vZmL1JUoqlSN302tK/5fnSJKOxUW7y3CkCt5w5m+YarzXOaCS4sWhSpaFc1PL8xJ3kOBoZBXkcTRa7SgIkQAIkYIsABbktXMl18WM/PC2Lty0xBn1Dl2ulV5OzfEI4fOyI3P/NP6Vm+RrStmYr6VizvWSWzQgoyIPtns9a/7u8MmuCHD1+zGebzTKbyKie9wjcZGAfLJoqH//5ufq5VGopGXbKEHnp1/Fy/ETh8wwQ8Xedfpt0rt1BXTvii3sL7fCbG+tUq4OMPHNEck28R0dLQe7RiWG3SIAESIAEwiYQEUGOQ53wJddm9SFfu3Yto6yEPXWRrQAidsiHwwVCG1auZDkZf/FY2z7eTg914oAlhPKRk+1XLFVBzqh/muTk5siMtb8YIvvcxj1laNchqo8fL/lcPlg4Vf1cTIpJmbQyciD3gJQvWU5yjhyQE3LCgFazQg15/vwnBWvzmRljZd3uDbLz4E7j/SplKkuZEmWkVbWWMqTzlZGFzdpDIkBBHhImXkQCJEACJBCHBCjI43DSotHl/Uf2yw1TbzWagpvKY70fst20U0E+7rc35Mc1P6v2cNDzufOfkOrlq6nfp62cLq/Pmax+xm73uAEvSMVSFeXTpV/Kews+NPpYMjVN7jz9NulQs61s279dHp72hOw5lG28//JFz0lmuQz1+7Ks5ep9bTzUaXuqI16AgjziiNkACZAACZBAjAhQkMcIvNeb3ZazXe74fKTRzW51u8qdp99iu9tOBfmNH98uew/vVe11qNlO7ut5l9F23ok8ufY/wyU3L1e9dlO3odKz4elF3GP6t+gn/9dhkFHu4z8/kw8WfWz8/tA590mrai0oyG3PamwKUJDHhjtbJQESIAESiDwBCvLIM47LFnYe3CW3fFogghGS8F6TKA51UE4E+aFjh+Xa/wwzmoC7TK0KNQo1uXzHSuP385v3las7XlFEkD/S6wGBn7k2HNp8dsaLxu/3nHGHdKnTkYI81MmM8XUU5DGeADZPAiRAAiQQMQIU5BFDG98Vw3f8mv/caAyiTsVa8uz5BS4doY7OiSBHbPK///eBUJuQMxueLjd3G1pEkL/c/zl1sFTbku3L5JHvn6IgD5msty6kIPfWfLA3JEACJEAC7hGgIHePZcLVdNvn90hWzg41Lvhxv3TRs0bae1+D/X71T5KWkiqn1Okiaalp6hIngnzngZ1yy2d3F9wMpNeWVlXzXUt8WaMq9aVHg6IuK+MGjCnU3yVZy+SRaRTk8bpQKcjjdebYbxIgARIggWAEKMiDEUri9yf8Pkm+X/2jQaBXk7Plhi7X+CSy48BOuevL+yQ376iUKVFazmvaWy5rd4kjQY4IL1d9cIMcO54fqefUul1lRAj+68HCKFKQx/dipiCP7/lj70mABEiABPwToCDn6vBLwOo6gsQ6l7S+SAa26q8S9Gjbvj9LnvzxuUKxvCHcIeCd7JCj3ru+vF8279uimkDYwlf7v2DsuiMU4v9W/iDl0soJwiHWr1RHKpepHDQrqB1BPuK0W+TUel25OjxEgILcQ5PBrpAACZAACbhKgILcVZyJVxmyWH69/H+FBoZMmY0qNxTE6t66f5vM37xQEPlEW730uvLUef9SmTGdCvLvV/0oE2ZPMursVqezXN3xStXOh4s/lhlrfzXe+9e5/5DmVZuGJchX71ojo779l1Fnuxpt5PouV8vx4yekRoX8cIu02BKgII8tf7ZOAiRAAiQQOQIU5JFjmxA1Hzt+TF6Z9br8uv63kMYDMX7/WXdLpdLp6nqnghzC+76vH5IN2ZsCtntmg9Pl5lOHBm0LFwTaIc/JPSBDp95aJKtnrQo15fkLngxp7LwosgQoyCPLl7WTAAmQAAnEjgAFeezYx03LyHD505qZKhMm3FN8Wbm0stKzYQ/5W5v+UrpEaeMSp4IcFWQf3iuvznpdFm5dXKTJEsVLSJ+mZ8uV7S9XO/HBxH8wQY73kVQIyYXMRkHunWVKQe6duWBPSIAESIAE3CVAQe4uz4SuDcJ8094tsmrXGtl/ZJ86wFm5dCUVWrBZRhPDx9sMAYc9N+/barzUplpLlV0TFug9cx0b922W5VnLJefIQeW7nlGmsrSu3koqlCxfiHew+g4cPSgrd642yjSq3ED5p5ttWdYKWb9nvZwoJlKjXDWpWbGGVC2bmdDzGi+DoyCPl5liP0mABEiABOwSoCC3S4zXkwAJxIQABXlMsLNREiABEiCBKBCgII8CZDZBAiQQPgEK8vAZsgYSIAESIAFvEqAg9+a8sFckQAIWAhTkXBIkQAIkQAKJSoCCPFFnluMigQQjQEGeYBPK4ZAACZAACRgEKMi5GEiABOKCAAV5XEwTO0kCJEACJOCAAAW5A2gsQgIkEH0CFOTRZ84WSYAESIAEokOAgjw6nNkKCZBAmAQoyMMEyOIkQAIkQAKeJUBB7tmpYcdIgATMBCjIuR5IgARIgAQSlQAFeaLOLMdFAglGgII8wSaUwyEBEiABEjAIUJBzMZAACcQFAQryuJgmdpIESIAESMABAQpyB9BYhARIIPoEKMijz5wtkgAJkAAJRIcABXl0OLMVEiCBMAlQkIcJkMVJgARIgAQ8S4CC3LNTw46RAAmYCVCQcz2QAAmQAAkkKgEK8kSdWY6LBBKMAAV5gk0oh0MCJEACJGAQ8JQgP34oT664c45MHt6aU0QCsiMrSzKrViWJZCBQTKRM2TLSoksLKZ5a3OeIWw58U7LX/jMZaHCMJEACJEACSUbAU4Ic7AcN/y3JpoDD9UXg+LG9krNlvJSrfp2kpGUQEgkoAhTkXAgkQAIkQAKJSMBzgjwRIXNM9gmMHj1apk+fLl26dJFHHnlEihUrZr8SlogLAphb/KtcubJ06tQpLvrMTpIACZAACZCAmwQoyN2kybpcITB//ny5//77jbpGjRolPXr0cKVuVuI9AhTk3psT9ogESIAESCC6BCjIo8ubrQUhcOTIERk+fLhs3brVuDI9PV0mTJggFSpUIL8EJEBBnoCTyiGRAAmQAAnYIkBBbgsXL440gXfeeUfwz2p9+/aVESNGRLp51h8DAhTkMYDOJkmABEiABDxFgILcU9OR3J3ZuHGj2h3Py8vzCeKZZ56RNm3aJDekBBw9BXkCTiqHRAIkQAIkYItA1AX5nj17ZP369XL48GFbHeXFiU3gxIkTcs8998jixYv9DrRWrVoyfvx4SUtLS2wYCTy6lJQUwb/jx48bo9SCHK5JHTp0SODRc2gkQAIkQAIk4JtAVAU5RNehQ4eUf/DRo0c5JyRgEPj666/lwQcfDErkpptukuuuu45RV4KSKrgAf3dmi1XEmuLFi0uJEiWkTJkySpRbLTU1VXDTRSMBEiABEiCBZCMQVUEOuBAHVoGQbNA53sIEcnJypG3btrJz586gaLA7vnDhQgq3oKS8d4EW5BDlNBIgARIgARIggQICURfkhE8CVgIPPPCAjBkzJmQwvXv3lo8++sjnLmvIlfDCqBOAIMcuOP7RSIAESIAESIAEKMi5BjxCYNWqVXLOOef47M3BgweVixNcHEqXLl3omkmTJsnZZ5/tkVGwG6EQoCAPhRKvIQESIAESSEYC3CFPxlmPkzF/8MEHcv3118vEiRNl0KBBcdJrdtMfAQpyrg0SIAESIAES8E0gKoKc8EnACQEI8htuuEEJ8ssuu8xJFSzjIQLaXYUuKx6aFHaFBEiABEjAEwRcF+QIZ4Zsi+awZp4YKTsRdwS4Qx53Uxaww9whT6z55GhIgARIgATcIxARQX7s2DFGU3FvjpK2JhzcvOqqq1TmzoEDByYth0QYuI41DlGOfzQSIAESIAESIIECAq4LcsIlAbcI/PDDD+rA5/Tp06Vnz55uVct6SIAESIAE4pgAEgtu2LDBGEHTpk09O5pAfY2ncdgBHO1xRbs9OyzsXEtBbocWr40qgR9//FHOOusswf9nnnlmVNtmYyRAAiTgZQIHDhyQ2bNny8aNGwXRqvBkum7duipHw6mnnioZGRle7n5Yffvtt9/UGLVh7JF88rZ7925ZsGBByH0uW7asnHLKKer6QH2N9jhCHoDpQojdRYsWydy5c2XLli0qqWOTJk2kfv360qVLF6lQoUKRaqM9rmi354RjKGUoyEOhxGtiQoCCPCbY2SgJkICHCUAg3XbbbfLGG28E7GX37t0FTxlLlizp4dE461owAZaXlyevvvqqqhyBAaxhc+22ikzS/fr1C7kYduyXL18eliB3ewwhd/7khbjJ+ec//ylPPPFEwKKXXnqpIAwxbkK0BZsfu30Jdn202wvWH6fvU5A7JcdyESdAQR5xxGyABEggjgggWEKbNm1k6dKlIfW6devWKrNxSkpKSNfHy0XYpTVndq5Ro0ahrmM3t3Pnzuq17du3S9WqVcMaWjiCPFBfAwlJt8dgBwACc3Ts2DHkdQb+S5YskUqVKgW9CbHTj1CvDbYeQq0n1tdRkMd6Bti+XwIU5FwcJEACJFBAAC4q2hUCryLL8ahRo4wdYLhWXHfddfLZZ58ZhSDsIK6Sya6++mp5++23IybIP/nkE6lXr55fpNiRb968eVDkgQS522MI2hnTBRdddJF88cUXxitIzjd+/Hh1k5Oenq7cpLD2/ve//xnXdOrUSf7444+YCHI7Y/PytRTkXp6dJO8bBXmSLwAOnwRIoBCB1157TW666SbjNbg1WHe/sVsIAVWuXDl19ubmm2+W3r17F6oH12DXF5Gs/vrrL+XW0q1bNxkyZIi0bNnSJ3Xszn///ffyn//8R/788091E9C1a1cZMGCAuklAJCVt2JXXYg2+7KjXbFlZWfLWW28ZL91zzz1G+XXr1smHH36o3qtevbqKtIUbjJdeekmN9ZtvvhGU14Ib1+nyEMpwFbn//vuNunGDAnHco0cP5WsPP2hY5cqVVeI5q+H9KVOmGC/feuut6hyT2WUF/vtgHIpt27bNZ19R1pcg//zzzwOOwXxDZnceQ2G7du1aady4sTG0tm3byi+//KLWk9VeeeUVAR/zvON6X+PKyclRbkTffvutWjvnnnuuDB8+vJCri7n+7Oxsee+99+T3339XO/V16tRRPuuDBw+W2rVrF+pKIMbmMVerVk1wo4O6X3zxRdUXrH38fWAcvsYYyhy7dQ0FuVskWY/rBCjIXUfKCkmABOKYwJtvvllIRO7YscPn4U2IZ39uKtjdhCvLvn37fJKASIJwMgvsXbt2KVeZrVu3+iyD+rA7qv3VX375ZeXnDjP7U+vCuBbiShuEpU4YBtEPsQaDK8SECRPkwgsvNK6Fb/OcOXN8Huo877zzlGD3ZY8++qg0atRI/u///s9425ew/vvf/y7PPvusugY3ExD/qNOpILd7qPOCCy4IOAbsTMOczGMobP/xj3/I6NGjDUZwRfF3k4aLzj//fDnjjDME/caND+bROmbcwGF3HecfzIabGtwAWF2KcEME4e3PnnrqKbn33nuNtwMxRpS2s88+W10LQY6nTDiUmpubW6j6UqVKCcQ7romVUZDHijzbDUqAgjwoIl5AAiSQRASsLitwH3j33XeVIApldw876jVr1lQiEwYhjUN78MeGENciBbvPWhCdOHFCmjVrJitXrlRlILhwUBJRTbBDqg07t7NmzVJCPhxBjt3Y008/3WirSpUqyg9cWyBB/uSTT8qXX34pv/76q3E9hD8iz2CnHYLdvLP91VdfFRLaGCs4Hjx4UJXHjQmeSFh9yO3skNsV5E8//XTAMVxyySXiZB4xnmBscWOE3WfNG8J1xYoVtv/CrGOGyEWdDRo0kPXr1xdKHAlBjznTtmbNGnXjpA3vDx06VO2WI1mgNjwJ0eEuAzE2jxk3qXA1wk0Axob/sZ604aYLayJWRkEeK/JsNygBCvKgiHgBCZBAEhGAYNSixjps7DJee+21SmDCn9eXQDfvsON9+JyXKFFCVbVs2TJjJxS7hRCdEDBwF4Fbija4uECgw+Ca0r59+yLvhSPIreIKfYD7C6LGQDAizF4gAbZ3717l56zNeqgTjLS7DNxYfvrpJ+NaCLSGDRsav+PJAFxboinIcaMTbAxO5hGDCsYWa8IcPhI3Xq+//rrtvzBrO3jSgJ12rFHc9OHmzRxG0vyEBDvfuCmBmdchfsfcYI5guAZPM3yNyxwG01df4AKTmZmp1hP6Mn/+fGOM5r7YHniYBSjIwwTI4pEjQEEeObasmQRIID4JHDp0SO30moWkr5H07dtXCU+zOwDcTuA+AENIu4cffrhQUexGQ6TDsCMOX2L4lsOPF4ad659//rlQGYii8uXLqwgbSOQG9wY3BTn85ocNG1aozXAEOW4oWrRoYdQH32Ydsg+uKlrkYdzY8YdZBfk111yj/Nv9GW5gUN6uWNRCMpggdzKPvvpiZQsxmpaWZgzr+eeflzvvvNP2H4p1frADjp1ubVhDuBnStmfPHuMmCgzQDwh33ICab67QlzFjxqhicGOCv71dxtanIoH6YnvgYRagIA8TIItHjgAFeeTYsmYSIIH4JoBMlTjECB9rf2EQsbsM9xQIbYgbs1853AJ69epVCALqgv85DDvjiLaBHVP9Gg5Wmg/x+SPopiD35ScfjiAHB7iwaH94s1iEa4V255k2bZq6wfAlyIOtHDMnuy4rwXbInc6jL+FqZQsxrJ+Y4HrcsOHGza5Zx4wbDHMCIRycxRxow1xYb3CwvuG+gn94WoNQjHClQpIimPnphh3G1r6gbbhx+eoLWCOW/3fffad21C+++OJCT1Dscgl2PQV5MEJ8P2YEKMhjhp4NkwAJxBEB7CbCNxdRI3Aoz3xgE9mOISpwoM5Oghy4KsDvGm4D2hD95G9/+1tQMm4KcvTbmtwoHEGOzsMfWR/u1Lv+EOL6QB9uXNCuFqd245BHUpA7mUe4nvgS5L7Ymg/z9u/fXz799NOg8229wDo/VjcQRDnRMctR1izI9+/fr24U9VMZf407FeR2+vLggw/KY489pp4a6PMVcG8xu2nZhhOgQFQEOSYddzvatCO+v9fdHGCs6or22KLdXjS4UpBHgzLbIAESSCQC2Ens06dPIZcWHALELrd59xNuFVdeeaXfoXfo0EHq1q1byIUBLjAIGxfMzIIch+gQvcJsM2bMUCEZtZlFUihZF8MV5Di0ac4sCbcViG5knYQhVKT5wKpVkONAoXlX1coDNxCatZ3d21BcVqy72KHMoz4kGQrbnj17GmsHPuUQz2a/cutYwQKCFWcbtAVrx58gx440DuEidj4MN0ZYS1iLOIwLdyIdTtOpIDf7l6MNf33RNz46uRZuFOA+g/7hcHUkLGRBDr8ysxN+sM5gset4mf4mJ9ikBWsjWu9jYvCYBIsEj1rw4YETuvXr11eTY34UE+qCdLvv8cLSzrgpyO3Q4rUkQAKJTAA7dPgOXrx4sYoi8vjjj/v1YzaHtwMT+J1jpxu+3hCfMPji3nHHHUGRmcsgvrc1lTpiQEPsQ5Thex+78OPGjVOiVosq3BCYzSzY8Xq0BTnaNCfewRMEHBLUIRPNETxwrdcOdTqZR4wjFJ3wzjvvqCcj2vA04fLLL/e5TiBu8VQB+hAuKP/+979ViMFg7fgTwThEiwOg2jAfuLnUhps43MzBIi3I4QbWqlUreeGFF2TEiBGqTe27j79F881t0D+iEC8IWZDbfWRjjj3qVJDjjxhhh2B45GLncVuI4w94GRYb/KesH0DWQrirnjRpUqE77mAL0o3+meuIdntu999XfRTk0aDMNkiABOKBAHbozJs/OCSHQ22+4o0j4Q0icWjTCYTMGRh9hbRDfG/sAlasWFH5nWNnFDuwOvMn2oeY0m4N1jCB+hAg/LLNscPNLgnoC0QX6tEWSUGOp/NIKmM18+FObB5qFwkde9zsuhFrQW4dg5N5xPhD0QlWlxjcaEEYw/XJbJgz9MMc913HLA/Wjj9BjgPHEL3a4IaFpzQwuGFhXWoz71Q7eQqh6/HXl5kzZ6pwokiEpZ+cDBw4UD7++GPVF9wUuW1REeSYOMQ51YZg/6EsDuxII5g8zBq6yG0Q1vrw2A/phv0dlrFejzFhMWq/qGAL0u3++2PsdjvRrI+CPJq02RYJkIDXCWCn0hyLGaIaPq46IQue4GKnF4fQtGG3EzuXMHNoQ/yOqCLY/YOwnjhxoopFrk0ffkN2S7SjDZEuEO8bgvWhhx4qlEQGyWoQx1rvLuoyeOw/depUJfBxs2CNEGPecQzluzPQNTgAaA75iEQ66CfGaI4gYj3cqfuK3X0zB7webUEebAxO5jEUzaUZ4LAw4p2bDYIchxrhmoKnNFh3Ol47rhs0aJC8//77IWk7fyIYT1u0PkRFd999t1pruB474riJ0gYXFtyk4oY0EoJcJxSCAMe4YZdddpnKIqvDYbr9eeFYkGPC4Bvmz7CbjQ+JQBbsD8/8SCnagtx8B4oxYPLHjx+vbhCwg4APHvyha38mXIPYr8hAZmfhuz2hiVQfBXkizSbHQgIkEC4BbBSdeuqpheImB6oT4gbhC83+0nqXL1C5N954o1BGUOuOu6+y//rXv5TwhUHsQsSvXr3aZzO33367Sl2uzXy4MJguCPb9irbhnmPNxGhNQIN6rO4ZeA3uF+YDh3gt2oI8lDE4mcdQ2Oo5sboVBVovEONIUKWf1gRrx58gh+sTdsQ3b97sszncPOqwh7gATzPgRYEnIPi70BYoDnmoPuS46Wjbtq1MnjxZEOYS1rt3b3Wzq13Awv17tpZ3LMjtZKrCXQ/C1Wi755571N21v0mD2IcPF/zVtF133XVK4OMuSfum4z3sDOOP5aOPPlJ3TzhMgfifQ4YMKZLuFQdLcHcDQ4gd7BzgURxORGMh4dEL/seHCOKvasOkINuTr0QLOPhhDgOFRAm43tfY4LuHxYOT8LhhQXpg3ImbPyzNE4RFC/8tPErDjgMWHR7TIIMadiHM5o+xeczw9cJNDurFhyH6AV5YZBhDKJne3F6AgeqjII8mbbZFAiQQDwTwnQd3lFGjRhkxw639RjbNkSNHKoFsjVAC0QNXTOxwWg2bTdhNN7ub4BoIxOeee86I0W0uB/GL73dr9BVELUEyH7Mox/crvtPw3QeXGG1mPRFMzKFMsGvw3YY47GbzJcithzvRX3zXWy3aghztBxuDk3kMxs06bjwdgUbBmQRfhsOiY8eOVcmozC4+wdoJFGUF7jldu3YtlJ0VbeubRJx7MN/M4YkGop64LcgREhIx/M0HfOGmAu7QcubxuvW5ERVBbteHHEkPzH5J5sE++uijamcahl1qPAozh3gyX4uFBAGswZkPumDnADFXzR88+s7pvvvuK/QYTvtF+YOOP3T4Gl3qS3/LAAAgAElEQVRwwQXGo0PrmOEbhd117ASYDTvvyDxlTt6A96dMmWKkLvbV7lNPPSXIaKXNH2P92AXXQZDjdDB2Lqy7B/hQhXjXYZ/cWmDh1ENBHg49liUBEkhkAhDJeHSOpCoQD/j+wqYKon/g+8SXb7mZB3bbIZbhmgJXEmxSYaMnUDncDOD7Cu3iexVlsKPprwzEC3Y74QsMMYMMn/iu0X3X/TEf5MM4zP7l5vf09aFcg3HhOw39xPc9dr1xo2I2qyA3xx43X4dxoz5tuJkIVZAF6muwcYQyBjvzGKw9f38vaANCGU8P8DPmHfOCLKa+LFg71vm38sQ5A8wdbuqgkfS60W1hAxJrEOtdxzP3t2bC6Uu7du1UIi1s+GKzFU+BnnnmGcGmciTMk4IcPkM4FIKT5NqwMwzw2NWGbxMmDB88Oog/hDkOX8JXHUJcC07cuWNHGYY7X8QcheEPE4sArjDmP3L9waRf93XwJZSJsApkCF3UqdMe60QLqMt6545A+DpMkX5/6NChamfB7D9oPgnuT5Cbx4wPTbgZ4QMV48L/WKzacJeLLFZeMQpyr8wE+0ECJEACiUcAMdt10AaIS9zYBLuRSTwKHJE/ArgBgbbUSaSwgQsPjkBhIMOh6UlBjgEFSx2LR3bwa4PhLgngdBga84EH3I3jcZgvx3+8Bh9wPKbCHTBOkFuzYCG6CxIk2DWrQMbdJHbasXOBmwW43ZjDSJpPmWPnGwdzYOb+4/eGDRsqIQ3DNTrNb6hPIdAPuL8g6xTaRD8Q6F6bNWi+3XG7eT0FuZs0WRcJkAAJkAB2OnEYEE+hkTpeGw6dWg8ykhYJgADWC/SlOUlWJMg4FuRwcremOjV3EKGS4MsNC1Usmp3tgwlyHQ8S9cMfDilezYbdb4h0GA61wCfc2g/8MQ4bNqxQOQhS80lsHcbJLnxrW+b0vKjr559/Vv7w2vDYEf57MHBAPyDccYOgX8d7OOGuDzXgbg1hr+wwxg44dsK1BeqH3TG7fT0FudtEWR8JkAAJJDcBRE8zb0KBBs5RwU02VDeU5CbI0UeKgGNBHqxDoaSODeT4H0iQW3ex4d6BVKtmg3+4dgvBwU1ETbG2h8dTVv80axYsCH0IfrtmbUuHkNL1IDyV9n3Ca+Y4rfoa+GzBfQX/sMsP3y244CBJESyUwPjB+oF2zRnHfPXD7tjdup6C3C2SrIcESIAESAAErIIcm1yjR4+OSKIXEicBOwTiUpBbA9cHGzBcTuB6YhWn5lBL5jrMd8n9+/eXTz/9NFgTRd63tmV1BQl0yhiPR3CDoRMV+GvciSC30w/bg3a5AAW5y0BZHQmQAAkkOQFsumFzCxt7iHYWKX/gJMfM4Tsg4FiQ40CheWfV2jZCLWmfbrddVqy72HCPufLKK/0Ov0OHDuqQZLBQPLqCnj17GokL4J8O8RzojxYs4OaCA5vagrXlT5DjQwIHWJEUCQY/d8QDxRhw2hg+4zr2uRNBHmoMTgdryfUiFOSuI2WFJEACJEACJEACHiTgWJDbiUPutiAHR4RQQixIGHyqEZsymAUTybq8NVkAopsgQ5ovg8BFBBX4q8MFBTFczz777KDi358gRygfsxsN/Nr69OljNH3mmWfKjBkz1O8U5MFmnO+TAAmQAAmQAAmQgPcJxI0ghz81EuNoM2fS9BWacM6cOeowZMWKFVV4Q+xwhyrIrS4x2P2GMEbqWLPB/QP9MMdM1zHLg7XlT5Aj5iUOrGpD/FbEeYUh3jrGow076YgrDnNy04NygVxnYr18uUMe6xlg+yRAAiRAAiRAAtEg4FlBjh14c+ZIJANC1jG4dEAgm0MbAtSzzz4rSKuK9ydOnKhikWvTByqDiWQzcMSatIZAgiC/+OKLlWsK0qoi0xkSC2hD+tj3338/oEDW1/oTwgh4jyQG2u6++25BXHZcjx1xZCPVBhcW+Jv7CumoXVOCjZmCPBp/ZmyDBEiABEiABEiABPwT8Kwgh7BGzEdrRklzEp2BAwfKxx9/HHB+dbpVXBRMnForgu/2bbfdFtL6gRh/9913jaQCwdryJ4QRGQY74shu5stw06HDHuJ9uLcgGymeHvhKHeu0HyENOsIXcYc8woBZPQmQAAmQAAmQgCcIeFaQg863334rffv2LQTKLMghXhGSEDvVVoO7Cvy5EatbWzBx6mtGVq1apXbbv//+e58ThsOiY8eOVbG9zdFZgrUVaGca7jldu3YtlEUUjeubC/jLv/jii0Z/xo0bJ+3bt6cg98SfFDtBAiRAAtEjgKekSPamDWH9EFABT0l1cAC817x5c8Pl0RzBC2eg6tevr4ojxC7CAWtD4jgY8mSsWLHCeL1z587KDRQbZuaY3shqWLZsWXWduQ1sGOkgEHjKq9PQY9MN6clhaBfta8N3IL5TDx06ZIT6xXu4HuWwaaddNvE6kuYh4R0MyX/gegpDwr8WLVqonxFueOPGjUXGh/NocDfVhiAKeBKPjOB//PGH8XrTpk2lUqVK6ne0jT7AsDGms2sj5bs5A7hmiDGbn3B36tRJZQyH6+u8efOMNlq2bKnOyFkZgp9220VuFZ1nBXWgLhjOoEGzaINbK56gI6qMOREh3GLxhN3KEJm8dX4Z8NDn9DCnmFsYnuLDldY6T/AWgOeANmgSBPeAToMLsTbkhIEbMQzjxvhh4Aq+MMwR5kqbZgi3XXhHaAtnra9evVpldodhnWG9weyudStD81pHX9FnmHWtY9MVa9msG0MW5ICm/4hQOYCGGkQfHwwQoNr0oUV/rxsXnszYiQWOtuDKgUnDAjQbFhvgon/4kMCCql27dpEUuKG0V6hi0y9oA0IZfwT4GW1gHEi368uCtYVJxB+PNitPfBBg3FlZWeoPp1mzZoWyROGPAuXh1qPjmTthHKwf/nhE43XukEeDMtsgARKIRwL47Mb34k8//SSIDKYNYhAZofFdpYUP3sMGFxLgaAGir7/llltUJC/Y1VdfrXJdwCDk8D0EQ+hfuGtqg8iAaNy0aVOhs13YiIJ4gggzRybDphnS1MMQ9GD69OnqZ4hYLSCx4TR06FCjDR2WGCJWC2q8CZGDmwt8D5szJ+rwxrgGog+aAAZX0x9++EH9/PjjjwvcX7VhfBgnbh50IkO8B0EIDWE9twVXVkR1g2F8OtcJEiVOnjxZvQ6eeGqtTYt26wYj5gd6BvNlTrKI+YR7qjXfyv333y9PPPGEqhZ9QH4VGHSIvolC9tHBgwcbbUMkI7QjbnT0DQPehDiHGLRGrDMHyDDHa4fg1zcmuAax27XpUMq4CYII14Y24d6LPuibNLwHT4IrrrhCXWZO4IgxgS/svvvuU7HhtYGz22v9qquuEgTwgOkbI/xsdVf2t9axZiDirWsdc4S5gpkj9pnPOiJPDpJS6nnQ4wxZkBtk+AMJRIkABXmUQLMZEiCBuCKgBSQEMMRqKLuG2NTRWZ/97ZCbdw0BhDvkhXfIIar0Jlwsd8jxtAI7uVpMRmKHHAEmcJYPFqkdcjzBwU0BLJY75OGsdSc75MiYfsEFFyg3av03hj5QkMfVx3BydZaCPLnmm6MlARIIjYBZkJu/0EMrzatIgARiScDf3y8FeSxnhW0HJEBBzgVCAiRAAkUJUJBzVZBA/BLArjrcpeD25MiH3Dz0UJ334bOk/cX9Oe/DB80cUUTf7Yd6UCWUx3DJelAFj5vw2ElbOAdVcIgDfuvaonFQBWsA/n/33ntvIf9FHlQpfGDK36GscA6qYJ4T/VBW/H6cs+fJTgDnmeDLi6hbOk9FsjPh+Ekg3gk42iG3Ou/D7wwnnHEaGgcQtcFhXqe0x+lnfaK1f//+6pAIbNSoUSrOtjbtvI9slMhKqQ1iEMIDflPmg5TmTJbmO42bb75ZXnnlFVX82muvlbfeekv9HOigio5XnugHVSB0cfJcm7+DKjj0gEg1sFtvvdXgid/9HVTBQVPMDw6jYr60+TuoArH91FNPqctwaEivC9zIffjhh0WSMeE6nSV27dq1at1p83dQ5YUXXlBfXLBEP6gSy0NZ+qCKng9/h7JwSAs30qEeyjrnnHNk2rRpqlocDnvwwQeNOfd3KAt/wzjsbD2UhfWFzx99IC7eP8DZfxIgARIggfgigE1tRMrBmQSzZrYlyPU2OwSdOQSSv/A2ibJD3qpVKyNJkXnXEKewdYSTcEM5tW3bVp2Gth4QwCllnJiHRSqUk1cOqlhDOcXTDnkoaz3cUE6hPA1y61CWk4Mq8RK2DJ9diKhgPVATXx/p7C0JkAAJkEA8EnDFh5x+a/E49fHbZ/qQx+/cebnn/Bzz8uywb6EQQKhAhO/DEyOE+KORAAnEDwEK8viZK/b0JAEKci6FSBCgII8EVdYZTQJcw9GkXbgtxN2GuyTisCM3SrQMLn44y4WDgOaY4rr9WPUrWuNPpHYoyBNpNpNkLBTkSTLRUR4m/MuRuAPnTOB2RiOBeCNAQR67GXvmmWdk5MiR8sEHH8hll10WtY58/vnn6vwLAirA3c5q1n7hfA3ObsHl1nyey1wulGuiNsAkagg3V8hEiuyryGaqzZYPOQ5WYhFefvnlfic4iZhyqBEmQEEeYcCsngRIIC4JIBW5zgKINPa06BDIzc1VSXKQ2RFnnKxZwyPZCwSpwMF5bCQgy6PZfPULwQ+QyRuZV83ZO83lQrkmkmNi3YUJ2BLkhEcC0SRAQR5N2myLBEiABEggEAFEa0PUthdffFFuu+02z8DS/ULK9kceeUTdKOgoVjqyFDoLtxa4vCCaXaBrSpQo4ZmxJWJHwB9RyEqVKqUi/2mjIE/E2U6QMVGQJ8hEemwYiLKCR85PP/20NG3a1GO9Y3dIgAS8SADuHenp6YKQdTk5OSoqmhfM3K/Ro0fLP/7xD/UP7i2IgPfyyy+raHAIMYxIXX//+9/l3HPPDXgN3GNokSPgig85kszg7nDy5MnSunXryPWWNZOAiFCQcxlEggD9byNBlXVGk8Du3bvlhx9+kLPPPrtQXo5o9iHZ2vryyy/lwgsvVLlTHn/88ULDR44V5M2YOXOmLF++XPkGd+/eXW688cYi87N161ZBjhZoqL59+6rvuTfeeEOWLVum/L3/9re/yUUXXVQog2N2dra8/vrr6rV77rmnUNvmfp133nly1113CVyarIbwyTfccINaM9hJD3QNoveY87ok21xHeryuCHJ+kUV6mli/mQAFOddDJAjwcywSVFlnNAlwDUeTdn4iPOwyQ0zjZqhSpUpGByDEAx3u/OOPP6RTp07G9VOmTFE+3f369VOuI0huaLUBAwYIEvZp++6776R3797SvHlzJdy1+esX3FWQ20Tni9HJG83thHJNdCknT2sU5Mkz1wkzUgryhJlKTw1k3rx50qdPH/n2229V5lYaCcQbAQry6M7Yr7/+KqeddpoMGTJE3nzzTaPx7du3S/Xq1dXvyAiNA5dpaWmCQ5a33367jB8/Xh2sxAFQbXj9pZdeUr9CYGOHGxmnIa7hC37dddep95YuXSotWrRQPyM7MXatsbP9xBNPGHX569f06dPVTjiybeNQJ+qcOHFiIWihXBNdysnTGjKa40YMT0iqVKliDNyWDzlcVnRqbjxaoZFAuAT27NkjdevW9VkNPtTwDx9w+Ge2WbNm0W0qXPgsTwIkEJcEKMijO23QOxDICJmqs3OjBxDEjz76qOAQpNXvGt9tlStXVh1FNBOdIh3iG3HMMzIyVH3msHe4Fu4u2In/97//rQQ1rE2bNgL9BRGHzQRtvvoFsYebBGT5RgZx+JXDzeaLL76QCy64QBUN5ZroEmZrIGBLkBMZCUSCwGuvvSY33XRTyFXjQwofVjQSIAESSEYCOMh36NAhJfLMURqSkUWkx7x48WLl/gGXETxVC9Xg961dW+Aegk2lY8eOKfEOw874+eefX6Q6uL/ADQZCH9lYMdc6vOLGjRuN3An++rVmzRrp0aOHTJs2Te3AI7IK/Mefe+45Y/c9lGtCHSevc48ABbl7LFmTQwLwo0O0C/i5BTOECYIPn1dOuAfrL9/3HgEcwMIXq/Vxofd6yh6RAAnEmsCZZ54pM2bMUL7bELhW27t3r9o9h7/2jh071G44hDd2tBFyEGIaohiGZDB6h12LdGt92MX+6quvBBtViDdudovBE2Mt6AP1C+4v5kOZ+I613riFck2s2Sdq+3PnzlXfP1a3SVuCXCcGGjRokOE3lajAOK7oEli5cmVIIejMMVWj20O2ligE+Lg/UWYyeccBYYbvY7gmWN35kpeK+yNft26dcv1A+MD58+cXagBzAC2E76RABuH19ddfq0sQGeecc87xWZ+uQ7us6O+6n3/+We1416lTRzZs2KAuC9Qv9ymwRrcJ8FCn20RZn+sE7rzzThkzZozfert166Z89hiOyXX0SVUhBXlSTXdCDpZrODrTqt1HcGYJ3z/asLsMX25EP4GfOMIWIrY3snjqnWhESvnss89UHPBbbrlFFX344YflX//6lwwfPlzGjRtXZBAQ+dqnHJtUjRs3lqeeekod5hwxYoQ6OArz16/oUGEr4RKgIA+XIMtHnAA+jDIzM2Xfvn0+28KOULVq1SLeDzaQ2AQoZhJ7fpNhdFzDkZ9luJ/A9xo70+vXry+0EYTf69evrzqBA5r6Z90ruIhAWMN1Zfbs2dKlSxf1VocOHWTBggV+M30uXLhQ7Z7DtHvKqaeeKr/99pvaiUeyn0D9ijwVtuAGAX/J6Wy5rPBDwI2pYB2BCMBXD75xVsMuATKN0UggXAL+0haHWy/Lk0C0CPC7OPKk77jjDiWc4c+NmOFmw2vw9Ya7EHzBrabfx+s6bjk+d5C2HobvMnynWQ3hCSdNmqSSA+FgJ3bi9Y47DmLCfSZQvyJPhS1EkoAtQY7FgTs+HFKg20AkpyW568bJ8//+978GBByCwY6E/jBLbjocPQmQQLITwMFBHCRs2bKlcpOguUsAccMrVKig/iF8ofVApPYFx+uHDx82DlqiF4jvDfcVCHAYoqTgOr2zjdcQHQdC3RzyEIdGMZ8w7KA2adJEXaPjVKMd7JoH6pe7FFhbtAnYEuTR7hzbS04COLUOvzz9gYZHfO3atUtOGBy16wSwo4VoBzg8ZY0B7HpjrJAESCDuCGi/bXMscPMg8B2Vnp6uXsKBy2effVYJb6S3R+Kgu+++W4UZhCH8IPzP8T12+umnS40aNZTIhysMfM8RjxxPhuFnju+8e+65R5555hlVFu4up5xyiroGgj5Yv+IOdJJ2GOErdbjn2rVrGxRsCfKDBw/KqlWr1EEDHeQ+SXly2BEmgA/Ca665Rv2bPHlyhFtj9clEgI/7k2m2E3OseFqtQ9nxabW7c4wbdh3fHZpHhxm0toKdcMQmh9eANmTlRFQUJOzBplJOTo5667333hOIsJEjRyqxjgSLnTp1KlQW1yEL53333Wd4ICCjJzJ7Dh06VGX3DKVf7tJgbZEgwEOdkaDKOiNGAF84+MD65ZdfGHM8YpSTs2IK8uSc90QaNddw5GYT7irYmcZOtnYh8dca3EgQDQU73ri+UaNGhnsLYo8j4ybcVRCeEuEOsROOyCsXXXSRik2+fPlyFcQAO+DYMbfm10DyJ7gnQejj+lD7FTk6rNkNAvEhyI/nyc4bznJjvKwjAQhsOXBEapYtmQAj4RDcIpDx5oywq6KYCRshK4gxAa7hGE+AzeaxwYSzd3iqgQR4DRs2tFkDL08kAnEhyE/kHpZdw3tLmep5icSeYyEBEnCBwMFtxcUNQY7H0NjVwqEput65MDGsIuoEKMijjjysBrGDDhcWGHa9kXGaltwErJlSQcOWDzkez2zevFnghB6Jw1AU5Mm9QDl6EghEwC1BTsokEO8EcCgZ52zgi4zDyTRvE/jjjz9ULHKI8l27dnm7s+xdzAjYEuSR7iUFeaQJs34SiF8Cbgly7EwgIgLCaPJAXPyuB/acBOKFALJy3nzzzYI44xMnToyXbrOfESKAcwqIuoMkUOXLlzdasSXI4f+EE8jYHbfG5XSj3xTkblBkHSSQmATcEuR83J+Y64OjIgGvEoB3AVxVcGiT7ipenaXo9Ys+5NFjzZZIgAQiQICCPAJQWWVcEkBSIOy4Yue1RYsWcTkGdpoEkpUABXmyzjzHTQIJQoCCPEEmksMImwCf8oSNkBWQQMwIxIcgP3JQdt3Ul1FWYrZM2DAJeJeAW4J827ZtKlHHFVdcoeID00gg3ghQkMfbjLG/JFBAADHlcbi3SpUqhRJP2fIh37lzp3z99ddy3nnnqUD2Tgx+6Ah0j4NVVjuenSXHHr6OgtwJWJYhgQQn4JYgT3BMHF4SEFi4cKFceuml8uGHH0q7du2SYMQcIgkkPgFbgtwNHDhdumzZMnU41CrKS+7PkkZTX6QgdwM06yCBBCNAQZ5gE8rhkAAJkEASEjh27Jjk5OSoCCuI9qUt6oIcaWIR7gWnjq1W+kCWtPhiAgV5Ei5QDpkEghFwS5AvWbJEhgwZIpMmTZJWrVoFa5bvkwAJkAAJkIBrBFzxIZ83b57069dPua106NDBUefMgty6Qw5B3vLL1ynIHZFlIRJIbAJuCXL63yb2OkmG0WVlZcmnn34qF198sWRmZibDkDlGEkgYAq4Icje+yCjIE2ZNBRzI0h0HZfaW/cY1l7fKlFKpKeLv9eSgwlGGQ4CCPBx6LJtIBNz4Lk4kHhwLCcQTAQryeJotj/R1+rq9MnPD3pB7Uy6tuNzZrZa6/vlZm+XBH9cbZVfe2klqli/p9/WQG+GFSUvALUG+ePFiGTx4sEyZMkVat26dtDw58PglQEEev3PHnpNAdna2/Prrr9K9e3dJT083gNjyIV+xYoXcdddd8vzzz0vTpk0dUeUOuSNsMSn04PT18vxvm0Nuu0rpErJhRJewBPmW/bky6od1qo67T60lbaqWDbl9XpjYBNwS5IlNiaNLBgIU5MkwyxxjshGwJcjDhQOfcQhyhGzCoU76kIdLNLLlwxHka/YcliU7Dhod7NMoXdKKpwTdIX9x9ma5//v8nfWPLm0u5zWuHNlBsva4IUBBHjdTxY5GmAC+O3NzcyUtLU2KFSsW4dZYPQmQQDQIRESQI9a4L8OHyJ49ewRRDnyFPeShzmhMeehtWAX5LV1qSt0KJf1WULZEigzpUC1gA/5cWXShMyYvlHlbD1CQhz5NSXOlW4J8+/btKn4z4jhXqxZ4vSYNXA6UBEiABEggKgRc8SHftGmTjB8/XoYNGya1a9f22XGIcdy5+xLleA2CfPXq1eoa7pBHZe4dN2IV5DOHtJUO1cuFVN+XK3fLu4t3GNeO69dIKpZK9btDPnLaWlm/94h8uWK3UaZLrfJSs1yadK5RTu46Nd83HbY2+7CMn7tVftmwX7YfyJXiKSnSsFJJGdCsigxpX1VSU1KMaz9YskM+W55fZ6VSxWVM30bywA/r5etVu0WKFZPvB7eWzLIlQhoTL4otAbcEOR/3x3Ye2Xr4BA4dOiTr16+X+vXrS6lSpcKvkDWQAAlEjYArgjyUL7K8vDyfu98YKQT57t27Ze3atRTkUZt65w2FI8jtHupsP36erNxdNDY9et+vSWX58G/N1UCmLtspQ79YKUfyimZ6xfun1i4vnw5qKThgCntkxgYZ/csm9XP5tOJyXftqMnb2FgPK8ls6Se0Au/7O6bGk2wQoyN0myvrilUAo38XxOjb2mwQSnUBUBTl2vyHMtWkfNwry+Fpm0RTkl039SxZvOyAb9h0xINWqkCYVS6ZKz3oV5ZleDQQHPiHcDxzNd4mqWraEXNE6Q/YcypMpi7NEa3SI7pfOa6SugRiHKIelFCsmpVOLGeXxGgV5/KxJCvL4mSv2NLIEKMjD53si95DsGt4n/IqStIaMN2ck6cjDH/a6devkiSeekFGjRqmnXIZWPmH1GwnQVigfAhDiFOThT5gXaoimIMd4Z27YJ32m/GkM3Xqoc/hXq+TtRVnq/bTixWTu0PbSsFJp9fub87fLbd+sVj+nphQThFmsWjZNnpu1WR4yhV/E8aeR3evIgOZVJCc3T7rUKiclUngoygvrLVgf3BLk+MhD6uLU1FQeiAsGne97kkAo38We7LiHOnVi307ZNeISJiJ0MCdufRY7aDqhi9g+1Ikvs0CnuinIE2e9WAV5xxrlJL1Uqt8BnlW/otwVRhzyYIK8wdg5knXwqGq/b6NKMvWyFkZfjh0/IdWe+00OH8t3ZRl/QWMZ3KZqEZ/1K1pnyhsXNkmcSUqikfBLIIkmm0MNSIA+5OEvEApy5wz5WeycXaCStgV5sG5QkAcjFD/v2w17eFnLDJnUPz8+vV0fcpQJJMixm13tud8NeJVLp0qzKvm749p+27RftGf5bV1rylPn1C/Sj08HtZBeDSvFzySwpwYBt74EIGZwsLxRo0ZSunThNUTcJEACyUGAgtz5PLv1Wey8B/Fdcs2aNfLkk08ql5UGDRoYg7ElyPfv3y+LFi2Sdu3aSblyvqNtUJDH90Ix995LgnxJ1kHpOnFByHCvbJMpEy5oUkSQw82leUaZkOvhhd4h4NaXAB/3e2dO2RNnBBiH3Bk3cykKcucM3fosdt6D+C7JQ53xPX8x6b1VkL/ar7G0yPC/o4jwgQ3S80Nwub1DvnHvEWn+6lyDQ6vMMtKjbgW/XBCe8cq2RV1W4Ftes7z/WOoxAc1GQyLg1pcABXlIuHmRhwlwDYc/ORTkzhm69VnsvAfxXZKCPL7nLya999KhzrzjIhnPzJLc4/lOKQNbVJF/D2gWlEuwRERBK+AFniHg1pcAxYxnppQdcUiAa9ghOFMxCnLnDN36LHbeg/guSUEe3/MXk97HWpC/PaCpXNIiwxh7xwnzZfmuQ+r3KqVLyPJbO0rp1Px44wePHpcJ87aq1zPKpErbamWlVvmSfnfqYwKUjYZFwK0vgcOHD6b93VEAACAASURBVAuSnCG5GZOqhDUlLBwjAhTk4YOnIHfO0K3PYuc9SMyStnzIjx49Krt27ZIqVapIiRK+sxvShzxxFkq0BfncLTnS461FBsBeDdNlTJ+GgggqjSuXlkkLtsmtX68x3kfowqfPqa/ef+znjfLunwWZQb8b3Fq616lAQZ44y1H4JZBAk8mhhEVgx44d8sknn8jFF18smZmZYdWVrIUpyJ3PPD+LnbMLVNKWIA+lCxTkoVCKj2uiLcj3HDom9cbONhL8aEqIpjLvxg5y7LhI9zcXyJIdBwMCRLhDhD2Eheqysv9Inrzw+2aZs2W/VExLVdlB/68Nv+i8tFLd+hJAgjLkSkhLS5OUlBQvDZF9SQICy5cvlxdeeEGGDx8ubdq0keLF85/y0aJLgILcOW+3Poud9yC+S+7Zs0d++eUXOf300yU9Pd0YjC1BDrGdk5OjIqz4+xChII/vhWLufbQFOdpGEh8k8zGbFuR4bXvOUbnxq5UybU12EdClUlPkxo7V5LGz60vxYvnJfkIV5AM+WCrfrclW5fJO5PupP31uA7mlS43EmdA4H4lbXwJ83B/nCyHOu79s2TJp2bKlGgWSU11//fUU5zGYUwpy59Dd+ix23oP4Lkkf8viev5j0fs3uw7I6+7DRdvfa5aVsWmi7ORv2HjH8vVFBz/oVVUZMf6+bB/jrxv2ycHuOeqlR5VLStHIZqZ9eODLKsh0H5ddN+2XPoaOSWjxFapVPk7PrV5QqZQq7UoXS3p9ZB+WUiQsEUWJ+u669rNp9SGUMrVUhTf66uZOknBT3MZkENmoQcOtLgIKciyqWBMyC3NwPO+J84cKFcumll8qHH36owhDT7BOgILfPTJdw67PYeQ/iuyQFeXzPH3sfQQIT52+X279ZrQ6Q4iAprMGLcyTrwFFZPLyDNKzE5DERxB9y1W59CVCQh4ycF0aAgD9Bbkeccw2HPzEU5M4ZuvVZ7LwH8V2Sgjy+54+9jyCBp37ZKI/O2CjDOlWX53s3VC11fSPfV/37q1pLt9r+451HsFus2kLArS+BnTt3yldffSXnn3++ZGQURPEhcBKIBoFQBLkvcT5s2DBp27atchelIA9/pijInTN067PYeQ/iuyRcu5Fos3z58oXcv235kGdnZ8vMmTOLOKKb0dCHPL4XSjL2/tGfN8hTMzfJLZ1ryNO98tPYdpu4QBZnHZQvr2gpZ9UvOHSRjHy8MmZ+CXhlJtiPcAjYFeRWcf7ggw/KaaedJo8++qiMGzdOWrRoEU53krfs8TzZecNZyTv+MEee8eaMMGtgcSsBW4I8FHwU5KFQ4jVeIjB+7ja5639r5Jp21eTVfo1U19q+Nk9W7zksv1/fTlpXLeul7iZtXyjIk3bqYzbwYh45P9KgQQOBEL/gggsY5jBmqyG6DWPtnTgZYCC6LbO1SBPwF0KcgjzS5Fm/5wl8u3qPXPKfZYJDq99d1UYOHD0utV/4XfBZuGFEF6lQMtXzY0iGDrolyOfPny8XXnihfPHFF9KhQ4dkQMcxOiQQCVEU6g45RbjDSUuQYpFYewmCJu6HQR/yuJ9CDiBSBI7mnZCmr/whOw4elZs71ZRVuw/Kt2uyZUCzKjLlkmaRapb12iTgliCn/61N8El8eSREUSBBHqoI37Jli7z11ltyzTXXSM2aNZN4hhJ36JFYe4lLK75GRkEeX/PF3kaZwPS12XLFx8tlf26earl5ldLy2eUtpXaFwuEWo9wtNmciQEHO5RBtApEQRVZBHqoIN4+dN5XRXgnRby8Say/6o2CLvghQkHNdkEAQAgePHpdF23OkbFqqtMwsbSQXIjhvEHBLkCNT4ogRI2Ts2LHStGl+mEsaCfgiEAlRBEGOCD/h+IRTkCf+eo3E2kt8avExQkRYWbRokYqahEgr2mz5kK9du1Yee+wxeeCBBwR39b6MhzrjY0GwlyQQbwTcEuTxNm72N3YEIiGKcFAv3MOiFOSxWxPRajkSay9afWc7zgjYEuShNEFBHgolXkMCJGCXAAW5XWK8PlwCXhVFEPXHjx+XlJSUsMV9uIzitfyJ/btk1x0Xx2v3Y95vhj0Mbwp83ZhTkIfHlKVJgASiRMAtQb5p0yZ544035IYbbpDatWtHqfdsJh4JeFWQxyNLr/WZiYGcz4hbn8XOexDfJV3xIYfLyujRo+W+++6T+vXr+yTCHfL4XijsPQl4lYBbXwJ83O/VGfZev7wqyA8cOCBLly6Vli1bStmyzJPgZOVQkDuhll/Grc9i5z2I75KuCPJQvsgoyON7obD3JOBVAm59CYTyOeZVBuxXdAl4VZBzDYe/DijInTN067PYeQ/iuyQFeXzPH3tPAklPwK0vAYqZpF9KIQOgIA8ZVdxdSEHufMrc+ix23oP4Lgm3yfHjx8uwYcMKuU3a8iEP5YuMO+TxvVDYexLwKgE3vwT0gTivjpX98gYBCnJvzEMkekFB7pyqm5/FznuReCVtCfJQhk9BHgolXkMCJGCXAL8E7BLj9eES8Kogz83Nle3bt0u1atUkLS0t3GEmZXkKcufTzs9i5+wClaQgjwxX1koCJOAyAbe+BHJycmTx4sXSpk0bKVeunMu9ZHWJRMCrgjyRGMdqLBTkzsm79VnsvAfxXXLFihVy1113yfPPP18oOZ0tQZ6dnS2//vqrdO/eXdLT030SCWeHvHjeEWn/0bPxTZq9JwESiBgBN2LfhuJ6F7EBsOK4IuBVQY7v2UOHDkmZMmVULHKafQIU5PaZ6RIU5M7ZoWRcHOoMb4gsnUgEdu7cKRUrVpQSJUok0rA4Fh8EIHrwr3LlytKpU6eIM6IgjzjihGnAq4Kcazj8JUZB7pwhBblzdhTk4bFj6RgQePDBB6V169YyaNCgGLTOJqNJgII8mrTZlh0CFOR2aMXXtRTkzueLgtw5O5ScN2+e9OvXT77++mvp0KGDUZktl5VQ7srDcVkJb4gsnSgEZs6cKY899pikpqbKa6+9xmyKiTKxfsYRbUGOA3F4ApOZmcknMAm+tsIdHgV5uAS9W56C3PncUJA7ZxeopC1BfuzYMdm/f7+UL19eiSVfRkEemYlKllqRgQ4pzffs2aOG3LZtW5UdFl+MtMQkEG1BnpgUOapIEPCqIN+9e7f88MMPcvbZZytXL5p9AhTk9pnpEhTkztm5JshD6QIFeSiUeI0/AuPGjZPPPvus0Nv33HOPnHvuuYSWoASiLcjxGYVIK4iwUrx48QSlymG5QcCrgtyNsSV7HRTkzlcABblzdiiJJ7TffPON9O3bVzIyMozKbO2QHz16VHBnjjtyf4ftQhXkR44cCW9ELJ1wBBAK6Pbbby8yLjyRef311/1G9kk4EEk2oGgL8lBc75JsCjhcPwQoyBN7aey8rkdiDzCCo3Mj4lUEu+fpqj0TZWXfvn2ybt06oSD39HqJeudwIzd8+HBZs2aNz7bPOeccGTVqVNT7xQbdI6CFN8K0IVOmNv06Qrh17tzZvQb91ERBHnHECdOAVwX5nDlzpEePHjJjxgzp0qVLwvDmQAoIeHXtcY7CJ+AJQX7ixAnBP3wZc7GFP6mJVMNHH32kfMcDGXwmO3bsmEjDTqqxwD0ET9YCZRaMxlkBCvKkWnZhDdar31Ncw2FNa1wU9uraiwt4Hu+kJwS5xxmxezEigAOcLVq0UH69gaxp06Yya9YsKVmyZIx6ymbDIQBBjsPg/g6Eh1O3nbJYbz///LOcccYZUqlSJTtFeW2SEfCqKKIgT/yF6NW1l/jkIz9CbErDSwRaxpzYy5YPOSKsLFiwQNq3b68irfiyQD7kkR8mW4hHAjfddJO8/fbbIXX9iSee8OlnHlJhXhRTAl4R5DGFwMbjioBXRdHq1asFuRoeffRRadSoUVwxZWdDI+DVtRda73mVEwK2BHkoDVCQh0KJ12gCs2fPVqG7QjWIukWLFkm9evVCLcLrPEKAgtwjE8FuhEyAoihkVLzQZQJcey4D9VB12B3ftGmTyrFifuJvW5DDBzyQnycFuYdm3eNdQVz7wYMHy4YNG4r0dPv27YJ/1apVU//M1q1bN3nuuecYm9zj82vtnlcEOR/3x9nCiWF3KYpiCD/iTZ8QOXYs4q04baB59Yry17a9TotHtlzxVBHmBnHMOKY+5I57zYJJS+CDDz5QhzwnTpwol112WdJySKSBa//xWPuQU5An0qqK7Fi8KsixiTFmzBgZMWKE1K1bN7IQErR2HYc8QYcX8WEx7KFzxFET5NpZ3RzWzHm3WTJZCUCQX3/99UqQDxo0KFkxJNS4uUOeUNOZFIPxqiDnTWX4y4+JgZwzZGIg5+xQMqqCHK4IOsRheN1m6WQlgDCIV111lbzzzjsycODAZMWQMOPWscYhymOdHROx7h977DF54IEHpGHDhgnDmANxnwAFuftMvVIjBbnzmaAgd84OJQ8ePCgrV66UJk2aCPJvaLPlQ75x40ZBavObb75ZOaPTSCBSBBBzHMmApk+fLj179oxUM6yXBEiABPwSoCBP3MVBQe58binInbMLVNKWII9MF1grCRQl8OOPP8pZZ50l+P/MM88kIhIgARKIOgGvCvKog0jABinInU8qBblzdigJDxIEQMHTYnOQFAry8LiydIQIUJBHCCyrlXXr1sno0aPl3nvvlfr165MICcTdDjmnLHwCFOTOGVKQO2eHkq74kK9YsUJGjhwpTz/9tCBrIo0EIkWAgjxSZFkvD8RxDYRKwKs75Hv37pW5c+dK586dpUKFCqEOh9eZCFCQO18OFOTO2bkmyPlFFt4ksHToBCjIQ2fFK+0R4OeYPV7JfLVXBTnXcPirkoLcOUMKcufsKMjDY8fSMSBAQR4D6EnSJMVMkky0C8OkIHcBokeroCB3PjEU5M7ZoeS2bdsEoZ0vv/zyQokPbfmQz5s3T/r06SPffvutdOzYMbwesTQJBCBAQc7lQQIkEGsCFOSxnoHItU9B7pwtBblzdoFK2hLkkekCayWBogQoyLkqSIAEYk3Aq4IcuT6ys7MlPT1dYp35NtZz5LR9CnKn5EQoyJ2zoyCPDDvWGkECFOQRhJvkVUPIwG3llFNOUYKGRgL+CHhVkHPGwidAQe6cIQW5c3Yo+eeff8q1114rkydPltatWxuV2doh37lzp3JX6du3r1SpUiW8HrE0CQQgQEHO5REpAvQhjxTZxKvXq4IcO+SItFKxYkXukDtcdhTkDsEh0+S24pLx5gznFSR5SVfCHvKLLMlXURSHT0EeRdhJ1hQ/x5JswsMYrlcFOddwGJN6suiJA9my67aLpNwpLcOvLMlqyPl9KQV5GHNOQR4GPBaNPgEK8ugzT5YWKWaSZabDHycFefgMvVzDzut6eLl7nu4bd8idTw9cVq6++mp5++23pVWrVkZFtlxW+EXmfAJY0h4BCnJ7vHh16ATwuH///v1Svnx5Pu4PHVtSXklBnpTTzkGTQEwI2BLkx48fl8OHD0upUqUkJSUlJh1mo8lBgII8OeaZoyQBLxPwqiCH//icOXOka9euzNTp5QXEvpGADQK2BLmNenkpCYRFgII8LHwsHIDA0aNHZc+ePVKpUiUpUaIEWZGAXwJeFeScMhIggfgloBMDDRo0SKpXr24MxJYgP3LkiGzZskVq1qwpJUuWjF8a7LnnCVCQe36K4raDdL2L26mLescpyKOOnA2SQMIT4KHOhJ/ixBogBXlizaeXRkNB7qXZ8HZfvCrIuYa9vW7YOxIIRICCnOvDkwQefPBB9dTFagsXLpS5c+dKly5dpE2bNoXebtu2rdxxxx2eHA875X0CFDPenyOv9JCC3CszwX6QQOIQoCBPnLlMqJEsW7ZMWra0Fwc2KytLMjMzE4oDBxM9Avv27ZP58+dLx44dVaQVGgn4I0BBzrVBAiTgNoETJ04Ion2lpqYKPmO02fIhP3jwoKxcuVKaNGkiZcqUcbuPrC9JCdx0003y2muvhTT6F154QUaMGBHStbyIBEiABMIh4FVBvn79enn++efl7rvvlrp164YzRJYlARLwCAFbgtwjfWY3EowADgtnZGRITk5OwJHVq1dP1qxZw5CbCTb/sRgOdijMOxOx6APb9D4Brwpy75NjD0mABPwRwOb2qlWrpHHjxoU2t20JcnyJ5eXlSfHixfllxrXmKoFp06ZJr169Ata5ZMkS2+4trnaSlSUEAfqQJ8Q0RmUQFORRwcxGSCCpCNCHPKmmOz4H27t3b/nuu+98dn7o0KEyYcKE+BwYe+0pAhTknpoOT3fGq4J89erV8tBDD8kjjzwijRo18jRDdo4ESKAwAQpyrgjPE0CylsqVKxfpJ84r7Nq1S2WIpZFAuAQoyMMlmDzlvSrIuYaTZw1ypIlHgII88eY0IUf0xhtvCHbDzfbNN99Inz59EnK8HFT0CWzcuFFefvllufXWW6VOnTrR7wBbjBsCFORxM1XsKAnEDYHDhw/L5s2bpXbt2oWSbNryIUe6z/fee0+uuOKKQuk+44YCO+p5AsePH5cWLVrIihUrVF/PPPNMQZIgGgmQAAlEm4BXBfns2bPljDPOkJkzZ6pcDTQSIIH4J2BLkMf/cDmCeCCwfNlSad6ylerqti2bpVqNmvHQbfaRBEggwQh4VZAnGGYOhwSSigA2HhFdrmTJkoWixnlKkJ/IPSy7hvdOqonhYIsSQDSfgd8sliql0uT1s5oTEQkYBDLenBE2DTx9uf/+++Wpp55SORVoJOCPAAU51wYJkIDbBFzxIUfYuSFDhsikSZOkVav8HUw3TQvyMtXz3KyWdcUhgdW7D0u5kilSrWxaHPaeXXabQLGqDeTAog3ihiDngTi3Zydx6/OqIN+9e7dy5evZs6fPg/CJOyMcGQnEPwFXBHmkv8goyON/oXEEJBAJAhTkkaDKOoMR8Kog19/F//znP+Xhhx9Ww0BiNWyaaevQoYOkpaWp3CF//PGH8XrTpk2lUqVK6nf4ouOJJAzJ2XQIxXXr1sn27duNMqeccor6ee/evfLXX38Zr3fq1Eml/z569KjMmzfPeL1ly5ZSvnx59Tv6qq1mzZrGQWo8qUJkLViJEiWkY8eO6mdE1ELSFG3wkU9JSVGP+BcsWGC83qZNG5VUBf3HOLQhgVz16tXVr+ChE86VK1fO2EjEeThkO9XWtWtXlVsFCVsWL15svN6+fXvlVgAXgzlz5hivI6FLlSpV1O8YN8YPA1fwheHw+JYtW4ow3Ldvnyxbtsx4HePG+JFKfe7cucbrzZs3l4oVK8ry5cslOztbvY5IY+3atVM/79ixQyXKs44BBwYXLlxovN62bVspXbp0EU4NGjSQqlWrqusWLVokhw4dUj9j3jB/MPQf49Cm18GBAwfkzz//NF73t9bwBFJHTgM/cISZ1xrmAfNhbSPUtYYzZxUqVFDFzWutRo0aRhZbZJjHTSwM6xXrFhaptVa2bFlp3bq1agN/R/h7Ms8T1mu3bt3kt99+E80U79tyWaEgN5jyBxIggSgScFOQ40vv3HPPFSSj0h/MURwKm4ojAl4V5BCmEEEwCG4IVv39rPFu2rRJatWqJRCAEHbaPvnkExkwYID61Zyt9pprrpHJkyer12+55RZ59dVXjTJatH/77bfSt29f43WIHIhQiA4tgvHmTz/9JD169FAiEH3TBlexJ554Qv2KPnz22WfqZwg0CEzYlClTZPDgwUYZiGQISohPc8x1MIA4hZCFoNU2ZswYueOOO9SvELvz589XP+NvXd+Y4Jo777zTKANBDaEGIQsRrg1tQriiDxBZ2t59910V3AIGYa7F3iWXXCJTp05Vr997773y9NNPG2UgRsEbbPBkQ1tWVpZkZmaqOrTIx3tgjdwc5vwc6IsW4RMnTpQbbrjBqAdCHDcPuNFp1qyZ8frSpUtVoITc3NxCET1ee+01GTZsmLoONxEQrTBzIIUnn3xSRo0aZdSl1xoEpVlIQrQjYsj+/fsNcYxCH3/8sVx88cWqvL7pwM+Y37ffflu9fvvtt8tLL71ktKHXGnKSYOzaIJ4h7rFO9I0E3sOTIvTZutZGjhwpo0ePVsUHDhyo+gJLT083bgTff/99Yx7xHm40cJMHAQ3W2rCGsC6sa+3555831hFu6vRNG67V627s2LEyYsQIoy7MA25+cCOH9alvJnCBLUGOO0eAxB+MVv9GKy78EA875Et3HJTZW/Ybo728VaaUSi34wHEBQ8yqSKSxBRpLIo0zZoslyg27Kcij3HU2F8cEvCrIIT6wqwkRpoVRPO+QR2rXEru4EFkw866lmzvkuMGHUINFYoccTySwWwyD4NY3DNYdcv0kwckOOW5EUA4WaIdcP0lwskPu72lMtHfIkWm+c+fOaqyR2iGHqMcTHJivHXLzjbD549GWII/052qognz6ur0yc0P+Ai00GCkmZdNSpErpEtK2WhlpU7WsFE8p5mq3n5+1WR78seBR18pbO0nN8iVdbSNWlXltbP7m2R+fcmnF5c5utdTbgcbitXGiv8HGWqZEitRPLyWNKpWS9tWxU+Puuo7Vmgu1XQryUEnxOjcJeFWQuzlG1kUCJOANAnEpyB+cvl6e/21zUIIZZUrIDR2ryZ2n1BKINTfMi2LOzri27M+VUT/k+zPdfWotddOizWtjC3Wedf9xI7ZhRH5M3nAEeSBGdljbudbOWDvXLCeP9awnZ9QreAxtp614vNZNQY5dETwO7dWrV6FHxPHIhX2OLAEK8sjyZe0kQAIFBGwJcmy9f/jhh3LppZdKtWrVHHGEDxIed2jnfnMlJ7K3S94jQyVYlBU74gX1Y1fxo0tbSNMqpR312VzIa6LV7oBenL1Z7v8+f4f/o0uby3mNC1LVr9lzWJbsOGhU2adRuqQVj507jt15NgvyQGMJNoeBGNnlHer1dsdaongx+W5wa+lSM//gVKKbm4I80mdhEn0ukml8FOTJNNscKwnEloAtQe7GFxmc/nHCGCemtfO+RlByf5Y0mvqibUF+S5eaUrdCSTl87Lis2XNIFmcdkHnb8v3GtOFx/8/XtpHKpQsOfzhBH0zMOakzmmXOmLxQ5m3NZ2MV5NHsRyhtWUWqnmd/ZcuWSJEhHYLfKAabw1gwso51eKcaUrdivitU3vETsnnfEZn61y7ZcTD/ND8MN5qLhudHJkh0oyBP9Bn25vgoyL05L+wVCSQigagLcpz4xulofYDADLX0gSxp8cUE24J85pC20qF6uULz8+lfu+TO/62RrAMFAubWLjVl9Ln1C123NvuwjJ+7VX7ZsF+2H8iV4ikp0rBSSRnQrIoMaV9VUk0nxFEwmJizW9/xEyKTF2yTd5fskLV7jkjJ1BRpk1lG7jy1plRIS5XHfi4IOfRMr/pSy+KvPmNDtkxesENW7T4kW3NypVKpVGlYqZRc1jJDLmmBsEz5vsYjp62V9XuPyJcr8kP/wLrUKi81y6VJ5xrl5K5Ta8mXK3fLu4vzT7rDxvVrJBVLpaqfP1iyQz5bnl+2Uqni8kq/xvLzhr0y9vet8ueOA1IipZi0yiwrd3erqeq1mpNxWkWqr3n290cZaCz+5jAURro9O/NsZTembyN54If18vWq3QhzIN8Pbi0vzt5SyA3L11j3HsmT7hMXyLq9R4xh6zMMobSRWTb/ZjQnN08mLdgu/1uzR9ZlH5GDR/OkYslUaZFZRvo3rSwDW2ZI8WIFPuqv/rFVZm7YZ7T59+61Cv29HcjNk1u/WSNHjuWHtMKNUekSxWXnyZuH8mkpMv6CxkX83j9bvks+WLLTqHfkabWlfbUCFyrz3FKQ+1vpfD2SBCjII0mXdZMACRT6njth3aYOwMeNHXKzILc2DUHe8svXXRHkGMa0NXuk/wcF8T7Lligum+7sYrhhTF22U4Z+sVKO5OXHYbXaqbXLy6eDWhbyPw8kyJ3Ud/0XK+T9PwtEie4DXBKuaF1V/r2wIBbsnBvaS8vMMuoS9Pj2r1fLmwsK3rf2/8KmleX9gQh/VEzaj58nK3fnn6K2Wr8mleXDvzUPeLPx6IwN8tQvm04KLgjyhnL95yvFii41pZi8d0lz6dckP86tNifjDEeQO/EhD4URxmN3nh+ZsUFGn2RXPq24XNe+moydXRCfdvktnWT83G1BBTnafmD6Onnht4KyX13RUnrWT5dQ2qhdoaTM25Yjl334l7p582ddapaT//ytuVQ9mZRp5a7DctqkBXLgaL7gbpVZRn65rq2UOHmz+vfv1gpEu7aXzmskC7flyBvzC9bmzGvbSocahW+az39vify4Lv9wdukSKbLmti5SoaTvsx5uCnK4yyHsFEKpmUOy+QXCN5KWAAV50k49B04CUSdga4ccAhrhfRCiyF/YlmAjiKYgR1/6v79Upq3ND6oP+/bKVnJ63YqCg3sQYFpkVC1bQq5onSF7DuXJlMVZhtCEeILA0OZP6Dmp75cN+6T3lILg+tiT7FqrnKQWKya/bd5fROwuHNZBGlfO94N/988sGfpFQfKEZlVKSa+GleSnDXtl8fYCP/BX+zWSa9pVk8um/iWLtx2QDfsKdldrVUhTO6M961WUZ3o1CCjIn/5lk/xrxgbVNvqJnfPsw8ekcun8/7EDrg2++nOHtpeUk7usTscZbUEeCiMn8wwxDsEMA5PSqcWMdYfX7Ajy+75fKy/NLhC/X17RUs6qn64Ef7A2sOvd7c2Fxs412m5cuZQ0TC8lC7bnSNaB/NBdsO51ysv/BreWYiefsODG8Kb/rjbe/8cZdWTU6XXk90375Nx3/jTmv3+zyvLuJc1lwbYDctqkguQUd3arKY+dVfB0as/hY1J/7Bw5dnLhDGqVIW9elJ9Qw5e5Kcj9NsI3SMBCgIKcS4IESCBaBGwJcjc6FW1BDpePJ2cWuH2MP7+xDG5bVYZ/tUreXpSlhpRWvJgSkA0r5YvdN+dvl9u+yRcf2PGFW4DeLfQnyJ3Ud+mHl/YfAgAAIABJREFUy+S/q/IzlcGe7dVQbuqcn2Hso2U75ZpPVxRCvvTmjlKvYin12gXvLVGh8nQfV93WSTLLpCmh1/TlOZJ9OE+9179ZFXn3kvwkAXA76GO6AbD6kAfaVX5u1mZ5yBTuEWH43rm4ueDg5+o9h6X3O4tlW06Be9CymztK3ZN9dTrOaAvyUBg5mWcrO9zQjOxeRwY0r6LcR7rUKieP/LQh6A75tpxc6TZxoeFHjnog5mtVKCmhtDHyu7UyYV5BRrQ7utaUx8+pryT3viN5csl/lsqsTQUx9qde2lz6mg79Xv3JcuXHnv83kyLfX9VKbvhilSzflZ/hDTvwv1/fTtJPujmZffHrVSwpWL/aheq9P3fIDV/kJ6KA6RuLQgve9IubghznV7Zu3SrI5Ia4vjQS8LvuihUrctaJtEiABEggEgRsCXI85l29erXKloXHvU4s2oL8rYVZcvN/C3aSn+3VQG7qXEMajJ0jWSd9XPs2qiRTL2thDAe7dtWe+00OH8vf9oX/6+A2+Slm/YlWJ/XVHTNbdh3K35WsWT5N/rqlUyHf3TPfWiR/bMkx+mUWueuzj6idaQg6uI30qJefOhZ23pQ/ZcZJn9/mGditzs/oFo4gt477rm415VHTjudTMzfJoz/n7wLDvr6ylfSomx+Wz+k4rYK8Y41yhtjztfbOql9R7gozDnkwRk7m2cruitaZ8saFTQoNwTrWoR2rKYELw/xu3HtEPl62U+BHrg3j/fKKVj7XpbUNZMeuN7ZgvVUpkyorb+mszixo+3nDPulrumEb0r6avGx6OoSbvG4T58vGffnuLojxjwOn+uev/6+VnFanYB3CT/3Wrwt21Wdc21Y6nXRb+b+P/zLOJGCcWNv6iYqvuXVTkLvheuerj3wt8Qhwhzzx5pQjIgGvErAlyMP9IoPLCwS5zgoVaR9yQIdv7l3/W2Pwf+m8hnJZy0yp9tzvxmtwu2hmCYn426b9yk8bdlvXmvLUOfmP230J8golU23X988edSXj2d+MPuAQ6ZSTO9n6xYemr5fnTPHWzYIc1+TmnZDPl++Uv3Ydlk37jqgoM0ePn5BZG/fJ9pOHWRFdZslN+ZE4golNO37X065qLafWLhBfX6zYLZdP/csYzwcDm8kFTavIoaPHHY/TbihAHGSd1D/f7cHOWMzJnQIxws2Pk3Vj7cung1oo9yKz2R0rdqERNUg/1QnWxqZ9udLslT+MJs1PTvSLecdFKj39q+Eq1bVWeZl+dX62MW2/btovfd9ZXMSdCu4rcGMxW07ucWn00hx10wgbcUpNefzs+mqd4iZNu4uN7F5b/nlm3YCfkRTkAfHwzQgRoCCPEFhWSwIkUIRARAS5zxjjJ06oR3/Z2dmyZMkSn2EP3T7UidHeO22tvDynwOcWj+HrVCglXScuCHk5XNkmUyZckL+j6Uvowe/cbn33nVZH2rw2z+jD9R2qy4t9GxbqE5IfQahpMwvy3zfvk6s/XamEeCCLlCC33hzMWL9Xznt3idEVLcgRD9zpOO2K1EgL8iVZB23PM9aNdc3APap5Rv7hXG12xnpG3Qry8nmNlf+3tmBtLNp+QE59s8Cne1jH6vJ8n8LrDXXVfuF32XPS3QkHiHGQ2Go3frlSppii8SAB15rbOvvMinv7N6tl4snDndpt5ZtV2TLww/zD1nCXWTi8gzQ66S7mby1TkIf8ccULXSRAQe4iTFZFAiQQkIDrghxiPDc316ffHQQ5suTB7cXXNW4LcoRhw8HNDScfsYME/FhTpJg0f3WuAQZRI3rULdjttRJDSMUr2/p3WcHOot36+jSuJPXGzjGaurxVpky8qLAbw+MzN8oTprCHWgTD37fT6/PVwVQlaoqJCnOIsIMIOTdu7lZZdTKiSqQEuXlXGX2YsX6fnPduwQFVLcgR+s7pOK0i9dV+jaVFhn9XKYT1a5CeL1IjsUMOtxG784x1EyxUJvpb1GWlutQ56bKC93HOoVrZNEGWToS1tFqwNv7aeUitGW1Xt60q485HKMLCBlct7GzDWmeWkd8tgnxt9hE5deIC2X9y11uXHtu3odzQIf/8g9mshzt/vratCq2JNQrrXruCfHdV66Af024KciQmW7FihTRt2lTKlvUdZjFoh3hBUhCgIE+KaeYgScATBGwJcsQO37Rpk9SuXVtKlSoqCjAiZOLEoSnzLrmOyILXdu/eLWvXro2KIIe7B9w+tJ1Sq7z8cHUbgYDOeGaW5J70fx3Yoor8e0D+wcdg5kv4VCtb0nZ98Omt8swsI+QifGvhY2s2s58tXteC/Ie12XLh+0uNS+E3/ehZ9YzfW746V8Uch8VakIczTq8d6nS6boKJZcxTOGNF+WBt7D18TGq9MNtww8Iu+zdXFhbCOw8eU37m2no3qiSfWM5W9J6yWH7fVHCuQV9bpkRx+WVIG2lapfDOP943H+68//Q68tHSHUYIzlf6NZJr2wVP5uSmIA/2N873SUAToCDnWiABEogWAVuCPJROeUGQw7f6kRnrZcxvWwwBgr7/u38zGdgSyXJEOk6Yb0SHQMr15bd2lNKp+TGQDx49LhPmbRW8nlEmVdpWK2sk5PEnfJzU1+WNBbLUlKr+1+vaSbuTiVHW7jksHV+fr/zEtWlBPmHuNpX0SNvk/k3l0pYZ6tdZCEP3dsFOda3yabLi1s7qPat/9NsDmsolLfLLBRN1wQSfvx1y1Ot0nOGIVLd2yK2MnMxzMHZgFM5Yg82dnl+4rMB1BYYDlH/e1MGI2oPXxvy+Wf7xQ8EN7CM968ndp9Yy1scTMzfI4z/nx6KHq8k7FzdT5zP0eQUk9fnx2jZGfHJdELHybzt5uBMHOLWbFSL1rLm9iyA2ezBzU5DjSR0+p4oXL+44fGuw/vL9xCBAQZ4Y88hRkEA8ELAlyLU7Slpamt+EGviigzsK/tcW6R1yRPNA1AhI1w17j8iSrANFkv1c3jpDJl5YEOd40oJtcuvXBaIWIeiePqe+iouMUInv/lmQsfK7wa2l+8noEf7ElZP6kEwFSVW0IRb67V1rKrGD9zafdEnR72tBjiyUgz4qOECJCCuIhrFy1yEZ9tXqQnGmkWBoxS35YRvnbsmRHm8tMtrr1TBdxvRpqMaM+OZORSwqDCTInY4zHJHqdCzBGDmZZ68I8rcWbpebTbHEW2SUUQmekP31m9V7BGERdZIsJNGCexf8w2GzN++XXu/8acQNv7ZdVZWt9ZO/dsngT5Yba8r6tAZv4FBno5f+MA536osvb50pEy3RZvx9aLopyMM9nB4PH+zsozsEKMjd4chaSIAEghOwJchD+SKLhSAPNkyIh+d6N5RSphBvyPLd/c0FssS0Q+2rHoQ7zE/7nW/+xJWT+uCr22H8PNniJ2ti/fSSKrW5VZBnHTgqbV+bV8SPV193ep0KMnNjQapz7ERe1aaqPNijrnJJsGbXRISZeTd2iJggdzrOWAjyPYfy3Tb8MXIyz14R5PDQunzqMvlqZUHse19rPqWYqLCMg1plqrchqLtNXCDwH4fVKJcmc29sr5JKwQZN/Uu+XLFb/Yydd2QP7VEvP+SlNsT1R3x/s+kso8H+fvE+BXkolHiN2wQoyN0myvpIgAT8EUhYQY4Yyb0aVpShHWpI38aFQ8xpGNtzjsqNX62UaWsKMnnq9yDeb+xYTR47u36h2OCBxJWT+lbsOiQ3frFK5mwtSMhSsWRxueOUWuqA5r3frysiyPHC1KU75ab/riqU8fH/2bsO8Cqqpj2ENEroJfTeexEEFRBQREVBUfzEAoKiiH6oKArYG/aG+iFFAUERRURQUUAUFX+KNCmK9N5rAiEJ+Z/3xLNsbm7ZvVvulpnn4eFm72nznnN33zM7ZwbXb2lSlt66opbIUKom5dIaieQ+SCKjFqsJOfqKRs9YEHKMNRxG+F7vPDuFkGPsmdk59OSi7fS/FXvzvUXC9zVKJImsrd1VCYHunruJpqw5/8bo0+vrUY+6ua5fkL0nzwr3Khw2hiBR0VJVgiBcW7kvjS5WZe6sgkRB94SPPa5eo0zI+SEWCwSYkMcCde6TEfAnAq4k5FuOnKHNx84EnbGEuAJUISWBKhdLFoRWi2w4mE6Ir3z0dCbFF4wj+F13rg43mNzX9WqBS4zMTIjrnaoXJ/SpFj3tyXpbj52hPSfOipT0CGeHDcGTP22nV3/LJc+wPB4c1oaS//VzxzVEWVm07bhwbUlJKkiXVClGjcrlHqqD7/kPm48K6zvabFsxhaqVyE0089vOk7R6f+7BvFqlkqluqcIEa3w43SLpffxMNi3dc35T0bJCEeGDHyh69Ayc5/aVU6iIBn9j9GlEl3AYRTPPkbBDm0Z0jaRvsN/A4fRMWrT9BG0/dkbEBS9ZKF6cX0DscWSnVctP248rZxmSCsblSUIly/15MF0QcykXVMybxCkw2sqjF1UWb2y0ipmEHFk6p06dSrfccgulpuaPDKN1TFzO+wgwIff+HLOGjIBTENBFyA8dOkRz586lq666isqUOX8YUK2MHS4rTgHP6Dj+b9cJkaocSVtAqt+/qlaeTJSwKMKyCEGou7V35yb4cZv4RU+3zYtd48UZhes/20Dzt+a+icJmE8mqUosmah6CmYRcc6dc0PcIMCH3/RJgABgB2xDQRci1jIoJuRaUcstMWLmP7v/u/MHSLjVL0NMdqxJc3cevPEDj/9inNDa4dSq9cln+RC7ae4tdSb/oGTuEndnz+8v3EsIt/rD1OP2+6/yZhntapdKrl+tby0zInTnHXh8VE3KvzzDrxwg4BwEm5DGcCxx27DRpNW04dDrsKBBLfOnAZoTIF24Uv+jpxrmxcsy13llG+05l5ukC7lg/3d40z5sgLWMwk5CvX7+eBgwYQBMmTKCGDRtq6Z7L+BQBJuT2TfyJEydow4bcDL4lS5YUibsgyH2ye/f5c09t27YV10+ePEn4LUtp2bIlJSQkUFZWFq1YcT7xX7169ahEiRKiGAJTSClfvjxVr15d/LllyxY6ePD8ORnZx9GjR0USMSmtW7cW4VIRSW7lyvOJ1ho1akRFixbN1wdytlSqlBs6duPGjXT8+HHxGXlcmjVrJj6jX/QvpU2bNiIcK/K+rF59Prty06ZNqVChQiLp4tKl5/NF1KhRg8qVy01ciPKoBylWrBg1aNBAfN6zZw/t3LlT6UPqhyRpf/55PkxyixYtCFH0YFhdvny5Ur5OnTpUqlQp8feyZcuUPDPwlKhVq5a4vn37dtq377wRUfYBnaG7lFatWlF8fDxlZmbSH3+cz1aOsWLMgfNUoUIFqlpVu3uj0pELP+gi5FiAPXr0oDlz5lDz5vlTakN/tpDrWwWHT2fR8PlbaeaGQ/kO2cE3vX+L8jTy4ipK+Dl9rTuntF/0dA7isR9JICFHMiJkWw2WaTTSaM0k5FqiRUUaD3/vDwSYkNs3z4sWLaJLL71UdAieMXv2bPF55MiR9MILLygDQfhlzMvixYupQ4cOynWQQZBskGhJHvHlN998Q927dxflZAhmfB48eDC9++674nq/fv1o0qRJSlsgvZCvvvqKevbsqVwHuQRpxAYBZFvKkiVL6MILLxREFYRdyrPPPkujRo0Sf3bt2pUWLFggPoNESxIOw8DAgQOVOiDUSUlJ9Ndff1H9+vWV69h8gLRiM4DvpYwdO5buuusu8Sc2MZs2bRKfO3bsSMAU8uKLL9KIESOUOuBpcXFxgthL4owvQdqhFzY7khzj+syZM6lXr16ivtz04DPO4UyZMkVcv//+++mdd97Jh+H3339P3bp1U64jWzvmBxsRuZHAlxgrxgzsMTYpjzzyCL300kvK317+oIuQa3mQMSGPbrkcO5NNfx1Kp/3pmYQzddWKJ4uIF0U1HmKMrlf7a/lFT/uRdV6P249liJj42ZRDVYoliXCJ0QoT8miR43pGEGBCbgQ9fXX9ZCEHoZZGTass5CkpKcobwEALubTCR2MhB4mXGxa7LOTA6/PPP6fevXuLTZdXhQm5V2eW9WIEPISAmYR87dq1dPPNN9O0adOoSZMmHkKJVTEbASbkZiPK7TEC+hHQYgzW36rzaugi5HiFMnToUHrrrbcU/65AldhC7rxJ5hExAm5HwExC7nYsePz2IcCE3B6ssUm+/fbbafLkydS4cWN7OuVeXIMAE/Iop4oJeZTAcTVGgBEIiQATcl4csUCACbk9qPuFcNmDpvd68cv60GUh1zLNTMi1oMRlGAFGQA8CZhLy/fv3+8IfUQ++XDY4AkzI7VkZfiFc9qDpvV7gs47oOYjOoj6Y6zVNdRFyhB8aP368OBGsPmGsBoUJudeWCOvDCMQeATMJOT/8Q88nHnxefuDpXclMyPUiFl35devWCZcVRDpBCEEWRsCPCOgi5FoeZEzI/biMWGdGwFoEmJBbiy9ax737sssuEyHKhg8fbn2HLuiBCbkLJomH6HkETp8+LcJE1qxZU8Ri96owIffqzLJejICHEGBCbu1kgox36dKFkHwECT7at2/PpPzfuNUyxJu1M8CtMwKMQCgEtBiDvYAeE3IvzCLrwAh4HAEzCblf/BG1LglJxpE5EBG0kHjkhhtuoIsvvpgefvhhrc14shxbyO2ZViT1+fTTT+mmm26i1NRUezrlXlyDABPyEFOFTFTqLEqBxdhlxTVrnAfKCLgGATMJuWuUtmGg0k0F8dhBxqUwKc9Fggm5DYvw35T2yHT5+++/58kcaU/v3IvTEWBCHuUMMSGPEjiuxggwAiERMJOQ+8UfMdJyCkXGmZSfR44JeaRVZM73fiFc5qDlv1bOnDlDO3fupCpVqlBycrJnAdDlsnLq1ClCAH9YU4oWLRoUFCbknl0rrBgjEDMEzCTk/PA/f4Az0DIeOMF+t5QzIbfnJ8+/SXtw5l6cjYAuQq7lR8OE3NkTzqNjBNyIABNy82YtkmWcSTlbyM1bbdpawrkOrMuCBQty2E1tkPmqFFylYRxITEwM6zLtdlCYkLt9Bnn8jIAPEGBCbs4k6yXjsle/WsrZQm7OuuNWGAEjCGgxBhtp3yl1HU3I0/cVdApOPA5GgBGIAQKFU7NFr2YScr/4IwZOV7Rk3M+knAm5PT/69PR02rRpE9WpU4cKFy5sT6fci2sQYEIeZKpgJTl06BCVLVuWEhISgk6mmS4rIORlJv5s+aLJXvcTZcx+jZJuf5UKVqxraX/ZW1dSxrTHKemmp6lgrVaW9nVu3z+U8eGDlHD1AxTf5FJL+8o5upfOjL+PEi7+D8W3u97avtKOUcb4+ymu4UWUeNkga/s6e5oyJg2juNKVKbHXowi7YF1/2VmU8ekTROeyKOnm54kKBv+NmTKAnBzK+OpVytm/mZL7vU6UZO1DMHPhRMpau5CSB7xDBYqW1KTCoTs6kBWEXFPnHitklIz7lZQzIbfnh+AXwmUPmt7rxS/rQ5eFXMs0u42Q55LxVynp9tc8SsaHUnyTzlqmLuoyuWT8fkq4+CYm49GiyGQ8H3JWEXK/+CNKQM0i434k5UzIo72h6avnF8KlDxUuLRE4ePAgzZkzh3r06EFlypTxLDC6CDlu7Ii0gggrOHwRTNxEyJmMG1/X3ibjD1Nc6UretIzv20zJ/W2yjK9ZQMkDx2i2jMtVaRUh99PD32wyriblvXv3pg4dOtCwYcOM30gc2gITcnsmxk+/SXsQ5V7ciIAuQq7lR+MWQs5k3PhyZTJuHEOKhWV832ZK6v86FbDDTSVKMg5kmZAbW19WkXE/kXIm5MbWoNbaGRkZtHv3bqpUqRIlJSVprcblGAFPIeBLQm4rGd+2ijKmjrLJZ3wzZXz4ACVcbaebSh+Kb9fb0h9Fju0+4x61jM9+lXL22kXGP6SsNfOjsoyzhdz4z8lqMu4XUs6E3Pha5BYYAaMIrFq1iq655hqaPXs2NW/e3Ghzjq3vO0LOZNz4Wsw5uu/fA5xMxqNG027LuMvIuJUWcq/7I9pFxv1AypmQR32H01UR5zpgJYd1PC4uTlddLux9BLR4Z3gBBV2E/OjRo7R48WK65JJLqGTJ4JESnOyykr3uZ8qY/Yo9Bzi3raaMqSM9aBm3mYxPuJ/iGtgVTYUt40ZvapkLjVvGrbaQG9XRyfXtJuNeJ+VMyO1Z7X4hXPag6b1e/LI+dBFyLdPsVELOZFzL7IUvY7tl3KtkfPoTBN9xW0IbutAyzoQ8ut8q7r2XX345NW7cmN56663oGjFQC2FxvXbQkwm5gQWho6pfCJcOSLioCoGNGzfS/fffT++88w7Vq1fPs9j4gpALMv7VK5TUz4bQhmwZN/xjET7jniXjTxJlZVJSXxvijLuYjFvpsgJ/xJ49e9KsWbM8448oyXijRo3o7bffNvwbjLYBr5FyJuTRrgR99ZiQ68OLS3sTAV2EXMuPxmkWcibjxhcuW8aNYyiiqUz3OhlH0p9SJoCV2wRHWdEGpVPIuBytl0g5E3Jta9BoKSQc/O6776h79+6EMx7Hjx8XTSYnJ1OzZs3EZ1zfsmWL0lWbNm0I83P69Glas2aNch3lUS8nJ4eWLl2qXK9Zs6ZIaghZvXo1IWMvpFixYtSgQQPxec+ePbRz506lTtu2bcVnhHtet26dcr1FixaUmJhI+O0tX75cuV63bl3FnRd9YwwQxM6uVauW+Lx9+3bat29fvj6gMyzBUlq1akXx8fFCBzPayczMpD/++ENpv2HDhpSSkiL+BreTUrFiRapSpYr4E9lTjxw5Ij5jLBgT5PDhw/TPP/8odS644ALh+49zADB4SGnSpInIvBo4F9WqVaPU1FRRDLgCX0iRIkXEGz7I/v37adu2bUpbcr6VCx784GlCbicZFz+YM2lE8QlUIMHasE2ir4x0ooIFqUBCsuXLMgd9FShABRILWd/X2dNEOeeoQFIRG/o6I7JiFkguan1fWWeJsjL+7cvCbJ9ElJOdSXT2NBVITrE2sygRnfcZN5eMY0KYkEdelk4j43LEXiHlTMgjr0GzS3Tu3Jl+/PFH0SxIrCR+48ePpzvvvFPpDoQah0BBYiWhxpcbNmyg+vXrC3IIYi5l3LhxNHDgQPFn7dq1afPmzeLzpZdeSgsXLhSfn3/+eRo1apRSB78vEE1pjJRfgLRXrlyZTp48KQi9lC+//FK8fYMgVwsOq0JuvfVWmjx5svg8ZMgQevfdd5U6kmzPmzePrrjiCuU6SG+pUqVEVvSsrCzN7Xz//ffUrVu3fO0cOHCAypcvr1xftGgRdezYUZBl9UHa4cOH0+jRo0W5Xr16iTeJEIwFY4J88skndPPNNyttpaWlCeK9detWwsZHCsg5NkgYvzq7+xtvvEFDhw4VxVq3bk0rVqwQn7HRkZsGuN3JMvgOGwpsCrwsniXkdpJxLy8Q1o0RCIWAlWQcfVpFyL3ij+hUMi7XixdIORNy++9/+H0asZA3bdqUChUqlM8qW6NGDSpXrpxQyCoLeZ06dQRxhYSybMPqC+uvFGmFt9tCjk2M3EyoLeQVKlSgqlWriuHF0kKOtwh4myCFLeQBv0W8LnruuefEDlK9C1IXc4LLCpNx+2+i3KO/ELCajFtJyL0wU2aScVi3PvroI/rzzz+FhQtWRdzf27VrR9dff72hMHRuJ+VMyL3wa2EdGAF3IKDLQq5FpVgTcibjWmaJyzAC0SNgBxlnQh56fiQZhw8oog4Yka+//pruuuuuPD6t6vbgAzpjxgxDkQ3gOnDDDTdQhw4daNiwYUaGa3tdJuS2Q84dMgK+RcBThNxpZBwWJ/WroL59+wrrU6jrXliFdutmd39emCMjOmQu/Iiy1vxAyQPN9xkPHJdVLitI0T1hwgQaMGCASNXtJjGTjMO/86KLLqL09HTh7wprOLLgwao9f/58+uWXXwQ0iNyC1+/wEY1WJCmHz+pDDz0UbTO212NCbjvk3CEj4FsEdBFy+D698sor9PDDD1P16tWDghYrC7lVZHzBggX0008/aV4gRYsWpUceeUSUf+mll+jRRx9V6u7atUsQgFDXNXdiU0GcXMdBE/jb4TAH5hbjx2EWHD7BwzxQ7NbNiv4izTlOgsMfEQeDWrZsadNsxL4bO8l45rLZdPz9V6lwarZQvEC5GpS2ZgeVmfizYSC0RIsy3ImqAbiB4H4JcmdEzCTjGAdSUcNCjoNxIOAXX3xxnuE988wz9OSTT4prn3/+uSDsRsSNpJwJuZEZ57qMACOgBwFdhFzLgywWhPw8GX+VClY0N2g8CDVIn1ZBeCOEZzJCyGHBk6920b8M+6R1DEbL7dixQ7zGBhkPJxjXBx98QDhsIcUKghxuDFb0p2fOoTvG0KlTJ6OwO7q+3WQ868ePKG3jIU8QckQ2QFivBx98UERbwMEvveRcTcYRZ1xv/cDFhVBxuFfBOv7f//6X3nzzzXzrD30WL16c4GP++OOPEwi6UXEbKWdCbnTGuT4jwAhoRcD1hNxKMg4Q9ZAzlFcTcoRVWrt2rTIXV155pYhdGolEvv7668pr3Tlz5tBVV12ldT4Nl0PIKJBLhEjSIohjirBICFUVbhOipa1oyoTCOJq2ZB29c45wTosXLyZ5Wt5I306sGwsyDpeYw8P+4xlCrv49wfVDDzk3m4xjjSFcG0K0HT16VGT3VIeNU69BbCYwdvwmXnzxRVOWp5tIORNyU6ZcUyMnTpwQIQshJUuWJMT0huDNMoxUUuR9Fmt4/fr1ynW8rZQhAmUYPXyJzI4lSpQQ5dQupFjb8k0/AlZIQxrKyT7w+/j777+VPhCiD+5dcOtauXKlch1uXXg7HtgH3iZLtzi90WMQ1hFvp6VYET0Gm224fUoJFV9dHT1m2bJlSjhHI/HVA+Oia4n6omkhubiQqwl59vqfKWMWMnCabxkPRc4QFxNB7UMJ3BnUsVKDlYtEyBFkXyYbsJOQ4yaDH6T6JocbXP/+/UWsUNzAcHNCPFf1TQrtEyDMAAAgAElEQVQ3HMSKhX98JN3c8FsJJOT33XefMueIp4oHBA66qUNX4YalxsQNemoZo51kPGvZ15T544eUPOAdKlC6kmVhD6E34gOrY+9qwSLaMpLUBqsfiZxbQca16rFkyRJq3769KD5p0iS67bbbtFaNWM4tpJwJecSpNK0A4mIjJjikR48eNHv2bPF55MiR9MILLyj94LeLeYERBAeFpSBMHn5rINEy9CC+++abb0TCIYj6zdLgwYOVeOD9+vUTa1yKjA3+1VdfKXHF8R1CEyJUIDYIINtS8Fu58MILxX0FhF3Ks88+q8Q179q1K8EdEgKXR5nkCOdZZHx0fCfjq//1118inroUPJdBWvGchpuZlLFjx4o32hBsYhCqEILzGsAUgs30iBEjlDoyvjrOhqgNSaHiq8+cOVPEJIeo46LfcsstNGXKFHFdprYPxDBUXHRsgGQYStQJFRcdLsB6vBQUJV34QRch16KfXS4rdpBx6BtIzkCUZbaqSHjghqL+keOHh516KNIKso+4mzIQP9rHjwWEF/9L33Rcx48ZyQV+/vlnESEBAfORRKF3797ix60OoD9t2jT64osvxHBLly4t6iH4P/xHcYPC4S38MJC44Pbbb1fUQiYtjCXQ8oudLW5gaFcKoj0g4UEw3WDFhtUfbwvwY0bkBpxDULu6qLHEDxNJIEBw9+7dK6wl0A2JCBCtQS2hMFbrjJszNhFo97XXXhPjAD4YB+Y3UD8tc44bMzYv8A+WIs8IaMUb9WDlga7ffvutaAsWC6wRWFyuu+46uvHGG/Pc4JEsAXMuBTdZ9XpEfWwIQXggsNogJq+0/uBh8uGHH+ZburjhTp06VbmO0KaNj/9JWau+s+UAZyAZx0CsOtQZ6Xdr9vfhCLm6r0Byjoc7rNeIpmKGm4oevXB/ueyyy8R9BlZEWC7VSVb0tBWqrBtIORNyM2ZaWxt+spCDUOMANSRUBlKjFnK8vca9AxKYgVTG9I7GQm5V5tBwFnI8r0H8YRRAnHSviisJuV1kHJOuhZyFWhx6D3ViN4xdcTBRWww+++wzsTAl6Qosj8OWIHgyLS78PxE/HoJrgwYNoldffVWpBp9xpMrFw/+HH35Qrr///vt09913Bx0PfsiwmmPMeHDDrQZvDgJ1fu+998TOWWYak42BmOOVudodB1aJe+65h7DjDyXYpYM8SgmFMQ6jSZ9XkFKQXkS5wYZRLfihoz3gK0XrnGNT8/LLLyv1YP2A645WvLG5Q1Y39evYQL2xWcCmQ1oSsEnBq1ngD8GmAq9nZRY0+AODvEmBjz8yn/3vf/9TrgXbVKqtNyCG2AglfvIoJfV9jgoUzU10YZUEI+PoyypCDn9uvKZFimb5mtkq3dCuVkKuHgM2e7C0wepmNxnH7wGbelga8UoaKc21GiH04uh0Us6EXO+McnlGwHwEtJxfNL9X+1vURciPHTumpJDFYZ9gYrWF3E4yTuey6dERI/O8LtFjIddLyEHOEIpMnZ0Kr8VgMQXRg3UU5A0+cZKQ4WGP10Z4eMIaLwknXmFJYqtOB4zX9CBcICVSQMhhhcecyuuwpGNXDZ93PRKoMwgP2oSVG+tHvgpEm9gRgxhJ1wG5A5b94XtEc0EaZeAiBW8a7rjjDvFnKIzVOuOhCgyBEfTC/zKlMdrApmLdunXKOLQSchy8hcVdCjYzILZa8AbZgoVE7beI1414EwACrXaHwWtZWPfl61ZYuKX+6Pupp54S0TDw2hSRMqRuiIqB6BjwdVRHgwl8BQg8sI7w5gOCjcvHH39MOenHqUDh4L9zPWsiXNlQZDyQkB9Iy6SiJ5Op7IeLzera0e1g44yNNV63Gz3AqUdRbNyxoYTAijZ9+vSQEbX0tBuuLEg5fufy9bpZ7ZrVjvqeZVab3E5eBHB/x/MPLiJ2BzHguXA+AkzIg8yRFlCsJOR2kvHsbasp58BWGjXzd9sIOSCHOwJ8v6QE+pCDiEmXA5BlEEmE34PAGgrrNwSWX7hQgGgFklY84OGXB/cWuEzACovXhbCGSYFlDgRPrwT2BfIPiz4s4bDu4sAorK9SEEpT+uTD0o7wa3L82HzAMozNByz4II4QuHJIFxytmx6MA+QUvoTwdwfG2HBIkaHp8LcWQg4dQKjlYT1gio0UxqkFb7gn4e2BFMRmRkhRtAN3mKuvvlqJA40ygeugT58+AlcI1sFvv/0mInjIQ1FIfYyHHDZCEJArHMaBqP0X8TfIN+pKkRsLvXOvt3w4Mo62rLKQa7mP6dUlXHk9FnKsH7gLYROGOX7sscfopptuMnM4IduaO3euWHcQuKThfiLfvFg5gE8//VS8joYLnV1+/Vr1YQu5VqSMlbP7N2lstFzbbgT8sj50Wci1gGIVIbebjGdMHUnJt79MI8ZMzkPIceBSntgOtii7dOki/LMhWsmi9D1GnUiEHH7d0nqKqC14iEqBWwh8hBHSDALijgdr4DhAvuAvrhaQVBxMlAJfbUn49Pz4AvuCr7jarQOHXJ544gmlSVi/ZchAkHOQbljUsY7UoQRx2Eda0OAXh42IHowDrcLhxhFIyHH4B0QJAozxRgGHOmHxlwLLuHT3iYQ3LG7YaBw6dEhUL1u2LOEwjfqgDmLfq/WHXzgIkhT0jQ2BfJsCi7t8O4LPwPWSSy5RysOHXh78wUX4AWItQ7AxkxscEHlsTqwmRpHIOMblF0IuSfi1114rNtBSYDnGRsouUo7NKtxTcH4B0R3Uh9P03AP0lHUyGYceTMj1zGb0ZbVwi+hb55puRwDPTHkQ3843hnbj5gpCHgsyntTnKSpYu7XusIf/+c9/lMOOZhNyWLNBuKXgsGJguDJYSuUrVoRWg0tF4Djw0O3WrVuetQaSqY4eA4s2rLJ6JbAvHBhVJxCC3zgs3FJwaBRERApOkKMMLL0YEzYXcKX49ddflfTeaguvVowDx4F+5alx9K0eh96wh7BCw/oMdxNIJLxBvkF8pUjXEjXWINcg6JJkB3tjAZ1A2gP94qULi7o9bHIqVqwo3ohA5EYJ+GJDIF2gYJ3FZsVK0ULGrSTkWGNwFYLeel2yosElmIU8FAkPbN9OUo5NJTbF2PxJo0I0+mqt43QyzoRc60waL4eQgDhrhPMS6sgixlvmFhgB9yCgi5DDOgjXBpBCdRSPQCKBB56aJMgdDXY4R44cERY4lAn0zSuUdoAazhmnxB5O31eQSg57zvLQhnL8cFPJmDqCkvo8Lcg4RC85s5KQIzoIYpFqFURM+eijj/IRRBk+Sd0OCJn6gBusZOr4pFr7DCSjapcUtKEObRVIhOEig9f0IKzhJBpCrmccWucc6xquL7Bcq98uBGIQiDdcSXBoT8q9995LY8aMyacy/N3xe4HgAKI6pr0sHBiuCyQT7jTBrJs4MCsPdyJyBn6HajcF6AO3IukCpXXO9ZTTSsatJOR6xmtGWUnItZLwwD7tJOVm6KulDTeQcejBFnIts8llGAFrEQA/waYNmzWElvaq6CLkWkAw22WlcO3ilsYZlzoFI+PBCDkOFMpQQsHwgCtCzZo1xVdarbdaXVYCrdggaTJua7CxIDICSLnW2OCw8MrYqLAcIlyhOtZqYB+IXIJQaLB4w0c7nM6ybihCjo0ecJURR/AgRJhDRBHBDxBhFWWc72gIuRpjjCXcxiCYy4raog1s4DoEdwJpFVdjEwlvWP/VawjnArCuAgUbX2nRxkZMnSQCZTFXcFuRZWR9kG55lkDdJg6LqqNlwKoP1yVgC8GBUMT2tUr0kHGMwSqXFdyjcIPHurLDLeOTTz4huLKpY+7qxdgOUg6SDKMJ1qYMyaZ3nFrKu4WMQxcm5FpmlMswAtYi4BeXJl2EHK4D8PHFK/pQh33MJuQlnxtHBSvWs3S2Q5HxYITcyigr6C+cDzmwBfHF2wUIrMl4uEWSSARR1geJU/spw6KqPnio7ge+y3CXgcsDiCPC7SHMYKS+QhFh+F8j7KKUwMyA2OTImN92E3I9c47xR8IAhzbxG5JviOB2Ap9vtQQmTYB/LyJuSMHbKljn4aIUKCCaGHOwV7/qpFPw5UcUDRlqExusAQMGRFpOUX2vl4xbScjdenO3kpSrE5o88MADIm+AFeImMs6E3IoVELxNGGJk9Ci41rEwAmoE3HrP1juLugi5FlDMJuRlJp5PgqJXOS3lw5FxJxByECYkh5ECVxKZSRMuDXDvQOIXSHp6uiDQuA5rHMJHwcIdiSDKtgNdYmA9RDQWEDe1JRGWc/iYq2Omy5jlkfoKRcgxbrhuSIFVUUaXgK+0+oAidJJuLdG8hUAfeizkZhNy9A+XFRnKEdjiUK1M44zvEXFFnQgKmdawSZHy9NNPi3CHkjQgggzwQ5IoCMIc/v777/k2zurDnXChkDhio4e6Mna9lt+O1jLRkHEm5MHRRbIQREUy+6CnHYQc9zK8kXFiNJVQa5kt5Fp/5cbKaeEWxnrg2m5GwC/rw9eEXJLxxD5PU/y/PuOBi1ZLCLxQCz0asgg3AnUGS8TnRWZNWEQRp1od2hD9IkLGm2++KazmiEUt09jiO7gfwA0hEklWjx/h+BDvXC1wy4BlFUQYaXlhqZUxq1EOr7dBWkEsI/UViggHpihG3HXEUYebCvyk1fG68XYGRDJYSEfpmhLtOKCPkTlH/Uh9o8zEiRPzWKOx0QJZBsbw68Y8qLNt4u2ADEsJoo0Niky2hCQuqItIKVgPUnAwb/To0XnmEu4tiDkf6OaiToFs5o1bkPGFH+Zm+yxdSVfTVrmsuP3mbgUpx9sahBwFMccbKNxrzBQ3knG52eU45GauhOBtuf03aT1C/u4Bz0JEl4OrqB0H8WOFtm8J+Xky/hTF184N/xZMjJCzaAg5DvHBuh0YOQPuIbCMg4TB+hnsgJ96/CCxMl65FoIo64LYoy4s1FoEZBwEXaazjdRXKEKOeN44GAlf8mACtw514hBYdOF7DQKrthy7hZCD+CDKC7JwhhOEH0SccBwWhoBIw7qOtxQQvN5FCEgZihP+/IhSA0FdkKzAcwaBrkkoK7OMaplzrWXOk/G3qUDpylqrKeWsIuRwu0NYSbj8yDjtugcX4wpWkHKrVHIrGQcebCG3alXkbZcJuT04cy/ORkAXIQdZkln/Qr3adoPLilYyjqmzm5CjT7yODrRsSkKO7+Fa0L9/fxEzOFBwyBKuCyDG0s0kEkkObAMWIWT9RMZJuFIEE4RchL8xwuSpQzFG6iucqwge3LD2qrOIom9sEODSAj9qECkpsOriYKsbCTl0wFsGuAQh1Je0hquxht883lbIZC34Tp0YCn+DfCPDnRQkO8KhPPipQ+CWgsOgauK5YsUKat06N4oQBOEucUDUzNjjRsk4xmUVIXf2LVn76NxAyt1MxjETTMi1r0ejJWWcaaPtcH3vIYC1gfNqcM818znlNKR0EXItg3c6Ic/etoYypj5GiX3CW8alrrBEqkkpYmqrwwOGwwQHHxGqRwrcMOBuEeq6ui24m8DHGA8EuIyAkKt9jFEWllH4V8OqjjCUiASCaA7qjJsop6W/YHqAmMMqjyQycBkBAYC7AwgccJC+6+q6kfpCQhtYQ6SAGMLnXQoO98Bai/+BM6y7IN0QWO+//fZbkWETFuF27doJfKLBONw4jMx5NHgfPnxY6IzQjDgHADxgBUfs8cDwojj8KQ/1Ik65OnmQxBBvT9RZSOECpSbkgdFWzI49nrX8a8pcADeV6CzjUg8m5JHvuE4m5W4n40zII68/LsEI2IGAX96g6CbkIGnhMiU5mZALMj7tMUq8URsZt2OhcR+MgJ0IwOUJFvd58+aJbrGpwgZEuhwZHYtZZBzjsIqQ4+bevn17Qtx79XkNo7rHqj5IOc544G2LPAgdq7HIfr1AxpmQ27eK8FYUeS9kmFv7euae3IAAE/Igs6QFFKcScibjbvjZ8RitQgCxxuHGAjcnZD2Vgux4gYd4ox2DmWTcakKOtw84HIuIJV4QJ5Hyzz77TLi8uSmaSqg1wC4r9vw6tHALe0bCvTgRAb+sD10Wci2gOJGQMxl34k+Mx2QnAnA1UruxoG9E0sBvWh4INTKeXDI+8d9oKvoPcAbr20oLudcIOfBzAin3EhlnC7mRO4K+ulq4hb4WubSXEIBbLgIUdO3alXB+zavieUJuJxnPOXua6NRRKlCiPFFcQUvXTE5mBtGJQ1SgRDmiggmW9kXZWZRzbD8VKFaGKCHJ2r7OnaOcY/uoQOHiRMkWp8jNycntC/0UKmatXkS5GAK/IiWs7+vEIaICcVQgJffmFUjI4ZuPEJq1a9c2PBYryLiVFnK46Mg47jKrrmEQHNJALEm518g4E3L7FjUTcvuw5p6ci4AuQo7Yz2PGjKEhQ4aI6A3BxEkWcjvJ+Ln9Wyjjwwcooft9FN+sq6UzDmJ3ZvwQSmh3A8VfdD5pkBWd5qQfp4wJ/6W4um0psds9VnShtJlz9gxlTH6E4kqUp8TrHxOE0jI5l0UZnz5FlHmGkvq+SBRv4aYmJ4cyvn6dcnb/RUl3vEEFkqzdaGT+OImyVs+j5IFjqEDRXEKOA6M4mIvfJw7/mpUNzyoybiUht2xNOaRhScpxWBfZfO0QL5JxJuR2rJzcPnBQHaFvEfLXy3Gm7UOUe3IjAroIuRYFnULImYxrma3wZZiMG8eQHEDGTdAiaBNWknEm5MZmzU5SDjKOnAdIaOW1kGTsQ25sHXJtRsAMBJAwEVHqEGVMHbLXjLad1IYnCTmTceNLzLtkPJsyPn3SN5Zx4ysheAtWk3ErCTneFrz66qs0bNiwfKFErcIrFu3aQcq9TMbZQm7fqoUhDyFfkfBN5s+wr3fuyekI+MWlSRchRxpzmbQGWRWDSawt5EzGjf+0csn4UIqr28Zjbio+IOMD3qECKefjuhtfDflbsIOMW0nI/XJzB4ZWknKvk3Em5FbcPYK36affpH2oeqcnv6wPXYRcCyixJOQg42enjaCEG5+k+NoXWLoave0zzmTc0OKJlZuKh8g4E3JDKzBPZStIuR/IOBNy89ZgpJa0cItIbfD33kUAyRlHjBhBL7zwgimBCJyKlGcIOZNx40vM25ZxHOA8bdMBzjcoZ/dGew5wLppMWau+o2SPkfHsDb/Q0VdGUOHUbLGwC5SrQWlrdlCZiT8bXuh+fPibScr9QsaZkBv+qWluwI+/Sc3gcEHfIKCLkK9YsULEgUQ8yFatWgUFCRbyjIwMOnfunPK9zOyJa4gnuWXLFsrMzCRk/VRLobQD1HDOOOUhnL6voKYHsL1kfCtlfDiUEroPofhml1m6UOyPpuJVyziTcaML1S43FYwTZDzjy5co/Z/jlhByo1i4tb4ZpNxPZJwJuX0r/ejRo/TTTz9Rx44daf/+/SKJGSQ5OZmaNWsmPiNKFLiDFGTZBbc4ffo0rVmzRrmO8qgHfrF06VLlOkKcli1bVvy9evVq4c4FKVasGDVo0EB8Rq4GRJOTIhOHIZPounXrlOstWrQQ0WDAd5YvX65cR26HkiVLir/Rt+Q4ZcqUoVq1aonr27dvp3379uXrAzpv3LhRuQ6OFR8fb1o74Fx//PGH0n7Dhg0pJSVF/I0NkRRE4JJR9DZt2iQ4GwRjkbzv8OHDBKu1FGQKxoFucL9Vq1Yp15F5FecCAueiWrVqlJqaKsoBV+ALKVKkCDVu3Fh8xjrAeR8pcr6VCx78oIuQa9HfbkIuyPjUEZTQxw43FSbjWtZAuDL2hjaEzziTcaNzFgsynnTbK3T0ibuYkBudvID6kpQ//vjjdOON+kKm+o2MAzqOsmLyAtTQnIymgaIgsZL4jR8/nu68806lBazlpKQkQWIlocaXGzZsoPr16wtyCGIuZdy4cTRw4EDxJ/IvIB8BBDkZFi5cKD4///zzhHChUsBnQDSlBV9eB2mvXLkynTx5UhB6KV9++SX17NlT/InDqdIweeutt9LkyZPFdYSNfvfdd5U6krTPmzePrrjiCuU6SC+S4CQkJFBWVpa4rqWd77//nrp165avHYSVLF++vHJ90aJFYgOE/tXRkYYPH06jR48W5Xr16kWzZs0SnzEWjAnyySef0M0336y0lZaWJoj31q1bSZ3bAeQcGySMH3pIeeONN2jo0KHiT0RNgbEXgo2O3DQgg7Qsg++wocCmwMviakLOZNz40mQ3FeMY5oY2ZDcVo0hKyzjIeMHK9cmqTJ2wRMF6BYtL8eLFjQ7bdfWjIeV+JOOYWCbk9i9vEGwjFvKmTZtSoUKF8llla9SoIeKcQ6yykCPYhcwkGcpCDqsvrL9SpBXebgs5NjFyM6G2kFeoUEHkqoDE0kKOtwh4myCFLeQBv0Xsjn744Qe67LLLqHTp4JEc7LKQMxk3fqNkMm4cQybjJmCoclORZBytWkXI2V/1fPQVLZZyv5JxJuTm/La5FUaAEdCGgC4LuZYHmdmEXJsaXIoRYAS8iAAf6rRuVrVYyv1MxpmQW7f2uGVGgBHIj4AlhBxpcEHMpQQe6oSfEcpEOtTJE8YIMAKMgCBGHGXFkoUQjpT7nYwzIbdkyXGjjAAjEAIBJuS8NBgBRsDxCJhJyHHA6MSJE8J/0uuHhLRMbDBSzmQ8Fzn2IdeygrgMI8AImIGALkKOE8MIMYQDE+pTueqBmJkYyAwFuQ1GgBFwPwJmEnL3o2G+BpKUP/nkk+LN5cSJE2nu3Lkh7/Pmj8CZLTIhd+a88KgYAS8ioIuQawGACbkWlLgMI8AI6EHATEKO8FnHjh2jEiVK5AnFpWc8XiwLUo6ID4hDzGScLeR2r3G8tULIQghieSOmN2TXrl20e/duZTgyKglCDq5fv1653rJlSyVEoAyjhy/r1asnfusQdTQRhACsXr26uI745ohzLkX2gfjof//9t3IdIfoQzhAutytXrlSuN2rUiIoWLZqvD4RGrFSpkriuN3oMfo+IBiPFiugxCFf4559/Kn2Eiq+ujh6zbNkyJZyjkfjqgXHRtUR9sXtN2t2fLkKOuJ579+4lhMVB/M9gYoSQF8w+S80/f8VuDLg/ByLw55FTVLVoMhVL9HbcUQdC7+ghcaZOa6cHJADxgkE6WNhlxc41gLjYiAkO6dGjB82ePVt8HjlypEiZLgVv6vHmYvHixdShQwflOsLkgWSDRMvQg/jym2++oe7du4ty8jwbPg8ePFiJB96vXz+aNGmS0pY83/bVV18pccXxJUITwtUNGwSQbSlLliyhCy+8UBBV9W/n2WefVeKaI6niggULRBWEYJRJjiZMmKDER8d3Mr76X3/9JeKpS8HmA6QVmwE1/xo7dizdddddohg2MQhVCEGMcWAKefHFF0XqeSkyvjpCM8rNB74LFV995syZIiY5RB0X/ZZbbqEpU6aI6/fffz+98847+TAMFRcdGyAZhhKVQsVFf+SRR+ill15S2vXyB12EXGuUlWgPdXoZaNZNOwK4qQ0bNkzcfNSJILS3wCXdhAAekviHh2ioDMBm6qPlPmZmf9yWexFglxX75s5PFnIQ6ubNmwtwQ2UgNWohRxZOZOOEBGYglTG9o7GQm5WBVI+FHC7S2HgMGjQoz0bIvtVpT09MyO3BmXvRgcB3331Hb775pvBfffvtt0VWNRbvIsCE3Ltz63bNmJC7fQZ5/F5AwC9GFCbkXlitHtIBrxuR3hg7dwhSJ4OU8yt0D01ygCp2E3JY4pCeGT6n6rTX3kWYNYsWASbk0SKnr97y5cupS5cuwqUDftosjIAaASbkQdYDSBIOOMBPqUiRIkFXjBEfcl6CjMDLL79MCxcuzAPE3XffncePj1HyFgJ2E3JvocfaWIkAE3Ir0T3ftl8Ilz1oeq8Xv6wPXRZyLdPMhFwLSlwmGAKrVq2iRx99NN9X8Lf74IMPxIEdFu8hEAtCjkNb6gNe3kOVNTIDASbkZqAYuQ2/EK7ISHCJUAj44Z6ti5ADEBBuuA+EepgxIecfVDQI4CAwDmwgik8wueCCC+iZZ55hEhUNuA6vYzch54e/wxeEg4bHhNyeyUBkEEQBQTQQPjNkD+bci/MQ0EXItTzIIhFyxP/dtm2bCN3DwghIBCZPnkz4F05GjRpFnTp1YtBcioAk3sE28zjAizi+8Ou2WrTcx6weA7fvDgSYkLtjnniU3kYAMefXrFlDiMWO6DFeFVsJubSwg4zLOJ9eBZb10o4AYroiFirCIIWT1NRU+vXXX5UEDNp74JJOQADxa5OTk0X0nGCkHNdQxmphQm41wt5pnwm5d+aSNXEvAn65Z9tOyN27JHjkViCAjVmfPn3o22+/1dT8Qw89RE899ZSmslzIWQiAbCcmJsbc7WjHjh0igcV9991HVatWdRZIPBpHIcCE3J7p4N+kPTi7tRcm5EFmDv69U6dOJWRngrUymIRzWXHrYuBxW4fA/PnzdUdQQWICmfDAupFxy2YjEB8f7whCbrZe3J53EWBCbs/c+oVw2YOm93rxy/rQZSHXMs1MyLWgxGWAQFZWlsjIefjw4XyAIG0wUgU3atRIhNlUC/6GPzlHyXDXOmJC7q754tHmplpn90rrV4JfCJf1SHqzB7izgieULl3aFrfGWKHIhDxWyHO/YRGYPn06DRgwgCZMmCBcWljcj4BTCDkiOowcOZJeeOEFjujg/mVlqQZMyC2FV2mcCbk9OHMvzkZAFyGHxVKSpFAuA2whd/aEu2V0TMjdMlPax+kUQs4Pf+1z5veSTMjtWwF+iDNtH5re6gm8EpFWEGHFy1m7dRFyLQ8yScjPnTvnrRXB2tiKABNyW+G2pTMc6sS/WLsaabmP2QIId+J4BJiQO36KeIA+QMAv92zTCTmIOPx92O/OB78SC1WcMWMG3XbbbTRlyhTq3bu3hT1x03YhAMsGrOSxJuTLly+nSy+9lBYtWkStWrWyS33ux4UIMCG3Z9JOnDhBK1eupBYtWlCxYsXs6ZR7cQ0CTDzhyLEAACAASURBVMiDTNXatWvp5ptvpmnTplGTJk1cM5k8UPchsHDhQurSpQv9+OOPnAzIfdPHI2YEPIEAE3J7ptEvhMseNL3Xi1/Why4LufemmTVyKgKwXkorZseOHZ06TB4XI8AIeBgBJuT2TK5fCJc9aHqvF2R4/+WXX+jiiy+mEiVKeE/BfzViQu7ZqXW3YkzI3T1/Th49wmctWLCAunbtSqVKlXLyUHlsMUaACbk9E8CE3B6cuRdnI6CLkO/fv59mzpxJ1113HZUvX97ZmvHoXI0AE3JXT5+jB88Pf0dPj6MGx4TcnunAuTNYQWH9xMFvFkbAjwjoIuT8IPPjEomNzkzIY4O7H3rl+5gfZtkcHZmQm4Mjt8IIGEHAL/dsJuRGVgnXtQwBJuSWQev7hv1yc/f9RJsAABNyE0DU0ASyNiPSCiKsIBITCyOgRsAv92wm5LzuHYkAE3JHTosnBoXQrKdPn6ZChQpRXFycJ3RiJaxBgAm5NbgGtuoXwmUPmt7rxS/rQxchR2xx7GSdEEvYe0uONVIjwISc1wMjwAjEGgEm5PbMgF8Ilz1oeq+XrVu30gsvvEAjR46k6tWre0/BfzXSRcg9iwIr5jgEmJA7bko8M6CMjAzCAfXU1FRKTEz0jF6siPkIMCE3H9NgLTIhtwdn7sXZCOgi5HjNu2XLFqpZs6Z43cvCCFiFABNyq5Dldvnhz2tAKwJMyLUiZazc8ePHCb/Ltm3b0t69ewl/Q5KTk6lZs2bi88GDBwX/kNKmTRuR9Re8ZM2aNcp1lEc9vNFfunSpch28pWzZsuLv1atX05kzZ8Rn+K03aNBAfN6zZw/t3LlTqYPxQE6dOkXr1q1TriOjKDbz2dnZhMy/UurWrUslS5YUf6JvmbG8TJkyVKtWLXF9+/bttG/fvnx9QOeNGzcq15FFGN4IZrWDSDZ//PGH0n7Dhg0pJSVF/A3spVSsWJGqVKki/ty0aRMdOXJEfMZYZGZjhI79559/lDoXXHCBcP+DsWPVqlXKdSSQLFy4cL65qFatmjCIQIAr8IUUKVKEGjduLD7DaLJt2zalLTnfygUPftBFyPlB5sEV4FCVmJA7dGI8MCy+j3lgEm1SgQm5TUCruuncubPI0AwBiZXEb/z48XTnnXcqJUGok5KSBImVhBpfbtiwgerXry/IIYi5lHHjxtHAgQPFn7Vr16bNmzeLz0hAh8zQkOeff55GjRql1AHhBtGU9wz5BUh75cqV6eTJk4LQS/nyyy+pZ8+e4s+CBQsSzqtAbr31Vpo8ebL4PGTIEHr33XeVOpK0z5s3j6644grlOkgv8iQgDCRchbW28/3331O3bt3ytXPgwIE84arxjEXSPfSvPkszfPhwGj16tKjfq1cvmjVrlviMsWBMkE8++URkbZeSlpYmiDdcS7DxkQJyjg0Sxq8OZ/nGG2/Q0KFDRbHWrVvTihUrxGdsdOSm4a233lLK4DtsKLx+4JcJubJ0+IOTEGBC7qTZ8NZYmJB7az6t1IYJuZXoBm8bBNuIhbxp06biDX6ghbxGjRpUrlw50alVFvI6deooycZCWbZh9YX1V4q0wtttIccmRm4m1BbyChUqUNWqVcXwYmkhx1sEvE2QwhbygN8LP8jsvzn5tUcm5H6deev1hjUHD31Y0fCKlIURCIUAE3JeG4wAI2AXAros5HhFtGPHDrF7Ur8Ksmuw3I9/EGBC7p+5Zk0ZAaciwITcqTPD42IEvIeALkLuPfVZI6ciwITcqTPj/nHhVTZ8O+E3CcLFwgiwhZzXACPACMQaAV2EHA+xs2fPitPFnFAj1lPn7f6ZkHt7fmOpHbvexRJ9d/XNFnJ3zRePlhFwMwK6CDk/yNw81c4ce79+/ejPP//MNziEn0L4q0qVKinhkWSh7t2707PPPutMhXhUjkeA72OOnyLHDJAJuWOmggfCCHgeASbknp9iZyu4a9cuJeaplpEi7BHiosr4qVrqcBlGQI0AE3JeD1oRYEKuFSkuxwgwAkYRYEJuFEGubxiBZ555hp588klN7Xz88cfUt29fTWW5ECMQDAG8eUFM4Ntuu40Q4ouFEQiFABNyXhuMACNgFwK6CDkyZc2ZM4d69OhByDzFwgiYgQCSBsA1BYkLwgniyyLRAB/EMwN1boMRYAQiIcCEPBJC/D0jwAiYhYAuQm5Wp9wOIxCIANIPI/1uOEGSAJmwgBFkBBgBRsBqBJiQW40wt88IMAISASbkvBYcgwBcUaZNmxZ0PEhnzAc5HTNVrh7I+vXradCgQTR27Fhq2LChq3XhwVuLABNya/Hl1hkBRuA8AroIOdwFevbsSbNmzaLmzZszjoyAqQikp6dTyZIlRWhNtcA9Cn6/ONDJwggYRYAPdRpF0D/1mZD7Z65ZU0Yg1gjoIuT8IIv1dHm/f2z2evXqlUfR33//ndq2bet95VlDWxDg+5gtMHuiEybknphGVoIRcAUCTMhdMU3+GSSyKLZr145AmiC9e/emGTNm+AcA1tRyBNasWUN9+vSh6dOnEw4KszACoRBgQs5rgxFgBOxCQBch37hxI91///30zjvvUL169awZY3amNe1yq65BYMvfG6lWw6ZUsGBB2rttM5WtUNE1Y+eBWohAwQQLG+emGYH8CDAh51XBCDACdiGgi5BbPaics2fo8N2XW90Nt+8CBO5YuJ5KJyfSK+1ru2C0PES7ECgz8We7uuJ+GAERYhVv7VgYAUaAEbAaAUcS8sKp2Vbrze07HIG9J89S4cQ4Kp7EBzkdPlW2DS99X0Eyg5Dv37+fvvzyS7ruuuuoXLlyto2fO3IfAkzI3TdnPGJGwK0I6CLku3fvpgkTJtCAAQNEIhezRVrImZCbjSy3xwi4HwGzCDkf6nT/WrBLAybkdiHN/TACjIAuQm71g4wJOS9IRoARCIUAE3JeG3YjwITcbsS19XfmzBnasWOHUrhu3braKsagVLixukkPPdDZrZfd/enBQk9ZJuR60OKyjAAjEDMEmJDHDHrfduxkQp6WlkZLly6lnTt30j///ENZWVkikzHeXiNSFfI3eFUQChc6SoHuCAJglRw5coSQh0WrFClSRAnVG26sduuhdfzqciC7iEy1YsUK2rNnD2VmZlKdOnWoevXqIrt2sWLF8jVrt1529xcNjlrqMCHXghKXYQQYgZgjYBYhxyE9PFQSEhLEoT0WRiAUAk4k5CBI9913H40fPz7sxLVv354WLlxISUlJnpvgSAQsOzub3nvvPaH3wIEDqVChQoYw+Pbbb+nKK6/U3AYs9n/99ZcoHy0hN1sHzYP/tyA2OU8++SS98MILYavecMMN9OGHHxI2IVIizY/esUQqb3d/kcYT7fe6CDk6OXfuHMXFxUXbX9h67LJiCazcKCPgCQTMIuSeAIOVsAUBpxFyPH+bNGlC69ev16R/48aNafXq1ZY9szUNwoJC2FAfOnRIablChQp5eoE1t3Xr1uIaDnEbPbxthJCHG2s4Imm2DnqmISMjg1q2bKl5nQH/devWiUzbkTYhesahtWyk9aC1nViX003IjQ4Yuz68asONJVByju2n7GfuJD7UaRRlrs8IeA8Bswj56dOnaevWrVSjRg3DljPvocwaqRFwGiGHi4o6a/GoUaNoxIgRyjqGa8Udd9xBX331laIGiB3IlZ/ktttuoylTplhGyBGlqVq1aiEhhUW+fv36ESEPR8jN1iHiYFQFrrnmGvr666+VK4ULF6axY8eKTU6JEiWEmxTW3vfff6+UadWqFS1fvjwmhFyPbk4uq4uQnzp1iv7880/Crrto0aJR6XXy5EnasGEDYQcWGN816eQBqvXF20zIo0KWKzEC3kbALEJu9eF0b8+Cv7RzGiH/3//+R/fcc48yCTBwBb6xhrUQBArP6I4dO9LgwYPp8svz5vdAGVh9P//8c0LCP7i1XHjhhdS/f39q2LBh0EmGEW3BggX02WefCR4A0tmmTRvq2bOn2CSo3b9glZdkDb7saFctBw4coEmTJimXhg0bptTftm2bkp05NTWVbr31VrHBQEJC6Prdd98R6kvCjUZkfRBluIo89thjStvYoIAcd+jQQfjaww8aUqpUKRExLlDw/dSpU5XLQ4YMoUWLFuVxWYFRERhrkX379gUdK+oGI+SzZ88Oq4N6Q6Z3HrVgC2NF7drn838gm/Gvv/4alPO9++67BHykYN5RPphe4I9wI5o3b55YO127dqW77747j6uLGs9jx47RJ598IrJ2441QlSpVhM/6LbfcQpUrV84DfTiM1TqXL1+esNFB22+//bYYC9Y+fh/QI1peq2UdaCmji5Cb8SA7ceKEOBwBP7hAKZR2gBp8/QETci0zx2UYAZ8hwITcZxPuAHWdRsgnTpyYh0QePHgw6OHNcK6lsG7CqIZncTABSQJxUhPsw4cPC1eZvXv3Bq2D9mAdlf7qY8aMEX7uELU/tayMsiBXUkAs4+Nzc06A9IOsQeAK8cEHH1CPHj2UsvBtXrZsWdBDnd27dxeEPZg8++yzVKtWLbr55puVr4MR64cffpheffVVUQabCZB/tKn2IddDyPX6kF999dVhdYBlGhLNPGrBduTIkfTSSy8pGMEVJdQmDYWuuuoquuSSSwjjxsYH8xioMzZwsK4H8j5sarABCHQpwoYIxDuUjB49moYPH658HQ7jH3/8kTp37izKgpDjLRMOpZ49ezZP88nJyQTyjjKxkpgS8kALOQh5wznjmJDHajVwv4yAgxFgQu7gyfHo0JxGyANdVuA+MG3aNEGItFj3YFGvWLGiIJkQEGkc2oM/Noi4JCmwPktChOd0vXr1aNOmTaIOCBcOSiKqCSykUmC5XbJkiSDyRgg5rLEXX3yx0lfp0qWFH7iUcIT8xRdfpDlz5tBvv/2mlAfxR+QZWNpB2NWW7blz5+Yh2tAVOKanp4v62JjgjUSgD7mVhPzll18OqwMSmkUzj9AnErbYGMH6LPEGcf377791/7oDCTJILtqEm+D27dvzuCyD0GPOpGzZskVsnKTg+zvvvFNYy6dPn65cx5sQGe4yHCFX64w3LHA1wiYAuuF/rCcp2HRhTcRKmJDHCnnulxFgBHQhYBYhlzFrESIOVhEWRiAUAk4j5CCMktQEjhlWxn79+gmCCX/eYARdbWHH9/A5R7QhCFxJpSUUvwuQThAYuIvALUUKXFxA0CFwUWjevHm+74wQ8kByhTHA/QVRY0AYEWYvHAE7fvy48HOWEnioExhJdxm4sfz0009KWRC0mjVrKn/jzQBcW+wk5NjoRNIhmnmEUpGwxZpQh4/ExmvcuHG6bxCB/eBNAyztWKPY9GHzpg4jqX5DAss3NiUQ9TrE35gbzBEEZfA2I5he6jCYwcYCF5iyZcuK9YSxrFy5UtFRPRbdihusoIuQA0i8IoMiiYmJUXWtdllhC3lUELqi0vqD6bR0z0llrDc1KkvJ8XEU6rorlOJBxhQBswh5TJXgzl2FgNMIOcDDoWRYetVEMhioV1xxhSCeancAuJ3AfQCCkHZPPfVUnqqwRoOkQ2ARhy8xfMvhrgqB5Xrx4sV56oAUpaSkiAgbXbp0EaTeTEIOv/lBgwbl6dMIIceGokGDBkp78G2WIfvgqiJJHvSGxR8SSMhvv/12gn97KMEGBvX1kkVJJCMR8mjmMdhYArEFGVVzu9dff50eeOAB3b/ZwPmBBRyWbilYQ9gMSTl69KiyiQIGGAf4JjiienOFsbz55puiGtyY4G+vF+PAtyLhxqJbcYMVdBFyg32J6kzIzUDRnjZ+3HacftlxXHNnRRML0gMXVhLlX1+ymx5ftF2pu2lIK6qYkhTyuuZOuKBvETCLkMO/Vj54OA65b5eTJsWdSMjlwJGpEocY4WMdKgwirMtwTwHRBrlRHwCFW8Bll12WBwe0JSOgwTKOaBuwmMprOFipPsQXCkQzCXkwP3kjhBw4wIVF+sOrySJcK6Q7z/z588UGA6I37KEaJ70+5JEs5NHOYzDiGogtyLB8Y4Ly2LBh46ZXAnXGBkOdQAgHZzEHUjAXgRscrG+4r+Af3tYgEAhcqZCkCKJ+u6EH48CxoG+4cYUbi179oy2vi5DLkIXYTUaTFQsLCYQcr7nw2pgt5NFOmz31Hv9xO73++27NnZUulEA7huYe1ImWkO85eZZGLNwm2nioXSVqUu58sgHNA+GCnkTALEJuxuF0TwLMSuVDwMmEXD1YWBPhm4uoETiUpz6weemll4oEQXjm6kmQA1cF+F2r3bpmzJhBvXv3jrhSzCTkGHdgciMjhByDhz+yPNwprf4g4vJAHzYu6FeSUycR8mjmEa4nwQh5MGzVRoprr72WZs2aFXG+AwsEzk+gGwiinMiY5airJuSIxIeNonwrE6rzaAm5nrHoVtxgBV2EXOuDLFiMcYwTBByvJuBLFCzsIR/qNDibJlc3Qsi3HD1D6w7mHoyBdKtVghILxkW0kL+9dDc9tiDXsv75DfWpe+1SJmvFzbkVASbkbp05947bLYRcjTCerd26dcvj0gJjGp7Lausn3Cr69u0bcnJatGhBOGehdmGACwzCxkUSNSHHITpEr1DLzz//LEIySlGTJC1ZF40SchzaVGeWhNsKSDeyTkIQKlJ9YDWQkONAodqqGogHNhASaz3WWy0uK4FWbC3zKA9JasG2U6dOytqBTznIczgDLLDAGsHZBimR+glFyMERcQgXsfMh2BhhLWEt4jAu3IlkOM1oCbnavxx9hBsLdMM6wUFXbHjxD2NRW/sj/Rb0fG86IccPHz+uYKQc1+CftnnzZlGGLeR6psr+soGE/N4LKlLVYqHTMBdJiKP+LcKHDAplOZfaXfLRavpjbxoTcvun2/E9MiF3/BR5boBOIuSwguMg3Nq1a0UUkeeffz6kH7M6vB0mBX7nsHTD1xvkEwJf3P/+978R50xdB/G9A1OpIwY0nu0gZSAvsMK///77gtRKUgVeoBY1Ycd1uwk5+lQn3sEbBBwSlCET1RE8UNZphzqjmUfoEYkoo8zHH38s3oxIwduEm266Keg6AbnFWwXwOrigTJ48WYQYjNRPKBKMQ7Q4ACoF84HNpRRs4rCZg1hNyOXGB5FcmjVrpsTGR5Sh3bt3G87+GgxQSwg5duhqQi5fgUhCDp8gJuQR74MxLxBIyH/p35RapGpLCDVn0xGatvagosP7V9ai4snxIS3kj8zfStuPZ9Ccv3MPFEEuqJRCFYsmUusKRenBduf9zbYeO0NjV+ylX3ecpP1pZ6lgXBzVLJlEPeuVpv7Ny1F8XJzSxvR1B+mrv3LbLJlckN68ohaNWridvv3nCFGBArTglsZUtkhulAEWZyNgFiGH3yQOA8E/FgfUWRiBUAg4iZDjVb7aModDcljHgYmBoAsS3iAShxSZQEidgTFYSDvE98YhuuLFiwu/c1hGYYGVmT/RP8iUfKYHhgmUhwDhl62OHa52ScBYQLrQjhQrCTl8kZFUJlDUhzsRaUO6SMjY42rXjVgT8kAdoplH6B+JKKNMoEsMNlogxnB9UgvmDONQx32XMcsj9ROKkOPAMQ6sSoFFGm9pIHDDwrqUAks6woBG0ivasWCdytj4EyZMEJsUbEhfe+01zZtZvXdWXYQc7iY42Y1ditr/R90plGBCrncanFneCCHX60PefOwftOlI/mRRQObKOqVoRu/cNMRfbDhEd369iTKyc4KC1q5yCs3q05BwwBTyzM876KVfd4nPKYkF6Y7m5emtpbmZ2iB/3duKKoex+jtzZvw5KrMIuT/RY62jQcBJhBzjh6VSHYsZpPq5555TErLgsBwsvT/88IOiLogELJcQdWhD/I2oIkOHDhVvq0E6EItcijz8huyW6EcKIl0g3jeweeKJJ/IkkUGyGrzexyHTRo0aKXUQ7/yLL74QBB+bhcAIMbD+a3HxkA2GI1k4AKgO+YhEOhgndFS73wQe7pRtw7qvxgHX7SbkkXSIZh6hRyRyKjHAYWHEO1cLCHmvXr2Eawre0mDdyXjtKNenTx/69NNPRZVI/YQi5HjbgmRQUh566CGx1lAeFnFsoqTAhQWbVGxIo3ELku2EGouakMsNLbw7EHkISa+Q6dNs0UXItXTOhFwLSu4oYychv/GLjbR2XxrtOJGhgFOpWCIVT4qnTtWK0yuX1SAc+ARxT8s8J8qUK5JA/2lcho6ezqapaw+Q5Ogg3e90z00sADIOUg6JK1CACsUXUOrjGhNyd6xFjJIJuXvmyisjdRohh7GrXbt2eeImh8Ma5AbhC9X+0tdffz3NnDkz7BSNHz8+T0bQQIt7sMpPP/20IL4QkF2QeBCYYHL//ffnITTqw4WRyFwkwoe+4Z4TmIkxMAEN2gl0z8A1uF8EGhztJuRadIhmHrVgK+cr0K0o3IIBGUeCKvm2JlI/oUgwvChgEYdLSDDB5lGGPcT3eJuB5E14A4LfhZRwcci1+pBLQg7ijw0SREZkCTxjYNb9jgm5WUh6sB07CTng+2XHCeo2NTdGLiTwUOfdc/+hKWtyM8wlFixAK+5sTjVLFhJ/T1y5n+77LvfmHx9XgBBmsVyRRHptyW56QhV+sQARPdK+CvWsX5pOnc2mCyoVpYQ4XGVxOgJmEXJEeYKlB1Yg+AayMAKhEHAaIcc44SoAd5QRI0YoMcMDx49X7Y888oggyIERSkB6EMoOFs5AgbsKrOlqdxOUAUHEq3oZo1tdD+QX4egCo68gagmS+ahJOQgbfJK7du0qXGKkqDNfRiJzqBOpDKLNIA67WoIR8sDDnRgvMjsGit2EHP1H0iGaeYyEW6DeeDuCtwU4kxBMcFj0rbfeEsmo1C4+kfoJF2UF7jlt2rTJk50VfctNIs49qK3TeKOB5FS+I+TwscKCRbB8ABZM2ELunYdbICFvWaEolUiOD6ngpdWL04MG4pBHIuQ13lpGB9IzRf9X1CpJX9x4PrlD1rkcKv/a73QmK9eVZezVtemWJuXy+az/p3FZGt/j/OtX78yW9zUxi5BrjRblfURZw0gIOJGQyzGDJOMQHFxJcS4Clj+4aiD6B5IBBfMtV+sLazvIMlxT4EqCONBwNwlXD5sBZEpEv8AGdWDRDFUHpBHWTvgC4yAiMnyCwMuxy/GoD/JBD7V/ufo7WV5LGeiF6C4YJ94UwOotfYJlO4GEXB17XI0V9EZ7UrCZ0JrDINxYI+mhRQc98xipv1C/B/QBooy3B/iMece8IItpMInUT+D8B+IJHom5w6YOFmq5bmRfcG3BGsR6l/HMQ62ZaMfieAu5lgcZE/JIt3j3fK837OGNDcvQh9fWFQrq9SFHnXCEHNbs8q/lZouDlCoUT/VK51rHpfy+6yRJz/L72lSk0V2q5xvHrD4N6LKaJd0zCTxSBQEm5LwY7EbAyYTcbiy82B9itsuoMSCX2NhE2sh4EQfWKT8CTMjTDlDDOeOocGreEEm8WGKDgJMI+boD6dRmwirNQPRtUpY+uLpOPkION5f6ZQprbocLOgcBswg5DgYh2yB8JOvXzz0szMIIBEOACbn31gVc1nAYcOrUqYTU8VJw6DTwIKP3tGeN9CCAtwG4B8jDwLDs42wC3igFvm3R026osrp8yPF6Cwc3kE61Zs2aQdvErgIDVscdDQx7iFdeKMNxyM2YQuvaCCTk711ZmxqUyWuVVveO8IE1SiSLS2ZbyHcez6D67+UmC4A0KluYOlQtFlJ5hGfs2zS/ywp8yyumhI6lbh2a3LJRBMwi5EbHwfX9gwATcu/NdcuWLfMdir388stF+D6tbijeQ4U1cgICugi5lgEzIdeCkjvKOOlQZ/Y5ojKvLKGz53KdUq5vUJom96wXEchIiYgiNsAFHIMAE3LHTIVvBsKE3HtTHUjIEcbxpZdeypPF1Htas0ZuQIAJuRtmKUZjjDUhn9KzLl3X4HzWrpYfrKS/Dp8WaJQulEB/DWlJheJz442nZ56jD/7YK66XKRxPTcsXoUopSSEt9TGClLs1gIBZhByHzD766CPq379/2PTXBobKVT2CABNyj0ykSg0c8oMrAt7QI6touLTw3tOeNXIyAroIOU69IpHAsGHDqHr16kH1Ygu5k6db39jsJuQr9pyiDpPWKIO8rGYJerNbTUIEldqlCtGHq/bRkG+3KN8jdOHLXaqL759bvJOm/Xk+M+gPtzSm9lWKMSHXN+WOLm0WIddyON3RQPDgbEOACbltUHNHjIDvEdBFyLU8yJiQe2dN2U3Ij57OompvLVUS/EgkEU3lj7taUNY5ovYTV9G6g+lhQUa4Q4Q9hGh1WdlzMoPe/r+99OfBNEqOj6O2lVPonlYVlIyf3plV92rChNy9c+fWkTMhd+vM8bgZAfchwITcfXNm24jtJuRQDEl8kMxHLZKQ49r+U5l019xNNH/LsXw4gEjf1bI8Pde5OhUskJvsRwshP3Ymiy6csJp2nsCJaiTByG26U/XiNPc/59M/2wY8dxQUASbkvDDsRoAJud2Ic3+MgH8RYELu37mPqPmWI2do87EzSrn2lVOoSGKuz3Yk2XE8Q/H3luQWGTFDXVe399vOk7R6/ylxqVapZKpbqjBVL5E3MsqGg+n0266TdPR0JsUXjKNKKYnUuXpxKl04Ic/QtPQ3ZfUBuvubf6hysSRa3K8pbTh0mq6clpsxdPN9rSm1aGIkdfl7GxAwi5BjqEhYwvGGbZg0l3fBhNzlE8jDZwRchIAuQq5FL3ZZ0YISl3ESAofTs4R1vEhiHNUpVYj2nTpLtd5ZTrCx73zgAiqZnJfkO2nsfhqLmYTcT7ixrtEjwIQ8euy4JiPACOhDgAm5Pry4tMcRQLSW3jM20E/bj4s459/2bexxjd2jnlmE/NSpU7Ru3Tpq3LgxFSlSxD0A8EhtR4AJue2Qc4eMgG8R0EXIjx8/TkuXLqU2bdpQ8eLFg4LGFnLfriXXKw5Lea/P1tOKvaeoavEkG4M81QAAIABJREFUmte3sfifxRkImEXItRxOd4bGPIpYI+BUQo6QfWvWrKEzZ3JdCtu2bSv+P3HiBG3YsEGBrVWrViKjIEL9rVhxPrEaMtTKZzh+D1JSU1OpWrVq4k8kAjx06JD4DPeuCy64QHw+cuQIbdq0SamD6/geyf5WrlypXJcbXowVvEFKlSpVlHCj69evF1kzIQhB2LRpU/H5wIEDhASCUsA5MBenT58Wektp1qwZJScnCxe0ZcuWKdeRuLBs2bLib2TmlDiVKFGC6tXLzV+B8Ke7du1S6kgM5YZdfoG45QkJCSLZ4fLly5XydevWpZIlS4q/1RiiX5k4EZHp9u/fn6+PY8eO0V9//aVcb926tQi/mJmZSX/88YdyvWHDhpSSkpKvj0qVKlHlypXF9b///puOHj0qPiOjZIsWLcRnzB3mUIqcJ2ABTKQAc2AfOE+IpFe+fHlRbO3atZSenhtMAePBuCD79u2j7du3K23JeUpLS6M//8x1+4Q0b96ckpKS8s1T7dq1qXTp0qIMsJUJJXEN30F27NhBe/fuzYeh0bVeoUIFqlq1qmg3lmtdUYyIdBFyLQ8yJuRqePmzWxDYe/IsXf3pOtp46DS1rlCUPr2+PlVIYd9xJ80fE3InzYY/xuJUQr5q1SqFeGEmQEgx1h9//JE6d+6sTM7BgwepTJkydPjwYfG/lB9++IG6du0q/lRnpxw6dCi98cYb4vrNN99Mn3zyifgM0gsyDPn888/phhtuUNoCoS5atKggTpLM40sQZBBNcAJ1mvHRo0fT8OHDRf1LLrmEfvnlF/EZmwS5mUBK+3vuuUfpA3HDQTZB4Bs1On/QHqQWxBgkE6RSysSJE0WeAQhI186dO8VnZOScN2+e+Cyzjss6GCc2FkuWLKH27dsrbYG4V6xYkWCQBKGXMnv2bOrRo0c+DO+44w6aMGGCuH733XfT2LFjlToyO/ncuXPp6quvVq6DUKNtEFwQRSnA5qKLLhJkWX3mZdSoUfTss8+KYldddRV988034jPq7tmzR3yePHky3X777UpbmD/M4z///EN16tRRroNsY/OEzYBMEY8vx4wZQ/fee68o16RJE4VgX3jhhQIjCMJgP/zww0pb2PhhY4FNBTaDUrAxwdoAUcdakTJ9+nS68cYbxZ8g+tgMQbC+PvvsM/EZYbZfe+01pY7etT5//nzq0qVLvnkKtdYLFy4sxgmZMWOGMj78HWqtYzMBfbWudWxo8JY2UJiQ54OEL/gNgcxzOdTpozW0an8aXV23FE26tq4IfcjiLASYkDtrPvwwGqcSchA0kG1pRbbaQg4cYP2EBFrIpXXXqIUcZBEWb4iZFnJsXkDoIXgrAOIPYQt57i9Yr4UchFpuiqyykJcqVUrZNFhlITfyNgjrCetKSjRvg7CRhG7YMGLtQ5iQ++GpwjqGReDtpbvpsQW5r91ubVqWCiecjyQzoEUqNSpbmBF0AAJmEXIQBzzwy5Url8ci5AAVeQgOQ8CphNxhMPFwGAFGQCcCwTxOdBFyvI6A306xYsXyvIJSj4NdVnTOChePOQL3fbuZJq467+enHtBnvevTVXVKxXyMPAAiswg5Y8kIaEXAqYQc/rzw44brAV6xszACjIC7EDBMyLWoy4RcC0pcxkkI7E/LJGQJDSZViiVqjr3uJJ28OBazCDnuUSA0IDLwd2RhBEIh4FRCruU8F88qI8AIOBcBw4QcTv84HYzDBzh1HEyYkDt3AfDIGAE3I2AWIWcy4+ZVYO/YmZDbizf3xgj4BQEcst2yZYuIyCMPJOtyWdHyIGNC7pflxHoyAvYiwITcXry5t9wIJDIyhpPw0PIsdtJ4eSyMACMQGQEm5JEx4hKMACPgAASYkDtgEnw2BKcSckR5QHg7hONDfGcWRoARcBcC2OjjXCZCgsrQo0zI3TWHPFpGwLcImEXIEbbtp59+ok6dOimJPXwLKiseFgGnEnKeNm8gADdghK5EDG51/HFvaMdahEPAsA85Iqwg4DsyVyHSSjBhlxVehIwAI2AFAmYRcivGxm16EwGnEnIkR0EyHMQvVieM8eYseFerV155hR555BFCgpzrr79eGAoQ41tmyAzUHPwqUhnvouUtzQwTci1wMCHXghKXYQQYAb0IMCHXixiXN4qAUwk5+5AbndnY10c+hCJFigiXBWSAhBsSku5MmTKFbrnllqADlJkuw5WJvWY8Ai0ImELI4feiTrUbbAeHhQZiLkWWx64er4vxigZlAg/LFEo7QA3njKPCqefralGMyzACjID3ETCLkC9dulSk7F68eLGSfdD76LGG0SDAhDwa1LiOFgQmTZpE/fr1o9dff50eeOABQcjxxmPWrFl07bXXiibg0oLQrOBOIO6hyoSKeqdlHFwmNgjs37+fZs6cSdddd53yRoR9yGMzF9wrI8AI6ETALELO1kWdwPu4OBNyH0++harDYInw0adOnRLZgkeOHClIePPmzWnMmDFUqVIlGj58ONWrV48efvhh6tq1a9gys2fPtnC03LRdCDAhtwtp7ocRYAQMIcCE3BB8XDkKBJxKyA8fPkzfffcdXXHFFVS6dOkoNOMqsURgzpw51KNHD2rfvr2wgi9btizfcMqVK0cDBw6kzp0702OPPRa2zHPPPRfWcyGWunLf2hFwFCFPPHOcmnw1hk41rqtdAy7JCDACrkcAxCchKYlK12pMcSGyZx6fNoXKTPzZsK6bN2+mJ554gp555hmqVauW4fa4Ae8i4FRC7l3Eva8ZXHVhAd+7d69w4S1ZsqRwRWnatCn9/fffAgDco5AwRi1ayngfPe9ouGbNGurbty9NmzaNmjRpIhTTRch37NhB77zzDt13331UtWrVoMgYOdSJBltNf947iLMmUSMwdt1ualU2hVqXCx7NJ+qGuaKrETCDkLsaAB68rQgwIbcVbl909ttvv9FFF11E/fv3p4kTJwqdf/zxR2EJv/XWW8WhzjvuuIMmTJiQBw8tZXwBoEeUNOVQZyQsjBLySO3z995H4OjRo+JVHawIb7zxhjjUwuJdBEB68K9UqVLUqlUr7yrKmrkOAacS8hUrVgh3lXnz5okwxCzuQQBhDdevX0+7du0Szzi4H6WmplKNGjVo48aN9NJLL9GIESPo66+/pquvvloopqWMexDgkQIBJuS8DlyBwMsvv0wLFy4UYx08eDBdc801rhg3DzI6BOwm5Nu3bxeRDR588EGqVq1adIPmWr5AwKmEnA8mu3P5rV27VrimXH755WIzBdmyZQt16NCB5s+fT/Xr1xc+5fAff+2114SlXGsZdyLi31FjUzZgwADxJqRhw4YCCF0uK5s2bRInfV944QWqXbt2UCTZQu7fBWaG5qtWraJHH31UaQphoMaNG0dly5Y1o3luw4EI2E3Imcw4cBE4dEhMyB06MS4dVseOHennn3+mDRs2CPItJTCcNMIcBiZ80lLGpbDwsP9FQBch1/IgY0LOaytaBBCbftCgQeKwi1ratm1LTz31FJ8ijxZYh9djQu7wCfLx8JxKyHH4Dxke8Taxbl0OguCGJbpt2zbhloLQhitXrnTDkHmMNiMQM0KOE8MsjIAagY8//pjwL5jgzQySubB4DwEm5N6bU69o5FRC7hV8/aTHjTfeSDNmzKAlS5bQhRde6CfVWdcgCMDwOHXqVBFppUKFCqKELkK+fPlyuvTSS8WJ4NatWwcFOZKF/NixY4SdIhNyXqNqBBDB56677sqT4VX9PUJDwdcqJSWFgXMxAiA48pCuOuMvPhcvXpyaNWvmYu146F5DgAm512Y0NvocPHhQ+IVXqVKFcIYlXLbz2IyQe7UbAUcc6kxPT6cDBw4Q/KFYGAEggLWAqCrY8IUT7CTxmpbFfQjgAQSfSGSlK1y4cL4HEtYA0j/jocXCCDgFAacS8p07d9L7778vDr1XrlzZKXDxOEIg8N///pfefvttmjt3Ll155ZWMEyMQ+ygreOjKf7xD5BUpEfj++++pd+/eEQHBmsGuUn0YJmIlLuAYBGAZj4+PF6Q8lnL8+HGR9e6CCy4QVnkWRiAUAk4l5FrOc/GsOgOBkydPUrFixcQ/hPQNPKzpjFHyKOxGwLCFHLEwFyxYQF27dhUxg4NJOJcVuxXm/pyPwKlTp0QYKLw10SItWrQQIRFhTWVxFwKSkIOUx1KYzMQSfXf1zYTcXfPlxNGOHj2aHnvsMZo8ebJI/MPCCAABGKfBl/FclAZqXT7kWh5kTMh5selB4PHHHxfJf/TImDFjqF+/fnqqcFkHIMCE3AGTwEPQhQATcl1wceEABHBWDi56sIrDXZcNSbxEwiHAhJzXR8wQyMrKEi4oweSrr76i9957T/hIXnvttXmKwMLapk0bPhgTs5mLrmMm5NHhxrVih4BTCbm0sLHrZ+zWhpae4a6ydOlSEUVDJn/RUo/LeB+BtLQ0QvhShC0tUqSIUJgJuffn3ZUaTp8+Xcli1adPH1fqwIM+jwBez2EjJf/FEhtsBOFHDv/xWLvPxBIH7jsyAk4m5JFHzyUYAUbAqQgY9iFH9qjTp09ToUKFQh5MkC4rKMvCCESLABPyaJFzbj2nWMidixCPzGkIOJWQw/KKrMZIMsOhYJ22ang8jEBkBAwT8shdEIGIZ2ZmclhDLWBxmZAIIIHCbbfdRlOmTNEUgYWhdD4CIDewSMs45LEaMSzkyIdQokQJtpDHahJc0q9TCbmW81wugZiHyQj4EgHDhBwHFPbv30+pqakxD13myxn0kdKIpNKlSxeRhKpTp04+0pxVtRoBJjNWI+yd9pmQe2cuWRNGwEkIgE8jWyfOFyQlJYmhme5D7iSFeSzuRWDRokUiKyz+79ixo3sV4ZE7DgEm5I6bEscOiAm5Y6eGB8YIeA4BJuSem1JvKMSE3Bvz6EQtmJA7cVacOSanEnK4hR45ckTkA+FQes5cOzwqRiAcAsHOZDIh5zXjSASYkDtyWjwxqBMnTtDy5cupdevWInseCyMQCgGnEnKeMUaAEXA3AoZ9yBE3cePGjSJ1uYyb6G5IePRORYAJuVNnhsfFCPgHAacSchxMRqQVRFjh0J3RrceczDN0eNDl0VXmWlRm4s+MggEEDBNyA31zVUZAFwJMyHXBxYUZAUbAAgScSsjZ7cr4ZOekHaPD911DhVOzjTfmsxbS9xVkQm5wzg0TciT3gN8L0sByhjCDs8HVwyLAhJwXiFUIMJmxClnvtcuE3HtzKjViQh793DIhjx47WfPw4cP0ww8/0GWXXUalS5cWl9mH3Diu3IIFCDAhtwBUblIgwIScF4JWBJiQa0XKfeWYkEc/Z0zIo8cuXE0m5Nbgyq0aRIAJuUEAuXpIBJiQ8+LQioBTCTkSW/3222/Uvn17keCKRT8CTMj1YyZrMCGPHjsm5NZgx61aiAATcgvB9XnTO3bsoDfffJOGDh1KVatW9TkarH7YB2SBApx12qNLhAl59BPLhDx67GRNRPqCu8r8+fOpVatW4rIuCzmyCk2ePFmkNEd2IRZGwCoEmJBbhSy3ywgwAloRcKqFXOv4uVxoBJiQR786mJBHj52safhQp/EhcAuMgDYEmJBrw4lLMQKMgHUIOJWQs9uV8TlnQh49hkzIo8eOCblx7LgFmxFgQm4z4D7q7p9//qFRo0bRc889R7Vr1/aR5qyqXgSYkOtFzD3lmZBHP1dMyKPHTtbctGkTPfroozR69GiqU6eOuKzLZWX9+vU0aNAgGjt2LDVs2ND4iLgFRiAEAkzIeWlYhQBbF61C1nvtMiH33pxKjZiQRz+3TMijxy5cTV2EnB9k1kwCt5ofASbkvCqsQoDvY1Yh6712nUrIt23bJixrsLBVr17de8DboBET8uhBZkIePXZMyK3Bjlu1EAEm5BaC6/Omly1bRh06dKDFixdT69atfY4Gqx/2AclRVjy7QJiQRz+1TMijx07WRLSvd999l4YMGUJVqlQRl3VZyNesWUN9+vSh6dOnU9OmTY2PiFvwPQIHDx4MisHnn39OgwcPpvfee4969+6dpwysVmXKlPE9dgwAI8AIWIuAUy3k1mrtj9aZkEc/z0zIo8dO1uQoK8Yx5BZMRuCJJ56gZ599VlerH3/8MfXt21dXHS7MCDACjIBeBJxKyLds2UIvvvgijRgxgmrUqKFXLS5PREzIo18GTMijx44JuXHsuAWLEMjKyhIx7Q8dOqSpB7yZWbVqFeFBycIIRIPAkSNHaOHChdS5c2cqVapUNE1wHZ8g4FRCzucgTFiAOefo0IBOJjTkzybKTPzZn4qbpLVhC/n+/fvpyy+/pOuuu47KlStn0rC4Gb8jsHTpUmrbtq0mGLZv387ZFTUhxYVCIcBkhteGVgSYkGtFisuZjYBT157Zevq5vZycnDzGRV0+5Pwg8/PSsVb3m266SZxNCCd4Pfv8889bOxBu3fMI8H3M81NsmoJOJUW8hk2bYsc25NS151jAPDAwJuQemEQvqJCWlkYlSpQguLAEExzi3Lt3L8XHx3tBXdYhhggwmYkh+C7rmkmRyybMQ8PlteehyQyiyokTJ2jlypXUsmVLSklJESWYkHt7zl2l3cyZM+n6668POubffvuN2rVr5yp9eLDORCA7O5tOnz5NhQsXpri4OGcOkkflCASYFDliGnw5CF573p52wz7k8HfJzMykhIQEPlTn7bUSE+2wvuBLjjjRasGZhS+++CImY+JOGQFGwL8IOJUUHT16lH799Ve6+OKLxZtFFu8h4NS15z2kY6ORYUIem2Fzr35CAG4pFStWVFSGiwqiYshXOn7CgnW1BoGzZ88SDqiXL1+eEhMTremEW/UEAk4lRex25YnlFVYJp6497yNvj4aGCTle827dulXEPS1UqJA9o+ZefIcAUkI/9thjQm+OOe676bdcYSYzlkPsmQ6cSop4DRtfYjnpx+nwkB7GG/JpCxz20NjEw9sEb7pKliwpvE4gzvIhP5dNhwZeakxLru16BPakZdBFX66gwvEF6bfrWlHxRD7I6fpJNUkBMx4CTGZMmgwfNGMFIYdR68EHH6QHHnhAuOglJSXpRpLXsG7I8lXgxEDRY8iJgaLHLlxNRxHynLNn6PDdl1Ph1GxrtOVWXYPA+8v2UtkiCdS7YRnXjJkHai0CZj0EmMxYO09eat0qQl6zZk0Fpp49e+om5ziYfPLkSeHKV7BgQS9BbpsuTMijh9qse3H0I3B/TUSUQ6SVYsWKKdHjmJC7f149qcG5HKI4TsbpybmNVimzHgIIsbl+/Xpq2LAhFSlSJNrhcD0fIGAHIVfDGA0598E0WKIiE/LoYTXrXhz9CNxf07AP+ZkzZ2jHjh0iU2JycrLpiLCF3HRIuUFGwDMI8EPAM1PpGkXsJuRayTn8Tw8fPkylS5dW/E9dA6pDBsqEPPqJ4Htx9NjJmoYJufEhhG+BCbnVCHP7jIB7ETDrIYDwmufOnRMxyEG4WBiBUAjEkpCHI+fsdmV8zTIhjx5Ds+7F0Y/A/TUNE3I8xLAzR6gwKx5kTMjdv8hYA0bAKgTMeggwmbFqhrzXrlMIuRrZYcOGUevWremmm26i33//XRwMZdGPABNy/ZjJGmbdi6MfgftrHjt2jOSzqHjx4kIh9iF3/7yyBoyALxAw6yHAhNwXy8UUJa0wPEUzsMaNG9OoUaOoW7duIhEQr+FoUMxbhwl59BiadS+OfgTerOksQp6RTofvuYKjrHhzrbFWjIAhBMx6CDCZMTQNXNkgAgh7qI6yEqq5QBKuLocIK2vWrKGmTZty0rQo54MJeZTAEZFZ9+LoR+DNmrYTcri9IMoB/DgD5dyxA5T11B1MyL251lgrRsAQAmY9BPbs2UOTJk2i22+/PU9WWEOD48qMgEYEwhHycCRcY/NcTCMCTMg1AhWkmFn34uhH4P6ahn3IDx48SLNnz6ZrrrmGypYtGxUi2Nlv2LCBMjIy8pHypJMHqNYXbzMhjwpZrsQIeBsBfgh4e379ol0gIY+WhMOo5RSXGjfOHRPy6GeN78XRYydrGibkxodAIhD6qlWrCCEUA6VQ2gFq8PUHTMjNAJrbYAQ8hgA/BDw2oT5VB4QcRi21T7heKNjtSi9i+cszIY8eQ74XR4+dYwl5oNsKCHnDOeOYkBufa26BEfAcAmY9BJAUaPDgwfT+++9TgwYNPIcTK+RsBMywbDMhNz7HTMijx9Cse3H0I3B/zW3bttErr7xCDz/8MFWvXl0opMuHfPXq1dSrVy/68ssvqVmzZlEhoraQMyGPCkKuxAj4EgGzHgJMZny5fDylNK9h49PJhDx6DM26F0c/Am/W1EXIzbgJMCH35kJirRgBqxEw6yFgxn3Mal25fUYgHAK7du2isWPH0qBBg6hy5coMVpQIHLqjQ5Q1uVqZiT8zCCYjwITcZEC5OUaAEbAGAbMIOd703XDDDTRjxoyo3/RZoyG3yggwAoxALgJWJKVibJ2DwObNm+n5558XZ0lkGFRdhBzRUe6991567733qH79+ro1g4sKLOR4IOJQJ7us6IaQK2hAYP3BdFq656RS8qZGZSk5Pk5DTS7iZATMIuRO1pHHxggwAowAE3LvrwHboqwg1ngwAQE/evQorVu3LmjYQz7UGftFuGzPSfp+8zHac/Is7Tl1lrLO5VC5wglUrmgCda5egrrUKE5xBQrEfqBhRvD6kt30+KLtSolNQ1pRxZQkR4+ZBxcZASbkkTHiEv5A4O+//6YHH3yQXn/9dapbt64/lPaZlmwh9/aE20LIQcbPnj1LwUg5roGQw1SPMmwhd86CW3cgjYZ8t5mW7j4VdlBViyXRFzc2oIZlCztn8AEjsYKQY4MyYuE20dND7SpRk3JFHKu/VwdmFiE/cOAAzZo1SxxQjzafglcxZr3cgQCfg3DHPBkZJRNyI+g5v65hQo4Mdx9++CH1798/ZIa77OzsoNZvwANCfuTIEUIcVibkzlkwh9IzqfW4VXQwPVPToMoVSaBlA5tTmcIJmsrbXcgKQv720t302IJcq/vnN9Sn7rVL2a2W7/szi5AzmfH9UnI9ALyGXT+FERVgQh4RIs8V0OVDruUmAEIOso3/pchsYkzInbl+3vh9N4368byLR9eaJejpjtWoQZlClJ2TI6zmw77fQhsOn1YUGN2lOt3XpqIjFbKCkF/y0Wr6Y28aE/IYzjgT8hiCz107CoGVK1dS9+7d6dtvv6UWLVo4amzuGUzO/7d3JtBRFWse/0P2DRISCIQtkLCGJbK5nAMCbqCiLMMo4vZU3Bf0Oe+4Heaoz4XHyEHRQRBxEGF0GARUFMc3CmSeIsi+BghrWLMQIBthm/Ovpi6dpAPdt293+nZ/3zk5p9N9q+qrX9Wt+t+6tQBnqgLW3Z6tk7HhQFFg+hceATSQdVlWF44IcquJ2jC+R77dgf/cXGh4vu+5vrVGv/ccr0SP6WsRGdYQ7RKjcFuHJnh9YNtqud1TUonpaw7jH/tP4WhZFcIaNkT7pCgM75SMP2U3Q3jDSzfwV1sKsDi3WIVPig7DlCEZeO3nffhhVzGXl6Ob05SY1o0iMfHGdrXILtlZhLmbLvn952vT0LtFAq4kyD3x8y9/34N9J07jux0OX2l9WyYgLT4SfVrE44VrW9qwxO3psghye5abeC0EApGA3oc8EH2zg0+y7aF3pcTp2zk5Oejfvz+SkpJUZCLIvWMaFKEfX7ILczYeM/Ky+K4uuLG9o4I4G6e2JMdGwNWSzgXbCjHu2504fe6CSybXtkrAoru6Ij4yTP3+xor9mPiPfPU5ITIMD2Wn4v1Vh4ywfdLi8cchx3x2LiLNe6Y3msVFVot72Jdb8fOeEvVdZBiv6YMmMRGXFeSe+pk9fS12Fle6zNOtHZpg/j95vttQUFSaesiEVYKca1f4Fi8yMlJtLSYmBIRA6BGQg4HMl7lVbbF5D+wf0us55OzI+NfQaaSzJhaZsmK/ijJl5UG86jRlhVsEPtmnOe7omIyrWsRVG9l2lTsueKRwLTvj2F2Hc8zHdEvB8YpzmLvpGLRGp+ieOjRDXUMxTlGuBXdMeAMjPL/71+vb4PXljt9pHw7NwJ+yU43/iyvOot0Hq9UuMLQ7OzXBvJEOcVzXCLkZP/95wXZsOlKG/SdPG2m3bBSJxlHhGNi2MSbdVHvk3n41wB4eSydgj3ISL31PoLCwUE1X4bSVlJQU3ycYhCmIIDdfqNIWm2enQ3otyN1xQQS5O5QC65qiirPoMW0NSk5fmvevPYyLCEO/lgm4rlUCbspIBEeuG9QYI3ceYedI9Zpx2WifFKOimLXuKJ5Zmqc+hzdsAG5ByJHu9347iAlOWxNynPIv17XG8M7JKK06hy5NY9Bx6h8oP+sQ+UMyk7BgdBcD3JyNR/H4Eke8tK9GdcbtHR0LLesS5Gb8ZHz/t/8kbpm72UhLFnXWT/21qhOoqKjAvn37kJ6ejujo6PrJjKQqBLwg4M56Li+iD4mgIsjNF7NVbbF5D+wf0mtBXlZWpvYQz8rKQlyc623fRJDbs6JsOFqKe77egb0lrqdn6Fx1aBKDd25Mx9CMS1Na2r2/Gscu7tAyJCNJbYuojSPYqe+tROVZx0j29NszcW/3ZrVE85huTTFzWIdq8B5cvAPztzrmiHPUnnPb9ZSXkf+1DT/mHVe/JceGI+/pPogIc8xRr0uQm/FTBHng1GerOgERM4FTpuKJOQJSh81xcw4lgtw8Q6vaYvMe2D8ktXJpaSni4+MRFuaYyitzyO1frpbl4My5C2qh5Te5hVix/2Sd2yBy2u0izjNvl6RGs1Pf+93woUlMODolO0bHta3MPwU9s5w7s3CHlpqimfHdVGPe+tJdxzFq/jYjni9GdMSIzik4WXkObT9YhaqLc2Ge6NMc/3ZTe+M6V4K8UVS4KT9FkFtWvbyOyKpOQMSM10UhEdQzAanD3heACHLzDK1qi82zG6JpAAATEklEQVR7EJwhRZAHZ7l6nasLF4CdxRX4/eAp/O/uEizeUWQIYEbePjEam57ohS3HytHv0/Vupze2e1PMuL1DLUHOaS6dU6ofNsQHhMypq1FYcVbFf3dWU3x6Rwd8ubkAD3+700gz58Ee6NUi/rKCnPPZzfgpgtztovX5hVZ1AiJmfF5UkoCPCXAL4dOnTyMqKuqya7p87IatoxdBbr74rGqLzXtg/5DcWIBrQXg4XUSE40wXEeT2L1e/5GB7QQVGzd+KvScuLW7kFJKKM+fR+d/XGD5kNY3FgDaN6vTpqubxGNuj9pSVuo63f+F/dmP6miMqvsTocDVt5f5FO7A417E/a+eUGKwZV30fXlcj5OfOw5SfIsj9Ur3cSsSqTkDmkLuFWy4SAkFNQAS5+eK1qi0274H9Q3o9h5yKnsdON2vWTG0Z5spkDrm9KsrOogos2VWM7YUV2F5Yjn+5rpXaY9yVvbF8Pyb+6tiqkLbqkWx0To5FyqTfUHVxt5NRXZLx+fBOV4Rwpb3CjTQOnsKgzzcZ8X1zdxeMWZBr7MjyxsA2+PO1raql5yru1LgoU36KIL9iUfrtAukE/IZaEgpwApWVlTh48CBatWqlRsnFPCcggtxzZjqEtMXm2emQXgtyd1wQQe4OpcC5hvO7b5hzSfBy/vfSsVm19vyuPHte7TSi9wZnDrjvd/P4SPSasQ65F0/xTI6JQO7TvRAT7likUH7mPGasPQx+nxIbjh6pcWiZEHXFw3s0IU6d6fHxWuy+uNi0Z2osNhwtVz9zf/Lcp3ohLaF6h1SX2DfjpytBPmd4R4zsIluN+bsWW9UJyD7k/i45Sc9qAjLtynuiIsjNM7SqLTbvgf1Dei3IKbbLy8sRGxtrrAqtiUUEuf0qyrWfbsDGY45j4WkUzxzp7pQcrXYuyT9Zha+3F2FXcYVxDedsc+427bP1R/D0D7uN37h14d9uSFd7hP815wDmbS4wfvvp3m64rnUjtwU5A765Yj/evXiIkDPdwemJ+HZM11rA6xLkZvxk5GsOlWLA7I1GOje1T8SUW9qr/GU2qb6A1X6lbx+PreoERMzYp8zFU9cEpA57XzNEkJtnaFVbbN4D+4fkDiubNm1C9+7d1U4rNJlDbv9y9ToH24sqcPu8LThcWuVWXNx68PsxWeid5qhE3Cr8ulnrsaXAMXJdl3G7Q257SHN3ygqv5eLS7OnrakU78/YOGNO9qduC3IyfjPx4xVm0fX+VccCRTpBvE9Y+Wn3+ulsA5SJTBKzqBETMmMIvgQKIgNRh7wtDBLl5hla1xeY9CM6QIsiDs1w9ztWektN4K2c/Fm4vAqenuLKGDQCOSr9zQzt0bVp9ZPho6Rk8umQn/r7bcZS9s3EP8Ud7peKvg9MRdvGock8EOeMa8B8bseZwqREtHwr2PNsHsRGOqTHOdrm4PfVTx8tDjHiYkbOJIPe4mnkVwKpOQMSMV8UggQOAAN9U79q1C5mZmeqNtZjnBESQe85Mh7CqLTbvQXCE5G5JziffiyAPjnK1LBclleew+tBJHCk9gyOlVeDWgwlRYWiXGIO+afFIjXdsz1OXbSsox6/5p3C84gzCwxqiZUIkBqc3RnJs9XD7T5w25p0zroHpjRFBxV+HcY46w2hLig5Xp4a6MnfidtdP5/h/PXAKPECJltEkGh2bxCI9URZUWVb5rhCRVZ1AQUEBFi5ciBEjRqgtp8SEgBAIPQIXKstQ9ORQJPTvHZCZ3/77cnS++vqA9O1UzhqkzFoRkL7ZxSmv55AXFxdj2bJlGDRoEJKSLp3U6AxA5pDbpTqIn0LAXgSsEuT2yrV4KwRqE+DCZPa1POGvwcW3jsLJcwKFDw3wPJCEUAREkHtXEbwW5O4kL4LcHUpyjRAQAp4SEEHuKTG5PlgJyLSrYC3ZS/nigxYfvMSCk4AI8uAsV8mVEAgJAlYJ8g0bNmD06NGYP38+evbsGRLsJJPBRUAEeXCVp6vciCAP7jLOz8/HzJkzMW7cOLRs2VJl1qM55KtWrUL//v2Rk5ODfv36uaQlI+TBXYkkd0KgvghYJchFzNRXCUq6VhGQOmwVycCNRwR54JaNrzzzSJC70wiIIPdVUUm8QiC0CYggD+3yl9xfInDkyBF89dVXuPvuu5GamipogpCACPIgLNQrZEkEeeiVueRYCNiSgFWCfNu2bXjiiScwbdo0dOnSxZYsxGkhIASCm4AI8uAu39zcXIwfPx5TpkxBp06dVGY9EuR5eXmYMGEC3njjDWRkZLikJSPkwV2JJHdCoL4IWCXI68t/SVcICAEh4C4BEeTukrLndbKo057lJl4LASEAQAS5VAMh4CCwefNm3H///fj888/RrVs3wRKEBLZu3YquXbsGYc4kSyQgglzqgRAQArYlYJUgP3ToEGbPno0HHngAaWlptuUhjocuAXfWc4UuHTdzfu4MCsfd4ObFcllNArIPuXd1Yt26dRg2bBi+++47ZGdnq8g8mrKyb98+TJ48GS+88ALatm3r0huZsuJdIUloISAEXBOwSpCLmJEaZncCUoe9L8ELZSUoeuYOxDY/531kIRaDVW1xiGG7YnY9EuTuNAIiyK/IXC4QAkLABAGrOgF32jET7kkQIeA3AnrKypw5c5CVleW3dIMpIRHk5kvTqrbYvAfBGVIEeXCWq+RKCAQdAas6ARHkQVc1JENCwGMCIsg9RmYEsKotNu+B/UMWFhZiyZIluO2225CSkqIyJILc/uUqORACIUHAqk6Ax1GfP38eDRs2BHcyEBMCQiD0CIggN1/mVrXF5j2wf0hZ1Gn/MpQcCIGQJSCdQMgWvWS8BgF9MNBdd92F5s2bCx8TBESQm4B2MYi0xebZ6ZABL8jDzlUh+78neZ9TiUEICIGgJGDFyv6ysjLoLcXi4uKCkpNkKrgJyLQr78tXBLl5hiLIzbOzTJCfOHECq1evRt++fdG4cWOXHnmzqNP7LEoMQkAI2I0Ap43wr0mTJujdu7fP3Rcx43PEkoCPCUgd9h6wCHLzDEWQm2enQ3LaZFVVFSIjI9X0SVpAzSH3PosSgxAQAnYjIILcbiUm/tY3ARHk3peACHLzDEWQm2d3uZAiyH3DVWIVAkLATQIiyN0EJZcJgYsEuDCZb6PDwsJkYbLJWiGC3CQ4OTXZPDinkJWVlcjPz0erVq0QHR0tI+SWUJVIhIAQ8IqAvwU5XxMePXoUqamp6nWhmBAQAqFHQAS5+TKXEXLz7HRIrxd1nj17FpxHzvnj4eHhLj2SOeTeF5TEIARCiYC/BXkosZW8BieB8vJy7Nq1C5mZmYiNjQ3OTPo4VyLIzQMWQW6enWWC3B0X3BXkp0+fdic6uUYICIEgJ+BvQc42qqKiQgkZvZgmyBFL9oKMgMwh975ARZCbZyiC3Dw7ywQ5R8hLSkqQmJhoeoT85MmT2Lt3L0SQe1+gEoMQsBMBLbwpgrnCXJv+ngK5T58+Ps+SiBmfI5YEfExA6rD3gEWQm2cogtw8Ox2Sg0J5eXnIyMhATEyM+tqvizq5EEWfksdOmJ/FhIAQCA0CXIAWERFx2Xnb/jg5U8RMaNS3YM6l1GELSvfcWRSOG2xBRKEZhRVnQoQmubpz7VdBLvCFgBAIXQIU5Fx7Utf6E3+RETHjL9KSjq8IcIeGgwcPqh0aoqKifJWMxCsEhICPCHBAmrNO2B/qgSgR5D6CLdEKASFQnUCgCPLi4mL8/PPPGDx4sDqMSEwICAEhIASEgD8JeL3LCud///HHH2qeZ6NGjVz6frlFnf7MrKQlBIRAYBEIFEEeWFTEGyHgOQGuweA6LI6Oy8Jkz/lJCCFQ3wS8FuTuZEAEuTuU5BohEHoERJCHXplLjn1DQKZd+YarxCoE/EWg3gS5vzIo6QgBIRC4BPT88fqeQ7569WoMGDAAK1asQN++fQMXmHgmBOogIIJcqoYQsDcBHk43f/58jB49Wh1SR7N8Drl+lea8rZm9sYn3QkAIWEEgUEbIRcxYUZoSR30SkDpcn/QlbSHgGwI+EeRcOaq3OPSN2xKrEBACdiKg9xqnKOdffZqImfqkL2lbQaCwsBA//PADhg4dipSUFCuilDiEgBCoZwKWC/J6zo8kLwSEgBC4LAEeOf7aa6/hrbfeUocyiAkBISAEhIAQ8CeBTZs24d5778UXX3yB7t27q6Q9EuT79+/HlClTMH78eLRp08afvktaQkAICAEhIASEgBAQAkLA9gT8sqjT9pQkA0JACAgBISAEApjA2rVrceutt+K5557DSy+9pA4WKS8vB0fdtGVnZ6ttEbmeiwuZtfGtkJ7mwnjOnDmjfkpKSkLHjh3V5/z8fHXwkLarr75afTx16hS2bt1qfN+rVy91+i6nqa5Zs8b4vlOnTkhMTFT/U3ho4+K19PR09e/u3btRUFBQK43jx49jx44dxvfcZpnT3KqqqrBu3Trj+27duiEuLq5WGq1bt0ZaWpr6fvv27Thx4oT6HB0djZ49e6rPTJfpa+vXr59iyAOXNmzYYHzP6xmOU3BXrVplfN++fXs0bdpU/c/rGY7G7aC7dOmiPh86dAgHDhyolb+ysjJs3rzZ+P6qq65SpxdzhzpuK62tQ4cO6pwEK5nv2bMHx44dM808KysL8fHxtZjzgKqWLVuq73Nzc1FSUqI+s/6xHrpizgX13LKzJvMePXqoo+RrMm/Xrh2aNWum4tq4cSN49DwtISEBXbt2dclcl6unzBkZ7xm9FpL3i36bum/fPhw5cqQWQ9Yz1jdtvXv3Vof+8P7ifaaN9YP1xBJBzr3It23bFrSw+Rbg8OHDXsNmBM4NUYsWLYy3CnxlXlRUpNJgQ8MGh8bv+Js2XWG53+z69euN7/l6IzY2tlaFbdu2LZo3b66uY6PJG5nGa/UrEa7s3bt3rxGXrrBmGnM2jmwkaVY35mwc3ancvBF5Q9bkzQaZDTNt586d4GEwNN4gvFGs5r1lyxaUlpaqeNlJsLOg8cblDazNU96ZmZlITk5WwevqPNnos/HXpjtP53uVv9XVeXbu3BmNGzeuxdC588zLywPnrdJYNswHzcrOk+0Kfaa503myQWbDrM3dzpOdIcWDvOkz0MkHmxFgf0AhR2OHz3aNwlCLH37Pe5bCkfcJ+wBtfEU+duxY9S9Fpb6v77zzTixatEh9/8orr+Cdd94xwlCY8L7nzkTXX3+98T3bN7YTbAecD9launQpbrnlFqO90AGefPJJfPTRR+rfBx98ELNnz1afKcwoSGn0YcSIEUYaFDoUMPpkUv3DypUrwbaOvjmvS3nzzTfVlDQaD//65Zdf1GcKKt2/zpw5E+PGjTPSoCikeGSfowU1f2SbxPaRfTDbJG2ffPIJHnnkEfUv22iypg0aNEgdOkbjlDjtB/9n/phPLcR0XGy/KWjZXzuf77Jw4UIMHz4cOTk5alcobXUx//7779WaApo++ZGfH3/8cUybNk19/9BDD+Gzzz4z4qLopX3zzTdg+WvTzNmvaKHN33777Tdcc801tZi//vrrmDBhggp+880346efflKfqUm03pg1axYefvjhWsz58MUHOG3sS9mvU1s4n0L78ccf47HHHlOX8Xr90Mb6uGzZMvU96yzrrjY+KLJuUFzrPou/1cV8wYIFGDlypArOtLW+4dSSOXPmqO+fffZZTJ06tRZD5pl510Y9x3uCD3/6QYK/0Vf6rO8Z3sv6QdGjKSs6MlY6f8FmRVy+fLlK791338XLL798RdgU1RRjFEharDFQXbDvuecezJ07V8XLEYcPPvjgirDZiFEo1YTNm3/gwIFKLDsf2PDiiy9i0qRJKt5Ro0bh66+/Vp85isCCoX355ZcYM2aMkTaf6tiQskLz6VAbhTAbXlY2jk5omzx5Mp5//nn1LyufHhXhtXpkgRWJFUobKxzjoLDRlYK/seFiA1azMWelZOWksSHWT9vDhg1TNzXt1Vdfxdtvv22koRtzTxoWshsyZIgRBwU1RT8fKPRDB39k3WAdqcmb9UT7wEZt8eLFKi4+6epRGZa5zgt/40MJn8w5cuI8t1jfMDV5c/oW6wuNYlczpuDXIx28RpcJr6ur82SaLGP6oEd9eP28efOMOsH6ph8smCc22DSOkE2cOLEWb7JhXdRGdmwYGIcW+fztxx9/NBoS54b8qaeewocffqiC33fffWquG00/9fMzfdANGP+noOY9xxE2/UDE79kJsU7W7DxZRvqepq/6XufokG5wZ8yYYTTEjIudI0eU2FnqkRF+z86UDXXNzpOdr+4IKFA4SkRzbggNSPJBCNiAANs7ttkUkp4+5AfLCLk7o7WejpDXfMh3Z7TW0xFy6hKKTm3+HCH39q2Ep8x9NULuzNyuI+TOfZDudz0W5ME+Qm7V6wgtQvRN5zxC7jxi66sRcucR21AfIaew0w89vhoh56grH6Bovhoh56guHwpozm8k/D1CzvT1KLynI+Q1X0M6v162aoS85it6V6+X2VHwAdT5AcQGOkxcFAJCQAgIgSAl8P+EG0D2DZUUSQAAAABJRU5ErkJggg==" class="kg-image" alt="Spring Security 6.x &#x8FC7;&#x6EE4;&#x5668;&#x94FE;SecurityFilterChain&#x662F;&#x5982;&#x4F55;&#x5DE5;&#x4F5C;&#x7684;" loading="lazy"></figure><h3></h3><p></p>]]></content:encoded></item><item><title><![CDATA[Spring Security 6.x 一文快速搞懂配置原理]]></title><description><![CDATA[<h3 id="%E4%B8%80%E3%80%81%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5">&#x4E00;&#x3001;&#x57FA;&#x672C;&#x6982;&#x5FF5;</h3><p>Spring Security&#x6846;&#x67B6;&#x770B;&#x4F3C;&#x6BD4;&#x8F83;&#x590D;&#x6742;&#xFF0C;&#x4F46;&#x8BF4;&#x5230;&#x5E95;&#xFF0C;&#x6846;&#x67B6;&#x4E2D;&#x7684;&#x5404;&#x79CD;&#x5B89;&#x5168;&#x529F;&#x80FD;&#xFF0C;&#x57FA;&#x672C;&#x4E0A;&#x4E5F;&#x5C31;&#x662F;&#x4E00;&#x4E2A;&#x4E2A;Filter(javax.servlet.Filter)&#x7EC4;&#x6210;&#x7684;&#x6240;</p>]]></description><link>http://www.fullstackyang.com/1-spring-security-6-2-x-jiao-ni-ru-he-kuai-su-gao-ding-pei-zhi/</link><guid isPermaLink="false">66238b35dfefff00015998c6</guid><category><![CDATA[dev]]></category><category><![CDATA[Spring Security]]></category><category><![CDATA[Java]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Sat, 20 Apr 2024 09:53:01 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2024/04/spring_security_lg-1280x720.png" medium="image"/><content:encoded><![CDATA[<h3 id="%E4%B8%80%E3%80%81%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5">&#x4E00;&#x3001;&#x57FA;&#x672C;&#x6982;&#x5FF5;</h3><img src="http://www.fullstackyang.com/content/images/2024/04/spring_security_lg-1280x720.png" alt="Spring Security 6.x &#x4E00;&#x6587;&#x5FEB;&#x901F;&#x641E;&#x61C2;&#x914D;&#x7F6E;&#x539F;&#x7406;"><p>Spring Security&#x6846;&#x67B6;&#x770B;&#x4F3C;&#x6BD4;&#x8F83;&#x590D;&#x6742;&#xFF0C;&#x4F46;&#x8BF4;&#x5230;&#x5E95;&#xFF0C;&#x6846;&#x67B6;&#x4E2D;&#x7684;&#x5404;&#x79CD;&#x5B89;&#x5168;&#x529F;&#x80FD;&#xFF0C;&#x57FA;&#x672C;&#x4E0A;&#x4E5F;&#x5C31;&#x662F;&#x4E00;&#x4E2A;&#x4E2A;Filter(javax.servlet.Filter)&#x7EC4;&#x6210;&#x7684;&#x6240;&#x8C13;&#x201C;&#x8FC7;&#x6EE4;&#x5668;&#x94FE;&#x201D;&#x5B9E;&#x73B0;&#x7684;&#xFF0C;&#x8FD9;&#x4E9B;Filter&#x4EE5;&#x804C;&#x8D23;&#x94FE;&#x7684;&#x8BBE;&#x8BA1;&#x6A21;&#x5F0F;&#x7EC4;&#x7EC7;&#x8D77;&#x6765;&#xFF0C;&#x73AF;&#x73AF;&#x76F8;&#x6263;&#xFF0C;&#x4E0D;&#x8FC7;&#x5728;&#x521A;&#x63A5;&#x89E6;Spring Security&#x6846;&#x67B6;&#x65F6;&#x4E0D;&#x5FC5;&#x76EF;&#x7740;&#x6BCF;&#x4E2A;Filter&#x7740;&#x91CD;&#x53BB;&#x7814;&#x7A76;&#xFF0C;&#x6211;&#x4EEC;&#x9996;&#x8981;&#x7684;&#x76EE;&#x7684;&#x662F;&#x5B66;&#x4F1A;&#x5982;&#x4F55;&#x5BF9;Spring Security&#x8FDB;&#x884C;&#x914D;&#x7F6E;&#xFF0C;&#x5F88;&#x591A;&#x4EBA;&#xFF0C;&#x7279;&#x522B;&#x662F;&#x65B0;&#x624B;&#xFF0C;&#x5728;&#x770B;&#x8FC7;&#x5B98;&#x65B9;&#x6587;&#x6863;&#x4E2D;&#x914D;&#x7F6E;&#x793A;&#x4F8B;&#x4EE3;&#x7801;&#xFF08;&#x5982;&#x4E0B;&#x6240;&#x793A;&#xFF09;&#x4E4B;&#x540E;&#xFF0C;&#x5728;&#x6CA1;&#x6709;&#x8DB3;&#x591F;&#x80CC;&#x666F;&#x77E5;&#x8BC6;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x90FD;&#x4F1A;&#x5BF9;&#x8FD9;&#x4E2A;http.build()&#x65B9;&#x6CD5;&#x611F;&#x5230;&#x83AB;&#x540D;&#x7684;&#x56F0;&#x60D1;&#xFF0C;&#x60F3;&#x8981;&#x5B9A;&#x5236;&#x5F00;&#x53D1;&#x4E5F;&#x4E0D;&#x77E5;&#x4ECE;&#x4F55;&#x4E0B;&#x624B;&#xFF0C;&#x672C;&#x6587;&#x4E3B;&#x8981;&#x5BF9;&#x6574;&#x4E2A;Spring Security&#x914D;&#x7F6E;&#x8FC7;&#x7A0B;&#x505A;&#x4E00;&#x5B9A;&#x7684;&#x5256;&#x6790;&#xFF0C;&#x5E0C;&#x671B;&#x53EF;&#x4EE5;&#x5BF9;&#x5B66;&#x4E60;Spring Sercurity&#x6846;&#x67B6;&#x7684;&#x540C;&#x5B66;&#x6240;&#x6709;&#x5E2E;&#x52A9;&#x3002;</p><blockquote>&#x7248;&#x672C;&#x8BF4;&#x660E;&#xFF1A;&#x4E0B;&#x6587;&#x6240;&#x8D34;&#x51FA;&#x7684;&#x5404;&#x6BB5;&#x6E90;&#x7801;&#x5747;&#x6E90;&#x81EA;6.2.3&#x7248;&#x672C;&#xFF0C;&#x4F46;&#x5176;&#x5B9E;5.7&#x4EE5;&#x4E0A;&#x7684;&#x5404;&#x4E2A;&#x7248;&#x672C;&#xFF0C;&#x8DDF;&#x914D;&#x7F6E;&#x76F8;&#x5173;&#x7684;&#x4EE3;&#x7801;&#x57FA;&#x672C;&#x76F8;&#x540C;&#xFF0C;&#x53D8;&#x52A8;&#x4E0D;&#x7B97;&#x592A;&#x5927;</blockquote><pre><code class="language-Java">@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
            .authorizeHttpRequests(authorize -&gt; authorize
                    .anyRequest().authenticated()
            )
            .formLogin(withDefaults())
            .httpBasic(withDefaults());
    return http.build();
}</code></pre><p>&#x6982;&#x51B5;&#x5730;&#x8BF4;&#xFF0C;HttpSecurity&#x7684;&#x914D;&#x7F6E;&#x8FC7;&#x7A0B;&#xFF0C;&#x4E3B;&#x8981;&#x5C31;&#x662F;&#x5411;&#x8FD9;&#x4E2A;SecurityFilterChian&#x4E2D;&#x6DFB;&#x52A0;&#x4E0D;&#x540C;&#x529F;&#x80FD;&#x7684;Filter&#x5BF9;&#x8C61;&#xFF0C;&#x4E3A;&#x4E86;&#x65B9;&#x4FBF;&#x540E;&#x6587;&#x7406;&#x89E3;&#xFF0C;&#x9996;&#x5148;&#x6765;&#x770B;&#x4E00;&#x4E0B;&#x5176;&#x4E2D;&#x6D89;&#x53CA;&#x7684;&#x51E0;&#x4E2A;&#x91CD;&#x8981;&#x7684;&#x63A5;&#x53E3;&#x548C;&#x7C7B;&#xFF08;&#x5173;&#x7CFB;&#x5982;&#x4E0B;&#x56FE;&#xFF09;<strong>&#x63A5;&#x53E3;</strong></p><ul><li>SecurityBuilder&#xFF1A;&#x9876;&#x5C42;&#x63A5;&#x53E3;&#xFF0C;&#x5B9A;&#x4E49;&#x4E86;&#x62BD;&#x8C61;&#x7684;&#x6CDB;&#x578B;&#x6784;&#x9020;&#x5668;&#x65B9;&#x6CD5;&#x2014;&#x2014;build()</li><li>SecurityConfigurer&#xFF1A;&#x9876;&#x5C42;&#x63A5;&#x53E3;&#xFF0C;&#x7528;&#x6765;&#x5B9A;&#x4E49;&#x914D;&#x7F6E;&#x7C7B;&#x7684;&#x901A;&#x7528;&#x65B9;&#x6CD5;&#xFF0C;&#x6BCF;&#x4E2A;Filter&#x90FD;&#x662F;&#x7531;&#x7279;&#x5B9A;&#x7684;SecurityConfigurer&#x7684;&#x5B9E;&#x73B0;&#x7C7B;&#x6784;&#x5EFA;&#x51FA;&#x6765;&#x5E76;&#x6DFB;&#x52A0;&#x5230;FilterChain&#x4E2D;&#x7684;</li><li>SecurityFilterChain&#xFF1A;&#x9876;&#x5C42;&#x63A5;&#x53E3;&#xFF0C;&#x5373;&#x8FC7;&#x6EE4;&#x5668;&#x94FE;&#xFF0C;&#x5B9A;&#x4E49;&#x4E86;&#x83B7;&#x53D6;List&#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x4EE5;&#x53CA;matches&#xFF0C;&#x7528;&#x4E8E;&#x5224;&#x65AD;&#x67D0;&#x4E2A;&#x8BF7;&#x6C42;&#x662F;&#x5426;&#x6EE1;&#x8DB3;&#x8FDB;&#x94FE;&#x7684;&#x6761;&#x4EF6;</li><li>HttpSecurityBuilder&#xFF1A;&#x7EE7;&#x627F;SecurityBuilder&#xFF0C;&#x5B9A;&#x4E49;&#x4E86;&#x6784;&#x5EFA;SecurityFilterChain&#x8FC7;&#x7A0B;&#x4E2D;&#x7684;&#x5404;&#x79CD;&#x8F85;&#x52A9;&#x65B9;&#x6CD5;&#xFF0C;&#x5982;&#x6DFB;&#x52A0;Filter&#x5230;SecurityFilterChain&#xFF0C;&#x83B7;&#x53D6;SecurityConfigurer&#x914D;&#x7F6E;&#x5B9E;&#x73B0;&#x7C7B;&#x7B49;<strong>&#x7C7B;</strong></li><li>AbstractSecurityBuilder&#xFF1A;&#x9876;&#x5C42;&#x7684;&#x62BD;&#x8C61;&#x7236;&#x7C7B;&#xFF0C;&#x5B83;&#x6CA1;&#x6709;&#x5B9E;&#x73B0;build&#x5177;&#x4F53;&#x7684;&#x903B;&#x8F91;&#xFF0C;&#x5B9E;&#x9645;&#x4EA4;&#x7531;doBuild&#x65B9;&#x6CD5;&#x5B9E;&#x73B0;&#xFF0C;&#x53EA;&#x662F;&#x7528;CAS&#x5BF9;doBuild&#x8FC7;&#x7A0B;&#x8FDB;&#x884C;&#x4E86;&#x5E76;&#x53D1;&#x63A7;&#x5236;</li><li>AbstractConfiguredSecurityBuilder&#xFF1A;&#x7EE7;&#x627F;&#x4E86;AbstractSecurityBuilder&#xFF0C;&#x5B83;&#x5185;&#x90E8;&#x7EF4;&#x62A4;&#x4E86;&#x4E00;&#x4E2A;SecurityConfigurer&#x7684;&#x5217;&#x8868;&#xFF0C;&#x5B9E;&#x73B0;&#x4E86;doBuild&#x65B9;&#x6CD5;&#xFF0C;&#x786E;&#x7ACB;&#x4E86;&#x6574;&#x4E2A;&#x6784;&#x5EFA;&#x7684;&#x6D41;&#x7A0B;</li><li>HttpSecurity &#x4F5C;&#x4E3A;final&#x5B9E;&#x73B0;&#x7C7B;&#xFF0C;&#x5B83;&#x4E3B;&#x8981;&#x9762;&#x5411;&#x5F00;&#x53D1;&#x8005;&#xFF0C;&#x6211;&#x4EEC;&#x5728;&#x5F00;&#x53D1;&#x8FC7;&#x7A0B;&#x4E2D;&#x5C31;&#x662F;&#x7528;&#x5B83;&#x63D0;&#x4F9B;&#x7684;&#x4E00;&#x7CFB;&#x5217;&#x7684;&#x914D;&#x7F6E;&#x5165;&#x53E3;&#xFF0C;&#x65B9;&#x4FBF;&#x5F00;&#x53D1;&#x8005;&#x5BF9;SecurityFilterChain&#x4E2D;&#x4E0D;&#x540C;&#x7684;Filter&#x8FDB;&#x884C;&#x5B9A;&#x5236;&#xFF0C;&#x5305;&#x62EC;&#x6DFB;&#x52A0;&#x81EA;&#x5B9A;&#x4E49;&#x7684;Filter&#xFF0C;&#x5173;&#x95ED;&#x67D0;&#x4E9B;Filter&#xFF0C;&#x6216;&#x6269;&#x5C55;&#x539F;&#x6765;Filter&#x7684;&#x80FD;&#x529B;&#x7B49;&#x7B49;</li></ul><figure class="kg-card kg-image-card"><img src="data:image/png;base64,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" class="kg-image" alt="Spring Security 6.x &#x4E00;&#x6587;&#x5FEB;&#x901F;&#x641E;&#x61C2;&#x914D;&#x7F6E;&#x539F;&#x7406;" loading="lazy"></figure><h3 id="%E4%BA%8C%E3%80%81%E5%9F%BA%E6%9C%AC%E6%B5%81%E7%A8%8B">&#x4E8C;&#x3001;&#x57FA;&#x672C;&#x6D41;&#x7A0B;</h3><p>&#x63A5;&#x4E0B;&#x6765;&#xFF0C;&#x91CD;&#x70B9;&#x5206;&#x6790;&#x4E00;&#x4E0B;AbstractConfiguredSecurityBuilder&#x7C7B;&#xFF0C;&#x6574;&#x4E2A;&#x6784;&#x5EFA;&#x8FC7;&#x7A0B;&#x56F4;&#x7ED5;doBuild&#x65B9;&#x6CD5;&#xFF0C;&#x4E3B;&#x8981;&#x5206;&#x4E3A;&#xFF1A;</p><ol><li>&#x521D;&#x59CB;&#x5316;&#xFF0C;&#x5305;&#x62EC;beforeInit&#x548C;init&#x65B9;&#x6CD5;&#xFF0C;&#x5176;&#x4E2D;beforeInit&#x662F;&#x6269;&#x5C55;&#x7528;&#x7684;&#x94A9;&#x5B50;&#x65B9;&#x6CD5;&#xFF0C;&#x9ED8;&#x8BA4;&#x5B9E;&#x73B0;&#x4E3A;&#x7A7A;</li><li>&#x914D;&#x7F6E;&#xFF0C;&#x5305;&#x62EC;beforeConfigure&#x548C;configure&#x65B9;&#x6CD5;&#xFF0C;&#x5176;&#x4E2D;beforeConfigure&#x662F;&#x6269;&#x5C55;&#x7528;&#x7684;&#x94A9;&#x5B50;&#x65B9;&#x6CD5;&#xFF0C;&#x9ED8;&#x8BA4;&#x5B9E;&#x73B0;&#x4E3A;&#x7A7A;</li><li>&#x6784;&#x9020;&#xFF0C;&#x5373;performBuild&#x65B9;&#x6CD5;&#xFF0C;&#x5177;&#x4F53;&#x7531;HttpSecurity&#x5B9E;&#x73B0;&#xFF0C;&#x4E3B;&#x8981;&#x662F;&#x5BF9;Filter&#x8FDB;&#x884C;&#x6392;&#x5E8F;&#xFF0C;&#x5E76;&#x6700;&#x7EC8;&#x8FD4;&#x56DE;DefaultSecurityFilterChain&#x7684;&#x5B9E;&#x4F8B;</li></ol><p>&#x800C;&#x5728;AbstractConfiguredSecurityBuilder&#x4E2D;&#x7EF4;&#x62A4;&#x4E86;&#x4E00;&#x4E2A;Map&lt;Class,List&lt;SecurityConfigure&gt;&gt;&#x5BF9;&#x8C61;&#xFF0C;&#x7528;&#x4E8E;&#x7F13;&#x5B58;&#x5404;&#x79CD;SecurityConfigure&#x7684;&#x5B9E;&#x73B0;&#x7C7B;&#xFF0C;&#x5F53;&#x8C03;&#x7528;init&#x548C;configure&#x65F6;&#xFF0C;&#x5B9E;&#x9645;&#x4E0A;&#x5C31;&#x4F1A;&#x904D;&#x5386;&#x8FD9;&#x4E2A;Map&#x6240;&#x6709;configurer&#xFF0C;&#x4F9D;&#x6B21;&#x8C03;&#x7528;&#x5BF9;&#x5E94;&#x65B9;&#x6CD5;&#xFF0C;<strong>&#x901A;&#x5E38;&#x5C31;&#x662F;&#x5728;configure&#x65B9;&#x6CD5;&#x4E2D;&#xFF0C;&#x5C06;Filter&#x52A0;&#x5165;&#x5230;FilterChain&#x4E2D;&#xFF08;&#x4E0B;&#x6587;&#x8BE6;&#x8FF0;&#xFF09;</strong></p><pre><code class="language-Java">protected final O doBuild() throws Exception {
    synchronized (this.configurers) {
       this.buildState = BuildState.INITIALIZING;
       beforeInit();
       init();
       this.buildState = BuildState.CONFIGURING;
       beforeConfigure();
       configure();
       this.buildState = BuildState.BUILDING;
       O result = performBuild();
       this.buildState = BuildState.BUILT;
       return result;
    }
}
 
 private void configure() throws Exception {
    Collection&lt;SecurityConfigurer&lt;O, B&gt;&gt; configurers = getConfigurers();
    for (SecurityConfigurer&lt;O, B&gt; configurer : configurers) {
       configurer.configure((B) this);
    }
}</code></pre><p>&#x90A3;&#x4E48;&#xFF0C;&#x8FD9;&#x4E9B;SecurityConfigure&#x5B9E;&#x4F8B;&#x5219;&#x662F;&#x5982;&#x4F55;&#x6DFB;&#x52A0;&#x4E0A;&#x8FF0;&#x7684;Map&#x4E2D;&#x7684;&#xFF1F;&#x53EF;&#x4EE5;&#x5728;HttpSecurityConfiguration&#x627E;&#x5230;&#x76F8;&#x5173;&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x6E90;&#x7801;&#x5982;&#x4E0B;</p><pre><code class="language-Java">@Bean(HTTPSECURITY_BEAN_NAME)
@Scope(&quot;prototype&quot;)
HttpSecurity httpSecurity() throws Exception {
    LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);
    AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(
          this.objectPostProcessor, passwordEncoder);
    authenticationBuilder.parentAuthenticationManager(authenticationManager());
    authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher());
    HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
    WebAsyncManagerIntegrationFilter webAsyncManagerIntegrationFilter = new WebAsyncManagerIntegrationFilter();
    webAsyncManagerIntegrationFilter.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
    // @formatter:off
    http
       .csrf(withDefaults())
       .addFilter(webAsyncManagerIntegrationFilter)
       .exceptionHandling(withDefaults())
       .headers(withDefaults())
       .sessionManagement(withDefaults())
       .securityContext(withDefaults())
       .requestCache(withDefaults())
       .anonymous(withDefaults())
       .servletApi(withDefaults())
       .apply(new DefaultLoginPageConfigurer&lt;&gt;());
    http.logout(withDefaults());
    // @formatter:on
    applyCorsIfAvailable(http);
    applyDefaultConfigurers(http);
    return http;
}</code></pre><p>&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x5728;&#x6784;&#x9020;&#x8FC7;&#x7A0B;&#x4E2D;&#xFF08;&#x90A3;&#x6BB5;&#x5F88;&#x957F;&#x94FE;&#x5F0F;&#x914D;&#x7F6E;&#xFF09;&#xFF0C;&#x5DF2;&#x7ECF;&#x5E2E;&#x6211;&#x4EEC;&#x6DFB;&#x52A0;&#x4E86;&#x82E5;&#x5E72;SecurityConfgurer&#x5B9E;&#x4F8B;&#xFF0C;&#x56E0;&#x6B64;&#x6211;&#x4EEC;&#x5728;&#x4F7F;&#x7528;&#x914D;&#x7F6E;SecurityFilterChain&#x65F6;&#xFF0C;&#x4EC5;&#x9700;&#x8981;&#x5F88;&#x5C11;&#x7684;&#x914D;&#x7F6E;&#x5C31;&#x53EF;&#x4EE5;&#x5F97;&#x5230;&#x4E00;&#x4E2A;&#x5B8C;&#x6574;&#x7684;&#x5177;&#x5907;&#x57FA;&#x672C;&#x529F;&#x80FD;&#x7684;SecurityFilterChain&#xFF0C;&#x5F53;&#x7136;&#x6211;&#x4EEC;&#x4E5F;&#x53EF;&#x4EE5;&#x5229;&#x7528;&#x8FD9;&#x4E9B;&#x914D;&#x7F6E;&#x9879;&#x505A;&#x5F88;&#x591A;&#x5B9A;&#x5236;&#x5F00;&#x53D1;&#x3002;&#x4E8B;&#x5B9E;&#x4E0A;&#xFF0C;HttpSecurity&#x5927;&#x7EA6;&#x63D0;&#x4F9B;&#x4E86;24&#x4E2A;Filter&#x76F8;&#x5173;&#x7684;Configurer&#x914D;&#x7F6E;&#x65B9;&#x6CD5;&#xFF0C;&#x5176;&#x4E2D;11&#x4E2A;Filter&#x662F;&#x9ED8;&#x8BA4;&#x52A0;&#x8F7D;&#x7684;&#xFF0C;&#x6574;&#x7406;&#x6210;&#x8868;&#x683C;&#xFF1A;</p><!--kg-card-begin: html--><table style="border-collapse:collapse;table-layout:fixed;white-space:nowrap;width:0;">
                <colgroup>
                    <col style="width: 100px;"><col style="width: 171px;"><col style="width: 431px;"><col style="width: 511px;">
                </colgroup>
                <tbody>
                    <tr style="height: 40px;">
            <td data-cell-id="9ghM-1713605505955" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x5E8F;&#x53F7;</span></div></td><td data-cell-id="6UOg-1713605505958" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x65B9;&#x6CD5;</span></div></td><td data-cell-id="2FBQ-1713605505961" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x5BF9;&#x5E94;Filter</span></div></td><td data-cell-id="wXPz-1713605505964" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x4F5C;&#x7528;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="Lmw4-1713605505968" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">1</span></div></td><td data-cell-id="Im76-1713605505971" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">headers</span></div></td><td data-cell-id="KnCY-1713605505974" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">HeaderWriterFilter(&#x9ED8;&#x8BA4;&#x52A0;&#x8F7D;&#xFF09;</span></div></td><td data-cell-id="Gb9B-1713605505978" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x6DFB;&#x52A0;Security HTTP header&#x5230;response&#x4E2D;&#xFF0C;&#x4F8B;&#x5982;X-Frame-Options</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="0uos-1713605505982" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">2</span></div></td><td data-cell-id="z1fR-1713605505985" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">cors</span></div></td><td data-cell-id="8b5X-1713605505988" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">CorsFilter&#xFF08;&#x901A;&#x5E38;&#x5728;Spring MVC&#x73AF;&#x5883;&#x65F6;&#x9ED8;&#x8BA4;&#x52A0;&#x8F7D;&#xFF09;</span></div></td><td data-cell-id="ExwO-1713605505991" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x652F;&#x6301;&#x8DE8;&#x57DF;&#x8BF7;&#x6C42;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="5Z6S-1713605505995" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">3</span></div></td><td data-cell-id="feTy-1713605505998" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">sessionManagement</span></div></td><td data-cell-id="fSG7-1713605506007" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">SessionManagementFilter</span></div><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">ConcurrentSessionFilter</span></div><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">DisableEncodeUrlFilter(&#x9ED8;&#x8BA4;&#x751F;&#x6548;&#xFF09;</span></div><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">ForceEagerSessionCreationFilter</span></div></td><td data-cell-id="oMna-1713605506010" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x7BA1;&#x7406;session&#xFF0C;&#x5982;&#x4FDD;&#x5B58;session&#xFF0C;&#x5E76;&#x53D1;&#x63A7;&#x5236;&#x7B49;&#x64CD;&#x4F5C;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="LaPU-1713605506014" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">4 </span></div></td><td data-cell-id="DZrI-1713605506017" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">jee</span></div></td><td data-cell-id="V7qt-1713605506020" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">J2eePreAuthenticatedProcessingFilter</span></div></td><td data-cell-id="CSyM-1713605506023" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x652F;&#x6301;Java EE &#x5BB9;&#x5668;&#x9884;&#x8BA4;&#x8BC1;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="gBiJ-1713605506027" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">5</span></div></td><td data-cell-id="B6AF-1713605506030" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">x509</span></div></td><td data-cell-id="7oRT-1713605506033" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">X509AuthenticationFilter</span></div></td><td data-cell-id="oXU3-1713605506036" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x652F;&#x6301;X.509&#x8BC1;&#x4E66;&#x9884;&#x8BA4;&#x8BC1;&#xFF0C;&#x901A;&#x5E38;&#x662F;&#x6307;&#x5728;&#x6D4F;&#x89C8;&#x5668;&#x4E2D;&#x4F7F;&#x7528;HTTPS&#x534F;&#x8BAE;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="MPPk-1713605506040" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">6</span></div></td><td data-cell-id="brs4-1713605506043" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">rememberMe</span></div></td><td data-cell-id="2HHh-1713605506046" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">RememberMeAuthenticationFilter</span></div></td><td data-cell-id="Loqh-1713605506049" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5728;&#x767B;&#x5F55;&#x65F6;&#x8BB0;&#x5F55;&#x7528;&#x6237;&#x767B;&#x5F55;&#x4FE1;&#x606F;&#xFF0C;&#x4EE5;&#x4FDD;&#x6301;&#x767B;&#x5F55;&#x6001;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="C3X3-1713605506053" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">7</span></div></td><td data-cell-id="eqGK-1713605506056" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">authorizeHttpRequests</span></div></td><td data-cell-id="UeMh-1713605506059" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">AuthorizationFilter</span></div></td><td data-cell-id="Ab5C-1713605506062" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;&#x6388;&#x6743;&#x8BBF;&#x95EE;&#x7684;&#x903B;&#x8F91;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="AEas-1713605506066" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">8</span></div></td><td data-cell-id="V5EF-1713605506069" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">requestCache</span></div></td><td data-cell-id="Mf0p-1713605506072" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">RequestCacheAwareFilter(&#x9ED8;&#x8BA4;&#x52A0;&#x8F7D;&#xFF09;</span></div></td><td data-cell-id="vOd2-1713605506075" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;&#x7528;&#x6237;&#x767B;&#x5F55;&#x4E4B;&#x540E;&#xFF0C;&#x8DF3;&#x8F6C;&#x56DE;&#x767B;&#x5F55;&#x4E4B;&#x524D;&#x8BF7;&#x6C42;&#x7684;&#x5730;&#x5740;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="RbeY-1713605506079" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">9</span></div></td><td data-cell-id="2hLX-1713605506082" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">exceptionHanding</span></div></td><td data-cell-id="vZie-1713605506085" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">ExceptionTranslationFilter(&#x9ED8;&#x8BA4;&#x52A0;&#x8F7D;&#xFF09;</span></div></td><td data-cell-id="K3pl-1713605506088" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x914D;&#x7F6E;&#x5F02;&#x5E38;&#x5904;&#x7406;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="JWAw-1713605506092" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">10</span></div></td><td data-cell-id="FcL2-1713605506095" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">securityContext</span></div></td><td data-cell-id="cZrY-1713605506100" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">SecurityContextHolderFilter(&#x9ED8;&#x8BA4;&#x52A0;&#x8F7D;&#xFF09;</span></div><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">SecurityContextPersistenceFilter&#xFF08;&#x65E7;&#x7248;&#x672C;&#xFF0C;&#x73B0;&#x4E0D;&#x63A8;&#x8350;&#x4F7F;&#x7528;&#xFF09;</span></div></td><td data-cell-id="YQar-1713605506104" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x52A0;&#x8F7D;&#x7528;&#x6237;&#x7684;&#x767B;&#x5F55;&#x6001;&#x4FE1;&#x606F;&#xFF0C;&#x5E76;&#x4FDD;&#x5B58;&#x5728;SecurityContextHolder&#x4E2D;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="vI6Y-1713605506108" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">11</span></div></td><td data-cell-id="RPfg-1713605506111" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">servletApi</span></div></td><td data-cell-id="0Fzv-1713605506114" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">SecurityContextHolderAwareRequestFilter(&#x9ED8;&#x8BA4;&#x52A0;&#x8F7D;&#xFF09;</span></div></td><td data-cell-id="93uo-1713605506117" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5C06;HttpServletRequest&#x5305;&#x88C5;&#x4E3A;Servlet3SecurityContextHolderAwareRequestWrapper&#xFF0C;&#x65B9;&#x4FBF;&#x5176;&#x4ED6;Filter&#x4F7F;&#x7528;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="BTEF-1713605506121" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">12</span></div></td><td data-cell-id="zYSa-1713605506124" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">csrf</span></div></td><td data-cell-id="a3Hn-1713605506127" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">CsrfFilter(&#x9ED8;&#x8BA4;&#x52A0;&#x8F7D;&#xFF09;</span></div></td><td data-cell-id="BLxs-1713605506130" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x9632;&#x8303;&#x8DE8;&#x7AD9;&#x8BF7;&#x6C42;&#x4F2A;&#x9020;&#xFF08;CSRF&#xFF09;&#x653B;&#x51FB;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="veRK-1713605506134" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">13</span></div></td><td data-cell-id="dl2D-1713605506137" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">logout</span></div></td><td data-cell-id="nvdy-1713605506140" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">LogoutFilter(&#x9ED8;&#x8BA4;&#x52A0;&#x8F7D;&#xFF09;</span></div></td><td data-cell-id="z6rA-1713605506143" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;&#x767B;&#x51FA;&#x6CE8;&#x9500;&#x903B;&#x8F91;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="KBlc-1713605506147" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">14</span></div></td><td data-cell-id="kLoi-1713605506150" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">anonymous</span></div></td><td data-cell-id="l1VA-1713605506153" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">AnonymousAuthenticationFilter(&#x9ED8;&#x8BA4;&#x52A0;&#x8F7D;&#xFF09;</span></div></td><td data-cell-id="9zNM-1713605506156" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;&#x533F;&#x540D;&#x767B;&#x5F55;&#x903B;&#x8F91;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="xxw5-1713605506160" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">15</span></div></td><td data-cell-id="I0rM-1713605506163" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">formLogin</span></div></td><td data-cell-id="HbES-1713605506166" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">UsernamePasswordAuthenticationFilter</span></div></td><td data-cell-id="9dw2-1713605506169" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;&#x7528;&#x6237;&#x540D;&#x5BC6;&#x7801;&#x767B;&#x5F55;&#x903B;&#x8F91;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="XEuC-1713605506173" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">16</span></div></td><td data-cell-id="dzR8-1713605506176" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">saml2Login</span></div></td><td data-cell-id="aK4S-1713605506179" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">Saml2WebSsoAuthenticationFilter</span></div></td><td data-cell-id="suKy-1713605506182" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;SAML 2.0&#x8BA4;&#x8BC1;&#x534F;&#x8BAE;&#x767B;&#x5F55;&#x903B;&#x8F91;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="hP5W-1713605506186" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">17</span></div></td><td data-cell-id="cSV7-1713605506189" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">saml2Logout</span></div></td><td data-cell-id="F0OV-1713605506196" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">Saml2LogoutRequestFilter</span></div><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">Saml2LogoutResponseFilter</span></div><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">Saml2RelyingPartyInitiatedLogoutFilter</span></div></td><td data-cell-id="ZCYg-1713605506199" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;SAML 2.0&#x8BA4;&#x8BC1;&#x534F;&#x8BAE;&#x767B;&#x51FA;&#x903B;&#x8F91;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="CbIj-1713605506203" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">18</span></div></td><td data-cell-id="m313-1713605506206" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">oauth2Login</span></div></td><td data-cell-id="o7Wx-1713605506209" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">OAuth2AuthorizationRequestRedirectFilter</span></div></td><td data-cell-id="rNyt-1713605506212" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x63A5;&#x5165;OAuth2.0&#x8BA4;&#x8BC1;&#x534F;&#x8BAE;&#x767B;&#x5F55;&#x903B;&#x8F91;&#xFF0C;&#x4F8B;&#x5982;Github&#x767B;&#x5F55;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="bHAQ-1713605506216" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">19</span></div></td><td data-cell-id="IOAd-1713605506219" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">oidcLogout</span></div></td><td data-cell-id="AOYU-1713605506223" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">OidcBackChannelLogoutFilter</span></div></td><td data-cell-id="ZB1W-1713605506226" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;OIDC&#x8BA4;&#x8BC1;&#x534F;&#x8BAE;&#x767B;&#x51FA;&#x903B;&#x8F91;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="Ceky-1713605506230" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">20</span></div></td><td data-cell-id="1zBV-1713605506233" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">oauth2Client</span></div></td><td data-cell-id="DTdq-1713605506238" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">OAuth2AuthorizationRequestRedirectFilter</span></div><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">OAuth2AuthorizationCodeGrantFilter</span></div></td><td data-cell-id="BFTV-1713605506241" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;OAuth2.0&#x5BA2;&#x6237;&#x7AEF;&#x903B;&#x8F91;&#xFF0C;&#x4F8B;&#x5982;&#x6388;&#x6743;&#x7801;&#x6A21;&#x5F0F;&#x7B49;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="X4XE-1713605506245" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">21</span></div></td><td data-cell-id="25bz-1713605506248" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">oauth2ResourceServer</span></div></td><td data-cell-id="gWWU-1713605506251" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">BearerTokenAuthenticationFilter</span></div></td><td data-cell-id="x4Kv-1713605506254" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;OAuth2.0&#x670D;&#x52A1;&#x7AEF;&#x903B;&#x8F91;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="xaoJ-1713605506258" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">22</span></div></td><td data-cell-id="aBAa-1713605506261" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">requiresChannel</span></div></td><td data-cell-id="i2Cr-1713605506264" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">ChannelProcessingFilter</span></div></td><td data-cell-id="Y89m-1713605506267" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5224;&#x65AD;&#x54EA;&#x4E9B;&#x8D44;&#x6E90;&#x9700;&#x8981;&#x88AB;&#x4FDD;&#x62A4;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="JB3k-1713605506271" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">23</span></div></td><td data-cell-id="zw00-1713605506274" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">httpBasic</span></div></td><td data-cell-id="dElu-1713605506277" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">BasicAuthenticationFilter</span></div></td><td data-cell-id="yC5a-1713605506280" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;HTTP&#x57FA;&#x7840;&#x8BA4;&#x8BC1;&#x7684;&#x903B;&#x8F91;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="L07q-1713605506284" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">24</span></div></td><td data-cell-id="KI2F-1713605506287" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">passwordManagement</span></div></td><td data-cell-id="5V36-1713605506290" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">RequestMatcherRedirectFilter(&quot;/change-password&quot;)</span></div></td><td data-cell-id="7OTA-1713605506293" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5B9E;&#x73B0;&#x5728;&#x9700;&#x8981;&#x4FEE;&#x6539;&#x5BC6;&#x7801;&#x65F6;&#xFF0C;&#x8DF3;&#x8F6C;&#x9875;&#x9762;&#x7684;&#x903B;&#x8F91;</span></div></td>
        </tr><tr style="height: 40px;">
            <td data-cell-id="2I2m-1713605506297" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">25</span></div></td><td data-cell-id="LRV5-1713605506300" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">HttpSecurityConfiguraion&#x76F4;&#x63A5;&#x6DFB;&#x52A0;</span></div></td><td data-cell-id="CTot-1713605506303" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">WebAsyncManagerIntegrationFilter(&#x9ED8;&#x8BA4;&#x52A0;&#x8F7D;&#xFF09;</span></div></td><td data-cell-id="0z4G-1713605506306" style="border:1px solid rgb(167, 167, 167);overflow:hidden;font-size:14px;overflow-wrap:break-word;white-space:pre-wrap;color:rgb(57, 57, 57);"><div class="table-cell-line"><span style="font-family: Microsoft YaHei, STXihei;background-color: rgba(0, 0, 0, 0);font-size: 14px;color: rgb(0, 0, 0);">&#x7528;&#x4E8E;&#x5728;&#x5F02;&#x6B65;&#x7EBF;&#x7A0B;&#x4E2D;&#xFF0C;&#x652F;&#x6301;&#x901A;&#x8FC7;SecurityContextHolder&#x83B7;&#x53D6;&#x8BA4;&#x8BC1;&#x5BF9;&#x8C61;Authentication</span></div></td>
        </tr>
                </tbody>
            </table><!--kg-card-end: html--><p>&#x5982;&#x679C;&#x6211;&#x4EEC;&#x4E0D;&#x5BF9;HttpSecurity&#x505A;&#x4EFB;&#x4F55;&#x6539;&#x52A8;&#x7684;&#x8BDD;&#xFF0C;&#x9ED8;&#x8BA4;&#x5F97;&#x5230;&#x7684;SecurityFilterChain&#x662F;&#x5982;&#x4E0B;&#x8FD9;&#x6837;&#x7684;&#xFF0C;&#x5148;&#x4E86;&#x89E3;&#x5927;&#x6982;&#xFF0C;&#x540E;&#x7EED;&#x8FD8;&#x9488;&#x5BF9;&#x90E8;&#x5206;&#x91CD;&#x8981;&#x7684;filter&#x505A;&#x6DF1;&#x5165;&#x5206;&#x6790;&#x3002;</p><pre><code class="language-Java">org.springframework.security.web.session.DisableEncodeUrlFilter
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter
org.springframework.security.web.context.SecurityContextHolderFilter
org.springframework.security.web.header.HeaderWriterFilter
org.springframework.web.filter.CorsFilter
org.springframework.security.web.csrf.CsrfFilter
org.springframework.security.web.authentication.logout.LogoutFilter
org.springframework.security.web.savedrequest.RequestCacheAwareFilter
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
org.springframework.security.web.authentication.AnonymousAuthenticationFilter
org.springframework.security.web.access.ExceptionTranslationFilter</code></pre><h3 id="%E4%B8%89%E3%80%81securityconfigurer%E4%B8%BE%E4%BE%8B">&#x4E09;&#x3001;SecurityConfigurer&#x4E3E;&#x4F8B;</h3><p>&#x8FD9;&#x91CC;&#x8FD8;&#x662F;&#x4EE5;Spring Security&#x5B98;&#x65B9;&#x6587;&#x6863;&#x4E2D;&#x914D;&#x7F6E;&#x7684;&#x793A;&#x4F8B;&#x4EE3;&#x7801;&#x4E3A;&#x4F8B;&#xFF0C;&#x914D;&#x7F6E;&#x4EE3;&#x7801;&#x53EA;&#x9700;&#x51E0;&#x884C;&#xFF0C;&#x6BD4;&#x8F83;&#x4F18;&#x96C5;&#xFF0C;&#x8FD9;&#x79CD;&#x8BBE;&#x8BA1;&#x662F;&#x503C;&#x5F97;&#x5B66;&#x4E60;&#x7684;&#xFF0C;&#x5C3D;&#x91CF;&#x8BA9;&#x590D;&#x6742;&#x7684;&#x914D;&#x7F6E;&#x903B;&#x8F91;&#x5C01;&#x88C5;&#x8D77;&#x6765;&#xFF0C;&#x8BA9;&#x5F00;&#x53D1;&#x8005;&#x5728;&#x4F7F;&#x7528;&#x65F6;&#xFF0C;&#x53EA;&#x9700;&#x8981;&#x5173;&#x6CE8;&#x4E1A;&#x52A1;&#x903B;&#x8F91;&#x5373;&#x53EF;</p><pre><code class="language-Java">@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
            .authorizeHttpRequests(authorize -&gt; authorize
                    .anyRequest().authenticated()
            )
            .formLogin(withDefaults())
            .httpBasic(withDefaults());
    return http.build();
}</code></pre><p>Spring Security&#x63D0;&#x4F9B;&#x4E86;&#x4E24;&#x79CD;&#x65B9;&#x5F0F;&#x8FDB;&#x884C;&#x914D;&#x7F6E;&#xFF0C;&#x4E00;&#x79CD;&#x5C31;&#x662F;&#x793A;&#x4F8B;&#x4EE3;&#x7801;&#x4E2D;&#xFF0C;&#x5373;&#x5229;&#x7528;lambda&#x8868;&#x8FBE;&#x5F0F;&#x5B9E;&#x73B0;&#x914D;&#x7F6E;&#x903B;&#x8F91;&#xFF0C;&#x8FD9;&#x662F;5.5&#x7248;&#x672C;&#x5F15;&#x5165;&#x7684;&#xFF0C;&#x5728;&#x8FD9;&#x4E4B;&#x524D;&#x662F;&#x4F7F;&#x7528;&#x65E0;&#x53C2;&#x7684;&#x65B9;&#x6CD5;&#x83B7;&#x53D6;&#x914D;&#x7F6E;&#x5BF9;&#x8C61; &#xFF0C;&#x7136;&#x540E;&#x8FDB;&#x884C;&#x94FE;&#x5F0F;&#x7684;&#x914D;&#x7F6E;&#xFF0C;&#x5982;&#x4E0A;&#x8FF0;&#x793A;&#x4F8B;&#x4EE3;&#x7801;&#x53EF;&#x4EE5;&#x6539;&#x5199;&#x4E3A;</p><pre><code class="language-Java">@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.
            authorizeHttpRequests().anyRequest().authenticated()
            .and().formLogin()
            .and().httpBasic();
    return http.build();

}</code></pre><p>&#x4EE5;authorizeHttpRequests&#x4E3A;&#x4F8B;&#x770B;&#x4E00;&#x4E0B;&#x6E90;&#x7801;&#x5B9E;&#x73B0;&#xFF0C;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x4E24;&#x79CD;&#x65B9;&#x5F0F;&#x5927;&#x540C;&#x5C0F;&#x5F02;&#xFF0C;&#x53EA;&#x662F;&#x4F7F;&#x7528;&#x4E86;Customer&#x51FD;&#x6570;&#x5F0F;&#x63A5;&#x53E3;&#x8FDB;&#x884C;&#x4E86;&#x5C01;&#x88C5;</p><pre><code class="language-Java">@Deprecated(since = &quot;6.1&quot;, forRemoval = true)
public AuthorizeHttpRequestsConfigurer&lt;HttpSecurity&gt;.AuthorizationManagerRequestMatcherRegistry authorizeHttpRequests()
       throws Exception {
    ApplicationContext context = getContext();
    return getOrApply(new AuthorizeHttpRequestsConfigurer&lt;&gt;(context)).getRegistry();
}

public HttpSecurity authorizeHttpRequests(
       Customizer&lt;AuthorizeHttpRequestsConfigurer&lt;HttpSecurity&gt;.AuthorizationManagerRequestMatcherRegistry&gt; authorizeHttpRequestsCustomizer)
       throws Exception {
    ApplicationContext context = getContext();
    authorizeHttpRequestsCustomizer
       .customize(getOrApply(new AuthorizeHttpRequestsConfigurer&lt;&gt;(context)).getRegistry());
    return HttpSecurity.this;
}</code></pre><p>&#x5176;&#x4E2D;getOrApply&#x65B9;&#x6CD5;&#xFF0C;&#x7528;&#x4E8E;&#x83B7;&#x53D6;&#x5230;Configurer&#x7684;&#x5177;&#x4F53;&#x5B9E;&#x4F8B;&#xFF08;&#x4E0A;&#x6587;&#x4E2D;&#x63D0;&#x5230;&#x8FC7;&#x5728;AbstractConfiguredSecurityBuilder&#x4E2D;&#x7EF4;&#x62A4;&#x4E86;&#x4E00;&#x4E2A;Configurers&#x7684;Map&#xFF0C;&#x8FD9;&#x4E9B;Configurer&#x5B9E;&#x4F8B;&#x4FBF;&#x662F;&#x4ECE;&#x8FD9;&#x4E2A;Map&#x83B7;&#x53D6;&#x7684;&#xFF09;</p><p>&#x4E0D;&#x8FC7;&#x7B2C;&#x4E8C;&#x79CD;&#x5199;&#x6CD5;&#xFF0C;&#x6839;&#x636E;&#x6E90;&#x7801;&#x7684;&#x6CE8;&#x91CA;&#xFF0C;&#x5E94;&#x8BE5;&#x4F1A;&#x5728;Spring Security 7&#x7248;&#x672C;&#x91CC;&#x9762;&#x79FB;&#x9664;&#xFF0C;&#x6240;&#x4EE5;&#x8FD8;&#x662F;&#x8981;&#x9002;&#x5E94;&#x8FD9;&#x79CD;Customizer&#x53C2;&#x6570;&#x7684;&#x914D;&#x7F6E;&#x65B9;&#x6CD5;&#x3002;</p><p>&#x4E0A;&#x9762;authorizeHttpRequests&#x65B9;&#x6CD5;&#x8FD4;&#x56DE;&#x7684;&#x662F;AuthorizeHttpRequestsConfigurer&#x7C7B;&#x4E2D;&#x7684;AuthorizationManagerRequestMatcherRegistry&#x5BF9;&#x8C61;&#xFF0C;&#x53EF;&#x4EE5;&#x5148;&#x770B;&#x4E00;&#x4E0B;AuthorizeHttpRequestsConfigurer&#x4E2D;&#x7684;configure&#x65B9;&#x6CD5;</p><pre><code class="language-Java">public void configure(H http) {
    AuthorizationManager&lt;HttpServletRequest&gt; authorizationManager = this.registry.createAuthorizationManager();
    AuthorizationFilter authorizationFilter = new AuthorizationFilter(authorizationManager);
    authorizationFilter.setAuthorizationEventPublisher(this.publisher);
    authorizationFilter.setShouldFilterAllDispatcherTypes(this.registry.shouldFilterAllDispatcherTypes);
    authorizationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
    http.addFilter(postProcess(authorizationFilter));
}</code></pre><p>&#x8FD9;&#x91CC;&#x521B;&#x5EFA;&#x4E86;&#x4E00;&#x4E2A;AuthorizationFilter&#xFF0C;&#x5E76;&#x6DFB;&#x52A0;&#x5230;HttpSecurity&#x7684;List&#x4E2D;&#xFF0C;&#x800C;AuthorizationManagerRequestMatcherRegistry&#x5219;&#x53C8;&#x662F;&#x4E00;&#x4E2A;&#x6784;&#x9020;&#x5668;&#x6A21;&#x5F0F;&#x5B9E;&#x73B0;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#xFF0C;&#x4E3B;&#x8981;&#x529F;&#x80FD;&#x5C31;&#x662F;&#x914D;&#x7F6E;&#x4E00;&#x4E9B;&#x6743;&#x9650;&#x62E6;&#x622A;&#x7684;&#x5177;&#x4F53;&#x903B;&#x8F91;&#xFF0C;&#x5982;&#x54EA;&#x4E9B;&#x5730;&#x5740;&#x9700;&#x8981;&#x4EC0;&#x4E48;&#x89D2;&#x8272;&#x8BBF;&#x95EE;&#x7B49;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x4E0D;&#x5C55;&#x5F00;&#x4E86;&#x3002;</p><p>&#x518D;&#x770B;&#x4E00;&#x4E0B;formLogin&#x7684;&#x4F8B;&#x5B50;</p><pre><code class="language-Java">public HttpSecurity formLogin(Customizer&lt;FormLoginConfigurer&lt;HttpSecurity&gt;&gt; formLoginCustomizer) throws Exception {
    formLoginCustomizer.customize(getOrApply(new FormLoginConfigurer&lt;&gt;()));
    return HttpSecurity.this;
}
</code></pre><p>formLogin&#x65B9;&#x6CD5;&#x5B9E;&#x9645;&#x4E0A;&#x521B;&#x5EFA;FormLoginConfigurer&#x7684;&#x793A;&#x4F8B;&#xFF0C;&#x8BE5;&#x7C7B;&#x4E3B;&#x8981;&#x7528;&#x4E8E;&#x521B;&#x5EFA;UsernamePasswordAuthenticationFilter&#xFF0C;&#x5373;&#x9ED8;&#x8BA4;&#x7684;&#x7528;&#x6237;&#x540D;&#x5BC6;&#x7801;&#x8BA4;&#x8BC1;&#x7684;&#x8FC7;&#x6EE4;&#x5668;&#x3002;</p><p>&#x5176;&#x4E2D;&#x7684;configure&#x65B9;&#x6CD5;&#x7531;&#x7236;&#x7C7B;AbstractAuthenticationFilterConfigurer&#x5B9E;&#x73B0;&#xFF0C;&#x6E90;&#x7801;&#x5982;&#x4E0B;&#xFF0C;&#x867D;&#x7136;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x6709;&#x70B9;&#x957F;&#xFF0C;&#x4F46;&#x57FA;&#x672C;&#x662F;&#x56F4;&#x7ED5;&#x914D;&#x7F6E;UsernamePasswordAuthenticationFilter&#x5B9E;&#x4F8B;&#x800C;&#x5C55;&#x5F00;&#xFF08;this.authFilter&#x5C31;&#x662F;UsernamePasswordAuthenticationFilter&#x7684;&#x5B9E;&#x4F8B;&#xFF0C;&#x5B83;&#x5728;FormLoginConfigurer&#x7684;&#x6784;&#x9020;&#x51FD;&#x6570;&#x4E2D;&#x521B;&#x5EFA;&#x51FA;&#x6765;&#xFF09;&#xFF0C;&#x4E3B;&#x8981;&#x5C31;&#x662F;&#x521B;&#x5EFA;&#x7528;&#x6237;&#x8BA4;&#x8BC1;&#x6240;&#x7528;&#x5230;&#x7684;&#x4E00;&#x4E9B;&#x57FA;&#x672C;&#x7EC4;&#x4EF6;&#xFF0C;&#x4F8B;&#x5982;AuthenticationManager&#x7528;&#x4E8E;&#x5C01;&#x88C5;&#x4E0D;&#x540C;&#x7684;&#x7528;&#x6237;&#x8BA4;&#x8BC1;&#x65B9;&#x5F0F;&#xFF08;&#x5982;&#x7528;&#x6237;&#x540D;&#x5BC6;&#x7801;&#xFF09;&#xFF0C;AuthenticationSuccessHandler&#x7528;&#x4E8E;&#x5C01;&#x88C5;&#x8BA4;&#x8BC1;&#x6210;&#x529F;&#x540E;&#x6267;&#x884C;&#x7684;&#x64CD;&#x4F5C;&#xFF0C;AuthenticationFailureHandler&#x7528;&#x4E8E;&#x5C01;&#x88C5;&#x8BA4;&#x8BC1;&#x5931;&#x8D25;&#x540E;&#x6267;&#x884C;&#x7684;&#x64CD;&#x4F5C;&#x7B49;&#x7B49;</p><pre><code class="language-Java">@Override
public void configure(B http) throws Exception {
    PortMapper portMapper = http.getSharedObject(PortMapper.class);
    if (portMapper != null) {
       this.authenticationEntryPoint.setPortMapper(portMapper);
    }
    RequestCache requestCache = http.getSharedObject(RequestCache.class);
    if (requestCache != null) {
       this.defaultSuccessHandler.setRequestCache(requestCache);
    }
    this.authFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
    this.authFilter.setAuthenticationSuccessHandler(this.successHandler);
    this.authFilter.setAuthenticationFailureHandler(this.failureHandler);
    if (this.authenticationDetailsSource != null) {
       this.authFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
    }
    SessionAuthenticationStrategy sessionAuthenticationStrategy = http
       .getSharedObject(SessionAuthenticationStrategy.class);
    if (sessionAuthenticationStrategy != null) {
       this.authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
    }
    RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
    if (rememberMeServices != null) {
       this.authFilter.setRememberMeServices(rememberMeServices);
    }
    SecurityContextConfigurer securityContextConfigurer = http.getConfigurer(SecurityContextConfigurer.class);
    if (securityContextConfigurer != null &amp;&amp; securityContextConfigurer.isRequireExplicitSave()) {
       SecurityContextRepository securityContextRepository = securityContextConfigurer
          .getSecurityContextRepository();
       this.authFilter.setSecurityContextRepository(securityContextRepository);
    }
    this.authFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
    F filter = postProcess(this.authFilter);
    http.addFilter(filter);
}</code></pre><p>&#x901A;&#x8FC7;&#x4E0A;&#x9762;&#x4E24;&#x4E2A;&#x6E90;&#x7801;&#x793A;&#x4F8B;&#xFF0C;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x914D;&#x7F6E;Filter&#x7684;&#x8FC7;&#x7A0B;&#x5176;&#x5B9E;&#x5E76;&#x4E0D;&#x590D;&#x6742;&#xFF0C;&#x5F53;&#x6211;&#x4EEC;&#x5728;&#x7814;&#x7A76;Spring Security&#x4E0D;&#x540C;&#x8FC7;&#x6EE4;&#x5668;&#x529F;&#x80FD;&#x65F6;&#xFF0C;&#x53EF;&#x4EE5;&#x53C2;&#x8003;&#x6E90;&#x7801;&#x4E2D;configure&#x7684;&#x914D;&#x7F6E;&#x8FC7;&#x7A0B;&#xFF0C;&#x5206;&#x6790;&#x5B83;&#x4EEC;&#x6709;&#x54EA;&#x4E9B;&#x914D;&#x7F6E;&#x9879;&#xFF0C;&#x8FD9;&#x4E9B;&#x914D;&#x7F6E;&#x70B9;&#x4E3B;&#x8981;&#x80FD;&#x63D0;&#x4F9B;&#x4EC0;&#x4E48;&#x6837;&#x80FD;&#x529B;&#x7684;&#x7B49;&#xFF0C;&#x4ECE;&#x800C;&#x6253;&#x5F00;&#x601D;&#x8DEF;&#xFF0C;&#x5FEB;&#x901F;&#x5B9E;&#x73B0;&#x4E0D;&#x540C;&#x7684;&#x5B9A;&#x5236;&#x9700;&#x6C42;&#x3002;</p><h3 id="%E5%9B%9B%E3%80%81%E6%80%BB%E7%BB%93">&#x56DB;&#x3001;&#x603B;&#x7ED3;</h3><p>&#x6700;&#x540E;&#x505A;&#x4E00;&#x4E2A;&#x7B80;&#x5355;&#x7684;&#x603B;&#x7ED3;&#xFF0C;&#x5982;&#x56FE;&#x6240;&#x793A;&#xFF1A;</p><ol><li>&#x4ECE;HttpSercurityConfiguration&#x5B9A;&#x4E49;HttpSecurity&#x7684;Bean&#x5BF9;&#x8C61;&#x5F00;&#x59CB;&#xFF0C;&#x4FBF;&#x5411;HttpSecurity&#x4E2D;&#x6DFB;&#x52A0;&#x4E86;&#x82E5;&#x5E72;SecurityConfigurer&#x5BF9;&#x8C61;&#xFF0C;&#x53E6;&#x5916;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x5728;&#x81EA;&#x5B9A;&#x4E49;&#x7684;&#x914D;&#x7F6E;&#x7C7B;&#x4E2D;&#x5BF9;&#x5176;&#x8FDB;&#x884C;&#x4E00;&#x4E9B;&#x5B9A;&#x5236;&#x8C03;&#x6574;</li><li>&#x7136;&#x540E;&#x5F53;&#x8C03;&#x7528;HttpSecurity#Build()&#x65B9;&#x6CD5;&#x65F6;&#xFF0C;&#x5C31;&#x4F1A;&#x5C06;&#x53D6;&#x5F97;&#x6240;&#x6709;SecurityConfigurer&#x8FDB;&#x884C;&#x904D;&#x5386;&#xFF0C;&#x4F9D;&#x6B21;&#x8C03;&#x7528;&#x5BF9;&#x5E94;&#x7684;init&#x548C;configurer&#x65B9;&#x6CD5;&#xFF0C;&#x800C;&#x5728;configurer&#x65B9;&#x6CD5;&#x4E2D;&#xFF0C;&#x521B;&#x5EFA;&#x51FA;&#x5404;&#x79CD;&#x529F;&#x80FD;&#x7684;Filter&#x5B9E;&#x4F8B;&#xFF0C;&#x5E76;&#x6DFB;&#x52A0;&#x5230;List&#x5217;&#x8868;&#x4E2D;</li><li>&#x6700;&#x540E;&#x901A;&#x8FC7;performBuild&#x65B9;&#x6CD5;&#xFF0C;&#x5C06;List&#x8FDB;&#x884C;&#x6392;&#x5E8F;&#xFF0C;&#x5E76;&#x521B;&#x5EFA;&#x51FA;DefaultSecurityFilterChian&#x81F3;&#x6B64;&#x6574;&#x4E2A;&#x8FC7;&#x6EE4;&#x5668;&#x94FE;&#x7684;&#x6784;&#x5EFA;&#x5C31;&#x5B8C;&#x6210;&#x4E86;&#x3002;</li></ol><figure class="kg-card kg-image-card"><img src="http://www.fullstackyang.com/content/images/2024/04/1.jpg" class="kg-image" alt="Spring Security 6.x &#x4E00;&#x6587;&#x5FEB;&#x901F;&#x641E;&#x61C2;&#x914D;&#x7F6E;&#x539F;&#x7406;" loading="lazy" width="1273" height="418" srcset="http://www.fullstackyang.com/content/images/size/w600/2024/04/1.jpg 600w, http://www.fullstackyang.com/content/images/size/w1000/2024/04/1.jpg 1000w, http://www.fullstackyang.com/content/images/2024/04/1.jpg 1273w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA[[轮子系列]Google Guava之CharMatcher源码分析]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>&#x6700;&#x8FD1;&#x9047;&#x5230;&#x4E86;&#x4E00;&#x4E9B;&#x5B57;&#x7B26;&#x5339;&#x914D;&#x7684;&#x9700;&#x6C42;&#xFF0C;&#x8FDB;&#x800C;&#x4ED4;&#x7EC6;&#x5730;&#x770B;&#x4E86;CharMatcher&#x7684;&#x6E90;&#x7801;&#xFF0C;&#x53D1;&#x73B0;&#x8FD8;&#x662F;&#x6709;&#x70B9;&#x4E1C;&#x897F;&#x503C;&#x5F97;&#x56DE;&#x5473;&#xFF0C;&#x4F8B;&#x5982;&#x5B83;&#x4E3A;&#x6211;&#x4EEC;&#x63D0;&#x4F9B;&#x4E86;&#x5982;</p>]]></description><link>http://www.fullstackyang.com/lun-zi-xi-lie-google-guavazhi-charmatcher/</link><guid isPermaLink="false">624567890d2dd3000190a005</guid><category><![CDATA[dev]]></category><category><![CDATA[guava]]></category><category><![CDATA[轮子系列]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Mon, 23 Jul 2018 07:01:54 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2018/07/004.00.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="http://www.fullstackyang.com/content/images/2018/07/004.00.png" alt="[&#x8F6E;&#x5B50;&#x7CFB;&#x5217;]Google Guava&#x4E4B;CharMatcher&#x6E90;&#x7801;&#x5206;&#x6790;"><p>&#x6700;&#x8FD1;&#x9047;&#x5230;&#x4E86;&#x4E00;&#x4E9B;&#x5B57;&#x7B26;&#x5339;&#x914D;&#x7684;&#x9700;&#x6C42;&#xFF0C;&#x8FDB;&#x800C;&#x4ED4;&#x7EC6;&#x5730;&#x770B;&#x4E86;CharMatcher&#x7684;&#x6E90;&#x7801;&#xFF0C;&#x53D1;&#x73B0;&#x8FD8;&#x662F;&#x6709;&#x70B9;&#x4E1C;&#x897F;&#x503C;&#x5F97;&#x56DE;&#x5473;&#xFF0C;&#x4F8B;&#x5982;&#x5B83;&#x4E3A;&#x6211;&#x4EEC;&#x63D0;&#x4F9B;&#x4E86;&#x5982;&#x4F55;&#x5728;&#x591A;&#x79CD;&#x5B57;&#x7B26;&#x7C7B;&#x578B;&#x573A;&#x666F;&#x4E0B;&#x63D0;&#x9AD8;&#x7075;&#x6D3B;&#x6027;&#x4ECE;&#x800C;&#x6EE1;&#x8DB3;&#x4E0D;&#x540C;&#x5339;&#x914D;&#x9700;&#x6C42;&#x7684;&#x4F18;&#x79C0;&#x793A;&#x8303;&#x3002;&#x4E0B;&#x9762;&#x5C31;&#x5BF9;CharMatcher&#x7C7B;&#x7684;&#x7ED3;&#x6784;&#xFF0C;&#x8BBE;&#x8BA1;&#x6A21;&#x5F0F;&#xFF0C;&#x4EE5;&#x53CA;&#x51E0;&#x4E2A;&#x7B97;&#x6CD5;&#x505A;&#x4E00;&#x4E9B;&#x7C97;&#x6D45;&#x7684;&#x5206;&#x6790;&#x3002;</p>
<h2 id>&#x4E00;&#x3001;&#x5173;&#x4E8E;&#x6E90;&#x7801;&#x4E2D;&#x7684;&#x5F69;&#x86CB;</h2>
<p>CharMatcher&#x7C7B;&#x4E2D;&#xFF0C;&#x5F00;&#x5934;&#x90E8;&#x5206;&#x6709;&#x4E00;&#x5F20;&#x5BA0;&#x7269;&#x5C0F;&#x7CBE;&#x7075;&#x201C;&#x5C0F;&#x706B;&#x9F99;&#x201D;&#x7684;&#x5B57;&#x7B26;&#x753B;&#xFF0C;&#x5C31;&#x50CF;&#x672C;&#x6587;&#x7684;&#x5C01;&#x9762;&#x56FE;&#x4E00;&#x6837;&#xFF0C;&#x4E00;&#x5F00;&#x59CB;&#x4E0D;&#x89E3;&#x4E3A;&#x4F55;&#x8981;&#x653E;&#x4E00;&#x53EA;&#x201C;&#x5C0F;&#x706B;&#x9F99;&#x201D;&#x5728;&#x8FD9;&#x91CC;&#xFF0C;&#x540E;&#x6765;&#x770B;&#x5230;&#x5176;&#x82F1;&#x6587;&#x540D;Charmander&#x624D;&#x660E;&#x767D;&#x8FC7;&#x6765;&#x3002;&#x597D;&#x5427;&#xFF0C;&#x8C10;&#x97F3;&#x6897;&#x2026;&#x2026;&#x7565;&#x51B7;&#x3002;</p>
<h2 id>&#x4E8C;&#x3001;&#x7C7B;&#x7684;&#x7ED3;&#x6784;&#x548C;&#x5173;&#x7CFB;</h2>
<p>&#x4E0B;&#x56FE;&#x662F;CharMatcher&#x7684;&#x7C7B;&#x5173;&#x7CFB;&#x56FE;&#xFF0C;&#x56FE;&#x4E2D;&#x84DD;&#x8272;&#x7684;&#x662F;abstract&#x7C7B;&#xFF0C;&#x7EA2;&#x8272;&#x7684;&#x662F;final&#x7C7B;<br>
<img src="/content/images/2018/08/WX20180804-143922.png" alt="[&#x8F6E;&#x5B50;&#x7CFB;&#x5217;]Google Guava&#x4E4B;CharMatcher&#x6E90;&#x7801;&#x5206;&#x6790;" loading="lazy"><br>
&#x9996;&#x5148;CharMatcher&#x4FEE;&#x9970;&#x4E3A;abstract&#xFF0C;&#x5176;&#x4E2D;&#x53EA;&#x6709;&#x4E00;&#x4E2A;abstract&#x65B9;&#x6CD5;matches&#xFF0C;&#x5373;&#x5224;&#x65AD;&#x7ED9;&#x5B9A;&#x5B57;&#x7B26;&#x662F;&#x5426;&#x5339;&#x914D;&#xFF0C;&#x4EE5;&#x53CA;&#x4E00;&#x4E9B;&#x5176;&#x4ED6;&#x7684;&#x5E38;&#x7528;&#x64CD;&#x4F5C;&#xFF08;&#x5B83;&#x4EEC;&#x7684;&#x529F;&#x80FD;&#x4ECE;&#x65B9;&#x6CD5;&#x540D;&#x53EF;&#x4EE5;&#x5F97;&#x77E5;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x4E0D;&#x4E00;&#x4E00;&#x4ECB;&#x7ECD;&#x4E86;&#xFF0C;&#x4E0B;&#x6587;&#x4F1A;&#x9009;&#x5176;&#x4E2D;&#x7684;&#x4E00;&#x4E9B;&#x505A;&#x5206;&#x6790;&#xFF09;&#xFF0C;&#x6B64;&#x5916;&#x8FD8;&#x6709;&#x4E09;&#x4E2A;&#x7528;&#x4E8E;&#x7EC4;&#x5408;&#x7684;&#x65B9;&#x6CD5;&#xFF1A;negate&#x3001;or&#x3001;and&#x3002;</p>
<pre><code class="language-java">public abstract boolean matches(char c);

public int indexIn(CharSequence sequence) // &#x67E5;&#x627E;&#x5339;&#x914D;&#x5B57;&#x7B26;&#x9996;&#x6B21;&#x51FA;&#x73B0;&#x7684;&#x7D22;&#x5F15;&#x4F4D;&#x7F6E;

public int countIn(CharSequence sequence) // &#x5BF9;&#x5339;&#x914D;&#x7684;&#x5B57;&#x7B26;&#x8BA1;&#x6570;

public String retainFrom(CharSequence sequence) // &#x62BD;&#x53D6;&#x5339;&#x914D;&#x7684;&#x5B57;&#x7B26;

public CharMatcher negate() // &#x53D6;&#x53CD;

public CharMatcher and(CharMatcher other) // &#x4E0E;

public CharMatcher or(CharMatcher other) // &#x6216;

...
</code></pre>
<p>&#x5982;&#x4E0A;&#x56FE;&#x6240;&#x793A;&#xFF0C;CharMatcher&#x7C7B;&#x6709;&#x5F88;&#x591A;&#x7684;&#x5B50;&#x7C7B;&#xFF0C;&#x4E00;&#x90E8;&#x5206;&#x662F;&#x76F4;&#x63A5;&#x7EE7;&#x627F;&#x4E8E;&#x7236;&#x7C7B;&#xFF0C;&#x4E00;&#x90E8;&#x5206;&#x662F;&#x7EE7;&#x627F;&#x4E8E;FastMatcher&#xFF0C;&#x53E6;&#x5916;&#x8FD8;&#x6709;&#x7EE7;&#x627F;&#x4E8E;Negated&#x548C;RangeMatcher&#x3002;&#x5B50;&#x7C7B;&#x901A;&#x8FC7;&#x5B9E;&#x73B0;matches&#x65B9;&#x6CD5;&#x6216;&#x91CD;&#x5199;&#x5176;&#x4ED6;&#x7236;&#x7C7B;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x4ECE;&#x800C;&#x63D0;&#x4F9B;&#x4E86;&#x5404;&#x79CD;&#x4E0D;&#x540C;&#x7684;&#x5177;&#x4F53;&#x64CD;&#x4F5C;&#xFF0C;&#x5982;Is&#xFF08;&#x5224;&#x65AD;&#x662F;&#x5426;&#x4E3A;&#x67D0;&#x4E00;&#x4E2A;&#x5B57;&#x7B26;&#xFF09;&#xFF0C;Digit&#xFF08;&#x5224;&#x65AD;&#x662F;&#x5426;&#x4E3A;&#x6570;&#x5B57;&#x5B57;&#x7B26;&#xFF09;&#xFF0C;Ascii&#xFF08;&#x5224;&#x65AD;&#x662F;&#x5426;&#x4E3A;ASCII&#x5B57;&#x7B26;&#xFF09;&#x7B49;&#x3002;<br>
&#x518D;&#x6765;&#x8BF4;&#x8BF4;&#x5176;&#x4E2D;&#x4E00;&#x4E2A;&#x6BD4;&#x8F83;&#x91CD;&#x8981;&#x7684;&#x5B50;&#x7C7B;&#x2014;&#x2014;FastMatcher&#xFF0C;&#x5B83;&#x548C;CharMatcher&#x7684;&#x4E3B;&#x8981;&#x533A;&#x522B;&#x5728;&#x4E8E;&#xFF0C;FastMatcher&#x53D6;&#x6D88;&#x4E86;&#x7236;&#x7C7B;&#x4E2D;&#x76F8;&#x5BF9;&#x590D;&#x6742;&#x7684;precomputed&#x65B9;&#x6CD5;&#xFF0C;&#x5176;&#x6CE8;&#x91CA;&#x5199;&#x9053;&#xFF0C;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x53EF;&#x4EE5;&#x5F97;&#x5230;&#x4E00;&#x4E2A;&#x5904;&#x7406;&#x901F;&#x5EA6;&#x66F4;&#x5FEB;&#x7684;&#x5B9E;&#x4F8B;&#xFF0C;&#x4F46;&#x662F;&#x6267;&#x884C;&#x8BE5;&#x65B9;&#x6CD5;&#x672C;&#x8EAB;&#x9700;&#x8981;&#x82B1;&#x8D39;&#x4E00;&#x5B9A;&#x65F6;&#x95F4;&#xFF0C;&#x6240;&#x4EE5;&#x53EA;&#x6709;&#x5728;&#x9700;&#x8981;&#x9891;&#x7E41;&#x8C03;&#x7528;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x8FD9;&#x6837;&#x505A;&#x624D;&#x6BD4;&#x8F83;&#x5212;&#x7B97;&#x3002;<br>
&#x81F3;&#x4E8E;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x7684;&#x5965;&#x79D8;&#x5728;&#x4E8E;&#xFF0C;&#x5B83;&#x4F7F;&#x7528;BitSet&#x4F5C;&#x4E3A;&#x5B58;&#x50A8;&#x5B57;&#x7B26;&#x7684;&#x6570;&#x636E;&#x7ED3;&#x6784;&#xFF0C;&#x7136;&#x540E;&#x904D;&#x5386;&#x6240;&#x6709;&#x7684;&#x5B57;&#x7B26;&#xFF08;Character.MIN_VALUE~Character.MAX_VALUE&#xFF09;&#xFF0C;&#x6839;&#x636E;matches&#x65B9;&#x6CD5;&#x653E;&#x5165;&#x8FD9;&#x4E2A;BitSet&#x4E2D;&#xFF0C;&#x6700;&#x540E;&#x6839;&#x636E;&#x8FD9;&#x4E2A;BitSet&#x4E2D;1&#x7684;&#x6570;&#x91CF;&#x751F;&#x6210;&#x5176;&#x4ED6;&#x7C7B;&#x578B;&#x7684;CharMatcher&#x5B9E;&#x4F8B;&#xFF0C;&#x5305;&#x62EC;None&#xFF0C;Is&#xFF0C;IsEither&#xFF0C;SmallCharMatcher&#xFF08;&#x4E00;&#x4E2A;&#x5355;&#x72EC;&#x7684;&#x5B50;&#x7C7B;&#xFF09;&#x4EE5;&#x53CA;BitSetMatcher&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x907F;&#x514D;&#x4E86;&#x9891;&#x7E41;&#x8C03;&#x7528;&#x8FC7;&#x7A0B;&#x4E2D;&#xFF0C;&#xFF08;&#x7279;&#x522B;&#x662F;&#x590D;&#x6742;&#x7EC4;&#x5408;&#x7684;&#x60C5;&#x51B5;&#xFF09;&#x6267;&#x884C;&#x4E0D;&#x5FC5;&#x8981;&#x5B9E;&#x4F8B;&#x5316;&#x64CD;&#x4F5C;&#xFF0C;&#x800C;&#x662F;&#x76F4;&#x63A5;&#x5F52;&#x7EA6;&#x5230;&#x67D0;&#x4E00;&#x4E2A;&#x7C7B;&#x7684;&#x5B9E;&#x4F8B;&#x4E0A;&#x3002;<br>
&#x800C;&#x4E0A;&#x8FF0;&#x90A3;5&#x4E2A;&#x7C7B;&#x6B63;&#x662F;&#x7EE7;&#x627F;&#x4E8E;FasterMatcher&#xFF08;&#x6216;NamedFasterMatcher&#xFF09;&#x3002;</p>
<h2 id>&#x4E09;&#x3001;&#x8BBE;&#x8BA1;&#x6A21;&#x5F0F;</h2>
<p>&#x4E0A;&#x4E00;&#x8282;&#x8BF4;&#x5230;CharMatcher&#x63D0;&#x4F9B;&#x5F88;&#x591A;&#x5B50;&#x7C7B;&#xFF0C;&#x4E3A;&#x4E86;&#x8F83;&#x597D;&#x5730;&#x7BA1;&#x7406;&#x548C;&#x4F7F;&#x7528;&#x8FD9;&#x4E9B;&#x7C7B;&#xFF0C;CharMatcher&#x5BF9;&#x5916;&#x63D0;&#x4F9B;&#x4E86;&#x57FA;&#x4E8E;&#x5185;&#x90E8;&#x7C7B;&#x7684;&#x9759;&#x6001;&#x5DE5;&#x5382;&#x65B9;&#x6CD5;&#x6216;&#x8005;&#x5355;&#x4F8B;&#x6A21;&#x5F0F;&#x6765;&#x83B7;&#x5F97;&#x67D0;&#x4E2A;&#x5B9E;&#x4F8B;&#xFF0C;&#x4E3E;&#x4F8B;&#x6765;&#x8BF4;&#xFF1A;</p>
<ul>
<li>&#x9759;&#x6001;&#x5DE5;&#x5382;&#x65B9;&#x6CD5;</li>
</ul>
<pre><code class="language-java">public static CharMatcher is(final char match) {
    return new Is(match);
}

private static final class Is extends FastMatcher {
    
    private final char match;

    Is(char match) {
      this.match = match;
    }
    ...
  }
</code></pre>
<blockquote>
<p>&#x4F7F;&#x7528;&#x9759;&#x6001;&#x5DE5;&#x5382;&#x65B9;&#x6CD5;&#x7684;&#x597D;&#x5904;&#xFF0C;&#x8FD9;&#x70B9;&#x5728;&#x300A;Effective Java&#x300B;&#x4E00;&#x4E66;&#x4E2D;&#x6709;&#x8BE6;&#x7EC6;&#x7684;&#x4ECB;&#x7ECD;</p>
</blockquote>
<ul>
<li>&#x5355;&#x4F8B;&#x6A21;&#x5F0F;</li>
</ul>
<pre><code class="language-java">public static CharMatcher ascii() {
    return Ascii.INSTANCE;
}

private static final class Ascii extends NamedFastMatcher {

    static final Ascii INSTANCE = new Ascii();

    Ascii() {
      super(&quot;CharMatcher.ascii()&quot;);
    }
    ...
}
</code></pre>
<p>&#x8FD9;&#x6837;&#x6211;&#x4EEC;&#x5C31;&#x53EF;&#x4EE5;&#x5F88;&#x65B9;&#x4FBF;&#x5730;&#x83B7;&#x5F97;&#x4E00;&#x4E2A;&#x5B9E;&#x4F8B;&#xFF0C;&#x5E76;&#x5BF9;&#x76F8;&#x5E94;&#x7684;&#x5B57;&#x7B26;&#x7C7B;&#x578B;&#x505A;&#x5904;&#x7406;&#xFF0C;&#x6BD4;&#x5982;&#x62BD;&#x53D6;&#x5B57;&#x7B26;&#x4E32;&#x4E2D;&#x6240;&#x6709;&#x7684;&#x6570;&#x5B57;</p>
<pre><code class="language-java">CharMatcher.inRange(&apos;0&apos;, &apos;9&apos;).retainFrom(&quot;abc12d34ef&quot;);
// &#x5F53;&#x7136;&#x4E5F;&#x53EF;&#x4EE5;&#x7528;Digit&#x7C7B;&#xFF0C;&#x4E0D;&#x8FC7;&#x6700;&#x8FD1;&#x7684;&#x7248;&#x672C;&#x5DF2;&#x7ECF;&#x88AB;&#x6807;&#x8BB0;&#x4E3A;Deprecated
// &#x533A;&#x522B;&#x5728;&#x4E8E;Digit&#x7C7B;&#x5904;&#x7406;&#x4E86;&#x5B57;&#x7B26;0&#x5230;9&#x7684;&#x5404;&#x79CD;unicode&#x7801;&#xFF0C;&#x4E0D;&#x8FC7;&#x5927;&#x591A;&#x6570;&#x60C5;&#x51B5;&#x8FD8;&#x662F;&#x5904;&#x7406;ASCII&#x6570;&#x5B57;&#xFF0C;&#x6240;&#x4EE5;&#x5EFA;&#x8BAE;&#x4F7F;&#x7528;inRange
CharMatcher.digit().retainFrom(&quot;abc12d34ef&quot;)&#xFF1B;
// 1234
</code></pre>
<p>&#x5F53;&#x7136;&#x4E5F;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;negate/or/and&#x4EA7;&#x751F;&#x4E00;&#x4E9B;&#x590D;&#x6742;&#x7684;&#x7EC4;&#x5408;:</p>
<pre><code class="language-java">CharMatcher.inRange(&apos;0&apos;,&apos;9&apos;).or(CharMatcher.is(&apos;d&apos;)).retainFrom(&quot;abc12d34ef&quot;);
// 12d34
</code></pre>
<p>&#x53E6;&#x5916;&#x8FD8;&#x6709;&#x4E00;&#x4E2A;ForPredicate&#x7684;&#x5B50;&#x7C7B;&#xFF0C;&#x5B83;&#x63A5;&#x6536;Predicate&#x5BF9;&#x8C61;&#x4F5C;&#x4E3A;&#x53C2;&#x6570;&#xFF0C;&#x7136;&#x540E;&#x7528;Predicate&#x7684;apply&#x65B9;&#x6CD5;&#x6765;&#x5B9E;&#x73B0;matches&#x65B9;&#x6CD5;&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x7528;lamda&#x8868;&#x8FBE;&#x5F0F;&#x521B;&#x5EFA;&#x4E00;&#x4E9B;&#x5B9E;&#x4F8B;&#x4E86;&#xFF0C;&#x4F8B;&#x5982;&#xFF1A;</p>
<pre><code class="language-java">CharMatcher.inRange(&apos;0&apos;, &apos;9&apos;).or(CharMatcher.is(&apos;d&apos;))
                .or(CharMatcher.forPredicate(c -&gt; c &lt;= &apos;b&apos; || c &gt; &apos;e&apos;)).retainFrom(&quot;abc12d34ef&quot;);
// ab12d34f
</code></pre>
<h2 id>&#x56DB;&#x3001;&#x7B97;&#x6CD5;&#x5206;&#x6790;</h2>
<ul>
<li>collapseFrom&#x65B9;&#x6CD5;&#xFF0C;&#x5982;&#x4EE3;&#x7801;&#x6CE8;&#x91CA;&#x6240;&#x793A;&#xFF0C;&#x628A;&#x4E00;&#x4E2A;&#x5B57;&#x7B26;&#x4E32;&#x4E2D;&#x5339;&#x914D;&#x5230;&#x7684;(&#x8FDE;&#x7EED;)&#x90E8;&#x5206;&#x66FF;&#x6362;&#x4E3A;&#x7ED9;&#x5B9A;&#x7684;&#x5B57;&#x7B26;&#xFF0C;</li>
</ul>
<pre><code class="language-java">//CharMatcher.anyOf(&quot;eko&quot;).collapseFrom(&quot;bookkeeper&quot;, &apos;-&apos;) returns &quot;b-p-r&quot;
public String collapseFrom(CharSequence sequence, char replacement) {
    // This implementation avoids unnecessary allocation.
    int len = sequence.length();
    for (int i = 0; i &lt; len; i++) {
      char c = sequence.charAt(i);
      if (matches(c)) {
        if (c == replacement &amp;&amp; (i == len - 1 || !matches(sequence.charAt(i + 1)))) {
          // a no-op replacement
          i++;
        } else {
          StringBuilder builder = new StringBuilder(len).append(sequence, 0, i).append(replacement);
          return finishCollapseFrom(sequence, i + 1, len, replacement, builder, true);
        }
      }
    }
    // no replacement needed
    return sequence.toString();
}
  
private String finishCollapseFrom(
      CharSequence sequence,
      int start,
      int end,
      char replacement,
      StringBuilder builder,
      boolean inMatchingGroup) {
    for (int i = start; i &lt; end; i++) {
      char c = sequence.charAt(i);
      if (matches(c)) {
        if (!inMatchingGroup) {
          builder.append(replacement);
          inMatchingGroup = true;
        }
      } else {
        builder.append(c);
        inMatchingGroup = false;
      }
    }
    return builder.toString();
} 
</code></pre>
<blockquote>
<p>&#x4E8B;&#x5B9E;&#x4E0A;&#xFF0C;CharMatcher&#x91CC;&#x9762;&#x7684;&#x7B97;&#x6CD5;&#x57FA;&#x672C;&#x4E0A;&#x90FD;&#x548C;&#x8FD9;&#x4E2A;&#x5DEE;&#x4E0D;&#x591A;&#x7A0B;&#x5EA6;&#x3002;</p>
</blockquote>
<p>&#x6B63;&#x5982;&#x6CE8;&#x91CA;&#x90E8;&#x5206;&#x6240;&#x8FF0;&#xFF0C;&#x8FD9;&#x4E2A;&#x7B97;&#x6CD5;&#x6CA1;&#x6709;&#x5206;&#x914D;&#x4E0D;&#x5FC5;&#x8981;&#x7684;&#x7A7A;&#x95F4;&#x3002;&#x904D;&#x5386;&#x8FC7;&#x7A0B;&#x4E2D;&#x5F53;&#x53D1;&#x73B0;&#x5F53;&#x524D;&#x5B57;&#x7B26;&#x6EE1;&#x8DB3;&#x5339;&#x914D;&#x6761;&#x4EF6;&#xFF0C;&#x8FD9;&#x65F6;&#x518D;&#x505A;&#x4E00;&#x6B21;&#x5224;&#x65AD;&#xFF0C;&#x5982;&#x679C;&#x5F53;&#x524D;&#x5B57;&#x7B26;&#x672C;&#x8EAB;&#x5C31;&#x662F;&#x6240;&#x9700;&#x8981;&#x66FF;&#x6362;&#x7684;&#x5B57;&#x7B26;replacement&#xFF0C;&#x90A3;&#x4E48;&#x8FD9;&#x79CD;&#x60C5;&#x51B5;&#x662F;&#x4E0D;&#x9700;&#x8981;&#x8FDB;&#x884C;&#x66FF;&#x6362;&#x64CD;&#x4F5C;&#xFF08;&#x611F;&#x89C9;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x7528;&#x4E00;&#x4E2A;if(c != replacement)&#x6362;&#x6389;else&#xFF0C;&#x5E76;&#x4E0D;&#x9700;&#x8981;i++&#x7684;&#x64CD;&#x4F5C;&#xFF09;&#xFF0C;&#x5426;&#x5219;&#x5C06;i&#x4E4B;&#x524D;&#x7684;&#x5B57;&#x7B26;&#x62FC;&#x4E0A;replacement&#x5F62;&#x6210;&#x4E00;&#x4E2A;&#x201C;&#x534A;&#x6210;&#x54C1;&#x201D;&#x4F20;&#x5165;finishCollapseFrom&#xFF0C;&#x5728;&#x8BE5;&#x65B9;&#x6CD5;&#x4E2D;&#x5229;&#x7528;&#x4E86;&#x4E00;&#x4E2A;&#x5E03;&#x5C14;&#x503C;inMatchingGroup&#x6765;&#x63A7;&#x5236;&#x662F;&#x5426;&#x9700;&#x8981;&#x62FC;&#x63A5;replacement&#xFF0C;&#x5F53;&#x53D1;&#x73B0;&#x6EE1;&#x8DB3;&#x5339;&#x914D;&#x6761;&#x4EF6;&#x65F6;&#xFF0C;&#x518D;&#x68C0;&#x67E5;inMatchingGroup&#x662F;&#x5426;&#x4E3A;false&#xFF0C;&#x5B83;&#x8868;&#x793A;&#x4E0A;&#x4E00;&#x8F6E;&#x62FC;&#x63A5;&#x7684;&#x4E0D;&#x662F;replacement&#xFF0C;&#x4EE5;&#x4FDD;&#x8BC1;&#x8FD4;&#x56DE;&#x7684;&#x7ED3;&#x679C;&#x4E2D;&#x4E0D;&#x4F1A;&#x51FA;&#x73B0;&#x4E24;&#x4E2A;&#x4EE5;&#x4E0A;&#x8FDE;&#x7EED;&#x7684;replacement&#x3002;</p>
<ul>
<li>Whitespace.matches &#x5373;&#x5224;&#x65AD;&#x8BE5;&#x5B57;&#x7B26;&#x662F;&#x5426;&#x4E3A;&#x7A7A;&#x767D;&#x5B57;&#x7B26;&#xFF0C;&#x5305;&#x62EC;&#x7A7A;&#x683C;&#xFF0C;&#x6362;&#x884C;&#x7B49;</li>
</ul>
<pre><code class="language-java">static final class Whitespace extends NamedFastMatcher {

    static final String TABLE =
        &quot;\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000&quot;
            + &quot;\u2029\u000B\u3000\u2008\u2003\u205F\u3000\u1680&quot;
            + &quot;\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009&quot;
            + &quot;\u3000\u2004\u3000\u3000\u2028\n\u2007\u3000&quot;;
    static final int MULTIPLIER = 1682554634;
    static final int SHIFT = Integer.numberOfLeadingZeros(TABLE.length() - 1);

    static final Whitespace INSTANCE = new Whitespace();

    @Override
    public boolean matches(char c) {
      return TABLE.charAt((MULTIPLIER * c) &gt;&gt;&gt; SHIFT) == c;
    }
}
</code></pre>
<p>&#x8FD9;&#x4E2A;&#x7B97;&#x6CD5;&#x672C;&#x8EAB;&#x5F88;&#x7B80;&#x5355;&#xFF0C;&#x5373;TABLE&#x5B57;&#x7B26;&#x4E32;&#x4E2D;&#x662F;&#x5426;&#x5B58;&#x5728;&#x540C;&#x6837;&#x7684;&#x5B57;&#x7B26;c&#xFF0C;&#x5DE7;&#x5999;&#x7684;&#x662F;&#x5B83;&#x7684;&#x5B9A;&#x4F4D;&#x65B9;&#x5F0F;&#x3002;<br>
&#x5148;&#x8BF4;&#x660E;Integer.numberOfLeadingZeros&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x8FD4;&#x56DE;&#x7684;&#x662F;&#x8BE5;int&#x53D8;&#x91CF;&#x4E8C;&#x8FDB;&#x5236;&#x5F00;&#x5934;&#x90E8;&#x5206;&#x8FDE;&#x7EED;&#x7684;&#x96F6;&#x7684;&#x4E2A;&#x6570;&#x3002;TABLE&#x7684;&#x957F;&#x5EA6;&#x4E3A;32&#xFF0C;&#x6545;SHIFT&#x7684;&#x503C;&#x4E3A;27&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x8BF4;&#xFF0C;&#x901A;&#x8FC7;&#x5B57;&#x7B26;c&#x548C;&#x67D0;&#x4E00;&#x4E2A;&#x4E58;&#x5B50;&#x7684;&#x4E58;&#x79EF;&#xFF08;&#x8D85;&#x51FA;int&#x8303;&#x56F4;&#x4E4B;&#x540E;&#x53D6;&#x4F4E;32&#x4F4D;&#xFF09;&#x5411;&#x53F3;&#x79FB;&#x52A8;27&#x4F4D;&#x5F97;&#x5230;&#x7684;&#x6570;&#x503C;&#xFF0C;&#x5373;&#x4E3A;TABLE&#x7684;&#x4E0B;&#x6807;&#x7D22;&#x5F15;&#xFF0C;&#x4F8B;&#x5982;&#x5B57;&#x7B26;&apos;\u2002&apos;&#x5176;&#x503C;&#x4E3A;8194&#xFF0C;&#x5B83;&#x548C;1682554634&#x7684;&#x4E58;&#x79EF;&#x518D;&#x53F3;&#x79FB;27&#x4F4D;&#x5F97;&#x5230;0&#xFF0C;&#x800C;TABLE&#x7B2C;0&#x4E2A;&#x5B57;&#x7B26;&#x5C31;&#x662F;&apos;\u2002&apos;&#xFF0C;&#x5219;&#x5224;&#x5B9A;&#x76F8;&#x7B49;&#xFF0C;&#x5B57;&#x7B26;&apos;\u3000&apos;&#x7684;&#x503C;&#x4E3A;12288&#xFF0C;&#x5E94;&#x7528;&#x76F8;&#x540C;&#x7B97;&#x6CD5;&#x5F97;&#x5230;26&#xFF0C;TABLE&#x7B2C;26&#x4E2A;&#x5B57;&#x7B26;&#x4E5F;&#x662F;&apos;\u3000&apos;&#xFF0C;&#x540C;&#x6837;&#x5224;&#x5B9A;&#x76F8;&#x7B49;&#x3002;&#x7531;&#x6B64;&#x53EF;&#x4EE5;&#x770B;&#x51FA;&#xFF0C;1682554634&#x8FD9;&#x4E2A;&#x9B54;&#x6570;&#x548C;TABLE&#x662F;&#x523B;&#x610F;&#x8BBE;&#x8BA1;&#x6210;&#x8FD9;&#x6837;&#x7684;&#x3002;&#x4F46;&#x662F;&#x6E90;&#x7801;&#x4E2D;&#x6CA1;&#x6709;&#x89E3;&#x91CA;&#x5982;&#x4F55;&#x751F;&#x6210;&#xFF0C;&#x5728;GitHub&#x4E0A;&#x5012;&#x662F;&#x4E5F;&#x6709;&#x4EBA;&#x8FD9;&#x4E48;&#x95EE;&#x8FC7;&#xFF0C;Guava owner&#x56DE;&#x590D;&#x8BF4;&#x9053;&#xFF1A;&#x4ED6;&#x4EEC;&#x786E;&#x5B9E;&#x6709;&#x4E00;&#x4E2A;&#x751F;&#x6210;&#x5668;&#xFF0C;&#x4F46;&#x662F;&#x7531;&#x4E8E;&#x4E00;&#x4E9B;&#x4F9D;&#x8D56;&#x7684;&#x539F;&#x56E0;&#xFF0C;&#x5E76;&#x6CA1;&#x6709;&#x5F00;&#x6E90;&#x51FA;&#x6765;&#x3002;&#x5176;&#x5B9E;&#x5982;&#x679C;&#x4E0D;&#x8003;&#x8651;&#x6027;&#x80FD;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x7528;&#x6700;&#x7B80;&#x5355;&#x7684;&#x66B4;&#x529B;&#x6CD5;&#x751F;&#x6210;&#x4E58;&#x5B50;&#x548C;TABLE&#xFF0C;&#x4EE3;&#x7801;&#x5982;&#x4E0B;&#xFF1A;</p>
<pre><code>    @Test
    public void test() {
        // &#x53BB;&#x6389;table&#x4E2D;&#x91CD;&#x590D;&#x7684;&#x5B57;&#x7B26;
        String WHITE = &quot;\u2002\r\u0085\u200A\u2005\u2000&quot;
                + &quot;\u2029\u000B\u2008\u2003\u205F\u1680&quot;
                + &quot;\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009&quot;
                + &quot;\u2004\u2028\n\u2007\u3000&quot;;

        char[] chars = WHITE.toCharArray();
        char filler = chars[chars.length - 1];
        char[] table = new char[32];

        int shift = Integer.numberOfLeadingZeros(WHITE.length());

        for (int i = 0; i &lt;= Integer.MAX_VALUE; i++) {
            Arrays.fill(table, filler);//&#x5148;&#x7528;&#x6700;&#x540E;&#x4E00;&#x4E2A;&#x5B57;&#x7B26;&#x586B;&#x5145;&#x6574;&#x4E2A;table
            boolean conflict = false;
            for (char c : chars) {
                int index = (i * c) &gt;&gt;&gt; shift;
                //&#x5982;&#x679C;&#x5F53;&#x524D;&#x5B57;&#x7B26;&#x4E3A;&#x586B;&#x5145;&#x5B57;&#x7B26;&#xFF0C;&#x5219;&#x8986;&#x76D6;&#x586B;&#x5145;&#x5B57;&#x7B26;&#xFF0C;&#x5426;&#x5219;&#x8DF3;&#x8FC7;
                if (table[index] != filler) { 
                    conflict = true;
                    continue;
                }
                table[index] = c;
            }
            if (conflict)
                continue;
            System.out.println(&quot;MULTIPLIER: &quot; + i);
            System.out.println(&quot;TABLE:&quot; + new String(table));
        }
    }
</code></pre>
<p>&#x4E0A;&#x9762;&#x53EF;&#x4EE5;&#x5F97;&#x5230;&#x591A;&#x79CD;MULTIPLIER&#x548C;TABLE&#x7684;&#x7ED3;&#x679C;&#x3002;&#x5F53;&#x7136;&#xFF0C;&#x53CD;&#x63A8;&#x8FC7;&#x7A0B;&#x6BD4;&#x8F83;&#x7B80;&#x5355;&#x7C97;&#x66B4;&#xFF0C;&#x4E00;&#x5B9A;&#x6709;&#x66F4;&#x4F18;&#x96C5;&#x66F4;&#x9AD8;&#x6548;&#x7684;&#x5B9E;&#x73B0;&#x65B9;&#x5F0F;&#x3002;&#x4E0D;&#x8FC7;&#x8FD9;&#x91CC;&#x60F3;&#x8981;&#x8868;&#x8FBE;&#x7684;&#x662F;&#xFF0C;&#x5B83;&#x672C;&#x8EAB;&#x662F;&#x4E00;&#x4E2A;&#x7B80;&#x5355;&#x7684;&#x67E5;&#x627E;&#x7B97;&#x6CD5;&#xFF0C;&#x901A;&#x5E38;&#x7684;&#x590D;&#x6742;&#x5EA6;&#x4E3A;O(logn)&#xFF0C;&#x8FD9;&#x91CC;&#x5DE7;&#x5999;&#x901A;&#x8FC7;&#x6620;&#x5C04;&#x51FD;&#x6570;&#xFF0C;&#x5C06;&#x5B57;&#x7B26;&#x6620;&#x5C04;&#x4E3A;&#x5B57;&#x7B26;&#x4E32;&#x4E0B;&#x6807;&#x7D22;&#x5F15;&#xFF0C;&#x4F7F;&#x5F97;&#x65F6;&#x95F4;&#x590D;&#x6742;&#x5EA6;&#x4E3A;O(1)&#xFF0C;&#x4E0D;&#x5F97;&#x4E0D;&#x4F69;&#x670D;Guava&#x5F00;&#x53D1;&#x8005;&#x4EEC;&#x8FFD;&#x6C42;&#x6781;&#x81F4;&#x7684;&#x7CBE;&#x795E;&#x3002;</p>
<ul>
<li>removeFrom&#x65B9;&#x6CD5;&#xFF0C;&#x5373;&#x5728;&#x7ED9;&#x5B9A;&#x5B57;&#x7B26;&#x4E32;&#x4E2D;&#xFF0C;&#x5220;&#x9664;&#x5176;&#x5339;&#x914D;&#x7684;&#x90E8;&#x5206;</li>
</ul>
<pre><code class="language-java">// CharMatcher.is(&apos;a&apos;).removeFrom(&quot;bazaar&quot;) returns &quot;bzr&quot;
public String removeFrom(CharSequence sequence) {
    String string = sequence.toString();
    int pos = indexIn(string);
    if (pos == -1) {
      return string;
    }

    char[] chars = string.toCharArray();
    int spread = 1;

    // This unusual loop comes from extensive benchmarking
    OUT:
    while (true) {
      pos++;
      while (true) {
        if (pos == chars.length) {
          break OUT;
        }
        if (matches(chars[pos])) {
          break;
        }
        chars[pos - spread] = chars[pos];
        pos++;
      }
      spread++;
    }
    return new String(chars, 0, pos - spread);
  }
</code></pre>
<p>&#x6BD4;&#x8F83;&#x8BE1;&#x5F02;&#x7684;&#x662F;&#xFF0C;&#x5B83;&#x4F7F;&#x7528;&#x4E86;&#x4E24;&#x5C42;while&#x5FAA;&#x73AF;&#xFF0C;&#x4EE5;&#x53CA;break [lable]&#x7684;&#x8BED;&#x6CD5;&#xFF08;&#x8FD9;&#x79CD;&#x7528;&#x6CD5;&#x5E76;&#x4E0D;&#x591A;&#x89C1;&#xFF0C;&#x53EF;&#x4EE5;&#x7406;&#x89E3;&#x4E3A;goto&#x8BED;&#x53E5;&#x7684;&#x6539;&#x826F;&#x5F62;&#x5F0F;&#xFF0C;&#x53EF;&#x4EE5;&#x65B9;&#x4FBF;&#x5730;&#x8DF3;&#x51FA;&#x591A;&#x5C42;&#x5FAA;&#x73AF;&#xFF09;,&#x4E0D;&#x8FC7;&#x5728;&#x5185;&#x5C42;&#x5FAA;&#x73AF;&#x65F6;&#x540C;&#x6837;&#x4E5F;&#x505A;&#x4E86;pos++&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x672C;&#x8D28;&#x4E0A;&#x8FD8;&#x662F;O(n)&#x7684;&#x65F6;&#x95F4;&#x590D;&#x6742;&#x5EA6;&#xFF0C;&#x7B97;&#x6CD5;&#x601D;&#x60F3;&#x662F;char&#x6570;&#x7EC4;&#x7684;&#x4F4D;&#x79FB;&#x64CD;&#x4F5C;&#xFF0C;&#x6BCF;&#x6B21;&#x5339;&#x914D;&#x5230;&#x4E00;&#x4E2A;&#x5B57;&#x7B26;&#x65F6;&#xFF0C;spread&#x5C31;&#x81EA;&#x589E;&#xFF0C;&#x5176;&#x4ED6;&#x60C5;&#x51B5;&#x5219;&#x6BCF;&#x4E2A;&#x6570;&#x7EC4;&#x5143;&#x7D20;&#x5411;&#x524D;&#x79FB;&#x52A8;&#xFF0C;&#x5177;&#x4F53;&#x6765;&#x8BF4;&#xFF0C;spread&#x7684;&#x4F5C;&#x7528;&#x76F8;&#x5F53;&#x4E8E;&#x5BF9;&#x5339;&#x914D;&#x5230;&#x7684;&#x5B57;&#x7B26;&#x8FDB;&#x884C;&#x8BA1;&#x6570;&#xFF0C;&#x5339;&#x914D;&#x5230;1&#x4E2A;&#x5143;&#x7D20;&#xFF0C;pos&#x6307;&#x5411;&#x7684;&#x5143;&#x7D20;&#x53CA;&#x5176;&#x4E4B;&#x540E;&#x7684;&#x5143;&#x7D20;&#x5411;&#x524D;&#x79FB;&#x52A8;1&#x6B65;&#x4EE5;&#x8986;&#x76D6;&#x6389;&#x4E0A;&#x4E00;&#x8F6E;&#x547D;&#x4E2D;&#x7684;&#x5B57;&#x7B26;&#xFF0C;&#x5339;&#x914D;&#x5230;2&#x4E2A;&#x5143;&#x7D20;&#xFF0C;pos&#x6267;&#x884C;&#x7684;&#x5143;&#x7D20;&#x53CA;&#x5176;&#x4E4B;&#x540E;&#x7684;&#x5143;&#x7D20;&#x5411;&#x524D;&#x79FB;&#x52A8;2&#x6B65;&#xFF0C;&#x4EE5;&#x8986;&#x76D6;&#x4E0A;&#x4E00;&#x6B21;&#x79FB;&#x52A8;&#x7559;&#x4E0B;&#x7684;&#x7A7A;&#x4F4D;&#x548C;&#x4E0A;&#x4E00;&#x8F6E;&#x547D;&#x4E2D;&#x7684;&#x5B57;&#x7B26;&#xFF0C;&#x4F9D;&#x6B21;&#x7C7B;&#x63A8;&#x3002;&#x6700;&#x7EC8;&#x5229;&#x7528;String&#x7684;&#x6784;&#x9020;&#x51FD;&#x6570;&#xFF08;&#x7B2C;&#x4E8C;&#x4E2A;&#x53C2;&#x6570;&#x662F;offset&#xFF0C;&#x5373;&#x521D;&#x59CB;&#x7684;&#x504F;&#x79FB;&#x4F4D;&#x7F6E;&#xFF0C;&#x7B2C;&#x4E09;&#x4E2A;&#x53C2;&#x6570;count&#xFF0C;&#x5373;&#x6240;&#x9700;&#x957F;&#x5EA6;&#xFF09;&#x8FD4;&#x56DE;&#x6B63;&#x786E;&#x7684;&#x5B57;&#x7B26;&#x4E32;&#x3002;<br>
&#x505A;&#x4E2A;&#x5BF9;&#x6BD4;&#xFF0C;&#x6211;&#x4EEC;&#x4EE5;Apache commons lang3&#x4E2D;&#x7684;StringUtils&#x4F5C;&#x4E3A;&#x6BD4;&#x8F83;&#x5BF9;&#x8C61;&#xFF0C;&#x5176;&#x5BF9;&#x5E94;&#x7684;&#x5B9E;&#x73B0;&#x57FA;&#x4E8E;Matcher(java.util.regex)&#x7684;replaceAll&#x65B9;&#x6CD5;&#xFF0C;&#x4EA6;&#x5373;&#x5C06;&#x5339;&#x914D;&#x7684;&#x5B57;&#x7B26;&#x66FF;&#x6362;&#x4E3A;&#x7A7A;&#x5B57;&#x7B26;&#x4E32;&#xFF0C;&#x6574;&#x4E2A;&#x904D;&#x5386;&#x7684;&#x8FC7;&#x7A0B;&#x4E2D;&#x91CD;&#x590D;&#x8C03;&#x7528;&#x4E86;find()&#x65B9;&#x6CD5;&#xFF0C;&#x8BE5;&#x65B9;&#x6CD5;&#x67E5;&#x627E;&#x5F53;&#x524D;&#x5B57;&#x7B26;&#x4E32;&#x4E2D;&#x5339;&#x914D;&#x7684;&#x5B57;&#x7B26;&#xFF0C;&#x5B83;&#x6BCF;&#x6B21;&#x90FD;&#x9700;&#x8981;&#x4ECE;&#x5934;&#x8FDB;&#x884C;&#x641C;&#x7D22;&#xFF0C;&#x56E0;&#x6B64;&#x65F6;&#x95F4;&#x590D;&#x6742;&#x5EA6;&#x4E3A;O(n^2)&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x6BD4;&#x8F83;&#x8D39;&#x65F6;&#x4E86;&#x3002;</p>
<h2 id>&#x4E94;&#x3001;&#x5176;&#x4ED6;</h2>
<p>&#x5728;CharMatcher&#x7F57;&#x5217;&#x591A;&#x79CD;&#x5B57;&#x7B26;&#x7684;&#x4E0D;&#x540C;Unicode&#x7801;&#xFF0C;&#x5982;&#x679C;&#x4F60;&#x5728;&#x5176;&#x4ED6;&#x7684;&#x5DE5;&#x4F5C;&#x573A;&#x666F;&#x4E0B;&#x9700;&#x8981;&#x7528;&#x7684;&#x8FD9;&#x4E9B;unicode&#xFF0C;&#x53EF;&#x4EE5;&#x53C2;&#x8003;&#x4E00;&#x4E0B;CharMatcher&#x3002;</p>
<ul>
<li>&#x6570;&#x5B57;&#x5B57;&#x7B26;</li>
</ul>
<pre><code class="language-java">private static final String ZEROES =
        &quot;0\u0660\u06f0\u07c0\u0966\u09e6\u0a66\u0ae6\u0b66\u0be6\u0c66\u0ce6\u0d66\u0de6&quot;
            + &quot;\u0e50\u0ed0\u0f20\u1040\u1090\u17e0\u1810\u1946\u19d0\u1a80\u1a90\u1b50\u1bb0&quot;
            + &quot;\u1c40\u1c50\ua620\ua8d0\ua900\ua9d0\ua9f0\uaa50\uabf0\uff10&quot;;
</code></pre>
<blockquote>
<p>&#x5982;&#x679C;&#x8981;&#x83B7;&#x5F97;&#x5176;&#x4ED6;&#x6570;&#x5B57;&#x7684;unicode&#xFF0C;&#x5C31;&#x76F4;&#x63A5;&#x5BF9;&#x5E94;&#x52A0;&#x4E0A;&#x5BF9;&#x5E94;&#x7684;&#x6570;&#x503C;</p>
</blockquote>
<ul>
<li>&#x7A7A;&#x767D;&#x5B57;&#x7B26;</li>
</ul>
<pre><code class="language-java">static final String TABLE =
        &quot;\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000&quot;
            + &quot;\u2029\u000B\u3000\u2008\u2003\u205F\u3000\u1680&quot;
            + &quot;\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009&quot;
            + &quot;\u3000\u2004\u3000\u3000\u2028\n\u2007\u3000&quot;;
</code></pre>
<ul>
<li>&#x4E0D;&#x53EF;&#x89C1;&#x5B57;&#x7B26;</li>
</ul>
<pre><code class="language-java">private static final String RANGE_STARTS =
        &quot;\u0000\u007f\u00ad\u0600\u061c\u06dd\u070f\u08e2\u1680\u180e\u2000\u2028\u205f\u2066&quot;
            + &quot;\u3000\ud800\ufeff\ufff9&quot;;
private static final String RANGE_ENDS = // inclusive ends
        &quot;\u0020\u00a0\u00ad\u0605\u061c\u06dd\u070f\u08e2\u1680\u180e\u200f\u202f\u2064\u206f&quot;
            + &quot;\u3000\uf8ff\ufeff\ufffb&quot;;
</code></pre>
<ul>
<li>&#x5355;&#x5B57;&#x8282;&#x957F;&#x5EA6;&#x5B57;&#x7B26;</li>
</ul>
<pre><code class="language-java">&quot;\u0000\u05be\u05d0\u05f3\u0600\u0750\u0e00\u1e00\u2100\ufb50\ufe70\uff61&quot;
&quot;\u04f9\u05be\u05ea\u05f4\u06ff\u077f\u0e7f\u20af\u213a\ufdff\ufeff\uffdc&quot;
</code></pre>
<blockquote>
<p>&#x4E2D;&#x6587;&#x5B57;&#x7B26;&#x5C31;&#x662F;&#x53CC;&#x5B57;&#x8282;&#x957F;&#x5EA6;</p>
</blockquote>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[如何实现一个基本的微信文章分类器]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x53F7;&#x53D1;&#x5E03;&#x7684;&#x6587;&#x7AE0;&#x548C;&#x4E00;&#x822C;&#x95E8;&#x6237;&#x7F51;&#x7AD9;&#x7684;&#x65B0;&#x95FB;&#x6587;&#x672C;&#x7C7B;&#x578B;&#x6709;&#x6240;&#x4E0D;&#x540C;&#xFF0C;&#x901A;&#x5E38;&#x4E0D;&#x80FD;&#x7528;&#x73B0;&#x6709;&#x7684;&#x6587;&#x672C;&#x5206;&#x7C7B;&#x5668;&#x76F4;&#x63A5;&#x5BF9;&#x8FD9;&#x4E9B;&#x6587;&#x7AE0;&#x8FDB;</p>]]></description><link>http://www.fullstackyang.com/ru-he-shi-xian-yi-ge-ji-ben-de-wei-xin-wen-zhang-fen-lei-qi/</link><guid isPermaLink="false">624567890d2dd3000190a004</guid><category><![CDATA[dev]]></category><category><![CDATA[machine learning]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Wed, 28 Feb 2018 16:33:00 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2018/06/51f0a502d12754c5ac9a6d617f0b9f9a.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="http://www.fullstackyang.com/content/images/2018/06/51f0a502d12754c5ac9a6d617f0b9f9a.jpg" alt="&#x5982;&#x4F55;&#x5B9E;&#x73B0;&#x4E00;&#x4E2A;&#x57FA;&#x672C;&#x7684;&#x5FAE;&#x4FE1;&#x6587;&#x7AE0;&#x5206;&#x7C7B;&#x5668;"><p>&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x53F7;&#x53D1;&#x5E03;&#x7684;&#x6587;&#x7AE0;&#x548C;&#x4E00;&#x822C;&#x95E8;&#x6237;&#x7F51;&#x7AD9;&#x7684;&#x65B0;&#x95FB;&#x6587;&#x672C;&#x7C7B;&#x578B;&#x6709;&#x6240;&#x4E0D;&#x540C;&#xFF0C;&#x901A;&#x5E38;&#x4E0D;&#x80FD;&#x7528;&#x73B0;&#x6709;&#x7684;&#x6587;&#x672C;&#x5206;&#x7C7B;&#x5668;&#x76F4;&#x63A5;&#x5BF9;&#x8FD9;&#x4E9B;&#x6587;&#x7AE0;&#x8FDB;&#x884C;&#x5206;&#x7C7B;&#xFF0C;&#x4E0D;&#x8FC7;&#x6587;&#x672C;&#x5206;&#x7C7B;&#x7684;&#x539F;&#x7406;&#x662F;&#x76F8;&#x901A;&#x7684;&#xFF0C;&#x672C;&#x6587;&#x4EE5;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x53F7;&#x6587;&#x7AE0;&#x4E3A;&#x5BF9;&#x8C61;&#xFF0C;&#x4ECB;&#x7ECD;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x5206;&#x7C7B;&#x5668;&#x7684;&#x5B9E;&#x73B0;&#x8FC7;&#x7A0B;&#x3002;</p>
<p>&#x6587;&#x672C;&#x5206;&#x7C7B;&#x7684;&#x79D1;&#x5B66;&#x539F;&#x7406;&#x548C;&#x6570;&#x5B66;&#x8BC1;&#x660E;&#x5728;&#x7F51;&#x4E0A;&#x6709;&#x5F88;&#x591A;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x4E0D;&#x505A;&#x8D58;&#x8FF0;&#xFF0C;&#x672C;&#x6587;&#x5C3D;&#x91CF;&#x4F7F;&#x7528;&#x901A;&#x719F;&#x6613;&#x61C2;&#x7684;&#x8868;&#x8FF0;&#x65B9;&#x5F0F;&#xFF0C;&#x7B80;&#x660E;&#x627C;&#x8981;&#x5730;&#x68B3;&#x7406;&#x4E00;&#x4E0B;&#x6587;&#x672C;&#x5206;&#x7C7B;&#x5668;&#x7684;&#x5404;&#x4E2A;&#x77E5;&#x8BC6;&#x70B9;&#x3002;</p>
<p>&#x53C2;&#x8003;&#x4E86;&#x4E00;&#x4E0B;Github&#xFF0C;&#x53D1;&#x73B0;&#x5C11;&#x6709;Java 8&#x98CE;&#x683C;&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x6240;&#x4EE5;&#x8FD9;&#x91CC;&#x7684;&#x5B9E;&#x73B0;&#x5C3D;&#x91CF;&#x5229;&#x7528;Java 8&#x7684;&#x7279;&#x6027;&#xFF0C;&#x76F8;&#x6BD4;&#x4E4B;&#x524D;&#x4F18;&#x52BF;&#x6709;&#x5F88;&#x591A;&#xFF0C;&#x4F8B;&#x5982;stream&#x5728;&#x7EDF;&#x8BA1;&#x805A;&#x5408;&#x7B49;&#x8FD0;&#x7B97;&#x4E0A;&#x6BD4;&#x8F83;&#x65B9;&#x4FBF;&#xFF0C;&#x4EE3;&#x7801;&#x4E0D;&#x4EC5;&#x7B80;&#x6D01;&#xFF0C;&#x800C;&#x4E14;&#x66F4;&#x52A0;&#x8BED;&#x4E49;&#x5316;&#xFF0C;&#x53E6;&#x5916;&#x5728;&#x591A;&#x7EBF;&#x7A0B;&#x5E76;&#x884C;&#x63A7;&#x5236;&#x4E0A;&#x4E5F;&#x7701;&#x53BB;&#x4E0D;&#x5C11;&#x7684;&#x5DE5;&#x4F5C;&#x3002;</p>
<p>&#x672C;&#x9879;&#x76EE;&#x7684;&#x5730;&#x5740;&#xFF1A;<a href="https://github.com/fullstackyang/article-classifier">https://github.com/fullstackyang/article-classifier</a></p>
<h2 id>&#x4E00;&#x3001;&#x6587;&#x672C;&#x5206;&#x7C7B;&#x5668;&#x7684;&#x6982;&#x8FF0;</h2>
<p>&#x6587;&#x672C;&#x5206;&#x7C7B;&#x5668;&#x53EF;&#x4EE5;&#x770B;&#x4F5C;&#x662F;&#x4E00;&#x4E2A;&#x9884;&#x6D4B;&#x51FD;&#x6570;&#xFF0C;&#x5728;&#x7ED9;&#x5B9A;&#x7684;&#x6587;&#x672C;&#x65F6;&#xFF0C;&#x5728;&#x9884;&#x5B9A;&#x7684;&#x7C7B;&#x522B;&#x96C6;&#x5408;&#x4E2D;&#xFF0C;&#x5224;&#x65AD;&#x8BE5;&#x6587;&#x672C;&#x6700;&#x53EF;&#x80FD;&#x5C5E;&#x4E8E;&#x54EA;&#x4E2A;&#x7C7B;&#x3002;</p>
<p>&#x8FD9;&#x91CC;&#x9700;&#x8981;&#x6CE8;&#x610F;&#x4E24;&#x4E2A;&#x95EE;&#x9898;&#xFF1A;</p>
<ol>
<li>&#x5728;&#x6587;&#x672C;&#x4E2D;&#x542B;&#x6709;&#x6BD4;&#x8F83;&#x591A;&#x7684;&#x6807;&#x70B9;&#x7B26;&#x53F7;&#x548C;&#x505C;&#x7528;&#x8BCD;&#xFF08;&#x7684;&#xFF0C;&#x662F;&#xFF0C;&#x4E86;&#x7B49;&#xFF09;&#xFF0C;&#x76F4;&#x63A5;&#x4F7F;&#x7528;&#x6574;&#x6BB5;&#x6587;&#x672C;&#x5904;&#x7406;&#x80AF;&#x5B9A;&#x4F1A;&#x4EA7;&#x751F;&#x5F88;&#x591A;&#x4E0D;&#x5FC5;&#x8981;&#x7684;&#x8BA1;&#x7B97;&#xFF0C;&#x800C;&#x4E14;&#x8BA1;&#x7B97;&#x91CF;&#x4E5F;&#x975E;&#x5E38;&#x5927;&#xFF0C;&#x56E0;&#x6B64;&#x9700;&#x8981;&#x628A;&#x7ED9;&#x5B9A;&#x7684;&#x6587;&#x672C;&#x6709;&#x6548;&#x5730;&#x8FDB;&#x884C;&#x8868;&#x793A;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x9009;&#x62E9;&#x4E00;&#x7CFB;&#x5217;&#x7684;&#x7279;&#x5F81;&#x8BCD;&#x6765;&#x4EE3;&#x8868;&#x8FD9;&#x7BC7;&#x6587;&#x672C;&#xFF0C;&#x8FD9;&#x4E9B;&#x7279;&#x5F81;&#x8BCD;&#x65E2;&#x53EF;&#x4EE5;&#x6BD4;&#x8F83;&#x597D;&#x5730;&#x53CD;&#x5E94;&#x6240;&#x5C5E;&#x6587;&#x672C;&#x7684;&#x5185;&#x5BB9;&#xFF0C;&#x53C8;&#x53EF;&#x4EE5;&#x5BF9;&#x4E0D;&#x540C;&#x6587;&#x672C;&#x6709;&#x6BD4;&#x8F83;&#x597D;&#x7684;&#x533A;&#x5206;&#x80FD;&#x529B;&#x3002;</li>
<li>&#x5728;&#x8FDB;&#x884C;&#x6587;&#x672C;&#x8868;&#x793A;&#x4E4B;&#x540E;&#xFF0C;&#x5982;&#x4F55;&#x5BF9;&#x8FD9;&#x4E9B;&#x7279;&#x5F81;&#x8BCD;&#x8FDB;&#x884C;&#x9884;&#x6D4B;&#xFF0C;&#x8FD9;&#x5C31;&#x662F;&#x5206;&#x7C7B;&#x5668;&#x7684;&#x7B97;&#x6CD5;&#x8BBE;&#x8BA1;&#x95EE;&#x9898;&#x4E86;&#xFF0C;&#x6BD4;&#x8F83;&#x5E38;&#x89C1;&#x7684;&#x6A21;&#x578B;&#x6709;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#xFF0C;&#x57FA;&#x4E8E;&#x652F;&#x6301;&#x5411;&#x91CF;&#x673A;&#xFF08;SVM&#xFF09;&#xFF0C;K-&#x8FD1;&#x90BB;&#xFF08;KNN&#xFF09;&#xFF0C;&#x51B3;&#x7B56;&#x6811;&#x7B49;&#x5206;&#x7C7B;&#x7B97;&#x6CD5;&#x3002;&#x8FD9;&#x91CC;&#x6211;&#x4EEC;&#x9009;&#x62E9;&#x7B80;&#x5355;&#x6613;&#x61C2;&#x7684;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x7B97;&#x6CD5;&#x3002;&#x5728;&#x673A;&#x5668;&#x5B66;&#x4E60;&#x4E2D;&#xFF0C;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x5EFA;&#x6A21;&#x5C5E;&#x4E8E;&#x6709;&#x76D1;&#x7763;&#x5B66;&#x4E60;&#xFF0C;&#x56E0;&#x6B64;&#x9700;&#x8981;&#x6536;&#x96C6;&#x5927;&#x91CF;&#x7684;&#x6587;&#x672C;&#x4F5C;&#x4E3A;&#x8BAD;&#x7EC3;&#x8BED;&#x6599;&#xFF0C;&#x5E76;&#x6807;&#x6CE8;&#x5206;&#x7C7B;&#x7ED3;&#x679C;</li>
</ol>
<p>&#x7EFC;&#x4E0A;&#xFF0C;&#x5B9E;&#x73B0;&#x4E00;&#x4E2A;&#x5206;&#x7C7B;&#x5668;&#x901A;&#x5E38;&#x5206;&#x4E3A;&#x4EE5;&#x4E0B;&#x51E0;&#x4E2A;&#x6B65;&#x9AA4;&#xFF1A;</p>
<ol>
<li>&#x6536;&#x96C6;&#x5E76;&#x5904;&#x7406;&#x8BAD;&#x7EC3;&#x8BED;&#x6599;&#xFF0C;&#x4EE5;&#x53CA;&#x6700;&#x540E;&#x6D4B;&#x8BD5;&#x7528;&#x7684;&#x6D4B;&#x8BD5;&#x8BED;&#x6599;</li>
<li>&#x5728;&#x8BAD;&#x7EC3;&#x96C6;&#x4E0A;&#x8FDB;&#x884C;&#x7279;&#x5F81;&#x9009;&#x62E9;&#xFF0C;&#x5F97;&#x5230;&#x4E00;&#x7CFB;&#x5217;&#x7684;&#x7279;&#x5F81;&#x9879;&#xFF08;&#x8BCD;&#xFF09;&#xFF0C;&#x8FD9;&#x4E9B;&#x7279;&#x5F81;&#x9879;&#x7EC4;&#x6210;&#x4E86;&#x6240;&#x8C13;&#x7684;&#x7279;&#x5F81;&#x7A7A;&#x95F4;</li>
<li>&#x4E3A;&#x4E86;&#x8868;&#x793A;&#x67D0;&#x4E2A;&#x7279;&#x5F81;&#x9879;&#x5728;&#x4E0D;&#x540C;&#x6587;&#x6863;&#x4E2D;&#x7684;&#x91CD;&#x8981;&#x7A0B;&#x5EA6;&#xFF0C;&#x8BA1;&#x7B97;&#x8BE5;&#x7279;&#x5F81;&#x9879;&#x7684;&#x6743;&#x91CD;&#xFF0C;&#x5E38;&#x7528;&#x7684;&#x8BA1;&#x7B97;&#x65B9;&#x6CD5;&#x6709;TF-IDF&#xFF0C;&#x672C;&#x6587;&#x91C7;&#x7528;&#x7684;&#x662F;&#x201C;&#x7ECF;&#x5178;&#x201D;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x6A21;&#x578B;&#xFF0C;&#x8FD9;&#x91CC;&#x4E0D;&#x8003;&#x8651;&#x7279;&#x5F81;&#x9879;&#x7684;&#x6743;&#x91CD;&#xFF08;&#x5F53;&#x7136;&#xFF0C;&#x4E00;&#x5B9A;&#x8981;&#x505A;&#x4E5F;&#x53EF;&#x4EE5;&#xFF09;</li>
<li>&#x8BAD;&#x7EC3;&#x6A21;&#x578B;&#xFF0C;&#x5BF9;&#x4E8E;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x6A21;&#x578B;&#x6765;&#x8BF4;&#xFF0C;&#x4E3B;&#x8981;&#x7684;&#x662F;&#x8BA1;&#x7B97;&#x6BCF;&#x4E2A;&#x7279;&#x5F81;&#x9879;&#x5728;&#x4E0D;&#x540C;&#x7C7B;&#x522B;&#x4E2D;&#x7684;&#x6761;&#x4EF6;&#x6982;&#x7387;&#xFF0C;&#x8FD9;&#x70B9;&#x4E0B;&#x9762;&#x518D;&#x505A;&#x89E3;&#x91CA;&#x3002;</li>
<li>&#x9884;&#x6D4B;&#x6587;&#x672C;&#xFF0C;&#x6A21;&#x578B;&#x8BAD;&#x7EC3;&#x5B8C;&#x6210;&#x4E4B;&#x540E;&#x53EF;&#x4EE5;&#x4FDD;&#x5B58;&#x5230;&#x6587;&#x4EF6;&#x4E2D;&#xFF0C;&#x5728;&#x9884;&#x6D4B;&#x65F6;&#x76F4;&#x63A5;&#x8BFB;&#x5165;&#x6A21;&#x578B;&#x7684;&#x6570;&#x636E;&#x8FDB;&#x884C;&#x8BA1;&#x7B97;&#x3002;</li>
</ol>
<h2 id>&#x4E8C;&#x3001;&#x51C6;&#x5907;&#x8BAD;&#x7EC3;&#x8BED;&#x6599;</h2>
<p>&#x8FD9;&#x91CC;&#x9700;&#x8981;&#x7684;&#x8BED;&#x6599;&#x5C31;&#x662F;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x53F7;&#x7684;&#x6587;&#x7AE0;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x6293;&#x53D6;&#x641C;&#x72D7;&#x5FAE;&#x4FE1;&#x641C;&#x7D22;&#x7F51;&#x7AD9;(<a href="http://weixin.sogou.com/">http://weixin.sogou.com/</a>)&#x9996;&#x9875;&#x4E0A;&#x5DF2;&#x7ECF;&#x5206;&#x7C7B;&#x597D;&#x7684;&#x6587;&#x7AE0;&#xFF0C;&#x76F4;&#x63A5;&#x91C7;&#x7528;&#x5176;&#x5206;&#x7C7B;&#x7ED3;&#x679C;&#xFF0C;&#x8FD9;&#x6837;&#x4E5F;&#x7701;&#x53BB;&#x4E86;&#x6807;&#x6CE8;&#x7684;&#x5DE5;&#x4F5C;&#x3002;&#x81F3;&#x4E8E;&#x5982;&#x4F55;&#x5F00;&#x53D1;&#x722C;&#x866B;&#x53BB;&#x6293;&#x53D6;&#x6587;&#x7AE0;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x4E0D;&#x518D;&#x8BA8;&#x8BBA;&#x4E86;&#x3002;<br>
<img src="http://www.fullstackyang.com/content/images/2018/06/2858811-871001832a946005..png" alt="&#x5982;&#x4F55;&#x5B9E;&#x73B0;&#x4E00;&#x4E2A;&#x57FA;&#x672C;&#x7684;&#x5FAE;&#x4FE1;&#x6587;&#x7AE0;&#x5206;&#x7C7B;&#x5668;" loading="lazy"><br>
&#x201C;&#x70ED;&#x95E8;&#x201D;&#x8FD9;&#x7C7B;&#x522B;&#x4E0B;&#x7684;&#x6587;&#x7AE0;&#x4E0D;&#x5177;&#x6709;&#x4E00;&#x822C;&#x6027;&#xFF0C;&#x56E0;&#x6B64;&#x4E0D;&#x628A;&#x5B83;&#x5F53;&#x4F5C;&#x4E00;&#x4E2A;&#x7C7B;&#x522B;&#x3002;&#x5254;&#x9664;&#x201C;&#x70ED;&#x95E8;&#x201D;&#x7C7B;&#x522B;&#x4E4B;&#x540E;&#xFF0C;&#x6700;&#x7EC8;&#x6211;&#x4EEC;&#x6293;&#x53D6;&#x4E86;30410&#x7BC7;&#x6587;&#x7AE0;&#xFF0C;&#x603B;&#x5171;20&#x4E2A;&#x7C7B;&#x522B;&#xFF0C;&#x6BCF;&#x4E2A;&#x7C7B;&#x522B;&#x7684;&#x6587;&#x7AE0;&#x6570;&#x5E76;&#x4E0D;&#x5747;&#x8861;&#xFF0C;&#x5176;&#x4E2D;&#x6700;&#x591A; &#x7684;&#x662F;&#x201C;&#x517B;&#x751F;&#x5802;&#x201D;&#x7C7B;&#x522B;&#xFF0C;&#x6709;2569&#x7BC7;&#x6587;&#x7AE0;&#xFF0C;&#x6700;&#x5C11;&#x7684;&#x662F;&#x201C;&#x519B;&#x4E8B;&#x201D;&#x7C7B;&#x522B;&#xFF0C;&#x6709;654&#x7BC7;&#xFF0C;&#x5927;&#x4F53;&#x7B26;&#x5408;&#x5FAE;&#x4FE1;&#x4E0A;&#x6587;&#x7AE0;&#x7684;&#x5206;&#x5E03;&#x60C5;&#x51B5;&#x3002;&#x5728;&#x4FDD;&#x5B58;&#x65F6;&#xFF0C;&#x6211;&#x4EEC;&#x4FDD;&#x7559;&#x4E86;&#x6587;&#x7AE0;&#x7684;&#x6807;&#x9898;&#xFF0C;&#x516C;&#x4F17;&#x53F7;&#x540D;&#x79F0;&#xFF0C;&#x6587;&#x7AE0;&#x6B63;&#x6587;&#x3002;</p>
<h2 id>&#x4E09;&#x3001;&#x7279;&#x5F81;&#x9009;&#x62E9;</h2>
<p>&#x5982;&#x524D;&#x6587;&#x6240;&#x8FF0;&#xFF0C;&#x7279;&#x5F81;&#x9009;&#x62E9;&#x7684;&#x76EE;&#x7684;&#x662F;&#x964D;&#x4F4E;&#x7279;&#x5F81;&#x7A7A;&#x95F4;&#x7684;&#x7EF4;&#x5EA6;&#xFF0C;&#x907F;&#x514D;&#x7EF4;&#x5EA6;&#x707E;&#x96BE;&#x3002;&#x7B80;&#x5355;&#x5730;&#x8BF4;&#xFF0C;&#x5047;&#x8BBE;&#x6211;&#x4EEC;&#x9009;&#x62E9;&#x4E86;2&#x4E07;&#x4E2A;&#x7279;&#x5F81;&#x8BCD;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x8BF4;&#x8BA1;&#x7B97;&#x673A;&#x901A;&#x8FC7;&#x5B66;&#x4E60;&#xFF0C;&#x5F97;&#x5230;&#x4E86;&#x4E00;&#x5F20;&#x6709;2&#x4E07;&#x4E2A;&#x8BCD;&#x7684;&#x201C;&#x5355;&#x8BCD;&#x8868;&#x201D;&#xFF0C;&#x4EE5;&#x540E;&#x5B83;&#x9047;&#x5230;&#x7684;&#x6240;&#x6709;&#x6587;&#x672C;&#x53EF;&#x4EE5;&#x591F;&#x7528;&#x8FD9;&#x5F20;&#x5355;&#x8BCD;&#x8868;&#x4E2D;&#x7684;&#x8BCD;&#x53BB;&#x8868;&#x793A;&#x5176;&#x5185;&#x5BB9;&#x5927;&#x610F;&#x3002;&#x8FD9;&#x4E9B;&#x7279;&#x5F81;&#x8BCD;&#x9488;&#x5BF9;&#x4E0D;&#x540C;&#x7684;&#x7C7B;&#x522B;&#x6709;&#x4E00;&#x5B9A;&#x7684;&#x533A;&#x5206;&#x80FD;&#x529B;&#xFF0C;&#x4E3E;&#x4F8B;&#x6765;&#x8BF4;&#xFF0C;&#x201C;&#x6B7C;&#x51FB;&#x673A;&#x201D;&#x53EF;&#x80FD;&#x6765;&#x81EA;&#x201C;&#x519B;&#x4E8B;&#x201D;&#xFF0C;&#x201C;&#x8D8A;&#x4F4D;&#x201D;&#x53EF;&#x80FD;&#x6765;&#x81EA;&#x201C;&#x4F53;&#x80B2;&#x201D;&#xFF0C;&#x201C;&#x6DA8;&#x505C;&#x201D;&#x53EF;&#x80FD;&#x6765;&#x81EA;&#x201C;&#x8D22;&#x7ECF;&#x201D;&#x7B49;&#x7B49;&#xFF0C;&#x800C;&#x901A;&#x5E38;&#x4E2D;&#x6587;&#x8BCD;&#x6C47;&#x91CF;&#x8981;&#x6BD4;&#x8FD9;&#x4E2A;&#x6570;&#x5B57;&#x5927;&#x5F97;&#x591A;&#xFF0C;&#x4E00;&#x672C;&#x5E38;&#x89C1;&#x7684;&#x6C49;&#x8BED;&#x8BCD;&#x5178;&#x6536;&#x5F55;&#x7684;&#x8BCD;&#x6761;&#x6570;&#x53EF;&#x8FBE;&#x6570;&#x5341;&#x4E07;&#x3002;</p>
<p>&#x5E38;&#x89C1;&#x7684;&#x7279;&#x5F81;&#x9009;&#x62E9;&#x65B9;&#x6CD5;&#x6709;&#x4E24;&#x4E2A;&#xFF0C;&#x4FE1;&#x606F;&#x589E;&#x76CA;&#x6CD5;&#x548C;&#x5361;&#x65B9;&#x68C0;&#x9A8C;&#x6CD5;&#x3002;</p>
<h3 id="31">3.1 &#x4FE1;&#x606F;&#x589E;&#x76CA;</h3>
<p>&#x4FE1;&#x606F;&#x589E;&#x76CA;&#x6CD5;&#x7684;&#x8861;&#x91CF;&#x6807;&#x51C6;&#x662F;&#xFF0C;&#x8FD9;&#x4E2A;&#x7279;&#x5F81;&#x9879;&#x53EF;&#x4EE5;&#x4E3A;&#x5206;&#x7C7B;&#x7CFB;&#x7EDF;&#x5E26;&#x6765;&#x591A;&#x5C11;&#x4FE1;&#x606F;&#x91CF;&#xFF0C;&#x6240;&#x8C13;&#x7684;&#x4FE1;&#x606F;&#x589E;&#x76CA;&#x5C31;&#x662F;&#x8BE5;&#x7279;&#x5F81;&#x9879;&#x5305;&#x542B;&#x7684;&#x80FD;&#x591F;&#x5E2E;&#x9884;&#x6D4B;&#x7C7B;&#x522B;&#x7684;&#x4FE1;&#x606F;&#x91CF;&#xFF0C;&#x8FD9;&#x91CC;&#x6240;&#x8BF4;&#x7684;&#x4FE1;&#x606F;&#x91CF;&#x53EF;&#x4EE5;&#x7528;&#x71B5;&#x6765;&#x8861;&#x91CF;&#xFF0C;&#x8BA1;&#x7B97;&#x4FE1;&#x606F;&#x589E;&#x76CA;&#x65F6;&#x8FD8;&#x9700;&#x8981;&#x5F15;&#x5165;&#x6761;&#x4EF6;&#x71B5;&#x7684;&#x6982;&#x5FF5;&#xFF0C;&#x516C;&#x5F0F;&#x5982;&#x4E0B;<br>
<img src="http://www.fullstackyang.com/content/images/2018/06/2096684073-5a97b3054c0a4.png" alt="&#x5982;&#x4F55;&#x5B9E;&#x73B0;&#x4E00;&#x4E2A;&#x57FA;&#x672C;&#x7684;&#x5FAE;&#x4FE1;&#x6587;&#x7AE0;&#x5206;&#x7C7B;&#x5668;" loading="lazy"><br>
&#x53EF;&#x80FD;&#x6709;&#x4E9B;&#x89C1;&#x5230;&#x516C;&#x5F0F;&#x5C31;&#x5934;&#x5927;&#x7684;&#x5C0F;&#x4F19;&#x4F34;&#x4E0D;&#x592A;&#x53CB;&#x597D;&#xFF0C;&#x4E0D;&#x8FC7;&#x8FD9;&#x4E2A;&#x516C;&#x5F0F;&#x867D;&#x7136;&#x770B;&#x8D77;&#x6765;&#x6709;&#x70B9;&#x590D;&#x6742;&#xFF0C;&#x5176;&#x5B9E;&#x5728;&#x8BA1;&#x7B97;&#x4E2D;&#x8FD8;&#x662F;&#x6BD4;&#x8F83;&#x7B80;&#x5355;&#x7684;&#xFF0C;&#x89E3;&#x91CA;&#x4E00;&#x4E0B;&#xFF1A;</p>
<p>P(Cj)&#xFF1A;Cj&#x7C7B;&#x6587;&#x6863;&#x5728;&#x6574;&#x4E2A;&#x8BED;&#x6599;&#x4E2D;&#x51FA;&#x73B0;&#x7684;&#x6982;&#x7387;&#xFF1B;</p>
<p>P(ti)&#xFF1A;&#x8BED;&#x6599;&#x4E2D;&#x5305;&#x542B;&#x7279;&#x5F81;&#x9879;ti&#x7684;&#x6587;&#x6863;&#x7684;&#x6982;&#x7387;&#xFF0C;&#x53D6;&#x53CD;&#x5C31;&#x662F;&#x4E0D;&#x5305;&#x542B;&#x7279;&#x5F81;&#x9879;ti&#x7684;&#x6587;&#x6863;&#x7684;&#x6982;&#x7387;&#xFF1B;</p>
<p>P(Cj|ti)&#xFF1A;&#x6587;&#x6863;&#x5305;&#x542B;&#x7279;&#x5F81;&#x9879;ti&#x4E14;&#x5C5E;&#x4E8E;Cj&#x7C7B;&#x7684;&#x6761;&#x4EF6;&#x6982;&#x7387;&#xFF0C;&#x53D6;&#x53CD;&#x5C31;&#x662F;&#x6587;&#x6863;&#x4E0D;&#x5305;&#x542B;&#x7279;&#x5F81;&#x9879;ti&#x4E14;&#x5C5E;&#x4E8E;Cj&#x7C7B;&#x7684;&#x6761;&#x4EF6;&#x6982;&#x7387;</p>
<p>&#x4E0A;&#x9762;&#x51E0;&#x4E2A;&#x6982;&#x7387;&#x503C;&#xFF0C;&#x90FD;&#x53EF;&#x4EE5;&#x6BD4;&#x8F83;&#x65B9;&#x4FBF;&#x5730;&#x4ECE;&#x8BAD;&#x7EC3;&#x8BED;&#x6599;&#x4E0A;&#x7EDF;&#x8BA1;&#x5F97;&#x5230;&#x3002;&#x82E5;&#x8FD8;&#x6709;&#x4E0D;&#x660E;&#x767D;&#x7684;&#x5C0F;&#x4F19;&#x4F34;&#xFF0C;&#x63A8;&#x8350;&#x9605;&#x8BFB;&#x8FD9;&#x7BC7;&#x535A;&#x5BA2;&#xFF1A;<a href="http://www.blogjava.net/zhenandaci/archive/2009/03/24/261701.html">&#x6587;&#x672C;&#x5206;&#x7C7B;&#x5165;&#x95E8;&#xFF08;&#x5341;&#x4E00;&#xFF09;&#x7279;&#x5F81;&#x9009;&#x62E9;&#x65B9;&#x6CD5;&#x4E4B;&#x4FE1;&#x606F;&#x589E;&#x76CA;</a></p>
<h3 id="32">3.2 &#x5361;&#x65B9;&#x68C0;&#x9A8C;</h3>
<p>&#x5361;&#x65B9;&#x68C0;&#x9A8C;&#xFF0C;&#x57FA;&#x4E8E;&#x3C7;2&#x7EDF;&#x8BA1;&#x91CF;(CHI)&#x6765;&#x8861;&#x91CF;&#x7279;&#x5F81;&#x9879;ti&#x548C;&#x7C7B;&#x522B;Cj&#x4E4B;&#x95F4;&#x7684;&#x76F8;&#x5173;&#x8054;&#x7A0B;&#x5EA6;&#xFF0C;CHI&#x7EDF;&#x8BA1;&#x503C;&#x8D8A;&#x9AD8;&#xFF0C;&#x8BE5;&#x7279;&#x5F81;&#x9879;&#x4E0E;&#x8BE5;&#x7C7B;&#x7684;&#x76F8;&#x5173;&#x6027;&#x8D8A;&#x5927;&#xFF0C;&#x5982;&#x679C;&#x4E24;&#x8005;&#x76F8;&#x4E92;&#x72EC;&#x7ACB;&#xFF0C;&#x5219;CHI&#x7EDF;&#x8BA1;&#x503C;&#x63A5;&#x8FD1;&#x96F6;&#x3002;&#x8BA1;&#x7B97;&#x65F6;&#x9700;&#x8981;&#x6839;&#x636E;&#x4E00;&#x5F20;&#x76F8;&#x4F9D;&#x8868;&#xFF08;contingency table&#xFF09;&#xFF0C;&#x516C;&#x5F0F;&#x4E5F;&#x6BD4;&#x8F83;&#x7B80;&#x5355;&#xFF1A;<br>
<img src="http://www.fullstackyang.com/content/images/2018/06/604997658-5a97b33c50d2c.png" alt="&#x5982;&#x4F55;&#x5B9E;&#x73B0;&#x4E00;&#x4E2A;&#x57FA;&#x672C;&#x7684;&#x5FAE;&#x4FE1;&#x6587;&#x7AE0;&#x5206;&#x7C7B;&#x5668;" loading="lazy"></p>
<center>
<p><img src="http://www.fullstackyang.com/content/images/2018/06/2233310779-5a97b3517d025.png" alt="&#x5982;&#x4F55;&#x5B9E;&#x73B0;&#x4E00;&#x4E2A;&#x57FA;&#x672C;&#x7684;&#x5FAE;&#x4FE1;&#x6587;&#x7AE0;&#x5206;&#x7C7B;&#x5668;" loading="lazy"></p>
</center>
&#x5176;&#x4E2D;N&#x5C31;&#x662F;&#x6587;&#x6863;&#x603B;&#x6570;&#xFF0C;&#x5982;&#x679C;&#x60F3;&#x7EE7;&#x7EED;&#x8BA8;&#x8BBA;&#x8FD9;&#x4E2A;&#x516C;&#x5F0F;&#xFF0C;&#x63A8;&#x8350;&#x9605;&#x8BFB;&#x8FD9;&#x7BC7;&#x535A;&#x5BA2;&#xFF1A;[&#x7279;&#x5F81;&#x9009;&#x62E9;&#xFF08;3&#xFF09;-&#x5361;&#x65B9;&#x68C0;&#x9A8C;](http://www.deeplearn.me/1446.html)
<h3 id="33">3.3 &#x7B97;&#x6CD5;&#x5B9E;&#x73B0;</h3>
<p>&#x4E0D;&#x8BBA;&#x4F55;&#x79CD;&#x65B9;&#x5F0F;&#x90FD;&#x9700;&#x8981;&#x5BF9;&#x6BCF;&#x4E2A;&#x7279;&#x5F81;&#x9879;&#x8FDB;&#x884C;&#x4F30;&#x7B97;&#xFF0C;&#x7136;&#x540E;&#x6839;&#x636E;&#x6240;&#x5F97;&#x7684;&#x6570;&#x503C;&#x8FDB;&#x884C;&#x7B5B;&#x9009;&#xFF0C;&#x901A;&#x5E38;&#x53EF;&#x4EE5;&#x8BBE;&#x5B9A;&#x4E00;&#x4E2A;&#x9608;&#x503C;&#xFF0C;&#x4F4E;&#x4E8E;&#x9608;&#x503C;&#x7684;&#x7279;&#x5F81;&#x9879;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x4ECE;&#x7279;&#x5F81;&#x7A7A;&#x95F4;&#x4E2D;&#x79FB;&#x9664;&#xFF0C;&#x53E6;&#x5916;&#x4E5F;&#x53EF;&#x4EE5;&#x6309;&#x7167;&#x6570;&#x503C;&#x4ECE;&#x9AD8;&#x5230;&#x4F4E;&#x6392;&#x5E8F;&#xFF0C;&#x5E76;&#x6307;&#x5B9A;&#x9009;&#x62E9;&#x524D;N&#x4E2A;&#x3002;&#x8FD9;&#x91CC;&#x6211;&#x4EEC;&#x91C7;&#x7528;&#x540E;&#x8005;&#xFF0C;&#x603B;&#x5171;&#x622A;&#x53D6;&#x524D;2&#x4E07;&#x4E2A;&#x7279;&#x5F81;&#x9879;&#x3002;</p>
<p>&#x7279;&#x5F81;&#x9009;&#x62E9;&#x5B9E;&#x73B0;&#x7C7B;&#x7684;&#x4EE3;&#x7801;&#x5982;&#x4E0B;&#xFF0C;&#x5176;&#x4E2D;&#xFF0C;&#x4E0D;&#x540C;&#x7279;&#x5F81;&#x9009;&#x62E9;&#x65B9;&#x6CD5;&#x9700;&#x5B9E;&#x73B0;Strategy&#x63A5;&#x53E3;&#xFF0C;&#x4EE5;&#x83B7;&#x5F97;&#x4E0D;&#x540C;&#x65B9;&#x6CD5;&#x8BA1;&#x7B97;&#x5F97;&#x5230;&#x7684;&#x4F30;&#x503C;&#xFF0C;&#x8FD9;&#x91CC;&#x5728;&#x622A;&#x53D6;&#x7279;&#x5F81;&#x9879;&#x65F6;&#x4E3A;&#x4E86;&#x907F;&#x514D;&#x4E0D;&#x5FC5;&#x8981;&#x7684;&#x9EBB;&#x70E6;&#xFF0C;&#x5254;&#x9664;&#x4E86;&#x5B57;&#x7B26;&#x4E32;&#x957F;&#x5EA6;&#x4E3A;1&#x7684;&#x8BCD;&#x3002;</p>
<p>Doc&#x5BF9;&#x8C61;&#x8868;&#x793A;&#x4E00;&#x7BC7;&#x6587;&#x6863;&#xFF0C;&#x5176;&#x4E2D;&#x5305;&#x542B;&#x4E86;&#x8BE5;&#x6587;&#x6863;&#x7684;&#x6240;&#x5C5E;&#x5206;&#x7C7B;&#xFF0C;&#x4EE5;&#x53CA;&#x5206;&#x8BCD;&#x7ED3;&#x679C;&#xFF08;&#x5DF2;&#x7ECF;&#x6EE4;&#x6389;&#x4E86;&#x505C;&#x7528;&#x8BCD;&#x7B49;&#xFF09;&#xFF0C;&#x5373;Term&#x96C6;&#x5408;&#xFF1B;</p>
<p>Term&#x5BF9;&#x8C61;&#x4E3B;&#x8981;&#x5305;&#x542B;3&#x4E2A;&#x5B57;&#x6BB5;&#xFF0C;&#x8BCD;&#x672C;&#x8EAB;&#x7684;&#x5B57;&#x7B26;&#x4E32;&#xFF0C;&#x8BCD;&#x6027;&#xFF08;&#x7528;&#x4E8E;&#x8FC7;&#x6EE4;&#xFF09;&#xFF0C;&#x8BCD;&#x9891;TF&#xFF1B;</p>
<p>Feature&#x8868;&#x793A;&#x7279;&#x5F81;&#x9879;&#xFF0C;&#x4E00;&#x4E2A;&#x7279;&#x5F81;&#x9879;&#x5BF9;&#x5E94;&#x4E00;&#x4E2A;Term&#x5BF9;&#x8C61;&#xFF0C;&#x8FD8;&#x5305;&#x542B;&#x4E24;&#x4E2A;hashmap&#xFF0C;&#x4E00;&#x4E2A;&#x7528;&#x6765;&#x7EDF;&#x8BA1;&#x4E0D;&#x540C;&#x7C7B;&#x522B;&#x4E0B;&#x8BE5;&#x7279;&#x5F81;&#x9879;&#x51FA;&#x73B0;&#x7684;&#x6587;&#x6863;&#x6570;&#x91CF;&#xFF08;categoryDocCounter&#xFF09;&#xFF0C;&#x53E6;&#x4E00;&#x4E2A;&#x7528;&#x6765;&#x7EDF;&#x8BA1;&#x4E0D;&#x540C;&#x7C7B;&#x522B;&#x4E0B;&#x8BE5;&#x7279;&#x5F81;&#x9879;&#x51FA;&#x73B0;&#x7684;&#x9891;&#x5EA6;&#xFF08;categoryTermCounter&#xFF09;&#xFF08;&#x5BF9;&#x5E94;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x4E24;&#x79CD;&#x4E0D;&#x540C;&#x6A21;&#x578B;&#xFF0C;&#x4E0B;&#x6587;&#x8BE6;&#x8FF0;&#xFF09;</p>
<p>&#x7EDF;&#x8BA1;&#x65F6;&#x5F15;&#x5165;FeatureCounter&#x5BF9;&#x8C61;&#xFF0C;&#x4F7F;&#x7528;stream&#x7684;reduce&#x65B9;&#x6CD5;&#x8FDB;&#x884C;&#x5F52;&#x7EA6;&#x3002;&#x4E3B;&#x8981;&#x7684;&#x601D;&#x60F3;&#x5C31;&#x662F;&#x628A;&#x6BCF;&#x4E00;&#x4E2A;&#x6587;&#x6863;&#x4E2D;&#x7684;Term&#x96C6;&#x5408;&#xFF0C;&#x6620;&#x5C04;&#x4E3A;Term&#x548C;Feature&#x7684;&#x952E;&#x503C;&#x5BF9;&#xFF0C;&#x7136;&#x540E;&#x518D;&#x548C;&#x5DF2;&#x6709;&#x7684;Map&#x8FDB;&#x884C;&#x5408;&#x5E76;&#xFF0C;&#x5408;&#x5E76;&#x65F6;&#x5982;&#x679C;&#x9047;&#x5230;&#x76F8;&#x540C;&#x7684;Term&#xFF0C;&#x5219;&#x8C03;&#x7528;Feature&#x7684;Merge&#x65B9;&#x6CD5;&#xFF0C;&#x8BE5;&#x65B9;&#x6CD5;&#x4F1A;&#x5C06;&#x53CC;&#x65B9;term&#x7684;&#x8BCD;&#x9891;&#xFF0C;&#x4EE5;&#x53CA;categoryDocCounter&#x548C;categoryTermCounter&#x4E2D;&#x7684;&#x7EDF;&#x8BA1;&#x7ED3;&#x679C;&#x8FDB;&#x884C;&#x7D2F;&#x52A0;&#x3002;&#x6700;&#x7EC8;&#x5C06;&#x6240;&#x6709;&#x6587;&#x6863;&#x5168;&#x90E8;&#x7EDF;&#x8BA1;&#x5B8C;&#x6210;&#x8FD4;&#x56DE;Feature&#x96C6;&#x5408;&#x3002;</p>
<pre><code>@AllArgsConstructor
public class FeatureSelection {

    interface Strategy {
        Feature estimate(Feature feature);
    }

    private final Strategy strategy;
    private final static int FEATURE_SIZE = 20000;

    public List&lt;Feature&gt; select(List&lt;Doc&gt; docs) {
        return createFeatureSpace(docs.stream())
                .stream()
                .map(strategy::estimate)
                .filter(f -&gt; f.getTerm().getWord().length() &gt; 1)
                .sorted(comparing(Feature::getScore).reversed())
                .limit(FEATURE_SIZE)
                .collect(toList());
    }

    private Collection&lt;Feature&gt; createFeatureSpace(Stream&lt;Doc&gt; docs) {

        @AllArgsConstructor
        class FeatureCounter {
            private final Map&lt;Term, Feature&gt; featureMap;

            private FeatureCounter accumulate(Doc doc) {
                Map&lt;Term, Feature&gt; temp = doc.getTerms().parallelStream()
                        .map(t -&gt; new Feature(t, doc.getCategory()))
                        .collect(toMap(Feature::getTerm, Function.identity()));
                if (!featureMap.isEmpty())
                    featureMap.values().forEach(f -&gt; temp.merge(f.getTerm(), f, Feature::merge));
                return new FeatureCounter(temp);
            }

            private FeatureCounter combine(FeatureCounter featureCounter) {
                Map&lt;Term, Feature&gt; temp = Maps.newHashMap(featureMap);
                featureCounter.featureMap.values().forEach(f -&gt; temp.merge(f.getTerm(), f, Feature::merge));
                return new FeatureCounter(temp);
            }
        }

        FeatureCounter counter = docs.parallel()
                .reduce(new FeatureCounter(Maps.newHashMap()),
                        FeatureCounter::accumulate,
                        FeatureCounter::combine);
        return counter.featureMap.values();
    }
}
public class Feature {
...
    public Feature merge(Feature feature) {
        if (this.term.equals(feature.getTerm())) {
            this.term.setTf(this.term.getTf() + feature.getTerm().getTf());
            feature.getCategoryDocCounter()
                    .forEach((k, v) -&gt; categoryDocCounter.merge(k, v, (oldValue, newValue) -&gt; oldValue + newValue));
            feature.getCategoryTermCounter()
                    .forEach((k, v) -&gt; categoryTermCounter.merge(k, v, (oldValue, newValue) -&gt; oldValue + newValue));
        }
        return this;
    }
}
</code></pre>
<p>&#x4FE1;&#x606F;&#x589E;&#x76CA;&#x5B9E;&#x73B0;&#x5982;&#x4E0B;&#xFF0C;&#x5728;&#x8BA1;&#x7B97;&#x6761;&#x4EF6;&#x71B5;&#x65F6;&#xFF0C;&#x5229;&#x7528;&#x4E86;stream&#x7684;collect&#x65B9;&#x6CD5;&#xFF0C;&#x5C06;&#x5305;&#x542B;&#x548C;&#x4E0D;&#x5305;&#x542B;&#x7279;&#x5F81;&#x9879;&#x7684;&#x4E24;&#x79CD;&#x60C5;&#x51B5;&#x7528;&#x4E00;&#x4E2A;hashmap&#x5206;&#x5F00;&#x518D;&#x8FDB;&#x884C;&#x5F52;&#x7EA6;&#x3002;</p>
<pre><code>@AllArgsConstructor
public class IGStrategy implements FeatureSelection.Strategy {

    private final Collection&lt;Category&gt; categories;

    private final int total;

    public Feature estimate(Feature feature) {
        double totalEntropy = calcTotalEntropy();
        double conditionalEntrogy = calcConditionEntropy(feature);
        feature.setScore(totalEntropy - conditionalEntrogy);
        return feature;
    }

    private double calcTotalEntropy() {
        return Calculator.entropy(categories.stream().map(c -&gt; (double) c.getDocCount() / total).collect(toList()));
    }

    private double calcConditionEntropy(Feature feature) {
        int featureCount = feature.getFeatureCount();
        double Pfeature = (double) featureCount / total;

        Map&lt;Boolean, List&lt;Double&gt;&gt; Pcondition = categories.parallelStream().collect(() -&gt; new HashMap&lt;Boolean, List&lt;Double&gt;&gt;() {{
                    put(true, Lists.newArrayList());
                    put(false, Lists.newArrayList());
                }}, (map, category) -&gt; {
                    int countDocWithFeature = feature.getDocCountByCategory(category);
                    //&#x51FA;&#x73B0;&#x8BE5;&#x7279;&#x5F81;&#x8BCD;&#x4E14;&#x5C5E;&#x4E8E;&#x7C7B;&#x522B;key&#x7684;&#x6587;&#x6863;&#x6570;&#x91CF;/&#x51FA;&#x73B0;&#x8BE5;&#x7279;&#x5F81;&#x8BCD;&#x7684;&#x6587;&#x6863;&#x603B;&#x6570;&#x91CF;
                    map.get(true).add((double) countDocWithFeature / featureCount);
                    //&#x672A;&#x51FA;&#x73B0;&#x8BE5;&#x7279;&#x5F81;&#x8BCD;&#x4E14;&#x5C5E;&#x4E8E;&#x7C7B;&#x522B;key&#x7684;&#x6587;&#x6863;&#x6570;&#x91CF;/&#x672A;&#x51FA;&#x73B0;&#x8BE5;&#x7279;&#x5F81;&#x8BCD;&#x7684;&#x6587;&#x6863;&#x603B;&#x6570;&#x91CF;
                    map.get(false).add((double) (category.getDocCount() - countDocWithFeature) / (total - featureCount));
                },
                (map1, map2) -&gt; {
                    map1.get(true).addAll(map2.get(true));
                    map1.get(false).addAll(map2.get(false));
                }
        );
        return Calculator.conditionalEntrogy(Pfeature, Pcondition.get(true), Pcondition.get(false));
    }
}
</code></pre>
<p>&#x5361;&#x65B9;&#x68C0;&#x9A8C;&#x5B9E;&#x73B0;&#x5982;&#x4E0B;&#xFF0C;&#x6BCF;&#x4E2A;&#x7279;&#x5F81;&#x9879;&#x8981;&#x5728;&#x6BCF;&#x4E2A;&#x7C7B;&#x522B;&#x4E0A;&#x5206;&#x522B;&#x8BA1;&#x7B97;CHI&#x503C;&#xFF0C;&#x6700;&#x7EC8;&#x4FDD;&#x7559;&#x5176;&#x6700;&#x5927;&#x503C;</p>
<pre><code>@AllArgsConstructor
public class ChiSquaredStrategy implements Strategy {

    private final Collection&lt;Category&gt; categories;

    private final int total;

    @Override
    public Feature estimate(Feature feature) {

        class ContingencyTable {
            private final int A, B, C, D;

            private ContingencyTable(Feature feature, Category category) {
                A = feature.getDocCountByCategory(category);
                B = feature.getFeatureCount() - A;
                C = category.getDocCount() - A;
                D = total - A - B - C;
            }
        }

        Double chisquared = categories.stream()
                .map(c -&gt; new ContingencyTable(feature, c))
                .map(ct -&gt; Calculator.chisquare(ct.A, ct.B, ct.C, ct.D))
                .max(Comparator.comparingDouble(Double::valueOf)).get();
        feature.setScore(chisquared);
        return feature;
    }
}
</code></pre>
<h2 id>&#x56DB;&#x3001;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x6A21;&#x578B;</h2>
<h3 id="41">4.1 &#x539F;&#x7406;&#x7B80;&#x4ECB;</h3>
<p>&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x6A21;&#x578B;&#x4E4B;&#x6240;&#x4EE5;&#x79F0;&#x4E4B;&#x201C;&#x6734;&#x7D20;&#x201D;&#xFF0C;&#x662F;&#x56E0;&#x4E3A;&#x5176;&#x5047;&#x8BBE;&#x7279;&#x5F81;&#x4E4B;&#x95F4;&#x662F;&#x76F8;&#x4E92;&#x72EC;&#x7ACB;&#x7684;&#xFF0C;&#x5728;&#x6587;&#x672C;&#x5206;&#x7C7B;&#x4E2D;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x8BF4;&#xFF0C;&#x4E00;&#x7BC7;&#x6587;&#x6863;&#x4E2D;&#x51FA;&#x73B0;&#x7684;&#x8BCD;&#x90FD;&#x662F;&#x76F8;&#x4E92;&#x72EC;&#x7ACB;&#xFF0C;&#x5F7C;&#x6B64;&#x6CA1;&#x6709;&#x5173;&#x8054;&#xFF0C;&#x663E;&#x7136;&#x6587;&#x6863;&#x4E2D;&#x51FA;&#x73B0;&#x7684;&#x8BCD;&#x90FD;&#x662F;&#x6709;&#x903B;&#x8F91;&#x6027;&#x7684;&#xFF0C;&#x8FD9;&#x79CD;&#x5047;&#x8BBE;&#x5728;&#x73B0;&#x5B9E;&#x4E2D;&#x51E0;&#x4E4E;&#x662F;&#x4E0D;&#x6210;&#x7ACB;&#x7684;&#xFF0C;&#x4F46;&#x662F;&#x8FD9;&#x79CD;&#x5047;&#x8BBE;&#x5374;&#x5927;&#x5927;&#x7B80;&#x5316;&#x4E86;&#x8BA1;&#x7B97;&#xFF0C;&#x6839;&#x636E;&#x8D1D;&#x53F6;&#x65AF;&#x516C;&#x5F0F;&#xFF0C;&#x6587;&#x6863;Doc&#x5C5E;&#x4E8E;&#x7C7B;&#x522B;Ci&#x7684;&#x6982;&#x7387;&#x4E3A;&#xFF1A;</p>
<center>
<p><img src="http://www.fullstackyang.com/content/images/2018/06/998168355-5a97b45d28de0.png" alt="&#x5982;&#x4F55;&#x5B9E;&#x73B0;&#x4E00;&#x4E2A;&#x57FA;&#x672C;&#x7684;&#x5FAE;&#x4FE1;&#x6587;&#x7AE0;&#x5206;&#x7C7B;&#x5668;" loading="lazy"></p>
</center>
P(Ci|Doc)&#x662F;&#x6240;&#x6C42;&#x7684;&#x540E;&#x9A8C;&#x6982;&#x7387;&#xFF0C;&#x6211;&#x4EEC;&#x5728;&#x5224;&#x5B9A;&#x5206;&#x7C7B;&#x65F6;&#xFF0C;&#x6839;&#x636E;&#x6BCF;&#x4E2A;&#x7C7B;&#x522B;&#x8BA1;&#x7B97;P(Ci|Doc)&#xFF0C;&#x6700;&#x7EC8;&#x628A;P(Ci|Doc)&#x53D6;&#x5F97;&#x6700;&#x5927;&#x503C;&#x7684;&#x90A3;&#x4E2A;&#x5206;&#x7C7B;&#x4F5C;&#x4E3A;&#x6587;&#x6863;&#x7684;&#x7C7B;&#x522B;&#x3002;&#x5176;&#x4E2D;&#xFF0C;P(Doc)&#x5BF9;&#x4E8E;&#x7C7B;&#x522B;Ci&#x6765;&#x8BF4;&#x662F;&#x5E38;&#x91CF;&#xFF0C;&#x5728;&#x6BD4;&#x8F83;&#x5927;&#x5C0F;&#x65F6;&#x53EF;&#x4EE5;&#x4E0D;&#x7528;&#x53C2;&#x4E0E;&#x8BA1;&#x7B97;&#xFF0C;&#x800C;P(Ci)&#x8868;&#x793A;&#x7C7B;&#x522B;Ci&#x51FA;&#x73B0;&#x7684;&#x6982;&#x7387;&#xFF0C;&#x6211;&#x4EEC;&#x79F0;&#x4E4B;&#x4E3A;&#x5148;&#x9A8C;&#x6982;&#x7387;&#xFF0C;&#x8FD9;&#x53EF;&#x4EE5;&#x65B9;&#x4FBF;&#x5730;&#x4ECE;&#x8BAD;&#x7EC3;&#x96C6;&#x4E2D;&#x7EDF;&#x8BA1;&#x5F97;&#x51FA;&#xFF0C;&#x81F3;&#x4E8E;P(Doc|Ci)&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x7C7B;&#x522B;&#x7684;&#x6761;&#x4EF6;&#x6982;&#x7387;&#xFF0C;&#x5982;&#x679C;&#x6CA1;&#x6709;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x7684;&#x5047;&#x8BBE;&#xFF0C;&#x90A3;&#x4E48;&#x8BA1;&#x7B97;&#x662F;&#x975E;&#x5E38;&#x56F0;&#x96BE;&#x7684;&#x3002;
<p>&#x4E3E;&#x4F8B;&#x6765;&#x8BF4;&#xFF0C;&#x5047;&#x8BBE;&#x6709;&#x4E00;&#x7BC7;&#x6587;&#x7AE0;&#xFF0C;&#x5185;&#x5BB9;&#x4E3A;&#x201C;&#x738B;&#x8005;&#x8363;&#x8000;&#xFF1A;&#x4E24;&#x6B3E;&#x4F20;&#x8BF4;&#x54C1;&#x8D28;&#x76AE;&#x80A4;&#x5C06;&#x4F18;&#x5316;&#xFF0C;&#x674E;&#x767D;&#x6700;&#x65B0;&#x6A21;&#x578B;&#x6D77;&#x62A5;&#x7206;&#x6599;&#x201D;&#xFF0C;&#x7ECF;&#x8FC7;&#x7279;&#x5F81;&#x9009;&#x62E9;&#xFF0C;&#x6587;&#x6863;&#x53EF;&#x4EE5;&#x8868;&#x793A;&#x4E3A;Doc=(&#x738B;&#x8005;&#x8363;&#x8000;&#xFF0C;&#x4F20;&#x8BF4;&#xFF0C;&#x54C1;&#x8D28;&#xFF0C;&#x76AE;&#x80A4;&#xFF0C;&#x4F18;&#x5316;&#xFF0C;&#x674E;&#x767D;&#xFF0C;&#x6700;&#x65B0;&#xFF0C;&#x6A21;&#x578B;&#xFF0C;&#x6D77;&#x62A5;&#xFF0C;&#x7206;&#x6599;)&#xFF0C;&#x90A3;&#x4E48;&#x5728;&#x9884;&#x6D4B;&#x65F6;&#x9700;&#x8981;&#x8BA1;&#x7B97;P(&#x738B;&#x8005;&#x8363;&#x8000;&#xFF0C;&#x4F20;&#x8BF4;&#xFF0C;&#x54C1;&#x8D28;&#xFF0C;&#x76AE;&#x80A4;&#xFF0C;&#x4F18;&#x5316;&#xFF0C;&#x674E;&#x767D;&#xFF0C;&#x6700;&#x65B0;&#xFF0C;&#x6A21;&#x578B;&#xFF0C;&#x6D77;&#x62A5;&#xFF0C;&#x7206;&#x6599;|Ci)&#xFF0C;&#x8FD9;&#x6837;&#x4E00;&#x4E2A;&#x6761;&#x4EF6;&#x6982;&#x7387;&#x662F;&#x4E0D;&#x53EF;&#x8BA1;&#x7B97;&#x7684;&#xFF0C;&#x56E0;&#x4E3A;&#x7B2C;&#x4E00;&#x4E2A;&#x7279;&#x5F81;&#x53D6;&#x503C;&#x4E3A;&#x201C;&#x738B;&#x8005;&#x8363;&#x8000;&#x201D;&#xFF0C;&#x7B2C;&#x4E8C;&#x4E2A;&#x7279;&#x5F81;&#x53D6;&#x503C;&#x201C;&#x4F20;&#x8BF4;&#x201D;&#x2026;&#x2026;&#x7B2C;&#x5341;&#x4E2A;&#x7279;&#x5F81;&#x53D6;&#x503C;&#x201C;&#x7206;&#x6599;&#x201D;&#x7684;&#x6587;&#x6863;&#x5F88;&#x53EF;&#x80FD;&#x4E3A;&#x6CA1;&#x6709;&#xFF0C;&#x90A3;&#x4E48;&#x6982;&#x7387;&#x5C31;&#x4E3A;&#x96F6;&#xFF0C;&#x800C;&#x57FA;&#x4E8E;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x7684;&#x5047;&#x8BBE;&#xFF0C;&#x8FD9;&#x4E2A;&#x6761;&#x4EF6;&#x6982;&#x7387;&#x53EF;&#x4EE5;&#x8F6C;&#x5316;&#x4E3A;&#xFF1A;</p>
<p>P(&#x738B;&#x8005;&#x8363;&#x8000;&#xFF0C;&#x4F20;&#x8BF4;&#xFF0C;&#x54C1;&#x8D28;&#xFF0C;&#x76AE;&#x80A4;&#xFF0C;&#x4F18;&#x5316;&#xFF0C;&#x674E;&#x767D;&#xFF0C;&#x6700;&#x65B0;&#xFF0C;&#x6A21;&#x578B;&#xFF0C;&#x6D77;&#x62A5;&#xFF0C;&#x7206;&#x6599;|Ci)=P(&#x738B;&#x8005;&#x8363;&#x8000;|Ci)P(&#x4F20;&#x8BF4;|Ci)&#x2026;&#x2026;P(&#x7206;&#x6599;|Ci)</p>
<p>&#x4E8E;&#x662F;&#x6211;&#x4EEC;&#x5C31;&#x53EF;&#x4EE5;&#x7EDF;&#x8BA1;&#x8FD9;&#x4E9B;&#x7279;&#x5F81;&#x8BCD;&#x5728;&#x6BCF;&#x4E2A;&#x7C7B;&#x522B;&#x4E2D;&#x51FA;&#x73B0;&#x7684;&#x6982;&#x7387;&#x4E86;&#xFF0C;&#x5728;&#x8FD9;&#x4E2A;&#x4F8B;&#x5B50;&#x4E2D;&#xFF0C;&#x6E38;&#x620F;&#x7C7B;&#x522B;&#x4E2D;&#x201C;&#x738B;&#x8005;&#x8363;&#x8000;&#x201D;&#x8FD9;&#x4E2A;&#x7279;&#x5F81;&#x9879;&#x4F1A;&#x9891;&#x7E41;&#x51FA;&#x73B0;&#xFF0C;&#x56E0;&#x6B64;P(&#x738B;&#x8005;&#x8363;&#x8000;|&#x6E38;&#x620F;)&#x7684;&#x6761;&#x4EF6;&#x6982;&#x7387;&#x8981;&#x660E;&#x663E;&#x9AD8;&#x4E8E;&#x5176;&#x4ED6;&#x7C7B;&#x522B;&#xFF0C;&#x8FD9;&#x5C31;&#x662F;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x6A21;&#x578B;&#x7684;&#x6734;&#x7D20;&#x4E4B;&#x5904;&#xFF0C;&#x7C97;&#x9C81;&#x7684;&#x806A;&#x660E;&#x3002;</p>
<h3 id="42">4.2 &#x591A;&#x9879;&#x5F0F;&#x6A21;&#x578B;&#x4E0E;&#x4F2F;&#x52AA;&#x5229;&#x6A21;&#x578B;</h3>
<p>&#x5728;&#x5177;&#x4F53;&#x5B9E;&#x73B0;&#x4E2D;&#xFF0C;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x53C8;&#x53EF;&#x4EE5;&#x5206;&#x4E3A;&#x4E24;&#x79CD;&#x6A21;&#x578B;&#xFF0C;&#x591A;&#x9879;&#x5F0F;&#x6A21;&#x578B;&#xFF08;Multinomial&#xFF09;&#x548C;&#x4F2F;&#x52AA;&#x5229;&#x6A21;&#x578B;&#xFF08;Bernoulli&#xFF09;&#xFF0C;&#x53E6;&#x5916;&#x8FD8;&#x6709;&#x9AD8;&#x65AF;&#x6A21;&#x578B;&#xFF0C;&#x4E3B;&#x8981;&#x7528;&#x4E8E;&#x5904;&#x7406;&#x8FDE;&#x7EED;&#x578B;&#x53D8;&#x91CF;&#xFF0C;&#x5728;&#x6587;&#x672C;&#x5206;&#x7C7B;&#x4E2D;&#x4E0D;&#x8BA8;&#x8BBA;&#x3002;</p>
<p>&#x591A;&#x9879;&#x5F0F;&#x6A21;&#x578B;&#x548C;&#x4F2F;&#x52AA;&#x5229;&#x6A21;&#x578B;&#x7684;&#x533A;&#x522B;&#x5728;&#x4E8E;&#x5BF9;&#x8BCD;&#x9891;&#x7684;&#x8003;&#x5BDF;&#xFF0C;&#x5728;&#x591A;&#x9879;&#x5F0F;&#x6A21;&#x578B;&#x4E2D;&#x6587;&#x6863;&#x4E2D;&#x7279;&#x5F81;&#x9879;&#x7684;&#x9891;&#x5EA6;&#x662F;&#x53C2;&#x4E0E;&#x8BA1;&#x7B97;&#x7684;&#xFF0C;&#x8FD9;&#x5BF9;&#x4E8E;&#x957F;&#x6587;&#x672C;&#x6765;&#x8BF4;&#x662F;&#x6BD4;&#x8F83;&#x516C;&#x5E73;&#x7684;&#xFF0C;&#x4F8B;&#x5982;&#x4E0A;&#x9762;&#x7684;&#x4F8B;&#x5B50;&#xFF0C;&#x201C;&#x738B;&#x8005;&#x8363;&#x8000;&#x201D;&#x5728;&#x6E38;&#x620F;&#x7C7B;&#x7684;&#x6587;&#x6863;&#x4E2D;&#x9891;&#x5EA6;&#x4F1A;&#x6BD4;&#x8F83;&#x9AD8;&#xFF0C;&#x800C;&#x4F2F;&#x52AA;&#x5229;&#x6A21;&#x578B;&#x4E2D;&#xFF0C;&#x6240;&#x6709;&#x7279;&#x5F81;&#x8BCD;&#x90FD;&#x5747;&#x7B49;&#x5730;&#x5BF9;&#x5F85;&#xFF0C;&#x53EA;&#x8981;&#x51FA;&#x73B0;&#x5C31;&#x8BB0;&#x4E3A;1&#xFF0C;&#x672A;&#x51FA;&#x73B0;&#x5C31;&#x8BB0;&#x4E3A;0&#xFF0C;&#x4E24;&#x8005;&#x516C;&#x5F0F;&#x5982;&#x4E0B;&#xFF1A;</p>
<center>
<p><img src="http://www.fullstackyang.com/content/images/2018/06/1596991951-5a97b4720d91e.png" alt="&#x5982;&#x4F55;&#x5B9E;&#x73B0;&#x4E00;&#x4E2A;&#x57FA;&#x672C;&#x7684;&#x5FAE;&#x4FE1;&#x6587;&#x7AE0;&#x5206;&#x7C7B;&#x5668;" loading="lazy"></p>
</center>
&#x5728;&#x4F2F;&#x52AA;&#x5229;&#x6A21;&#x578B;&#x8BA1;&#x7B97;&#x516C;&#x5F0F;&#x4E2D;&#xFF0C;N(Doc(tj)|Ci)&#x8868;&#x793A;Ci&#x7C7B;&#x6587;&#x6863;&#x4E2D;&#x7279;&#x5F81;tj&#x51FA;&#x73B0;&#x7684;&#x6587;&#x6863;&#x6570;&#xFF0C;|D|&#x8868;&#x793A;&#x7C7B;&#x522B;Ci&#x7684;&#x6587;&#x6863;&#x6570;&#xFF0C;P(Ci)&#x53EF;&#x4EE5;&#x7528;&#x7C7B;&#x522B;Ci&#x7684;&#x6587;&#x6863;&#x6570;/&#x6587;&#x6863;&#x603B;&#x6570;&#x6765;&#x8BA1;&#x7B97;&#xFF0C;
<p>&#x5728;&#x591A;&#x9879;&#x5F0F;&#x6A21;&#x578B;&#x8BA1;&#x7B97;&#x516C;&#x5F0F;&#x4E2D;&#xFF0C;TF(ti,Doc)&#x662F;&#x6587;&#x6863;Doc&#x4E2D;&#x7279;&#x5F81;ti&#x51FA;&#x73B0;&#x7684;&#x9891;&#x5EA6;&#xFF0C;TF(ti,Ci)&#x5C31;&#x8868;&#x793A;&#x7C7B;&#x522B;Ci&#x4E2D;&#x7279;&#x5F81;ti&#x51FA;&#x73B0;&#x7684;&#x9891;&#x5EA6;&#xFF0C;|V|&#x8868;&#x793A;&#x7279;&#x5F81;&#x7A7A;&#x95F4;&#x7684;&#x5927;&#x5C0F;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x7279;&#x5F81;&#x9009;&#x62E9;&#x4E4B;&#x540E;&#xFF0C;&#x4E0D;&#x540C;&#xFF08;&#x5373;&#x53BB;&#x6389;&#x91CD;&#x590D;&#x4E4B;&#x540E;&#xFF09;&#x7684;&#x7279;&#x5F81;&#x9879;&#x7684;&#x603B;&#x4E2A;&#x6570;&#xFF0C;&#x800C;P(Ci)&#x53EF;&#x4EE5;&#x7528;&#x7C7B;&#x522B;Ci&#x4E2D;&#x7279;&#x5F81;&#x8BCD;&#x7684;&#x603B;&#x6570;/&#x6240;&#x6709;&#x7279;&#x5F81;&#x8BCD;&#x7684;&#x603B;&#x6570;&#xFF0C;&#x6240;&#x6709;&#x7279;&#x5F81;&#x8BCD;&#x7684;&#x603B;&#x6570;&#x4E5F;&#x5C31;&#x662F;&#x6240;&#x6709;&#x7279;&#x5F81;&#x8BCD;&#x7684;&#x8BCD;&#x9891;&#x4E4B;&#x548C;&#x3002;</p>
<p>&#x81F3;&#x4E8E;&#x5206;&#x5B50;&#x548C;&#x5206;&#x6BCD;&#x90FD;&#x52A0;&#x4E0A;&#x4E00;&#x5B9A;&#x7684;&#x5E38;&#x91CF;&#xFF0C;&#x8FD9;&#x662F;&#x4E3A;&#x4E86;&#x9632;&#x6B62;&#x6570;&#x636E;&#x7A00;&#x758F;&#x800C;&#x4EA7;&#x751F;&#x7ED3;&#x679C;&#x4E3A;&#x96F6;&#x7684;&#x73B0;&#x8C61;&#xFF0C;&#x8FD9;&#x79CD;&#x64CD;&#x4F5C;&#x79F0;&#x4E3A;&#x62C9;&#x666E;&#x62C9;&#x65AF;&#x5E73;&#x6ED1;&#xFF0C;&#x81F3;&#x4E8E;&#x80CC;&#x540E;&#x7684;&#x539F;&#x7406;&#xFF0C;&#x63A8;&#x8350;&#x9605;&#x8BFB;&#x8FD9;&#x7BC7;&#x535A;&#x5BA2;&#xFF1A;<a href="https://zhuanlan.zhihu.com/p/24291822">&#x8D1D;&#x53F6;&#x65AF;&#x7EDF;&#x8BA1;&#x89C2;&#x70B9;&#x4E0B;&#x7684;&#x62C9;&#x666E;&#x62C9;&#x65AF;&#x5E73;&#x6ED1;</a></p>
<h3 id="43">4.3 &#x7B97;&#x6CD5;&#x5B9E;&#x73B0;</h3>
<p>&#x8FD9;&#x91CC;&#x4F7F;&#x7528;&#x4E86;&#x679A;&#x4E3E;&#x7C7B;&#x6765;&#x5C01;&#x88C5;&#x4E24;&#x4E2A;&#x6A21;&#x578B;&#xFF0C;&#x5E76;&#x5B9E;&#x73B0;&#x4E86;&#x5206;&#x7C7B;&#x5668;NaiveBayesClassifier&#x548C;&#x8BAD;&#x7EC3;&#x5668;NaiveBayesLearner&#x4E2D;&#x7684;&#x4E24;&#x4E2A;&#x63A5;&#x53E3;&#xFF0C;&#x5176;&#x4E2D;Pprior&#x548C;Pcondition&#x662F;&#x8BAD;&#x7EC3;&#x5668;&#x6240;&#x9700;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x524D;&#x8005;&#x7528;&#x6765;&#x8BA1;&#x7B97;&#x5148;&#x9A8C;&#x6982;&#x7387;&#xFF0C;&#x540E;&#x8005;&#x7528;&#x6765;&#x8BA1;&#x7B97;&#x4E0D;&#x540C;&#x7279;&#x5F81;&#x9879;&#x5728;&#x4E0D;&#x540C;&#x7C7B;&#x522B;&#x4E0B;&#x7684;&#x6761;&#x4EF6;&#x6982;&#x7387;&#xFF1B;getConditionProbability&#x662F;&#x5206;&#x7C7B;&#x5668;&#x6240;&#x9700;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;NaiveBayesKnowledgeBase&#x5BF9;&#x8C61;&#x662F;&#x6A21;&#x578B;&#x6570;&#x636E;&#x7684;&#x5BB9;&#x5668;&#xFF0C;&#x5B83;&#x7684;getPconditionByWord&#x65B9;&#x6CD5;&#x5C31;&#x662F;&#x7528;&#x4E8E;&#x67E5;&#x8BE2;&#x4E0D;&#x540C;&#x7279;&#x5F81;&#x8BCD;&#x5728;&#x4E0D;&#x540C;&#x7C7B;&#x522B;&#x4E0B;&#x7684;&#x6761;&#x4EF6;&#x6982;&#x7387;</p>
<pre><code>public enum NaiveBayesModels implements NaiveBayesClassifier.Model, NaiveBayesLearner.Model {
    Bernoulli {
        @Override
        public double Pprior(int total, Category category) {
            int Nc = category.getDocCount();
            return Math.log((double) Nc / total);
        }

        @Override
        public double Pcondition(Feature feature, Category category, double smoothing) {
            int Ncf = feature.getDocCountByCategory(category);
            int Nc = category.getDocCount();
            return Math.log((double) (1 + Ncf) / (Nc + smoothing));
        }

        @Override
        public List&lt;Double&gt; getConditionProbability(String category, List&lt;Term&gt; terms, final NaiveBayesKnowledgeBase knowledgeBase) {
            return terms.stream().map(term -&gt; knowledgeBase.getPconditionByWord(category, term.getWord())).collect(toList());
        }
    },
    Multinomial {
        @Override
        public double Pprior(int total, Category category) {
            int Nt = category.getTermCount();
            return Math.log((double) Nt / total);
        }

        @Override
        public double Pcondition(Feature feature, Category category, double smoothing) {
            int Ntf = feature.getTermCountByCategory(category);
            int Nt = category.getTermCount();
            return Math.log((double) (1 + Ntf) / (Nt + smoothing));
        }

        @Override
        public List&lt;Double&gt; getConditionProbability(String category, List&lt;Term&gt; terms, final NaiveBayesKnowledgeBase knowledgeBase) {
            return terms.stream().map(term -&gt; term.getTf() * knowledgeBase.getPconditionByWord(category, term.getWord())).collect(toList());
        }
    };
}
</code></pre>
<h2 id>&#x4E94;&#x3001;&#x8BAD;&#x7EC3;&#x6A21;&#x578B;</h2>
<p>&#x6839;&#x636E;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x6A21;&#x578B;&#x7684;&#x5B9A;&#x4E49;&#xFF0C;&#x8BAD;&#x7EC3;&#x6A21;&#x578B;&#x7684;&#x8FC7;&#x7A0B;&#x5C31;&#x662F;&#x8BA1;&#x7B97;&#x6BCF;&#x4E2A;&#x7C7B;&#x7684;&#x5148;&#x9A8C;&#x6982;&#x7387;&#xFF0C;&#x4EE5;&#x53CA;&#x6BCF;&#x4E2A;&#x7279;&#x5F81;&#x9879;&#x5728;&#x4E0D;&#x540C;&#x7C7B;&#x522B;&#x4E0B;&#x7684;&#x6761;&#x4EF6;&#x6982;&#x7387;&#xFF0C;NaiveBayesKnowledgeBase&#x5BF9;&#x8C61;&#x5C06;&#x8BAD;&#x7EC3;&#x5668;&#x5728;&#x8BAD;&#x7EC3;&#x65F6;&#x5F97;&#x5230;&#x7684;&#x7ED3;&#x679C;&#x90FD;&#x4FDD;&#x5B58;&#x8D77;&#x6765;&#xFF0C;&#x8BAD;&#x7EC3;&#x5B8C;&#x6210;&#x65F6;&#x5199;&#x5165;&#x6587;&#x4EF6;&#xFF0C;&#x542F;&#x52A8;&#x5206;&#x7C7B;&#x65F6;&#x4ECE;&#x6587;&#x4EF6;&#x4E2D;&#x8BFB;&#x5165;&#x6570;&#x636E;&#x4EA4;&#x7531;&#x5206;&#x7C7B;&#x5668;&#x4F7F;&#x7528;&#xFF0C;&#x90A3;&#x4E48;&#x5728;&#x5206;&#x7C7B;&#x65F6;&#x5C31;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x53C2;&#x4E0E;&#x5230;&#x8BA1;&#x7B97;&#x8FC7;&#x7A0B;&#x4E2D;&#x3002;</p>
<p>&#x8BAD;&#x7EC3;&#x5668;&#x7684;&#x5B9E;&#x73B0;&#x5982;&#x4E0B;&#xFF1A;</p>
<pre><code>public class NaiveBayesLearner {
    &#x2026;&#x2026;
    &#x2026;&#x2026;
    public NaiveBayesLearner statistics() {
        log.info(&quot;&#x5F00;&#x59CB;&#x7EDF;&#x8BA1;...&quot;);
        this.total = total();
        log.info(&quot;total : &quot; + total);
        this.categorySet = trainSet.getCategorySet();
        featureSet.forEach(f -&gt; f.getCategoryTermCounter().forEach((category, count) -&gt; category.setTermCount(category.getTermCount() + count)));
        return this;
    }

    public NaiveBayesKnowledgeBase build() {
        this.knowledgeBase.setCategories(createCategorySummaries(categorySet));
        this.knowledgeBase.setFeatures(createFeatureSummaries(featureSet, categorySet));
        return knowledgeBase;
    }

    private Map&lt;String, NaiveBayesKnowledgeBase.FeatureSummary&gt; createFeatureSummaries(final Set&lt;Feature&gt; featureSet, final Set&lt;Category&gt; categorySet) {
        return featureSet.parallelStream()
                .map(f -&gt; knowledgeBase.createFeatureSummary(f, getPconditions(f, categorySet)))
                .collect(toMap(NaiveBayesKnowledgeBase.FeatureSummary::getWord, Function.identity()));
    }

    private Map&lt;String, Double&gt; createCategorySummaries(final Set&lt;Category&gt; categorySet) {
        return categorySet.stream().collect(toMap(Category::getName, c -&gt; model.Pprior(total, c)));
    }

    private Map&lt;String, Double&gt; getPconditions(final Feature feature, final Set&lt;Category&gt; categorySet) {
        final double smoothing = smoothing();
        return categorySet.stream()
                .collect(toMap(Category::getName, c -&gt; model.Pcondition(feature, c, smoothing)));
    }

    private int total() {
        if (model == Multinomial)
            return featureSet.parallelStream().map(Feature::getTerm).mapToInt(Term::getTf).sum();//&#x603B;&#x8BCD;&#x9891;&#x6570;
        else if (model == Bernoulli)
            return trainSet.getTotalDoc();//&#x603B;&#x6587;&#x6863;&#x6570;
        return 0;
    }

    private double smoothing() {
        if (model == Multinomial)
            return this.featureSet.size();
        else if (model == Bernoulli)
            return 2.0;
        return 0.0;
    }

    public static void main(String[] args) {
        TrainSet trainSet = new TrainSet(System.getProperty(&quot;user.dir&quot;) + &quot;/trainset/&quot;);

        log.info(&quot;&#x7279;&#x5F81;&#x9009;&#x62E9;&#x5F00;&#x59CB;...&quot;);
        FeatureSelection featureSelection = new FeatureSelection(new ChiSquaredStrategy(trainSet.getCategorySet(), trainSet.getTotalDoc()));
        List&lt;Feature&gt; features = featureSelection.select(trainSet.getDocs());
        log.info(&quot;&#x7279;&#x5F81;&#x9009;&#x62E9;&#x5B8C;&#x6210;,&#x7279;&#x5F81;&#x6570;:[&quot; + features.size() + &quot;]&quot;);

        NaiveBayesModels model = NaiveBayesModels.Multinomial;
        NaiveBayesLearner learner = new NaiveBayesLearner(model, trainSet, Sets.newHashSet(features));
        learner.statistics().build().write(model.getModelPath());
        log.info(&quot;&#x6A21;&#x578B;&#x6587;&#x4EF6;&#x5199;&#x5165;&#x5B8C;&#x6210;,&#x8DEF;&#x5F84;:&quot; + model.getModelPath());
    }
}
</code></pre>
<p>&#x5728;main&#x51FD;&#x6570;&#x4E2D;&#x6267;&#x884C;&#x6574;&#x4E2A;&#x8BAD;&#x7EC3;&#x8FC7;&#x7A0B;&#xFF0C;&#x9996;&#x5148;&#x6267;&#x884C;&#x7279;&#x5F81;&#x9009;&#x62E9;&#xFF0C;&#x8FD9;&#x91CC;&#x4F7F;&#x7528;&#x5361;&#x65B9;&#x68C0;&#x9A8C;&#x6CD5;&#xFF0C;&#x7136;&#x540E;&#x5C06;&#x5F97;&#x5230;&#x7279;&#x5F81;&#x7A7A;&#x95F4;&#xFF0C;&#x6734;&#x7D20;&#x8D1D;&#x53F6;&#x65AF;&#x6A21;&#x578B;&#xFF08;&#x591A;&#x9879;&#x5F0F;&#x6A21;&#x578B;&#xFF09;&#xFF0C;&#x4EE5;&#x53CA;&#x8BAD;&#x7EC3;&#x96C6;TrainSet&#x5BF9;&#x8C61;&#x4F5C;&#x4E3A;&#x53C2;&#x6570;&#xFF0C;&#x521D;&#x59CB;&#x5316;&#x8BAD;&#x7EC3;&#x5668;&#xFF0C;&#x63A5;&#x7740;&#x8BAD;&#x7EC3;&#x5668;&#x5F00;&#x59CB;&#x8FDB;&#x884C;&#x7EDF;&#x8BA1;&#x7684;&#x5DE5;&#x4F5C;&#xFF0C;&#x4E8B;&#x5B9E;&#x4E0A;&#x6709;&#x4E00;&#x90E8;&#x5206;&#x7684;&#x7EDF;&#x8BA1;&#x5DE5;&#x4F5C;&#xFF0C;&#x5728;&#x521D;&#x59CB;&#x5316;&#x8BAD;&#x7EC3;&#x96C6;&#x5BF9;&#x8C61;&#x65F6;&#xFF0C;&#x5C31;&#x5DF2;&#x7ECF;&#x5B8C;&#x6210;&#x4E86;&#xFF0C;&#x4F8B;&#x5982;&#x603B;&#x6587;&#x6863;&#x6570;&#xFF0C;&#x6BCF;&#x4E2A;&#x7C7B;&#x522B;&#x4E0B;&#x7684;&#x6587;&#x6863;&#x6570;&#x7B49;&#xFF0C;&#x8FD9;&#x4E9B;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x62FF;&#x8FC7;&#x6765;&#x4F7F;&#x7528;&#xFF0C;&#x6700;&#x7EC8;&#x5C06;&#x6570;&#x636E;&#x90FD;&#x88C5;&#x8F7D;&#x5230;NaiveBayesKnowledgeBase&#x5BF9;&#x8C61;&#x5F53;&#x4E2D;&#x53BB;&#xFF0C;&#x5E76;&#x5199;&#x5165;&#x6587;&#x4EF6;&#xFF0C;&#x683C;&#x5F0F;&#x4E3A;&#x7B2C;&#x4E00;&#x884C;&#x662F;&#x4E0D;&#x540C;&#x7C7B;&#x522B;&#x7684;&#x5148;&#x9A8C;&#x6982;&#x7387;&#xFF0C;&#x4F59;&#x4E0B;&#x6BCF;&#x4E00;&#x884C;&#x5BF9;&#x5E94;&#x4E00;&#x4E2A;&#x7279;&#x5F81;&#x9879;&#xFF0C;&#x6BCF;&#x4E00;&#x5217;&#x5BF9;&#x5E94;&#x4E0D;&#x540C;&#x7C7B;&#x522B;&#x7684;&#x6761;&#x4EF6;&#x6982;&#x7387;&#x503C;&#x3002;</p>
<h2 id>&#x516D;&#x3001;&#x6D4B;&#x8BD5;&#x6A21;&#x578B;</h2>
<p>&#x5206;&#x7C7B;&#x5668;&#x9884;&#x6D4B;&#x8FC7;&#x7A0B;&#x5C31;&#x76F8;&#x5BF9;&#x4E8E;&#x6BD4;&#x8F83;&#x7B80;&#x5355;&#x4E86;&#xFF0C;&#x901A;&#x8FC7;NaiveBayesKnowledgeBase&#x8BFB;&#x5165;&#x6570;&#x636E;&#xFF0C;&#x7136;&#x540E;&#x5C06;&#x6307;&#x5B9A;&#x7684;&#x6587;&#x672C;&#x8FDB;&#x884C;&#x5206;&#x8BCD;&#xFF0C;&#x5339;&#x914D;&#x7279;&#x5F81;&#x9879;&#xFF0C;&#x7136;&#x540E;&#x8BA1;&#x7B97;&#x5728;&#x4E0D;&#x540C;&#x7C7B;&#x522B;&#x4E0B;&#x7684;&#x540E;&#x9A8C;&#x6982;&#x7387;&#xFF0C;&#x8FD4;&#x56DE;&#x53D6;&#x5F97;&#x6700;&#x5927;&#x503C;&#x5BF9;&#x5E94;&#x7684;&#x90A3;&#x4E2A;&#x7C7B;&#x522B;&#x3002;</p>
<pre><code>public class NaiveBayesClassifier {
    &#x2026;&#x2026;
    private final Model model;

    private final NaiveBayesKnowledgeBase knowledgeBase;

    public NaiveBayesClassifier(Model model) {
        this.model = model;
        this.knowledgeBase = new NaiveBayesKnowledgeBase(model.getModelPath());
    }

    public String predict(String content) {
        Set&lt;String&gt; allFeatures = knowledgeBase.getFeatures().keySet();
        List&lt;Term&gt; terms = NLPTools.instance().segment(content).stream()
                .filter(t -&gt; allFeatures.contains(t.getWord())).distinct().collect(toList());

        @AllArgsConstructor
        class Result {
            final String category;
            final double probability;
        }

        Result result = knowledgeBase.getCategories().keySet().stream()
                .map(c -&gt; new Result(c, Calculator.Ppost(knowledgeBase.getCategoryProbability(c),
                        model.getConditionProbability(c, terms, knowledgeBase))))
                .max(Comparator.comparingDouble(r -&gt; r.probability)).get();
        return result.category;
    }
}
</code></pre>
<p>&#x5728;&#x5B9E;&#x9645;&#x6D4B;&#x8BD5;&#x65F6;&#xFF0C;&#x6211;&#x4EEC;&#x53C8;&#x5355;&#x72EC;&#x6293;&#x53D6;&#x4E86;&#x641C;&#x72D7;&#x5FAE;&#x4FE1;&#x641C;&#x7D22;&#x7F51;&#x7AD9;&#x4E0A;&#x7684;&#x6587;&#x7AE0;&#xFF0C;&#x6309;&#x7167;100&#x7BC7;&#x4E00;&#x7EC4;&#xFF0C;&#x4E00;&#x5171;30&#x7EC4;&#x8FDB;&#x884C;&#x5206;&#x7C7B;&#x7684;&#x6D4B;&#x8BD5;&#xFF0C;&#x6700;&#x7EC8;&#x7ED3;&#x679C;&#x6BCF;&#x4E00;&#x7EC4;&#x7684;&#x51C6;&#x786E;&#x7387;&#x5747;&#x5728;90%&#x4EE5;&#x4E0A;&#xFF0C;&#x6700;&#x9AD8;&#x8FBE;98%&#xFF0C;&#x6548;&#x679C;&#x826F;&#x597D;&#x3002;&#x5F53;&#x7136;&#x6B63;&#x89C4;&#x7684;&#x8BC4;&#x6D4B;&#x9700;&#x8981;&#x540C;&#x65F6;&#x8BC4;&#x4F30;&#x51C6;&#x786E;&#x7387;&#x548C;&#x53EC;&#x56DE;&#x7387;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x5077;&#x61D2;&#x4E0D;&#x505A;&#x4E86;&#x3002;</p>
<p>&#x53E6;&#x5916;&#x8FD8;&#x9700;&#x8981;&#x8BF4;&#x660E;&#x4E00;&#x70B9;&#x7684;&#x662F;&#xFF0C;&#x7531;&#x4E8E;&#x8BAD;&#x7EC3;&#x96C6;&#x662F;&#x6765;&#x6E90;&#x4E8E;&#x641C;&#x72D7;&#x5FAE;&#x4FE1;&#x641C;&#x7D22;&#x7F51;&#x7AD9;&#x7684;&#x6587;&#x7AE0;&#xFF0C;&#x7C7B;&#x522B;&#x4EC5;&#x9650;&#x4E8E;&#x8FD9;20&#x4E2A;&#xFF0C;&#x8FD9;&#x4E0D;&#x8DB3;&#x4EE5;&#x8986;&#x76D6;&#x6240;&#x6709;&#x5FAE;&#x4FE1;&#x516C;&#x4F17;&#x53F7;&#x6587;&#x7AE0;&#x7684;&#x7C7B;&#x522B;&#xFF0C;&#x56E0;&#x6B64;&#x5728;&#x6D4B;&#x8BD5;&#x5176;&#x4ED6;&#x6765;&#x6E90;&#x7684;&#x5FAE;&#x4FE1;&#x6587;&#x7AE0;&#x51C6;&#x786E;&#x7387;&#x4E00;&#x5B9A;&#x4F1A;&#x6709;&#x6240;&#x5F71;&#x54CD;&#x3002;&#x5F53;&#x7136;&#x5982;&#x679C;&#x6709;&#x66F4;&#x52A0;&#x4E30;&#x5BCC;&#x7684;&#x5FAE;&#x4FE1;&#x6587;&#x7AE0;&#x8BAD;&#x7EC3;&#x96C6;&#x7684;&#x8BDD;&#xFF0C;&#x4E5F;&#x53EF;&#x4EE5;&#x5229;&#x7528;&#x8FD9;&#x4E2A;&#x6A21;&#x578B;&#x91CD;&#x65B0;&#x8BAD;&#x7EC3;&#xFF0C;&#x90A3;&#x4E48;&#x6548;&#x679C;&#x4E5F;&#x4F1A;&#x8D8A;&#x6765;&#x8D8A;&#x597D;&#x3002;</p>
<h2 id>&#x4E03;&#x3001;&#x53C2;&#x8003;&#x6587;&#x732E;&#x4E0E;&#x5F15;&#x7528;</h2>
<ol>
<li>&#x5B97;&#x6210;&#x5E86;. &#x7EDF;&#x8BA1;&#x81EA;&#x7136;&#x8BED;&#x8A00;&#x5904;&#x7406;[M]. &#x6E05;&#x534E;&#x5927;&#x5B66;&#x51FA;&#x7248;&#x793E;, 2013.</li>
<li>T.M.Mitchell. &#x673A;&#x5668;&#x5B66;&#x4E60;[M]. &#x673A;&#x68B0;&#x5DE5;&#x4E1A;&#x51FA;&#x7248;&#x793E;, 2003.</li>
<li>&#x5434;&#x519B;. &#x6570;&#x5B66;&#x4E4B;&#x7F8E;[M]. &#x4EBA;&#x6C11;&#x90AE;&#x7535;&#x51FA;&#x7248;&#x793E;, 2012.</li>
<li>Raoul-Gabriel Urma, Mario Fusco, Alan Mycroft. Java 8 &#x5B9E;&#x6218;[M]. &#x4EBA;&#x6C11;&#x90AE;&#x7535;&#x51FA;&#x7248;&#x793E;, 2016.</li>
<li>Ansj&#x4E2D;&#x6587;&#x5206;&#x8BCD;&#x5668;&#xFF0C;<a href="https://github.com/NLPchina/ansj_seg">https://github.com/NLPchina/ansj_seg</a></li>
<li>HanLP&#x4E2D;&#x6587;&#x5206;&#x8BCD;&#x5668;&#xFF0C;<a href="https://github.com/hankcs/HanLP">https://github.com/hankcs/HanLP</a></li>
</ol>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[[轮子系列]Google Guava之BloomFilter源码分析及基于Redis的重构]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id>&#x4E00;&#x3001;&#x80CC;&#x666F;&#x77E5;&#x8BC6;</h2>
<p>&#x5728;&#x7F51;&#x4E0A;&#x5DF2;&#x7ECF;&#x6709;&#x5F88;&#x591A;&#x5173;&#x4E8E;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x7684;&#x4ECB;&#x7ECD;&#x4E86;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x4E0D;&#x518D;&#x8D58;&#x8FF0;&#xFF0C;&#x4E0B;&#x9762;&#x7B80;&#x5355;&#x5730;&#x63D0;&#x70BC;&#x51E0;&#x4E2A;&#x8981;&#x70B9;&#xFF1A;</p>
<ol>
<li>&#x5E03;&#x9686;&#x8FC7;&#x6EE4;</li></ol>]]></description><link>http://www.fullstackyang.com/bu-long-guo-lu-qi-google-guavalei-ku-yuan-ma-fen-xi-ji-ji-yu-redis-bitmapsde-zhong-gou/</link><guid isPermaLink="false">624567890d2dd3000190a003</guid><category><![CDATA[dev]]></category><category><![CDATA[guava]]></category><category><![CDATA[轮子系列]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Sat, 23 Dec 2017 16:15:00 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2018/06/the-bloom-filter-e1506680747852.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id>&#x4E00;&#x3001;&#x80CC;&#x666F;&#x77E5;&#x8BC6;</h2>
<img src="http://www.fullstackyang.com/content/images/2018/06/the-bloom-filter-e1506680747852.jpg" alt="[&#x8F6E;&#x5B50;&#x7CFB;&#x5217;]Google Guava&#x4E4B;BloomFilter&#x6E90;&#x7801;&#x5206;&#x6790;&#x53CA;&#x57FA;&#x4E8E;Redis&#x7684;&#x91CD;&#x6784;"><p>&#x5728;&#x7F51;&#x4E0A;&#x5DF2;&#x7ECF;&#x6709;&#x5F88;&#x591A;&#x5173;&#x4E8E;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x7684;&#x4ECB;&#x7ECD;&#x4E86;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x4E0D;&#x518D;&#x8D58;&#x8FF0;&#xFF0C;&#x4E0B;&#x9762;&#x7B80;&#x5355;&#x5730;&#x63D0;&#x70BC;&#x51E0;&#x4E2A;&#x8981;&#x70B9;&#xFF1A;</p>
<ol>
<li>&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x662F;&#x7528;&#x6765;&#x5224;&#x65AD;&#x4E00;&#x4E2A;&#x5143;&#x7D20;&#x662F;&#x5426;&#x51FA;&#x73B0;&#x5728;&#x7ED9;&#x5B9A;&#x96C6;&#x5408;&#x4E2D;&#x7684;&#x91CD;&#x8981;&#x5DE5;&#x5177;&#xFF0C;&#x5177;&#x6709;&#x5FEB;&#x901F;&#xFF0C;&#x6BD4;&#x54C8;&#x5E0C;&#x8868;&#x66F4;&#x8282;&#x7701;&#x7A7A;&#x95F4;&#x7B49;&#x4F18;&#x70B9;&#xFF0C;&#x800C;&#x7F3A;&#x70B9;&#x5728;&#x4E8E;&#x6709;&#x4E00;&#x5B9A;&#x7684;&#x8BEF;&#x8BC6;&#x522B;&#x7387;&#xFF08;false-positive&#xFF0C;&#x5047;&#x9633;&#x6027;&#xFF09;&#xFF0C;&#x4EA6;&#x5373;&#xFF0C;&#x5B83;&#x53EF;&#x80FD;&#x4F1A;&#x628A;&#x4E0D;&#x662F;&#x96C6;&#x5408;&#x5185;&#x7684;&#x5143;&#x7D20;&#x5224;&#x5B9A;&#x4E3A;&#x5B58;&#x5728;&#x4E8E;&#x96C6;&#x5408;&#x5185;&#xFF0C;&#x4E0D;&#x8FC7;&#x8FD9;&#x6837;&#x7684;&#x6982;&#x7387;&#x76F8;&#x5F53;&#x5C0F;&#xFF0C;&#x5728;&#x5927;&#x90E8;&#x5206;&#x7684;&#x751F;&#x4EA7;&#x73AF;&#x5883;&#x4E2D;&#x662F;&#x53EF;&#x4EE5;&#x63A5;&#x53D7;&#x7684;&#xFF1B;</li>
<li>&#x5176;&#x539F;&#x7406;&#x6BD4;&#x8F83;&#x7B80;&#x5355;&#xFF0C;&#x5982;&#x4E0B;&#x56FE;&#x6240;&#x793A;&#xFF0C;S&#x96C6;&#x5408;&#x4E2D;&#x6709;n&#x4E2A;&#x5143;&#x7D20;&#xFF0C;&#x5229;&#x7528;k&#x4E2A;&#x54C8;&#x5E0C;&#x51FD;&#x6570;&#xFF0C;&#x5C06;S&#x4E2D;&#x7684;&#x6BCF;&#x4E2A;&#x5143;&#x7D20;&#x6620;&#x5C04;&#x5230;&#x4E00;&#x4E2A;&#x957F;&#x5EA6;&#x4E3A;m&#x7684;&#x4F4D;&#xFF08;bit&#xFF09;&#x6570;&#x7EC4;B&#x4E2D;&#x4E0D;&#x540C;&#x7684;&#x4F4D;&#x7F6E;&#x4E0A;&#xFF0C;&#x8FD9;&#x4E9B;&#x4F4D;&#x7F6E;&#x4E0A;&#x7684;&#x4E8C;&#x8FDB;&#x5236;&#x6570;&#x5747;&#x7F6E;&#x4E3A;1&#xFF0C;&#x5982;&#x679C;&#x5F85;&#x68C0;&#x6D4B;&#x7684;&#x5143;&#x7D20;&#x7ECF;&#x8FC7;&#x8FD9;k&#x4E2A;&#x54C8;&#x5E0C;&#x51FD;&#x6570;&#x7684;&#x6620;&#x5C04;&#x540E;&#xFF0C;&#x53D1;&#x73B0;&#x5176;k&#x4E2A;&#x4F4D;&#x7F6E;&#x4E0A;&#x7684;&#x4E8C;&#x8FDB;&#x5236;&#x6570;&#x4E0D;&#x5168;&#x662F;1&#xFF0C;&#x90A3;&#x4E48;&#x8FD9;&#x4E2A;&#x5143;&#x7D20;&#x4E00;&#x5B9A;&#x4E0D;&#x5728;&#x96C6;&#x5408;S&#x4E2D;&#xFF0C;&#x53CD;&#x4E4B;&#xFF0C;&#x8BE5;&#x5143;&#x7D20;&#x53EF;&#x80FD;&#x662F;S&#x4E2D;&#x7684;&#x67D0;&#x4E00;&#x4E2A;&#x5143;&#x7D20;&#xFF08;&#x53C2;&#x8003;1&#xFF09;&#xFF1B;</li>
<li>&#x7EFC;&#x4E0A;&#x63CF;&#x8FF0;&#xFF0C;&#x90A3;&#x4E48;&#x5230;&#x5E95;&#x9700;&#x8981;&#x591A;&#x5C11;&#x4E2A;&#x54C8;&#x5E0C;&#x51FD;&#x6570;&#xFF0C;&#x4EE5;&#x53CA;&#x521B;&#x5EFA;&#x957F;&#x5EA6;&#x4E3A;&#x591A;&#x5C11;&#x7684;bit&#x6570;&#x7EC4;&#x6BD4;&#x8F83;&#x5408;&#x9002;&#xFF0C;&#x4E3A;&#x4E86;&#x4F30;&#x7B97;&#x51FA;k&#x548C;m&#x7684;&#x503C;&#xFF0C;&#x5728;&#x6784;&#x9020;&#x4E00;&#x4E2A;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x65F6;&#xFF0C;&#x9700;&#x8981;&#x4F20;&#x5165;&#x4E24;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;&#x5373;&#x53EF;&#x4EE5;&#x63A5;&#x53D7;&#x7684;&#x8BEF;&#x5224;&#x7387;fpp&#x548C;&#x5143;&#x7D20;&#x603B;&#x4E2A;&#x6570;n&#xFF08;&#x4E0D;&#x4E00;&#x5B9A;&#x5B8C;&#x5168;&#x7CBE;&#x786E;&#xFF09;&#x3002;&#x81F3;&#x4E8E;&#x53C2;&#x6570;&#x4F30;&#x8BA1;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x6709;&#x5174;&#x8DA3;&#x7684;&#x540C;&#x5B66;&#x53EF;&#x4EE5;&#x53C2;&#x8003;&#x7EF4;&#x57FA;&#x82F1;&#x6587;&#x9875;&#x9762;&#xFF0C;&#x4E0B;&#x9762;&#x76F4;&#x63A5;&#x7ED9;&#x51FA;&#x516C;&#x5F0F;&#xFF1A;</li>
<li>&#x54C8;&#x5E0C;&#x51FD;&#x6570;&#x7684;&#x8981;&#x6C42;&#x5C3D;&#x91CF;&#x6EE1;&#x8DB3;&#x5E73;&#x5747;&#x5206;&#x5E03;&#xFF0C;&#x8FD9;&#x6837;&#x65E2;&#x964D;&#x4F4E;&#x8BEF;&#x5224;&#x53D1;&#x751F;&#x7684;&#x6982;&#x7387;&#xFF0C;&#x53C8;&#x53EF;&#x4EE5;&#x5145;&#x5206;&#x5229;&#x7528;bit&#x6570;&#x7EC4;&#x7684;&#x7A7A;&#x95F4;&#xFF1B;</li>
<li>&#x6839;&#x636E;&#x8BBA;&#x6587;&#x300A;Less Hashing, Same Performance: Building a Better Bloom Filter&#x300B;&#x63D0;&#x51FA;&#x7684;&#x4E00;&#x4E2A;&#x6280;&#x5DE7;&#xFF0C;&#x53EF;&#x4EE5;&#x7528;2&#x4E2A;&#x54C8;&#x5E0C;&#x51FD;&#x6570;&#x6765;&#x6A21;&#x62DF;k&#x4E2A;&#x54C8;&#x5E0C;&#x51FD;&#x6570;&#xFF0C;&#x5373;gi(x) = h1(x) + ih2(x) &#xFF0C;&#x5176;&#x4E2D;0&lt;=i&lt;=k-1&#xFF1B;</li>
<li>&#x5728;&#x5434;&#x519B;&#x535A;&#x58EB;&#x7684;&#x300A;&#x6570;&#x5B66;&#x4E4B;&#x7F8E;&#x300B;&#x4E00;&#x4E66;&#x4E2D;&#x5C55;&#x793A;&#x4E86;&#x4E0D;&#x540C;&#x60C5;&#x51B5;&#x4E0B;&#x7684;&#x8BEF;&#x5224;&#x7387;&#xFF0C;&#x4F8B;&#x5982;&#xFF0C;&#x5047;&#x5B9A;&#x4E00;&#x4E2A;&#x5143;&#x7D20;&#x7528;16&#x4F4D;&#x6BD4;&#x7279;&#xFF0C;8&#x4E2A;&#x54C8;&#x5E0C;&#x51FD;&#x6570;&#xFF0C;&#x90A3;&#x4E48;&#x5047;&#x9633;&#x6027;&#x7684;&#x6982;&#x7387;&#x662F;&#x4E07;&#x5206;&#x4E4B;&#x4E94;&#xFF0C;&#x8FD9;&#x5DF2;&#x7ECF;&#x76F8;&#x5F53;&#x5C0F;&#x4E86;&#x3002;</li>
</ol>
<p><img src="/content/images/2018/06/bloom-filter.jpg" alt="[&#x8F6E;&#x5B50;&#x7CFB;&#x5217;]Google Guava&#x4E4B;BloomFilter&#x6E90;&#x7801;&#x5206;&#x6790;&#x53CA;&#x57FA;&#x4E8E;Redis&#x7684;&#x91CD;&#x6784;" loading="lazy"></p>
<p>&#x9996;&#x5148;&#x6211;&#x4EEC;&#x6765;&#x4E86;&#x89E3;&#x4E00;&#x4E0B;&#x4E00;&#x4E9B;&#x5DF2;&#x7ECF;&#x6709;&#x76F8;&#x5E94;&#x5B9E;&#x73B0;&#x7684;&#x5F00;&#x6E90;&#x7C7B;&#x5E93;&#xFF0C;&#x5982;Google&#x7684;Guava&#x7C7B;&#x5E93;&#xFF0C;Twitter&#x7684;Algebird&#x7C7B;&#x5E93;&#xFF0C;&#x548C;ScalaNLP breeze&#x7B49;&#x7B49;&#xFF0C;&#x5176;&#x4E2D;Guava 11.0&#x7248;&#x672C;&#x4E2D;&#x589E;&#x52A0;&#x4E86;BloomFilter&#x7C7B;&#xFF0C;&#x5B83;&#x4F7F;&#x7528;&#x4E86;Funnel&#x548C;Sink&#x7684;&#x8BBE;&#x8BA1;&#xFF0C;&#x589E;&#x5F3A;&#x4E86;&#x6CDB;&#x5316;&#x7684;&#x80FD;&#x529B;&#xFF0C;&#x4F7F;&#x5176;&#x53EF;&#x4EE5;&#x652F;&#x6301;&#x4EFB;&#x4F55;&#x6570;&#x636E;&#x7C7B;&#x578B;&#xFF0C;&#x5176;&#x5229;&#x7528;murmur3 hash&#x6765;&#x505A;&#x54C8;&#x5E0C;&#x6620;&#x5C04;&#x51FD;&#x6570;&#xFF0C;&#x4E0D;&#x8FC7;&#x5B83;&#x5E95;&#x5C42;&#x5E76;&#x6CA1;&#x6709;&#x4F7F;&#x7528;&#x4F20;&#x7EDF;&#x7684;java.util.BitSet&#x6765;&#x505A;bit&#x6570;&#x7EC4;&#xFF0C;&#x800C;&#x662F;&#x7528;long&#x578B;&#x6570;&#x7EC4;&#x8FDB;&#x884C;&#x4E86;&#x91CD;&#x65B0;&#x5C01;&#x88C5;&#xFF0C;&#x5927;&#x90E8;&#x5206;&#x64CD;&#x4F5C;&#x5747;&#x57FA;&#x4E8E;&#x4F4D;&#x7684;&#x8FD0;&#x7B97;&#xFF0C;&#x56E0;&#x6B64;&#x80FD;&#x8FBE;&#x5230;&#x4E00;&#x4E2A;&#x975E;&#x5E38;&#x597D;&#x7684;&#x6027;&#x80FD;&#xFF1B;Algebird&#x662F;&#x57FA;&#x4E8E;Scala&#x5F00;&#x53D1;&#x7684;&#x7C7B;&#x5E93;&#xFF0C;&#x5176;&#x5B9E;&#x73B0;&#x7684;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x4EC5;&#x652F;&#x6301;&#x5B57;&#x7B26;&#x4E32;&#x4F5C;&#x4E3A;&#x5143;&#x7D20;&#x7C7B;&#x578B;&#xFF0C;&#x540C;&#x6837;&#x4E5F;&#x91C7;&#x7528;&#x4E86;Murmur hash3&#xFF0C;&#x5E95;&#x5C42;&#x5219;&#x662F;&#x91C7;&#x7528;&#x4E00;&#x79CD;&#x53EB;&#x201C;EWAHCompressedBitmap&#x201D;&#x7684;&#x6570;&#x636E;&#x7ED3;&#x6784;&#xFF0C;&#x5B83;&#x4E13;&#x95E8;&#x4E3A;&#x5185;&#x5B58;&#x5360;&#x7528;&#x800C;&#x4F18;&#x5316;&#xFF0C;&#x9002;&#x5408;&#x7A00;&#x758F;&#x6570;&#x636E;&#x7684;&#x573A;&#x666F;&#xFF0C;&#x662F;&#x4E00;&#x79CD;&#x53EF;&#x4EE5;&#x66FF;&#x4EE3;BitSet&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x4E0D;&#x8FC7;&#x7F3A;&#x70B9;&#x662F;&#x968F;&#x673A;&#x8BBF;&#x95EE;&#x7684;&#x6027;&#x80FD;&#x6BD4;&#x8F83;&#x5DEE;&#xFF1B;breeze&#x662F;ScalaNLP&#x4E0B;&#x7684;&#x6838;&#x5FC3;&#x7C7B;&#x5E93;&#xFF0C;&#x5305;&#x62EC;&#x7EBF;&#x6027;&#x4EE3;&#x6570;&#xFF0C;&#x6570;&#x503C;&#x8BA1;&#x7B97;&#x548C;&#x4F18;&#x5316;&#xFF0C;&#x662F;&#x4E00;&#x4E2A;&#x5F3A;&#x5927;&#x7684;&#x673A;&#x5668;&#x5B66;&#x4E60;&#x5DE5;&#x5177;&#xFF0C;&#x5B83;&#x5B9E;&#x73B0;&#x7684;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x6CA1;&#x6709;&#x4F7F;&#x7528;&#x901A;&#x7528;&#x7684;Murmur hash3&#x7B97;&#x6CD5;&#xFF0C;&#x800C;&#x662F;&#x76F4;&#x63A5;&#x4F7F;&#x7528;&#x4E86;&#x5BF9;&#x8C61;&#x7684;hash&#x503C;&#xFF0C;bit&#x6570;&#x7EC4;&#x5219;&#x662F;&#x91C7;&#x7528;&#x4E86;BitSet&#xFF0C;&#x4F46;&#x662F;&#x548C;Scala&#x7684;&#x901A;&#x75C5;&#x4E00;&#x6837;&#xFF0C;&#x5F53;&#x7F16;&#x8BD1;&#x6210;Java&#x4EE3;&#x7801;&#x65F6;&#x5206;&#x914D;&#x4E86;&#x8FC7;&#x591A;&#x7684;&#x5BF9;&#x8C61;&#xFF0C;&#x8FD9;&#x4F1A;&#x5728;&#x5185;&#x5B58;&#x5360;&#x7528;&#x4E0A;&#x5E26;&#x6765;&#x989D;&#x5916;&#x7684;&#x5F00;&#x9500;&#x3002;</p>
<p>&#x4E0B;&#x9762;&#x6211;&#x4EEC;&#x5C31;Guava&#x7C7B;&#x5E93;&#x4E2D;&#x5B9E;&#x73B0;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x7684;&#x6E90;&#x7801;&#x4F5C;&#x8BE6;&#x7EC6;&#x5206;&#x6790;&#xFF0C;&#x6700;&#x540E;&#x51FA;&#x4E8E;&#x7075;&#x6D3B;&#x6027;&#x548C;&#x89E3;&#x8026;&#x7B49;&#x56E0;&#x7D20;&#x7684;&#x8003;&#x8651;&#xFF0C;&#x6211;&#x4EEC;&#x60F3;&#x8981;&#x628A;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x4ECE;JVM&#x4E2D;&#x62FF;&#x51FA;&#x6765;&#xFF0C;&#x4E8E;&#x662F;&#x5229;&#x7528;&#x4E86;Redis&#x81EA;&#x5E26;&#x7684;Bitmaps&#x4F5C;&#x4E3A;&#x5E95;&#x5C42;&#x7684;bit&#x6570;&#x7EC4;&#x8FDB;&#x884C;&#x91CD;&#x6784;&#xFF0C;&#x53E6;&#x5916;&#x968F;&#x7740;&#x63D2;&#x5165;&#x7684;&#x5143;&#x7D20;&#x8D8A;&#x6765;&#x8D8A;&#x591A;&#xFF0C;&#x5F53;&#x5B9E;&#x9645;&#x6570;&#x91CF;&#x8FDC;&#x8FDC;&#x5927;&#x4E8E;&#x521B;&#x5EFA;&#x65F6;&#x8BBE;&#x7F6E;&#x7684;&#x9884;&#x8BA1;&#x6570;&#x91CF;&#x65F6;&#xFF0C;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x7684;&#x8BEF;&#x5224;&#x7387;&#x4F1A;&#x8D8A;&#x6765;&#x8D8A;&#x9AD8;&#xFF0C;&#x56E0;&#x6B64;&#x5728;&#x91CD;&#x6784;&#x7684;&#x8FC7;&#x7A0B;&#x4E2D;&#x589E;&#x52A0;&#x4E86;&#x81EA;&#x52A8;&#x6269;&#x5BB9;&#x7684;&#x7279;&#x6027;&#xFF0C;&#x6700;&#x540E;&#x901A;&#x8FC7;&#x6D4B;&#x8BD5;&#x9A8C;&#x8BC1;&#x5176;&#x6B63;&#x786E;&#x6027;&#x3002;</p>
<h2 id="guava">&#x4E8C;&#x3001;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x5728;Guava&#x4E2D;&#x7684;&#x5B9E;&#x73B0;</h2>
<p>Guava&#x4E2D;&#xFF0C;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x7684;&#x5B9E;&#x73B0;&#x4E3B;&#x8981;&#x6D89;&#x53CA;&#x5230;2&#x4E2A;&#x7C7B;&#xFF0C;BloomFilter&#x548C;BloomFilterStrategies&#xFF0C;&#x9996;&#x5148;&#x6765;&#x770B;&#x4E00;&#x4E0B;BloomFilter&#xFF1A;</p>
<pre><code> /** The bit set of the BloomFilter (not necessarily power of 2!) */
  private final BitArray bits;

  /** Number of hashes per element */
  private final int numHashFunctions;

  /** The funnel to translate Ts to bytes */
  private final Funnel&lt;? super T&gt; funnel;

  /**
   * The strategy we employ to map an element T to {@code numHashFunctions} bit indexes.
   */
  private final Strategy strategy;
</code></pre>
<p>&#x8FD9;&#x662F;&#x5B83;&#x7684;4&#x4E2A;&#x6210;&#x5458;&#x53D8;&#x91CF;</p>
<ul>
<li>BitArrays&#x662F;&#x5B9A;&#x4E49;&#x5728;BloomFilterStrategies&#x4E2D;&#x7684;&#x5185;&#x90E8;&#x7C7B;&#xFF0C;&#x5C01;&#x88C5;&#x4E86;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x5E95;&#x5C42;bit&#x6570;&#x7EC4;&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x540E;&#x6587;&#x8BE6;&#x8FF0;&#xFF1B;</li>
<li>numHashFunctions&#x8868;&#x793A;&#x54C8;&#x5E0C;&#x51FD;&#x6570;&#x7684;&#x4E2A;&#x6570;&#xFF0C;&#x5373;&#x4E0A;&#x6587;&#x63D0;&#x5230;&#x7684;k&#xFF1B;</li>
<li>Funnel&#xFF0C;&#x8FD9;&#x662F;Guava&#x4E2D;&#x5B9A;&#x4E49;&#x7684;&#x4E00;&#x4E2A;&#x63A5;&#x53E3;&#xFF0C;&#x5B83;&#x548C;PrimitiveSink&#x914D;&#x5957;&#x4F7F;&#x7528;&#xFF0C;&#x4E3B;&#x8981;&#x662F;&#x628A;&#x4EFB;&#x610F;&#x7C7B;&#x578B;&#x7684;&#x6570;&#x636E;&#x8F6C;&#x5316;&#x6210;Java&#x57FA;&#x672C;&#x6570;&#x636E;&#x7C7B;&#x578B;&#xFF08;primitive value&#xFF0C;&#x5982;char&#xFF0C;byte&#xFF0C;int&#x2026;&#x2026;&#xFF09;&#xFF0C;&#x9ED8;&#x8BA4;&#x7528;java.nio.ByteBuffer&#x5B9E;&#x73B0;&#xFF0C;&#x6700;&#x7EC8;&#x5747;&#x8F6C;&#x5316;&#x4E3A;byte&#x6570;&#x7EC4;&#xFF1B;</li>
<li>Strategy&#x662F;&#x5B9A;&#x4E49;&#x5728;BloomFilter&#x7C7B;&#x5185;&#x90E8;&#x7684;&#x63A5;&#x53E3;&#xFF0C;&#x4EE3;&#x7801;&#x5982;&#x4E0B;&#xFF0C;&#x6709;3&#x4E2A;&#x65B9;&#x6CD5;&#xFF0C;put&#xFF08;&#x63D2;&#x5165;&#x5143;&#x7D20;&#xFF09;&#xFF0C;mightContain&#xFF08;&#x5224;&#x5B9A;&#x5143;&#x7D20;&#x662F;&#x5426;&#x5B58;&#x5728;&#xFF09;&#x548C;ordinal&#x65B9;&#x6CD5;&#xFF08;&#x53EF;&#x4EE5;&#x7406;&#x89E3;&#x4E3A;&#x679A;&#x4E3E;&#x7C7B;&#x4E2D;&#x90A3;&#x4E2A;&#x9ED8;&#x8BA4;&#x65B9;&#x6CD5;&#xFF09;</li>
</ul>
<pre><code>interface Strategy extends java.io.Serializable {

    /**
     * Sets {@code numHashFunctions} bits of the given bit array, by hashing a user element.
     *
     * &lt;p&gt;Returns whether any bits changed as a result of this operation.
     */
    &lt;T&gt; boolean put(T object, Funnel&lt;? super T&gt; funnel, int numHashFunctions, BitArray bits);

    /**
     * Queries {@code numHashFunctions} bits of the given bit array, by hashing a user element;
     * returns {@code true} if and only if all selected bits are set.
     */
    &lt;T&gt; boolean mightContain(
        T object, Funnel&lt;? super T&gt; funnel, int numHashFunctions, BitArray bits);

    /**
     * Identifier used to encode this strategy, when marshalled as part of a BloomFilter. Only
     * values in the [-128, 127] range are valid for the compact serial form. Non-negative values
     * are reserved for enums defined in BloomFilterStrategies; negative values are reserved for any
     * custom, stateful strategy we may define (e.g. any kind of strategy that would depend on user
     * input).
     */
    int ordinal();
  }
</code></pre>
<p>&#x5BF9;&#x4E8E;&#x521B;&#x5EFA;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#xFF0C;BloomFilter&#x5E76;&#x6CA1;&#x6709;&#x516C;&#x6709;&#x7684;&#x6784;&#x9020;&#x51FD;&#x6570;&#xFF0C;&#x53EA;&#x6709;&#x4E00;&#x4E2A;&#x79C1;&#x6709;&#x6784;&#x9020;&#x51FD;&#x6570;&#xFF0C;&#x800C;&#x5BF9;&#x5916;&#x5B83;&#x63D0;&#x4F9B;&#x4E86;5&#x4E2A;&#x91CD;&#x8F7D;&#x7684;create&#x65B9;&#x6CD5;&#xFF0C;&#x5728;&#x7F3A;&#x7701;&#x60C5;&#x51B5;&#x4E0B;&#x8BEF;&#x5224;&#x7387;&#x8BBE;&#x5B9A;&#x4E3A;3%&#xFF0C;&#x91C7;&#x7528;BloomFilterStrategies.MURMUR128_MITZ_64&#x7684;&#x5B9E;&#x73B0;&#x3002;&#x5176;&#x4E2D;4&#x4E2A;create&#x65B9;&#x6CD5;&#x6700;&#x7EC8;&#x90FD;&#x8C03;&#x7528;&#x4E86;&#x540C;&#x4E00;&#x4E2A;create&#x65B9;&#x6CD5;&#xFF0C;&#x7531;&#x5B83;&#x6765;&#x8D1F;&#x8D23;&#x8C03;&#x7528;&#x79C1;&#x6709;&#x6784;&#x9020;&#x51FD;&#x6570;&#xFF0C;&#x5176;&#x6E90;&#x7801;&#x5982;&#x4E0B;&#xFF1A;</p>
<pre><code>static &lt;T&gt; BloomFilter&lt;T&gt; create(
      Funnel&lt;? super T&gt; funnel, long expectedInsertions, double fpp, Strategy strategy) {
    checkNotNull(funnel);
    checkArgument(
        expectedInsertions &gt;= 0, &quot;Expected insertions (%s) must be &gt;= 0&quot;, expectedInsertions);
    checkArgument(fpp &gt; 0.0, &quot;False positive probability (%s) must be &gt; 0.0&quot;, fpp);
    checkArgument(fpp &lt; 1.0, &quot;False positive probability (%s) must be &lt; 1.0&quot;, fpp);
    checkNotNull(strategy);

    if (expectedInsertions == 0) {
      expectedInsertions = 1;
    }
    /*
     * TODO(user): Put a warning in the javadoc about tiny fpp values, since the resulting size
     * is proportional to -log(p), but there is not much of a point after all, e.g.
     * optimalM(1000, 0.0000000000000001) = 76680 which is less than 10kb. Who cares!
     */
    long numBits = optimalNumOfBits(expectedInsertions, fpp);
    int numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);
    try {
      return new BloomFilter&lt;T&gt;(new BitArray(numBits), numHashFunctions, funnel, strategy);
    } catch (IllegalArgumentException e) {
      throw new IllegalArgumentException(&quot;Could not create BloomFilter of &quot; + numBits + &quot; bits&quot;, e);
    }
  }
</code></pre>
<p>&#x5728;create&#x4E2D;&#x63A5;&#x53D7;&#x4E86;4&#x4E2A;&#x53C2;&#x6570;&#xFF0C;funnel&#xFF08;&#x8F93;&#x5165;&#x7684;&#x6570;&#x636E;&#xFF09;&#xFF0C;expectedInsertions&#xFF08;&#x9884;&#x8BA1;&#x63D2;&#x5165;&#x7684;&#x5143;&#x7D20;&#x603B;&#x6570;&#xFF09;&#xFF0C;fpp&#xFF08;&#x671F;&#x671B;&#x8BEF;&#x5224;&#x7387;&#xFF09;&#xFF0C;strategy&#xFF08;&#x5B9E;&#x73B0;Strategy&#x7684;&#x5B9E;&#x4F8B;&#xFF09;&#xFF0C;&#x7136;&#x540E;&#x5B83;&#x8BA1;&#x7B97;&#x4E86;bit&#x6570;&#x7EC4;&#x7684;&#x957F;&#x5EA6;&#x4EE5;&#x53CA;&#x54C8;&#x5E0C;&#x51FD;&#x6570;&#x7684;&#x4E2A;&#x6570;&#xFF08;&#x516C;&#x5F0F;&#x53C2;&#x8003;&#x524D;&#x6587;&#xFF09;&#xFF0C;&#x6700;&#x540E;&#x7528;numBits&#x521B;&#x5EFA;&#x4E86;BitArray&#xFF0C;&#x5E76;&#x8C03;&#x7528;&#x4E86;&#x6784;&#x9020;&#x51FD;&#x6570;&#x5B8C;&#x6210;&#x8D4B;&#x503C;&#x64CD;&#x4F5C;&#x3002;</p>
<pre><code>static long optimalNumOfBits(long n, double p) {
    if (p == 0) {
      p = Double.MIN_VALUE;
    }
    return (long) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));
  }

static int optimalNumOfHashFunctions(long n, long m) {
    // (m / n) * log(2), but avoid truncation due to division!
    return Math.max(1, (int) Math.round((double) m / n * Math.log(2)));
  }
</code></pre>
<p>&#x63A5;&#x7740;&#x518D;&#x6765;&#x770B;&#x4E00;&#x4E0B;BloomFilterStrategies&#x7C7B;&#xFF0C;&#x9996;&#x5148;&#x5B83;&#x662F;&#x5B9E;&#x73B0;&#x4E86;BloomFilter.Strategy &#x63A5;&#x53E3;&#x7684;&#x4E00;&#x4E2A;&#x679A;&#x4E3E;&#x7C7B;&#xFF0C;&#x5176;&#x6B21;&#x5B83;&#x6709;&#x4E24;&#x4E2A;2&#x679A;&#x4E3E;&#x503C;&#xFF0C;MURMUR128_MITZ_32&#x548C;MURMUR128_MITZ_64&#xFF0C;&#x5206;&#x522B;&#x5BF9;&#x5E94;&#x4E86;32&#x4F4D;&#x54C8;&#x5E0C;&#x6620;&#x5C04;&#x51FD;&#x6570;&#xFF0C;&#x548C;64&#x4F4D;&#x54C8;&#x5E0C;&#x6620;&#x5C04;&#x51FD;&#x6570;&#xFF0C;&#x540E;&#x8005;&#x4F7F;&#x7528;&#x4E86;murmur3 hash&#x751F;&#x6210;&#x7684;&#x6240;&#x6709;128&#x4F4D;&#xFF0C;&#x5177;&#x6709;&#x66F4;&#x5927;&#x7684;&#x7A7A;&#x95F4;&#xFF0C;&#x4E0D;&#x8FC7;&#x539F;&#x7406;&#x662F;&#x76F8;&#x901A;&#x7684;&#xFF0C;&#x6211;&#x4EEC;&#x9009;&#x62E9;&#x9ED8;&#x8BA4;&#x7684;MURMUR128_MITZ_64&#x6765;&#x5206;&#x6790;&#xFF1A;</p>
<pre><code>MURMUR128_MITZ_64() {
    @Override
    public &lt;T&gt; boolean put(
        T object, Funnel&lt;? super T&gt; funnel, int numHashFunctions, BitArray bits) {
      long bitSize = bits.bitSize();
      byte[] bytes = Hashing.murmur3_128().hashObject(object, funnel).getBytesInternal();
      long hash1 = lowerEight(bytes);
      long hash2 = upperEight(bytes);

      boolean bitsChanged = false;
      long combinedHash = hash1;
      for (int i = 0; i &lt; numHashFunctions; i++) {
        // Make the combined hash positive and indexable
        bitsChanged |= bits.set((combinedHash &amp; Long.MAX_VALUE) % bitSize);
        combinedHash += hash2;
      }
      return bitsChanged;
    }

    @Override
    public &lt;T&gt; boolean mightContain(
        T object, Funnel&lt;? super T&gt; funnel, int numHashFunctions, BitArray bits) {
      long bitSize = bits.bitSize();
      byte[] bytes = Hashing.murmur3_128().hashObject(object, funnel).getBytesInternal();
      long hash1 = lowerEight(bytes);
      long hash2 = upperEight(bytes);

      long combinedHash = hash1;
      for (int i = 0; i &lt; numHashFunctions; i++) {
        // Make the combined hash positive and indexable
        if (!bits.get((combinedHash &amp; Long.MAX_VALUE) % bitSize)) {
          return false;
        }
        combinedHash += hash2;
      }
      return true;
    }
</code></pre>
<p>&#x62BD;&#x8C61;&#x6765;&#x770B;&#xFF0C;put&#x662F;&#x5199;&#xFF0C;mightContain&#x662F;&#x8BFB;&#xFF0C;&#x4E24;&#x4E2A;&#x65B9;&#x6CD5;&#x7684;&#x4EE3;&#x7801;&#x6709;&#x4E00;&#x70B9;&#x76F8;&#x4F3C;&#xFF0C;&#x90FD;&#x662F;&#x5148;&#x5229;&#x7528;murmur3 hash&#x5BF9;&#x8F93;&#x5165;&#x7684;funnel&#x8BA1;&#x7B97;&#x5F97;&#x5230;128&#x4F4D;&#x7684;&#x5B57;&#x8282;&#x6570;&#x7EC4;&#xFF0C;&#x7136;&#x540E;&#x9AD8;&#x4F4E;&#x5206;&#x522B;&#x53D6;8&#x4E2A;&#x5B57;&#x8282;&#xFF08;64&#x4F4D;&#xFF09;&#x521B;&#x5EFA;2&#x4E2A;long&#x578B;&#x6574;&#x6570;hash1&#xFF0C;hash2&#x4F5C;&#x4E3A;&#x54C8;&#x5E0C;&#x503C;&#x3002;&#x5FAA;&#x73AF;&#x4F53;&#x5185;&#x91C7;&#x7528;&#x4E86;2&#x4E2A;&#x51FD;&#x6570;&#x6A21;&#x62DF;&#x5176;&#x4ED6;&#x51FD;&#x6570;&#x7684;&#x601D;&#x60F3;&#xFF0C;&#x5373;&#x4E0A;&#x6587;&#x63D0;&#x5230;&#x7684;gi(x) = h1(x) + ih2(x) &#xFF0C;&#x8FD9;&#x76F8;&#x5F53;&#x4E8E;&#x6BCF;&#x6B21;&#x7D2F;&#x52A0;hash2&#xFF0C;&#x7136;&#x540E;&#x901A;&#x8FC7;&#x57FA;&#x4E8E;bitSize&#x53D6;&#x6A21;&#x7684;&#x65B9;&#x5F0F;&#x5728;bit&#x6570;&#x7EC4;&#x4E2D;&#x7D22;&#x5F15;&#x3002;</p>
<p>&#x8FD9;&#x91CC;&#x4E4B;&#x6240;&#x4EE5;&#x8981;&#x548C;Long.MAX_VALUE&#x8FDB;&#x884C;&#x6309;&#x4F4D;&#x4E0E;&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x662F;&#x56E0;&#x4E3A;&#x5728;&#x9664;&#x6570;&#x548C;&#x88AB;&#x9664;&#x6570;&#x7B26;&#x53F7;&#x4E0D;&#x4E00;&#x81F4;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#x8BA1;&#x7B97;&#x6240;&#x5F97;&#x7684;&#x7ED3;&#x679C;&#x662F;&#x6709;&#x5DEE;&#x522B;&#x7684;&#xFF0C;&#x5728;&#x7A0B;&#x5E8F;&#x8BED;&#x8A00;&#x91CC;&#xFF0C;&#x201C;%&#x201D;&#x51C6;&#x786E;&#x6765;&#x8BF4;&#x662F;&#x53D6;&#x4F59;&#x8FD0;&#x7B97;&#xFF08;C&#xFF0C;C++&#x548C;Java&#x5747;&#x5982;&#x6B64;&#xFF0C;python&#x662F;&#x53D6;&#x6A21;&#xFF09;&#xFF0C;&#x5982;-5%3=-2&#xFF0C;&#x800C;&#x53D6;&#x6A21;&#x7684;&#x6570;&#x5B66;&#x5B9A;&#x4E49;&#x662F;x mod y=x-y[x/y]&#xFF08;&#x5411;&#x4E0B;&#x53D6;&#x6574;&#xFF09;&#xFF0C;&#x6240;&#x4EE5;-5 mod 3= -5-3*(-2)=1&#xFF0C;&#x56E0;&#x6B64;&#x5F53;&#x54C8;&#x5E0C;&#x503C;&#x4E3A;&#x8D1F;&#x6570;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x5176;&#x53D6;&#x4F59;&#x7684;&#x7ED3;&#x679C;&#x4E3A;&#x8D1F;&#xFF08;bitSize&#x59CB;&#x7EC8;&#x4E3A;&#x6B63;&#x6570;&#xFF09;&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x4E0D;&#x65B9;&#x4FBF;&#x5728;bit&#x6570;&#x7EC4;&#x4E2D;&#x53D6;&#x503C;&#xFF0C;&#x56E0;&#x6B64;&#x901A;&#x8FC7;Long.MAX_VALUE(&#x4E8C;&#x8FDB;&#x5236;&#x4E3A;0111&#x2026;1111)&#xFF0C;&#x76F4;&#x63A5;&#x5C06;&#x5F00;&#x5934;&#x7684;&#x7B26;&#x53F7;&#x4F4D;&#x53BB;&#x6389;&#xFF0C;&#x4ECE;&#x800C;&#x8F6C;&#x53D8;&#x4E3A;&#x6B63;&#x6570;&#x3002;&#x5F53;&#x7136;&#x4E5F;&#x53EF;&#x4EE5;&#x53D6;&#x7EDD;&#x5BF9;&#x503C;&#xFF0C;&#x5728;&#x53E6;&#x4E00;&#x4E2A;MURMUR128_MITZ_32&#x7684;&#x5B9E;&#x73B0;&#x4E2D;&#x5C31;&#x662F;&#x8FD9;&#x4E48;&#x505A;&#x7684;&#x3002;</p>
<p>&#x5728;put&#x65B9;&#x6CD5;&#x4E2D;&#xFF0C;&#x5148;&#x662F;&#x5C06;&#x7D22;&#x5F15;&#x4F4D;&#x7F6E;&#x4E0A;&#x7684;&#x4E8C;&#x8FDB;&#x5236;&#x7F6E;&#x4E3A;1&#xFF0C;&#x7136;&#x540E;&#x7528;bitsChanged&#x8BB0;&#x5F55;&#x63D2;&#x5165;&#x7ED3;&#x679C;&#xFF0C;&#x5982;&#x679C;&#x8FD4;&#x56DE;true&#x8868;&#x660E;&#x6CA1;&#x6709;&#x91CD;&#x590D;&#x63D2;&#x5165;&#x6210;&#x529F;&#xFF0C;&#x800C;mightContain&#x65B9;&#x6CD5;&#x5219;&#x662F;&#x5C06;&#x7D22;&#x5F15;&#x4F4D;&#x7F6E;&#x4E0A;&#x7684;&#x6570;&#x503C;&#x53D6;&#x51FA;&#xFF0C;&#x5E76;&#x5224;&#x65AD;&#x662F;&#x5426;&#x4E3A;0&#xFF0C;&#x53EA;&#x8981;&#x5176;&#x4E2D;&#x51FA;&#x73B0;&#x4E00;&#x4E2A;0&#xFF0C;&#x90A3;&#x4E48;&#x7ACB;&#x5373;&#x5224;&#x65AD;&#x4E3A;&#x4E0D;&#x5B58;&#x5728;&#x3002;</p>
<p>&#x6700;&#x540E;&#x518D;&#x8BF4;&#x4E00;&#x4E0B;&#x5E95;&#x5C42;bit&#x6570;&#x7EC4;&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x4E3B;&#x8981;&#x4EE3;&#x7801;&#x5982;&#x4E0B;&#xFF1A;</p>
<pre><code> static final class BitArray {
    final long[] data;
    long bitCount;

    BitArray(long bits) {
      this(new long[Ints.checkedCast(LongMath.divide(bits, 64, RoundingMode.CEILING))]);
    }

    // Used by serialization
    BitArray(long[] data) {
      checkArgument(data.length &gt; 0, &quot;data length is zero!&quot;);
      this.data = data;
      long bitCount = 0;
      for (long value : data) {
        bitCount += Long.bitCount(value);
      }
      this.bitCount = bitCount;
    }

    /** Returns true if the bit changed value. */
    boolean set(long index) {
      if (!get(index)) {
        data[(int) (index &gt;&gt;&gt; 6)] |= (1L &lt;&lt; index);
        bitCount++;
        return true;
      }
      return false;
    }

    boolean get(long index) {
      return (data[(int) (index &gt;&gt;&gt; 6)] &amp; (1L &lt;&lt; index)) != 0;
    }

    /** Number of bits */
    long bitSize() {
      return (long) data.length * Long.SIZE;
    }
...
}
</code></pre>
<p>&#x4E4B;&#x524D;&#x4E5F;&#x63D0;&#x5230;&#x4E86;Guava&#x6CA1;&#x6709;&#x4F7F;&#x7528;java.util.BitSet&#xFF0C;&#x800C;&#x662F;&#x5C01;&#x88C5;&#x4E86;&#x4E00;&#x4E2A;long&#x578B;&#x7684;&#x6570;&#x7EC4;&#xFF0C;&#x53E6;&#x5916;&#x8FD8;&#x6709;&#x4E00;&#x4E2A;long&#x578B;&#x6574;&#x6570;&#xFF0C;&#x7528;&#x6765;&#x7EDF;&#x8BA1;&#x6570;&#x7EC4;&#x4E2D;&#x5DF2;&#x7ECF;&#x5360;&#x7528;&#xFF08;&#x7F6E;&#x4E3A;1&#xFF09;&#x7684;&#x6570;&#x91CF;&#xFF0C;&#x5728;&#x7B2C;&#x4E00;&#x4E2A;&#x6784;&#x9020;&#x51FD;&#x6570;&#x4E2D;&#xFF0C;&#x5B83;&#x628A;&#x4F20;&#x5165;&#x7684;long&#x578B;&#x6574;&#x6570;&#x6309;&#x957F;&#x5EA6;64&#x5206;&#x6BB5;&#xFF08;&#x4F8B;&#x5982;129&#x5206;&#x4E3A;3&#x6BB5;&#xFF09;&#xFF0C;&#x6BB5;&#x6570;&#x4F5C;&#x4E3A;&#x6570;&#x7EC4;&#x7684;&#x957F;&#x5EA6;&#xFF0C;&#x4F60;&#x53EF;&#x4EE5;&#x60F3;&#x8C61;&#x6210;&#x7531;&#x82E5;&#x5E72;&#x4E2A;64&#x4F4D;&#x6570;&#x7EC4;&#x62FC;&#x63A5;&#x6210;&#x4E00;&#x4E2A;&#x8D85;&#x957F;&#x7684;&#x6570;&#x7EC4;&#xFF0C;&#x5B83;&#x7684;&#x957F;&#x5EA6;&#x5C31;&#x662F;64&#x4E58;&#x4EE5;&#x6BB5;&#x6570;&#xFF0C;&#x5373;bitSize&#xFF0C;&#x5728;&#x7B2C;&#x4E8C;&#x4E2A;&#x6784;&#x9020;&#x51FD;&#x6570;&#x4E2D;&#x5229;&#x7528;Long.bitCount&#x65B9;&#x6CD5;&#x6765;&#x7EDF;&#x8BA1;&#x5BF9;&#x5E94;&#x4E8C;&#x8FDB;&#x5236;&#x7F16;&#x7801;&#x4E2D;&#x7684;1&#x4E2A;&#x6570;&#xFF0C;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x5728;JDK1.5&#x4E2D;&#x5C31;&#x6709;&#x4E86;&#xFF0C;&#x5176;&#x7B97;&#x6CD5;&#x8BBE;&#x8BA1;&#x5F97;&#x975E;&#x5E38;&#x7CBE;&#x5999;&#xFF0C;&#x6709;&#x7CBE;&#x529B;&#x7684;&#x540C;&#x5B66;&#x53EF;&#x4EE5;&#x81EA;&#x884C;&#x7814;&#x7A76;&#x3002;</p>
<p>&#x53E6;&#x5916;&#x4E24;&#x4E2A;&#x91CD;&#x8981;&#x7684;&#x65B9;&#x6CD5;&#x662F;set&#x548C;get&#xFF0C;&#x5728;get&#x65B9;&#x6CD5;&#x4E2D;&#xFF0C;&#x53C2;&#x8003;put&#x548C;mightContain&#x65B9;&#x6CD5;&#xFF0C;&#x4F20;&#x5165;&#x7684;&#x53C2;&#x6570;index&#x662F;&#x7ECF;&#x8FC7;bitSize&#x53D6;&#x6A21;&#x7684;&#xFF0C;&#x56E0;&#x6B64;&#x4E00;&#x5B9A;&#x80FD;&#x843D;&#x5728;&#x8FD9;&#x4E2A;&#x8D85;&#x957F;&#x6570;&#x7EC4;&#x7684;&#x8303;&#x56F4;&#x4E4B;&#x5185;&#xFF0C;&#x4E3A;&#x4E86;&#x83B7;&#x53D6;index&#x5BF9;&#x5E94;&#x7D22;&#x5F15;&#x4F4D;&#x7F6E;&#x4E0A;&#x7684;&#x503C;&#xFF0C;&#x9996;&#x5148;&#x5C06;&#x5176;&#x65E0;&#x7B26;&#x53F7;&#x53F3;&#x79FB;6&#x4F4D;&#xFF0C;&#x5E76;&#x4E14;&#x5F3A;&#x5236;&#x8F6C;&#x6362;&#x6210;int&#x578B;&#xFF0C;&#x8FD9;&#x76F8;&#x5F53;&#x4E8E;&#x9664;&#x4EE5;64&#x5411;&#x4E0B;&#x53D6;&#x6574;&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x6362;&#x7B97;&#x6210;&#x6BB5;&#x6570;&#xFF0C;&#x5F97;&#x5230;&#x8BE5;&#x6BB5;&#x4E0A;&#x7684;&#x6570;&#x503C;&#x4E4B;&#x540E;&#xFF0C;&#x53C8;&#x5C06;1&#x5DE6;&#x79FB;index&#x4F4D;&#xFF0C;&#x6700;&#x540E;&#x8FDB;&#x884C;&#x6309;&#x4F4D;&#x4E0E;&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x5982;&#x679C;&#x7ED3;&#x679C;&#x7B49;&#x4E8E;0&#xFF0C;&#x90A3;&#x4E48;&#x8FD4;&#x56DE;false&#xFF0C;&#x4ECE;&#x800C;&#x5728;mightContain&#x4E2D;&#x5224;&#x65AD;&#x4E3A;&#x4E0D;&#x5B58;&#x5728;&#x3002;&#x5728;set&#x65B9;&#x6CD5;&#x4E2D;&#xFF0C;&#x9996;&#x5148;&#x8C03;&#x7528;&#x4E86;get&#x65B9;&#x6CD5;&#x5224;&#x65AD;&#x662F;&#x5426;&#x5DF2;&#x7ECF;&#x5B58;&#x5728;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x5B58;&#x5728;&#xFF0C;&#x5219;&#x7528;&#x540C;&#x6837;&#x7684;&#x903B;&#x8F91;&#x53D6;&#x51FA;data&#x6570;&#x7EC4;&#x4E2D;&#x5BF9;&#x5E94;&#x7D22;&#x5F15;&#x4F4D;&#x7F6E;&#x7684;&#x6570;&#x503C;&#xFF0C;&#x7136;&#x540E;&#x6309;&#x4F4D;&#x6216;&#x5E76;&#x8D4B;&#x503C;&#x56DE;&#x53BB;&#x3002;</p>
<p>&#x5230;&#x8FD9;&#x91CC;&#xFF0C;&#x5BF9;Guava&#x4E2D;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x7684;&#x5B9E;&#x73B0;&#x5C31;&#x57FA;&#x672C;&#x8BA8;&#x8BBA;&#x5B8C;&#x4E86;&#xFF0C;&#x7B80;&#x5355;&#x603B;&#x7ED3;&#x4E00;&#x4E0B;&#xFF1A;</p>
<ol>
<li>BloomFilter&#x7C7B;&#x7684;&#x4F5C;&#x7528;&#x5728;&#x4E8E;&#x63A5;&#x6536;&#x8F93;&#x5165;&#xFF0C;&#x5229;&#x7528;&#x516C;&#x5F0F;&#x5B8C;&#x6210;&#x5BF9;&#x53C2;&#x6570;&#x7684;&#x4F30;&#x7B97;&#xFF0C;&#x6700;&#x540E;&#x521D;&#x59CB;&#x5316;Strategy&#x63A5;&#x53E3;&#x7684;&#x5B9E;&#x4F8B;&#xFF1B;</li>
<li>BloomFilterStrategies&#x662F;&#x4E00;&#x4E2A;&#x679A;&#x4E3E;&#x7C7B;&#xFF0C;&#x5177;&#x6709;&#x4E24;&#x4E2A;&#x5B9E;&#x73B0;&#x4E86;Strategy&#x63A5;&#x53E3;&#x7684;&#x6210;&#x5458;&#xFF0C;&#x5206;&#x522B;&#x4E3A;MURMUR128_MITZ_32&#x548C;MURMUR128_MITZ_64&#xFF0C;&#x53E6;&#x5916;&#x5C01;&#x88C5;&#x4E86;long&#x578B;&#x7684;&#x6570;&#x7EC4;&#x4F5C;&#x4E3A;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x5E95;&#x5C42;&#x7684;bit&#x6570;&#x7EC4;&#xFF0C;&#x5176;&#x4E2D;&#x5728;get&#x548C;set&#x65B9;&#x6CD5;&#x4E2D;&#x5B8C;&#x6210;&#x6838;&#x5FC3;&#x7684;&#x4F4D;&#x8FD0;&#x7B97;&#x3002;</li>
</ol>
<h2 id="redisbitmaps">&#x4E09;&#x3001;&#x5229;&#x7528;Redis Bitmaps&#x8FDB;&#x884C;&#x91CD;&#x6784;</h2>
<p>&#x901A;&#x8FC7;&#x4E0A;&#x9762;&#x7684;&#x5206;&#x6790;&#xFF0C;&#x4E3B;&#x8981;&#x7B97;&#x6CD5;&#x548C;&#x903B;&#x8F91;&#x7684;&#x90E8;&#x5206;&#x5927;&#x4F53;&#x90FD;&#x662F;&#x4E00;&#x6837;&#x7684;&#xFF0C;&#x771F;&#x6B63;&#x9700;&#x8981;&#x91CD;&#x6784;&#x7684;&#x90E8;&#x5206;&#x662F;&#x5E95;&#x5C42;&#x4F4D;&#x6570;&#x7EC4;&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x5728;Guava&#x4E2D;&#x662F;&#x5C01;&#x88C5;&#x4E86;&#x4E00;&#x4E2A;long&#x578B;&#x7684;&#x6570;&#x7EC4;&#xFF0C;&#x800C;&#x5BF9;&#x4E8E;redis&#x6765;&#x8BF4;&#xFF0C;&#x672C;&#x8EAB;&#x81EA;&#x5E26;&#x4E86;Bitmaps&#x7684;&#x201C;&#x6570;&#x636E;&#x7ED3;&#x6784;&#x201D;&#xFF08;&#x672C;&#x8D28;&#x4E0A;&#x8FD8;&#x662F;&#x4E00;&#x4E2A;&#x5B57;&#x7B26;&#x4E32;&#xFF09;&#xFF0C;&#x5DF2;&#x7ECF;&#x63D0;&#x4F9B;&#x4E86;&#x4F4D;&#x64CD;&#x4F5C;&#x7684;&#x63A5;&#x53E3;&#xFF0C;&#x56E0;&#x6B64;&#x91CD;&#x6784;&#x672C;&#x8EAB;&#x5E76;&#x4E0D;&#x590D;&#x6742;&#xFF0C;&#x76F8;&#x5BF9;&#x6BD4;&#x8F83;&#x590D;&#x6742;&#x7684;&#x662F;&#xFF0C;&#x4E4B;&#x524D;&#x63D0;&#x5230;&#x7684;&#x5B9E;&#x73B0;&#x81EA;&#x52A8;&#x6269;&#x5BB9;&#x7279;&#x6027;&#x3002;</p>
<p>&#x8FD9;&#x91CC;&#x5B9E;&#x73B0;&#x81EA;&#x52A8;&#x6269;&#x5BB9;&#x7684;&#x601D;&#x60F3;&#x662F;&#xFF0C;&#x5728;redis&#x4E2D;&#x8BB0;&#x5F55;&#x4E00;&#x4E2A;&#x81EA;&#x589E;&#x7684;&#x6E38;&#x6807;cursor&#xFF0C;&#x5982;&#x679C;&#x5F53;&#x524D;key&#x5BF9;&#x5E94;&#x7684;Bitmaps&#x5DF2;&#x7ECF;&#x8FBE;&#x5230;&#x9971;&#x548C;&#x72B6;&#x6001;&#xFF0C;&#x5219;cursor&#x81EA;&#x589E;&#xFF0C;&#x540C;&#x65F6;&#x7528;&#x5176;&#x751F;&#x6210;&#x4E00;&#x4E2A;&#x65B0;&#x7684;key&#xFF0C;&#x5E76;&#x521B;&#x5EFA;&#x89C4;&#x6A21;&#x540C;&#x7B49;&#x7684;Bitmaps&#x3002;&#x7136;&#x540E;&#x5728;get&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x9700;&#x8981;&#x5224;&#x65AD;&#x8BE5;&#x5143;&#x7D20;&#x662F;&#x5426;&#x5B58;&#x5728;&#x4E8E;&#x4EFB;&#x610F;&#x4E00;&#x4E2A;Bitmaps&#x4E2D;&#x3002;&#x4E8E;&#x662F;&#x6574;&#x4E2A;&#x7684;&#x903B;&#x8F91;&#x5C31;&#x53D8;&#x6210;&#xFF0C;&#x4E00;&#x4E2A;&#x5143;&#x7D20;&#x5728;&#x6BCF;&#x4E2A;Bitmaps&#x4E2D;&#x90FD;&#x4E0D;&#x5B58;&#x5728;&#x65F6;&#xFF0C;&#x624D;&#x80FD;&#x63D2;&#x5165;&#x5F53;&#x524D;cursor&#x5BF9;&#x5E94;key&#x7684;Bitmaps&#x4E2D;&#x3002;<br>
<img src="/content/images/2020/05/bf-cursor.png" alt="[&#x8F6E;&#x5B50;&#x7CFB;&#x5217;]Google Guava&#x4E4B;BloomFilter&#x6E90;&#x7801;&#x5206;&#x6790;&#x53CA;&#x57FA;&#x4E8E;Redis&#x7684;&#x91CD;&#x6784;" loading="lazy"><br>
&#x4E0B;&#x9762;&#x662F;&#x4EE3;&#x7801;&#x7684;&#x5B9E;&#x73B0;&#x90E8;&#x5206;&#x3002;</p>
<p>&#x9996;&#x5148;&#xFF0C;&#x4E3A;&#x4E86;&#x7B80;&#x5316;redis&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x5B9A;&#x4E49;&#x4E86;2&#x4E2A;&#x51FD;&#x6570;&#x5F0F;&#x63A5;&#x53E3;&#xFF0C;&#x5206;&#x522B;&#x6267;&#x884C;&#x5355;&#x6761;&#x547D;&#x4EE4;&#x548C;pipeline&#xFF0C;&#x53E6;&#x5916;&#x8FD8;&#x5B9E;&#x73B0;&#x4E86;&#x4E00;&#x4E2A;&#x7B80;&#x5355;&#x7684;&#x5DE5;&#x5177;&#x7C7B;</p>
<pre><code>@FunctionalInterface
public interface JedisExecutor&lt;T&gt; {
    T execute(Jedis jedis);
}

@FunctionalInterface
public interface PipelineExecutor {
    void load(Pipeline pipeline);
}

public class JedisUtils {

    private static final GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

    private JedisPool jedisPool;

    public JedisUtils() {
        jedisPool = new JedisPool(poolConfig, &quot;localhost&quot;, 6379);
    }

    public &lt;T&gt; T execute(JedisExecutor&lt;T&gt; jedisExecutor) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedisExecutor.execute(jedis);
        }
    }

    public List&lt;Object&gt; pipeline(List&lt;PipelineExecutor&gt; pipelineExecutors) {
        try (Jedis jedis = jedisPool.getResource()) {
            Pipeline pipeline = jedis.pipelined();
            for (PipelineExecutor executor : pipelineExecutors)
                executor.load(pipeline);
            return pipeline.syncAndReturnAll();
        }
    }
}
</code></pre>
<p>&#x5176;&#x6B21;&#x5728;Strategy&#x4E2D;&#xFF0C;&#x5BF9;put&#x548C;mightContain&#x4F5C;&#x4E86;&#x4E00;&#x70B9;&#x4FEE;&#x6539;&#xFF0C;&#x5176;&#x4E2D;&#x88AB;&#x6CE8;&#x91CA;&#x7684;&#x90E8;&#x5206;&#x662F;Guava&#x4E2D;&#x7684;&#x5B9E;&#x73B0;&#x3002;&#x4E3A;&#x4E86;&#x7B80;&#x5316;&#xFF0C;&#x8FD9;&#x91CC;&#x6211;&#x4EEC;&#x53EA;&#x63A5;&#x53D7;String&#x5BF9;&#x8C61;&#x3002;</p>
<p>&#x8FD9;&#x91CC;&#x5148;&#x628A;&#x6240;&#x6709;&#x7684;&#x968F;&#x673A;&#x51FD;&#x6570;&#x5BF9;&#x5E94;&#x7684;&#x7D22;&#x5F15;&#x4F4D;&#x7F6E;&#x6536;&#x96C6;&#x5230;&#x4E00;&#x4E2A;&#x6570;&#x7EC4;&#x4E2D;&#xFF0C;&#x7136;&#x540E;&#x4EA4;&#x7531;&#x5E95;&#x5C42;&#x7684;RedisBitmaps&#x5904;&#x7406;get&#x6216;set&#xFF0C;&#x5177;&#x4F53;&#x8FC7;&#x7A0B;&#x540E;&#x9762;&#x4F1A;&#x8BE6;&#x7EC6;&#x8BF4;&#x660E;&#x3002;</p>
<p>bits.ensureCapacityInternal()&#x65B9;&#x6CD5;&#xFF0C;&#x5373;&#x8868;&#x793A;&#x81EA;&#x52A8;&#x6269;&#x5BB9;&#xFF0C;&#x8FD9;&#x4E2A;&#x51FD;&#x6570;&#x540D;&#x662F;&#x4ECE;ArrayList&#x4E2D;&#x642C;&#x8FC7;&#x6765;&#x7684;&#x3002;</p>
<pre><code>    @Override
    public boolean put(String string, int numHashFunctions, RedisBitmaps bits) {
        long bitSize = bits.bitSize();
        byte[] bytes = Hashing.murmur3_128().hashString(string, Charsets.UTF_8).asBytes();
        long hash1 = lowerEight(bytes);
        long hash2 = upperEight(bytes);

        boolean bitsChanged = false;
        long combinedHash = hash1;
//        for (int i = 0; i &lt; numHashFunctions; i++) {
//            bitsChanged |= bits.set((combinedHash &amp; Long.MAX_VALUE) % bitSize);
//            combinedHash += hash2;
//        }
        long[] offsets = new long[numHashFunctions];
        for (int i = 0; i &lt; numHashFunctions; i++) {
            offsets[i] = (combinedHash &amp; Long.MAX_VALUE) % bitSize;
            combinedHash += hash2;
        }
        bitsChanged = bits.set(offsets);
        bits.ensureCapacityInternal();//&#x81EA;&#x52A8;&#x6269;&#x5BB9;
        return bitsChanged;
    }

    @Override
    public boolean mightContain(String object, int numHashFunctions, RedisBitmaps bits) {
        long bitSize = bits.bitSize();
        byte[] bytes = Hashing.murmur3_128().hashString(object, Charsets.UTF_8).asBytes();
        long hash1 = lowerEight(bytes);
        long hash2 = upperEight(bytes);
        long combinedHash = hash1;
//        for (int i = 0; i &lt; numHashFunctions; i++) {
//            if (!bits.get((combinedHash &amp; Long.MAX_VALUE) % bitSize)) {
//                return false;
//            }
//            combinedHash += hash2;
//        }
//        return true;
        long[] offsets = new long[numHashFunctions];
        for (int i = 0; i &lt; numHashFunctions; i++) {
            offsets[i] = (combinedHash &amp; Long.MAX_VALUE) % bitSize;
            combinedHash += hash2;
        }
        return bits.get(offsets);
    }
</code></pre>
<p>&#x6700;&#x540E;&#xFF0C;&#x4E5F;&#x662F;&#x6700;&#x91CD;&#x8981;&#x7684;RedisBitmaps&#xFF0C;&#x5176;&#x4E2D;bitSize&#x7528;&#x4E86;Guava&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x4E2D;&#x8BA1;&#x7B97;Long&#x578B;&#x6570;&#x7EC4;&#x957F;&#x5EA6;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x5F97;&#x5230;bitSize&#x4E4B;&#x540E;&#x4F7F;&#x7528;setbit&#x547D;&#x4EE4;&#x521D;&#x59CB;&#x5316;&#x4E00;&#x4E2A;&#x5168;&#x90E8;&#x4E3A;0&#x7684;&#x4F4D;&#x6570;&#x7EC4;&#x3002;get(long offset)&#x548C;set(long offset)&#xFF0C;&#x8FD9;&#x4E24;&#x4E2A;&#x4E0E;Guava&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x4E2D;&#x7684;&#x903B;&#x8F91;&#x7C7B;&#x4F3C;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x4E0D;&#x518D;&#x8D58;&#x8FF0;&#x4E86;&#xFF0C;&#x800C;get(long[] offsets)&#x65B9;&#x6CD5;&#x4E2D;&#xFF0C;&#x6240;&#x6709;&#x7684;offset&#x8981;&#x4E0E;&#x6BCF;&#x4E00;&#x4E2A;cursor&#x5BF9;&#x5E94;&#x7684;Bitmaps&#x8FDB;&#x884C;&#x5224;&#x65AD;&#xFF0C;&#x82E5;&#x5168;&#x90E8;&#x547D;&#x4E2D;&#xFF0C;&#x90A3;&#x4E48;&#x8FD9;&#x4E2A;&#x5143;&#x7D20;&#x5C31;&#x53EF;&#x80FD;&#x5B58;&#x5728;&#x4E8E;&#x8BE5;Bitmaps&#xFF0C;&#x53CD;&#x4E4B;&#x82E5;&#x4E0D;&#x80FD;&#x5B8C;&#x5168;&#x547D;&#x4E2D;&#xFF0C;&#x5219;&#x8868;&#x793A;&#x8BE5;&#x5143;&#x7D20;&#x4E0D;&#x5B58;&#x5728;&#x4E8E;&#x4EFB;&#x4F55;&#x4E00;&#x4E2A;Bitmaps&#xFF0C;&#x6240;&#x4EE5;&#x5F53;&#x6EE1;&#x8DB3;&#x8FD9;&#x4E2A;&#x6761;&#x4EF6;&#xFF0C;&#x5728;set(long[] offsets)&#x65B9;&#x6CD5;&#x4E2D;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x63D2;&#x5165;&#x5230;&#x5F53;&#x524D;key&#x7684;Bitmaps&#x4E2D;&#x4E86;&#x3002;</p>
<p>&#x5728;ensureCapacityInternal&#x65B9;&#x6CD5;&#xFF0C;&#x5224;&#x65AD;&#x9700;&#x8981;&#x6269;&#x5BB9;&#x7684;&#x6761;&#x4EF6;&#x662F;bitCount*2&gt;bitSize&#xFF0C;bitCount&#x8868;&#x793A;&#x4E00;&#x4E2A;Bitmaps&#x4E2D;&#x201C;1&#x201D;&#x51FA;&#x73B0;&#x7684;&#x4E2A;&#x6570;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x5F53;&#x201C;1&#x201D;&#x51FA;&#x73B0;&#x7684;&#x4E2A;&#x6570;&#x8D85;&#x8FC7;&#x603B;&#x6570;&#x7684;&#x4E00;&#x534A;&#x65F6;&#xFF0C;&#x8FDB;&#x884C;&#x6269;&#x5BB9;&#x64CD;&#x4F5C;&#x2014;&#x2014;&#x9996;&#x5148;&#x4F7F;&#x7528;incr&#x547D;&#x4EE4;&#x5BF9;cursor&#x81EA;&#x589E;&#xFF0C;&#x7136;&#x540E;&#x4F7F;&#x7528;&#x65B0;&#x7684;key&#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#x65B0;&#x7684;Bitmaps&#x3002;</p>
<pre><code>class RedisBitmaps {

    private static final String BASE_KEY = &quot;bloomfilter&quot;;
    private static final String CURSOR = &quot;cursor&quot;;

    private JedisUtils jedisUtils;
    private long bitSize;

    RedisBitmaps(long bits) {
        this.jedisUtils = new JedisUtils();
        this.bitSize = LongMath.divide(bits, 64, RoundingMode.CEILING) * Long.SIZE;//&#x4F4D;&#x6570;&#x7EC4;&#x7684;&#x957F;&#x5EA6;&#xFF0C;&#x76F8;&#x5F53;&#x4E8E;n&#x4E2A;long&#x7684;&#x957F;&#x5EA6;
        if (bitCount() == 0) {
            jedisUtils.execute((jedis -&gt; jedis.setbit(currentKey(), bitSize - 1, false)));
        }
    }

   boolean get(long[] offsets) {
        for (long i = 0; i &lt; cursor() + 1; i++) {
            final long cursor = i;
            //&#x53EA;&#x8981;&#x6709;&#x4E00;&#x4E2A;cursor&#x5BF9;&#x5E94;&#x7684;bitmap&#x4E2D;&#xFF0C;offsets&#x5168;&#x90E8;&#x547D;&#x4E2D;&#xFF0C;&#x5219;&#x8868;&#x793A;&#x53EF;&#x80FD;&#x5B58;&#x5728;
            boolean match = Arrays.stream(offsets).boxed()
                    .map(offset -&gt; jedisUtils.execute(jedis -&gt; jedis.getbit(genkey(cursor), offset)))
                    .allMatch(b -&gt; (Boolean) b);
            if (match)
                return true;
        }
        return false;
    }

    boolean get(final long offset) {
        return jedisUtils.execute(jedis -&gt; jedis.getbit(currentKey(), offset));
    }

    boolean set(long[] offsets) {
        if (cursor() &gt; 0 &amp;&amp; get(offsets)) {
            return false;
        }
        boolean bitsChanged = false;
        for (long offset : offsets)
            bitsChanged |= set(offset);
        return bitsChanged;
    }

    boolean set(long offset) {
        if (!get(offset)) {
            jedisUtils.execute(jedis -&gt; jedis.setbit(currentKey(), offset, true));
            return true;
        }
        return false;
    }

    long bitCount() {
        return jedisUtils.execute(jedis -&gt; jedis.bitcount(currentKey()));
    }

    long bitSize() {
        return this.bitSize;
    }

    private String currentKey() {
        return genkey(cursor());
    }

    private String genkey(long cursor) {
        return BASE_KEY + &quot;-&quot; + cursor;
    }

    private Long cursor() {
        String cursor = jedisUtils.execute(jedis -&gt; jedis.get(CURSOR));
        return cursor == null ? 0 : Longs.tryParse(cursor);
    }

    void ensureCapacityInternal() {
        if (bitCount() * 2 &gt; bitSize())
            grow();
    }

    void grow() {
        Long cursor = jedisUtils.execute(jedis -&gt; jedis.incr(CURSOR));
        jedisUtils.execute((jedis -&gt; jedis.setbit(genkey(cursor), bitSize - 1, false)));
    }

    void reset() {
        String[] keys = LongStream.range(0, cursor() + 1).boxed().map(this::genkey).toArray(String[]::new);
        jedisUtils.execute(jedis -&gt; jedis.del(keys));
        jedisUtils.execute(jedis -&gt; jedis.set(CURSOR, &quot;0&quot;));
        jedisUtils.execute(jedis -&gt; jedis.setbit(currentKey(), bitSize - 1, false));
    }

    private PipelineExecutor apply(PipelineExecutor executor) {
        return executor;
    }
}
</code></pre>
<p>&#x4E0B;&#x9762;&#x6211;&#x4EEC;&#x505A;&#x4E00;&#x4E2A;&#x5355;&#x5143;&#x6D4B;&#x8BD5;&#x6765;&#x9A8C;&#x8BC1;&#x5176;&#x6B63;&#x786E;&#x6027;&#x3002;</p>
<p>&#x5982;&#x679C;&#x6211;&#x4EEC;&#x63D2;&#x5165;&#x7684;&#x6570;&#x91CF;&#x7B49;&#x4E8E;&#x539F;&#x9884;&#x8BA1;&#x603B;&#x6570;&#xFF0C;RedisBloomFilter&#x6269;&#x5BB9;&#x4E86;1&#x6B21;&#xFF0C;&#x800C;&#x4E24;&#x4E2A;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x7684;&#x7ED3;&#x679C;&#x4E00;&#x81F4;&#xFF0C;&#x90FD;&#x4E3A;false,true,false&#x3002;</p>
<p>&#x5982;&#x679C;&#x63D2;&#x5165;&#x7684;&#x6570;&#x91CF;&#x4E3A;&#x539F;&#x9884;&#x8BA1;&#x603B;&#x6570;&#x7684;3&#x500D;&#xFF0C;RedisBloomFilter&#x6269;&#x5BB9;&#x4E86;3&#x6B21;&#xFF0C;&#x5E76;&#x4E14;&#x4ECD;&#x5224;&#x65AD;&#x6B63;&#x786E;&#xFF0C;&#x800C;Guava&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x5219;&#x5728;&#x5224;&#x65AD;str3&#x65F6;&#x51FA;&#x73B0;&#x8BEF;&#x5224;&#x3002;</p>
<pre><code>public class TestRedisBloomFilter {

    private static final int TOTAL = 10000;
    private static final double FPP = 0.0005;

    @Test
    public void test() {
        RedisBloomFilter redisBloomFilter = RedisBloomFilter.create(TOTAL, FPP);
        redisBloomFilter.resetBitmap();
        BloomFilter&lt;String&gt; bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), TOTAL, FPP);

        IntStream.range(0, /* 3* */TOTAL).boxed()
                .map(i -&gt; Hashing.md5().hashInt(i).toString())
                .collect(toList()).forEach(s -&gt; {
            redisBloomFilter.put(s);
            bloomFilter.put(s);
        });

        String str1 = Hashing.md5().hashInt(99999).toString();
        String str2 = Hashing.md5().hashInt(9999).toString();
        String str3 = &quot;abcdefghijklmnopqrstuvwxyz123456&quot;;
        System.out.println(redisBloomFilter.mightContain(str1) + &quot;:&quot; + bloomFilter.mightContain(str1));
        System.out.println(redisBloomFilter.mightContain(str2) + &quot;:&quot; + bloomFilter.mightContain(str2));
        System.out.println(redisBloomFilter.mightContain(str3) + &quot;:&quot; + bloomFilter.mightContain(str3));
    }
}
&gt;&gt;
grow bloomfilter-1
false:false
true:true
false:false
&gt;&gt;
grow bloomfilter-1
grow bloomfilter-2
grow bloomfilter-3
false:false
true:true
false:true
</code></pre>
<p>&#x7EFC;&#x4E0A;&#xFF0C;&#x672C;&#x6587;&#x5229;&#x7528;&#x4E86;Guava&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x7684;&#x601D;&#x60F3;&#xFF0C;&#x5E76;&#x7ED3;&#x5408;Redis&#x4E2D;&#x7684;Bitmaps&#x7B49;&#x7279;&#x6027;&#x5B9E;&#x73B0;&#x4E86;&#x652F;&#x6301;&#x52A8;&#x6001;&#x6269;&#x5BB9;&#x7684;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#xFF0C;&#x5B83;&#x5C06;&#x5E03;&#x9686;&#x8FC7;&#x6EE4;&#x5668;&#x5E95;&#x5C42;&#x7684;&#x4F4D;&#x6570;&#x636E;&#x88C5;&#x8F7D;&#x5230;&#x4E86;Redis&#x6570;&#x636E;&#x5E93;&#x4E2D;&#xFF0C;&#x8FD9;&#x6837;&#x7684;&#x597D;&#x5904;&#x5728;&#x4E8E;&#x53EF;&#x4EE5;&#x90E8;&#x7F72;&#x5728;&#x66F4;&#x590D;&#x6742;&#x7684;&#x591A;&#x5E94;&#x7528;&#x6216;&#x5206;&#x5E03;&#x5F0F;&#x7CFB;&#x7EDF;&#x4E2D;&#xFF0C;&#x8FD8;&#x53EF;&#x4EE5;&#x5229;&#x7528;Redis&#x5B8C;&#x6210;&#x6301;&#x4E45;&#x5316;&#xFF0C;&#x5B9A;&#x65F6;&#x8FC7;&#x671F;&#x7B49;&#x529F;&#x80FD;&#x3002;</p>
<p>&#x56DB;&#x3001;&#x53C2;&#x8003;&#x6587;&#x732E;</p>
<ol>
<li>&#x5434;&#x519B;. &#x6570;&#x5B66;&#x4E4B;&#x7F8E;[M]. &#x4EBA;&#x6C11;&#x90AE;&#x7535;&#x51FA;&#x7248;&#x793E;, 2012.</li>
<li>Kirsch A, Mitzenmacher M. Less hashing, same performance: building a better bloom filter[C]//ESA. 2006, 6: 456-467.</li>
<li>Bloom Filters for the Perplexed, <a href="https://sagi.io/2017/07/bloom-filters-for-the-perplexed/">https://sagi.io/2017/07/bloom-filters-for-the-perplexed/</a></li>
<li>Google Guava, <a href="https://github.com/google/guava">https://github.com/google/guava</a></li>
</ol>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[HttpClient获取cookie及常见错误的解决方法]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>&#x5728;&#x4F7F;&#x7528;HttpClient&#x8FDB;&#x884C;&#x6293;&#x53D6;&#x4E00;&#x4E9B;&#x7F51;&#x9875;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x7ECF;&#x5E38;&#x4F1A;&#x4FDD;&#x7559;&#x4ECE;&#x670D;&#x52A1;&#x5668;&#x7AEF;&#x53D1;&#x56DE;&#x7684;Cookie&#x4FE1;&#x606F;&#xFF0C;&#x4EE5;&#x4FBF;&#x53D1;&#x8D77;&#x9700;&#x8981;&#x8FD9;&#x4E9B;Cookie&#x7684;&#x8BF7;&#x6C42;&#x3002;&#x5927;&#x591A;&#x6570;&#x60C5;</p>]]></description><link>http://www.fullstackyang.com/httpclienthuo-qu-cookieji-chang-jian-cuo-wu-de-jie-jue-fang-fa/</link><guid isPermaLink="false">624567890d2dd3000190a001</guid><category><![CDATA[dev]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Mon, 11 Sep 2017 16:04:00 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2018/06/cookie-e1505202956389.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="http://www.fullstackyang.com/content/images/2018/06/cookie-e1505202956389.jpg" alt="HttpClient&#x83B7;&#x53D6;cookie&#x53CA;&#x5E38;&#x89C1;&#x9519;&#x8BEF;&#x7684;&#x89E3;&#x51B3;&#x65B9;&#x6CD5;"><p>&#x5728;&#x4F7F;&#x7528;HttpClient&#x8FDB;&#x884C;&#x6293;&#x53D6;&#x4E00;&#x4E9B;&#x7F51;&#x9875;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x7ECF;&#x5E38;&#x4F1A;&#x4FDD;&#x7559;&#x4ECE;&#x670D;&#x52A1;&#x5668;&#x7AEF;&#x53D1;&#x56DE;&#x7684;Cookie&#x4FE1;&#x606F;&#xFF0C;&#x4EE5;&#x4FBF;&#x53D1;&#x8D77;&#x9700;&#x8981;&#x8FD9;&#x4E9B;Cookie&#x7684;&#x8BF7;&#x6C42;&#x3002;&#x5927;&#x591A;&#x6570;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x6211;&#x4EEC;&#x4F7F;&#x7528;&#x5185;&#x7F6E;&#x7684;cookie&#x7B56;&#x7565;&#xFF0C;&#x4FBF;&#x80FD;&#x591F;&#x65B9;&#x4FBF;&#x76F4;&#x63A5;&#x5730;&#x83B7;&#x53D6;&#x8FD9;&#x4E9B;cookie&#x3002;</p>
<p>&#x4E0B;&#x9762;&#x7684;&#x4E00;&#x5C0F;&#x6BB5;&#x4EE3;&#x7801;&#xFF0C;&#x5C31;&#x662F;&#x8BBF;&#x95EE;http://www.baidu.com&#xFF0C;&#x5E76;&#x83B7;&#x53D6;&#x5BF9;&#x5E94;&#x7684;cookie&#xFF1A;</p>
<pre><code>    @Test
    public void getCookie(){
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet get=new HttpGet(&quot;http://www.baidu.com&quot;);
        HttpClientContext context = HttpClientContext.create();
        try {
            CloseableHttpResponse response = httpClient.execute(get, context);
            try{
                System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;&gt;headers:&quot;);
                Arrays.stream(response.getAllHeaders()).forEach(System.out::println);
                System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;&gt;cookies:&quot;);
                context.getCookieStore().getCookies().forEach(System.out::println);
            }
            finally {
                response.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
</code></pre>
<p>&#x6253;&#x5370;&#x7ED3;&#x679C;</p>
<pre><code>&gt;&gt;&gt;&gt;&gt;&gt;headers:
Server: bfe/1.0.8.18
Date: Tue, 12 Sep 2017 06:19:06 GMT
Content-Type: text/html
Last-Modified: Mon, 23 Jan 2017 13:28:24 GMT
Transfer-Encoding: chunked
Connection: Keep-Alive
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Pragma: no-cache
Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
&gt;&gt;&gt;&gt;&gt;&gt;cookies:
[version: 0][name: BDORZ][value: 27315][domain: baidu.com][path: /][expiry: null]
</code></pre>
<p>&#x4F46;&#x662F;&#x4E5F;&#x6709;&#x4E00;&#x4E9B;&#x7F51;&#x7AD9;&#x8FD4;&#x56DE;&#x7684;cookie&#x5E76;&#x4E0D;&#x4E00;&#x5B9A;&#x5B8C;&#x5168;&#x7B26;&#x5408;&#x89C4;&#x8303;&#xFF0C;&#x4F8B;&#x5982;&#x4E0B;&#x9762;&#x8FD9;&#x4E2A;&#x4F8B;&#x5B50;&#xFF0C;&#x4ECE;&#x6253;&#x5370;&#x51FA;&#x7684;header&#x4E2D;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;&#x8FD9;&#x4E2A;cookie&#x4E2D;&#x7684;Expires&#x5C5E;&#x6027;&#x662F;&#x65F6;&#x95F4;&#x6233;&#x5F62;&#x5F0F;&#xFF0C;&#x5E76;&#x4E0D;&#x7B26;&#x5408;&#x6807;&#x51C6;&#x7684;&#x65F6;&#x95F4;&#x683C;&#x5F0F;&#xFF0C;&#x56E0;&#x6B64;&#xFF0C;httpclient&#x5BF9;&#x4E8E;cookie&#x7684;&#x5904;&#x7406;&#x5931;&#x6548;&#xFF0C;&#x6700;&#x7EC8;&#x65E0;&#x6CD5;&#x83B7;&#x53D6;&#x5230;cookie&#xFF0C;&#x5E76;&#x4E14;&#x53D1;&#x51FA;&#x4E86;&#x4E00;&#x6761;&#x8B66;&#x544A;&#x4FE1;&#x606F;&#xFF1A;&#x201C;Invalid &#x2018;expires&#x2019; attribute: 1505204523&#x201D;&#x3002;</p>
<pre><code>&#x4E5D;&#x6708; 12, 2017 2:22:04 &#x4E0B;&#x5348; org.apache.http.client.protocol.ResponseProcessCookies processCookies
&#x8B66;&#x544A;: Invalid cookie header: &quot;Set-Cookie: yd_cookie=90236a64-8650-494b332a285dbd886e5981965fc4a93f023d; Expires=1505204523; Path=/; HttpOnly&quot;. Invalid &apos;expires&apos; attribute: 1505204523
&gt;&gt;&gt;&gt;&gt;&gt;headers:
Date: Tue, 12 Sep 2017 06:22:03 GMT
Content-Type: text/html
Connection: keep-alive
Set-Cookie: yd_cookie=90236a64-8650-494b332a285dbd886e5981965fc4a93f023d; Expires=1505204523; Path=/; HttpOnly
Cache-Control: no-cache, no-store
Server: WAF/2.4-12.1
&gt;&gt;&gt;&gt;&gt;&gt;cookies:
</code></pre>
<p>&#x867D;&#x7136;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;header&#x7684;&#x6570;&#x636E;&#xFF0C;&#x91CD;&#x65B0;&#x6784;&#x9020;&#x4E00;&#x4E2A;cookie&#x51FA;&#x6765;&#xFF0C;&#x4E5F;&#x6709;&#x5F88;&#x591A;&#x4EBA;&#x786E;&#x5B9E;&#x4E5F;&#x662F;&#x8FD9;&#x4E48;&#x505A;&#x7684;&#xFF0C;&#x4F46;&#x8FD9;&#x79CD;&#x65B9;&#x6CD5;&#x4E0D;&#x591F;&#x4F18;&#x96C5;&#xFF0C;&#x90A3;&#x4E48;&#x5982;&#x4F55;&#x89E3;&#x51B3;&#x8FD9;&#x4E2A;&#x95EE;&#x9898;&#xFF1F;&#x7F51;&#x4E0A;&#x76F8;&#x5173;&#x7684;&#x8D44;&#x6599;&#x53C8;&#x5F88;&#x5C11;&#xFF0C;&#x6240;&#x4EE5;&#x5C31;&#x53EA;&#x80FD;&#x5148;&#x4ECE;&#x5B98;&#x65B9;&#x6587;&#x6863;&#x5165;&#x624B;&#x3002;<br>
&#x5728;&#x5B98;&#x65B9;&#x6587;&#x6863;3.4&#x5C0F;&#x8282;custom cookie policy&#x4E2D;&#x8BB2;&#x5230;&#x5141;&#x8BB8;&#x81EA;&#x5B9A;&#x4E49;&#x7684;cookie&#x7B56;&#x7565;&#xFF0C;&#x81EA;&#x5B9A;&#x4E49;&#x7684;&#x65B9;&#x6CD5;&#x662F;&#x5B9E;&#x73B0;CookieSpec&#x63A5;&#x53E3;&#xFF0C;&#x5E76;&#x901A;&#x8FC7;&#x521B;&#x5EFA;CookieSpecProvider&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x6765;&#x5B8C;&#x6210;&#x5728;httpclient&#x4E2D;&#x7684;&#x521D;&#x59CB;&#x5316;&#x548C;&#x6CE8;&#x518C;&#x7B56;&#x7565;&#x5B9E;&#x4F8B;&#x7684;&#x5DE5;&#x4F5C;&#x3002;&#x597D;&#x4E86;&#xFF0C;&#x5173;&#x952E;&#x7684;&#x7EBF;&#x7D22;&#x5728;&#x4E8E;CookieSpec&#x63A5;&#x53E3;&#xFF0C;&#x6211;&#x4EEC;&#x6765;&#x770B;&#x4E00;&#x4E0B;&#x5B83;&#x7684;&#x6E90;&#x7801;&#xFF1A;</p>
<pre><code>public interface CookieSpec {
&#x2026;&#x2026;
    /**
      * Parse the {@code &quot;Set-Cookie&quot;} Header into an array of Cookies.
      *
      * &lt;p&gt;This method will not perform the validation of the resultant
      * {@link Cookie}s&lt;/p&gt;
      *
      * @see #validate
      *
      * @param header the {@code Set-Cookie} received from the server
      * @param origin details of the cookie origin
      * @return an array of {@code Cookie}s parsed from the header
      * @throws MalformedCookieException if an exception occurs during parsing
      */
    List&lt;Cookie&gt; parse(Header header, CookieOrigin origin) throws MalformedCookieException;
&#x2026;&#x2026;

}
</code></pre>
<p>&#x5728;&#x6E90;&#x7801;&#x4E2D;&#x6211;&#x4EEC;&#x53D1;&#x73B0;&#x4E86;&#x4E00;&#x4E2A;parse&#x65B9;&#x6CD5;&#xFF0C;&#x4ECE;&#x6CE8;&#x91CA;&#x4E2D;&#x53EF;&#x4EE5;&#x77E5;&#x9053;&#xFF0C;&#x6B63;&#x662F;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#xFF0C;&#x5C06;Set-Cookie&#x7684;header&#x4FE1;&#x606F;&#x89E3;&#x6790;&#x4E3A;Cookie&#x5BF9;&#x8C61;&#xFF0C;&#x81EA;&#x7136;&#x5730;&#x518D;&#x770B;&#x4E00;&#x4E0B;&#x5728;httplcient&#x4E2D;&#x7684;&#x9ED8;&#x8BA4;&#x5B9E;&#x73B0;DefaultCookieSpec&#xFF0C;&#x9650;&#x4E8E;&#x7BC7;&#x5E45;&#xFF0C;&#x6E90;&#x7801;&#x5C31;&#x4E0D;&#x8D34;&#x4E86;&#x3002;&#x5728;&#x9ED8;&#x8BA4;&#x7684;&#x5B9E;&#x73B0;&#x4E2D;&#xFF0C;DefaultCookieSpec&#x4E3B;&#x8981;&#x7684;&#x5DE5;&#x4F5C;&#x662F;&#x5224;&#x65AD;header&#x4E2D;Cookie&#x89C4;&#x8303;&#x7684;&#x7C7B;&#x578B;&#xFF0C;&#x7136;&#x540E;&#x518D;&#x8C03;&#x7528;&#x5177;&#x4F53;&#x7684;&#x67D0;&#x4E00;&#x4E2A;&#x5B9E;&#x73B0;&#x3002;&#x50CF;&#x4E0A;&#x8FF0;&#x8FD9;&#x79CD;Cookie&#xFF0C;&#x6700;&#x7EC8;&#x662F;&#x4EA4;&#x7531;NetscapeDraftSpec&#x7684;&#x5B9E;&#x4F8B;&#x6765;&#x505A;&#x89E3;&#x6790;&#xFF0C;&#x800C;&#x5728;NetscapeDraftSpec&#x7684;&#x6E90;&#x7801;&#x4E2D;&#xFF0C;&#x5B9A;&#x4E49;&#x4E86;&#x5BF9;&#x5E94;expires&#x65F6;&#x95F4;&#x683C;&#x5F0F;&#x4E3A;&#x201C;EEE, dd-MMM-yy HH:mm:ss z&#x201D;</p>
<pre><code>public class NetscapeDraftSpec extends CookieSpecBase {

    protected static final String EXPIRES_PATTERN = &quot;EEE, dd-MMM-yy HH:mm:ss z&quot;;

    /** Default constructor */
    public NetscapeDraftSpec(final String[] datepatterns) {
        super(new BasicPathHandler(),
                new NetscapeDomainHandler(),
                new BasicSecureHandler(),
                new BasicCommentHandler(),
                new BasicExpiresHandler(
                        datepatterns != null ? datepatterns.clone() : new String[]{EXPIRES_PATTERN}));
    }

    NetscapeDraftSpec(final CommonCookieAttributeHandler... handlers) {
        super(handlers);
    }

    public NetscapeDraftSpec() {
        this((String[]) null);
    }
&#x2026;&#x2026;
}
</code></pre>
<p>&#x5230;&#x8FD9;&#x91CC;&#x5DF2;&#x7ECF;&#x6BD4;&#x8F83;&#x6E05;&#x695A;&#x4E86;&#xFF0C;&#x6211;&#x4EEC;&#x53EA;&#x9700;&#x8981;&#x5C06;Cookie&#x4E2D;expires&#x7684;&#x65F6;&#x95F4;&#x8F6C;&#x6362;&#x4E3A;&#x6B63;&#x786E;&#x7684;&#x683C;&#x5F0F;&#xFF0C;&#x7136;&#x540E;&#x518D;&#x9001;&#x5165;&#x9ED8;&#x8BA4;&#x7684;&#x89E3;&#x6790;&#x5668;&#x5C31;&#x53EF;&#x4EE5;&#x4E86;&#x3002;</p>
<p>&#x89E3;&#x51B3;&#x65B9;&#x6CD5;&#xFF1A;</p>
<ol>
<li>&#x81EA;&#x5B9A;&#x4E49;&#x4E00;&#x4E2A;CookieSpec&#x7C7B;&#xFF0C;&#x7EE7;&#x627F;DefaultCookieSpec</li>
<li>&#x91CD;&#x5199;parser&#x65B9;&#x6CD5;</li>
<li>&#x5C06;Cookie&#x4E2D;&#x7684;expires&#x8F6C;&#x6362;&#x4E3A;&#x6B63;&#x786E;&#x7684;&#x65F6;&#x95F4;&#x683C;&#x5F0F;</li>
<li>&#x8C03;&#x7528;&#x9ED8;&#x8BA4;&#x7684;&#x89E3;&#x6790;&#x65B9;&#x6CD5;</li>
</ol>
<p>&#x5B9E;&#x73B0;&#x5982;&#x4E0B;&#xFF1A;</p>
<pre><code>public class TestHttpClient {
    
    String url = sth;

    class MyCookieSpec extends DefaultCookieSpec {
        @Override
        public List&lt;Cookie&gt; parse(Header header, CookieOrigin cookieOrigin) throws MalformedCookieException {
            String value = header.getValue();
            String prefix = &quot;Expires=&quot;;
            if (value.contains(prefix)) {
                String expires = value.substring(value.indexOf(prefix) + prefix.length());
                expires = expires.substring(0, expires.indexOf(&quot;;&quot;));
                String date = DateUtils.formatDate(new Date(Long.parseLong(expires) * 1000L),&quot;EEE, dd-MMM-yy HH:mm:ss z&quot;);
                value = value.replaceAll(prefix + &quot;\\d{10};&quot;, prefix + date + &quot;;&quot;);
            }
            header = new BasicHeader(header.getName(), value);
            return super.parse(header, cookieOrigin);
        }
    }

    @Test
    public void getCookie() {

        CloseableHttpClient httpClient = HttpClients.createDefault();

        Registry&lt;CookieSpecProvider&gt; cookieSpecProviderRegistry = RegistryBuilder.&lt;CookieSpecProvider&gt;create()
                .register(&quot;myCookieSpec&quot;, context -&gt; new MyCookieSpec()).build();//&#x6CE8;&#x518C;&#x81EA;&#x5B9A;&#x4E49;CookieSpec

        HttpClientContext context = HttpClientContext.create();
        context.setCookieSpecRegistry(cookieSpecProviderRegistry);

        HttpGet get = new HttpGet(url);
        get.setConfig(RequestConfig.custom().setCookieSpec(&quot;myCookieSpec&quot;).build());

        try {
            CloseableHttpResponse response = httpClient.execute(get, context);
            try{
                System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;&gt;headers:&quot;);
                Arrays.stream(response.getAllHeaders()).forEach(System.out::println);
                System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;&gt;cookies:&quot;);
                context.getCookieStore().getCookies().forEach(System.out::println);
            }
            finally {
                response.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
</code></pre>
<p>&#x518D;&#x6B21;&#x8FD0;&#x884C;&#xFF0C;&#x4FBF;&#x53EF;&#x987A;&#x5229;&#x5730;&#x6253;&#x5370;&#x51FA;&#x6B63;&#x786E;&#x7684;&#x7ED3;&#x679C;&#xFF0C;&#x5B8C;&#x7F8E;&#xFF01;</p>
<pre><code>&gt;&gt;&gt;&gt;&gt;&gt;headers:
Date: Tue, 12 Sep 2017 07:24:10 GMT
Content-Type: text/html
Connection: keep-alive
Set-Cookie: yd_cookie=9f521fc5-0248-4ab3ee650ca50b1c7abb1cd2526b830e620f; Expires=1505208250; Path=/; HttpOnly
Cache-Control: no-cache, no-store
Server: WAF/2.4-12.1
&gt;&gt;&gt;&gt;&gt;&gt;cookies:
[version: 0][name: yd_cookie][value: 9f521fc5-0248-4ab3ee650ca50b1c7abb1cd2526b830e620f][domain: www.sth.com][path: /][expiry: Tue Sep 12 17:24:10 CST 2017]
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Tomcat多实例单应用部署方案]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="tomcat">&#x4E00;&#x3001;Tomcat&#x90E8;&#x7F72;&#x7684;&#x573A;&#x666F;&#x5206;&#x6790;</h2>
<p>&#x901A;&#x5E38;&#xFF0C;&#x6211;&#x4EEC;&#x5BF9;tomcat&#x90E8;&#x7F72;&#x9700;&#x6C42;&#x53EF;&#x4EE5;&#x5206;&#x4E3A;&#x51E0;&#x79CD;&#xFF1A;&#x5355;&#x5B9E;&#x4F8B;&#x5355;&#x5E94;&#x7528;&#xFF0C;&#x5355;&#x5B9E;&#x4F8B;&#x591A;&#x5E94;&#x7528;&#xFF0C;&#x591A;&#x5B9E;&#x4F8B;&#x5355;&#x5E94;&#x7528;&#xFF0C;&#x591A;</p>]]></description><link>http://www.fullstackyang.com/tomcatduo-shi-li-dan-ying-yong-bu-shu-fang-an/</link><guid isPermaLink="false">624567890d2dd30001909fff</guid><category><![CDATA[arch]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Mon, 17 Oct 2016 15:36:00 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2018/06/tomcat-logo-e1476698462616.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="tomcat">&#x4E00;&#x3001;Tomcat&#x90E8;&#x7F72;&#x7684;&#x573A;&#x666F;&#x5206;&#x6790;</h2>
<img src="http://www.fullstackyang.com/content/images/2018/06/tomcat-logo-e1476698462616.png" alt="Tomcat&#x591A;&#x5B9E;&#x4F8B;&#x5355;&#x5E94;&#x7528;&#x90E8;&#x7F72;&#x65B9;&#x6848;"><p>&#x901A;&#x5E38;&#xFF0C;&#x6211;&#x4EEC;&#x5BF9;tomcat&#x90E8;&#x7F72;&#x9700;&#x6C42;&#x53EF;&#x4EE5;&#x5206;&#x4E3A;&#x51E0;&#x79CD;&#xFF1A;&#x5355;&#x5B9E;&#x4F8B;&#x5355;&#x5E94;&#x7528;&#xFF0C;&#x5355;&#x5B9E;&#x4F8B;&#x591A;&#x5E94;&#x7528;&#xFF0C;&#x591A;&#x5B9E;&#x4F8B;&#x5355;&#x5E94;&#x7528;&#xFF0C;&#x591A;&#x5B9E;&#x4F8B;&#x591A;&#x5E94;&#x7528;&#x3002;</p>
<p>&#x5BF9;&#x4E8E;&#x7B2C;&#x4E00;&#x79CD;&#x573A;&#x666F;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x8981;&#x6C42;&#x5468;&#x671F;&#x6027;&#x5730;&#x7EF4;&#x62A4;tomcat&#x7248;&#x672C;&#xFF0C;&#x4E00;&#x822C;&#x7684;&#x505A;&#x6CD5;&#x662F;&#x628A;&#x6253;&#x597D;&#x7684;war&#x5305;&#x4E22;&#x5230;webapps&#x76EE;&#x5F55;&#x4E0B;&#xFF0C;&#x7136;&#x540E;&#x6267;&#x884C;startup.sh&#x811A;&#x672C;&#xFF0C;&#x5E76;&#x4E14;&#x53EF;&#x4EE5;&#x5728;&#x6D4F;&#x89C8;&#x5668;&#x91CC;&#x8BBF;&#x95EE;&#x5C31;&#x884C;&#x4E86;&#x3002;</p>
<p>&#x5BF9;&#x4E8E;&#x7B2C;&#x4E8C;&#x79CD;&#x573A;&#x666F;&#xFF0C;&#x662F;&#x628A;&#x591A;&#x4E2A;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x7684;war&#x5305;&#x653E;&#x5728;&#x540C;&#x4E00;&#x4E2A;tomcat&#x7684;webapps&#x76EE;&#x5F55;&#xFF0C;&#x8FD9;&#x6837;&#x4E00;&#x6765;&#xFF0C;&#x5173;&#x95ED;&#x548C;&#x542F;&#x52A8;tomcat&#x4F1A;&#x5F71;&#x54CD;&#x6240;&#x6709;&#x9879;&#x76EE;&#x3002;</p>
<p>&#x5BF9;&#x4E8E;&#x7B2C;&#x4E09;&#x79CD;&#x573A;&#x666F;&#xFF0C;&#x5404;&#x4E2A;tomcat&#x90FD;&#x8FD0;&#x884C;&#x540C;&#x4E00;&#x4E2A;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#xFF0C;&#x5BF9;&#x5E94;&#x5730;&#x9700;&#x8981;&#x4FEE;&#x6539;&#x4E0D;&#x540C;&#x7684;&#x76D1;&#x542C;&#x7AEF;&#x53E3;&#xFF0C;&#x8FD9;&#x79CD;&#x65B9;&#x5F0F;&#x901A;&#x5E38;&#x4F1A;&#x548C;apache httpd&#x6216;&#x8005;nginx&#x6574;&#x5408;&#x4F7F;&#x7528;&#xFF0C;&#x505A;&#x4E00;&#x4E9B;&#x8D1F;&#x8F7D;&#x5747;&#x8861;&#x7684;&#x5904;&#x7406;&#x3002;</p>
<p>&#x5BF9;&#x4E8E;&#x7B2C;&#x56DB;&#x79CD;&#x573A;&#x666F;&#x76F8;&#x5F53;&#x4E8E;&#x7B2C;&#x4E00;&#x79CD;&#x573A;&#x666F;&#x7684;&#x590D;&#x6570;&#x5F62;&#x5F0F;&#xFF0C;&#x9664;&#x4E86;&#x4FEE;&#x6539;&#x4E0D;&#x540C;&#x7684;&#x76D1;&#x542C;&#x7AEF;&#x53E3;&#xFF0C;&#x6CA1;&#x6709;&#x672C;&#x8D28;&#x533A;&#x522B;&#x3002;</p>
<p>&#x4E00;&#x822C;&#x6765;&#x8BF4;&#xFF0C;&#x591A;&#x5B9E;&#x4F8B;&#x90E8;&#x7F72;tomcat&#xFF0C;&#x53EF;&#x4EE5;&#x5145;&#x5206;&#x5229;&#x7528;&#x7CFB;&#x7EDF;&#x8D44;&#x6E90;&#xFF0C;&#x4E0D;&#x8FC7;&#x8FD9;&#x79CD;&#x65B9;&#x5F0F;&#xFF0C;&#x4E5F;&#x6709;&#x51E0;&#x4E2A;&#x65B9;&#x9762;&#x9700;&#x8981;&#x8003;&#x8651;&#xFF1A;</p>
<ul>
<li>&#x591A;&#x5B9E;&#x4F8B;tomcat&#x7684;&#x66F4;&#x65B0;&#x7EF4;&#x62A4;&#xFF0C;&#x4F8B;&#x5982;&#x5BF9;tomcat&#x8FDB;&#x884C;&#x5347;&#x7EA7;&#x7B49;&#x64CD;&#x4F5C;&#xFF0C;&#x6211;&#x4EEC;&#x9700;&#x8981;&#x8003;&#x8651;&#x5982;&#x4F55;&#x80FD;&#x201C;&#x4F18;&#x96C5;&#x201D;&#x5730;&#x5BF9;&#x6240;&#x6709;&#x5B9E;&#x4F8B;&#x8FDB;&#x884C;&#x5347;&#x7EA7;</li>
<li>&#x5C3D;&#x91CF;&#x4E0D;&#x8981;&#x5F71;&#x54CD;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#xFF0C;&#x5728;&#x66F4;&#x65B0;tomcat&#x65F6;&#xFF0C;&#x4E00;&#x4E0D;&#x5C0F;&#x5FC3;&#x5C31;&#x628A;conf&#x76EE;&#x5F55;&#x7B49;&#x5168;&#x90E8;&#x8986;&#x76D6;&#xFF0C;&#x6240;&#x4EE5;&#x5C3D;&#x91CF;&#x8981;&#x628A;&#x914D;&#x7F6E;&#x6587;&#x4EF6;&#x548C;&#x5B89;&#x88C5;&#x76EE;&#x5F55;&#x9694;&#x79BB;</li>
<li>&#x5BF9;&#x4E8E;&#x5355;&#x5E94;&#x7528;&#x6765;&#x8BF4;&#xFF0C;&#x5982;&#x679C;&#x5C06;war&#x5305;&#x5206;&#x522B;&#x7F6E;&#x4E8E;&#x5404;&#x4E2A;tomcat&#x7684;webapps&#x76EE;&#x5F55;&#xFF0C;&#x90A3;&#x4E48;&#x5728;&#x53D1;&#x5E03;&#x65B0;&#x7248;&#x672C;&#x7684;war&#x65F6;&#xFF0C;&#x53EF;&#x80FD;&#x4F1A;&#x51FA;&#x73B0;&#x67D0;&#x4E2A;&#x5B9E;&#x4F8B;&#x66F4;&#x65B0;&#x5931;&#x8D25;&#xFF0C;&#x5BFC;&#x81F4;&#x7528;&#x6237;&#x5728;&#x8BBF;&#x95EE;&#x65F6;&#x53EF;&#x80FD;&#x4F1A;&#x8BBF;&#x95EE;&#x5230;&#x4E0D;&#x540C;&#x7248;&#x672C;&#x7684;web app&#xFF0C;&#x56E0;&#x6B64;&#xFF0C;&#x6BD4;&#x8F83;&#x597D;&#x7684;&#x65B9;&#x5F0F;&#x5C31;&#x662F;&#x6240;&#x6709;tomcat&#x5B9E;&#x4F8B;&#x90FD;&#x7EDF;&#x4E00;&#x6307;&#x5411;&#x540C;&#x4E00;&#x4E2A;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;</li>
</ul>
<p>&#x672C;&#x6587;&#x91CD;&#x70B9;&#x9610;&#x8FF0;&#x591A;&#x5B9E;&#x4F8B;&#x5E94;&#x7528;&#x7684;&#x90E8;&#x7F72;&#x65B9;&#x6848;&#xFF0C;&#x4F46;&#x662F;&#x4E3A;&#x4E86;&#x89E3;&#x51B3;&#x4E0A;&#x8FF0;&#x51E0;&#x4E2A;&#x95EE;&#x9898;&#xFF0C;&#x6211;&#x4EEC;&#x9700;&#x8981;&#x5148;&#x6765;&#x4E86;&#x89E3;&#x4E00;&#x4E0B;tomcat&#x7684;&#x4E00;&#x4E9B;&#x57FA;&#x672C;&#x60C5;&#x51B5;</p>
<h2 id>&#x4E8C;&#x3001;&#x57FA;&#x672C;&#x8981;&#x70B9;</h2>
<h3 id="21">2.1 &#x5206;&#x79BB;&#x76EE;&#x5F55;</h3>
<p>&#x9996;&#x5148;&#x6765;&#x770B;&#x4E00;&#x4E0B;tomcat&#x7684;&#x76EE;&#x5F55;&#x7ED3;&#x6784;&#xFF0C;&#x4E00;&#x4E2A;&#x521A;&#x89E3;&#x538B;&#x51FA;&#x6765;&#x7684;tomcat&#x6253;&#x5305;&#x6587;&#x4EF6;&#x5E94;&#x8BE5;&#x6709;&#x4EE5;&#x4E0B;&#x51E0;&#x4E2A;&#x76EE;&#x5F55;</p>
<table>
<thead>
<tr>
<th>&#x76EE;&#x5F55;</th>
<th>&#x7528;&#x9014;</th>
</tr>
</thead>
<tbody>
<tr>
<td>bin</td>
<td>&#x4E3B;&#x8981;&#x5B58;&#x653E;&#x811A;&#x672C;&#x6587;&#x4EF6;&#xFF0C;&#x4F8B;&#x5982;&#x6BD4;&#x8F83;&#x5E38;&#x7528;&#x7684;windows&#x548C;linux&#x7CFB;&#x7EDF;&#x4E2D;&#x542F;&#x52A8;&#x548C;&#x5173;&#x95ED;&#x811A;&#x672C;</td>
</tr>
<tr>
<td>conf</td>
<td>&#x4E3B;&#x8981;&#x5B58;&#x653E;&#x914D;&#x7F6E;&#x6587;&#x4EF6;&#xFF0C;&#x5176;&#x4E2D;&#x6700;&#x91CD;&#x8981;&#x7684;&#x4E24;&#x4E2A;&#x914D;&#x7F6E;&#x6587;&#x4EF6;&#x662F;server.xml&#x548C;web.xml</td>
</tr>
<tr>
<td>lib</td>
<td>&#x4E3B;&#x8981;&#x5B58;&#x653E;tomcat&#x8FD0;&#x884C;&#x6240;&#x4F9D;&#x8D56;&#x7684;&#x5305;</td>
</tr>
<tr>
<td>logs</td>
<td>&#x4E3B;&#x8981;&#x5B58;&#x653E;&#x8FD0;&#x884C;&#x65F6;&#x4EA7;&#x751F;&#x7684;&#x65E5;&#x5FD7;&#x6587;&#x4EF6;&#xFF0C;&#x4F8B;&#x5982;catalina.{date}.log&#x7B49;</td>
</tr>
<tr>
<td>temp</td>
<td>&#x5B58;&#x653E;tomcat&#x8FD0;&#x884C;&#x65F6;&#x4EA7;&#x751F;&#x7684;&#x4E34;&#x65F6;&#x6587;&#x4EF6;&#xFF0C;&#x4F8B;&#x5982;&#x5F00;&#x542F;&#x4E86;hibernate&#x7F13;&#x5B58;&#x7684;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#xFF0C;&#x4F1A;&#x5728;&#x8BE5;&#x76EE;&#x5F55;&#x4E0B;&#x751F;&#x6210;&#x4E00;&#x4E9B;&#x6587;&#x4EF6;</td>
</tr>
<tr>
<td>webapps</td>
<td>&#x90E8;&#x7F72;web&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x7684;&#x9ED8;&#x8BA4;&#x76EE;&#x5F55;</td>
</tr>
<tr>
<td>work</td>
<td>&#x4E3B;&#x8981;&#x5B58;&#x653E;&#x7531;JSP&#x6587;&#x4EF6;&#x751F;&#x6210;&#x7684;servlet&#xFF08;java&#x6587;&#x4EF6;&#x4EE5;&#x53CA;&#x6700;&#x7EC8;&#x7F16;&#x8BD1;&#x751F;&#x6210;&#x7684;class&#x6587;&#x4EF6;&#xFF09;</td>
</tr>
<tr>
<td>&#x518D;&#x4ECB;&#x7ECD;&#x4E24;&#x4E2A;tomcat&#x4E2D;&#x6BD4;&#x8F83;&#x91CD;&#x8981;&#x7684;&#x6982;&#x5FF5;&#xFF08;&#x901A;&#x5E38;&#x4E5F;&#x662F;&#x4E24;&#x4E2A;&#x7CFB;&#x7EDF;&#x53D8;&#x91CF;&#xFF09;&#x2014;&#x2014;CATALINA_HOME&#x548C;CATALINA_BASE&#xFF1A;</td>
<td></td>
</tr>
</tbody>
</table>
<ul>
<li>CATALINA_HOME&#xFF1A;&#x5373;&#x6307;&#x5411;Tomcat&#x5B89;&#x88C5;&#x8DEF;&#x5F84;&#x7684;&#x7CFB;&#x7EDF;&#x53D8;&#x91CF;</li>
<li>CATALINA_BASE&#xFF1A;&#x5373;&#x6307;&#x5411;&#x6D3B;&#x8DC3;&#x914D;&#x7F6E;&#x8DEF;&#x5F84;&#x7684;&#x7CFB;&#x7EDF;&#x53D8;&#x91CF;<br>
&#x901A;&#x8FC7;&#x8BBE;&#x7F6E;&#x8FD9;&#x4E24;&#x4E2A;&#x53D8;&#x91CF;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x5C06;tomcat&#x7684;&#x5B89;&#x88C5;&#x76EE;&#x5F55;&#x548C;&#x5DE5;&#x4F5C;&#x76EE;&#x5F55;&#x5206;&#x79BB;&#xFF0C;&#x4ECE;&#x800C;&#x5B9E;&#x73B0;tomcat&#x591A;&#x5B9E;&#x4F8B;&#x7684;&#x90E8;&#x7F72;&#x3002;</li>
</ul>
<p>Tomcat&#x5B98;&#x65B9;&#x6587;&#x6863;&#x6307;&#x51FA;&#xFF0C;CATALINA_HOME&#x8DEF;&#x5F84;&#x7684;&#x8DEF;&#x5F84;&#x4E0B;&#x53EA;&#x9700;&#x8981;&#x5305;&#x542B;bin&#x548C;lib&#x76EE;&#x5F55;&#xFF0C;&#x8FD9;&#x4E5F;&#x5C31;&#x662F;&#x652F;&#x6301;tomcat&#x8F6F;&#x4EF6;&#x8FD0;&#x884C;&#x7684;&#x76EE;&#x5F55;&#xFF0C;&#x800C;CATALINA_BASE&#x8BBE;&#x7F6E;&#x7684;&#x8DEF;&#x5F84;&#x53EF;&#x4EE5;&#x5305;&#x62EC;&#x4E0A;&#x8FF0;&#x6240;&#x6709;&#x76EE;&#x5F55;&#xFF0C;&#x4E0D;&#x8FC7;&#x5176;&#x4E2D;bin&#x548C;lib&#x76EE;&#x5F55;&#x5E76;&#x4E0D;&#x662F;&#x5FC5;&#x9700;&#x7684;&#xFF0C;&#x7F3A;&#x7701;&#x65F6;&#x4F1A;&#x4F7F;&#x7528;CATALINA_HOME&#x4E2D;&#x7684;bin&#x548C;conf&#x3002;&#x5982;&#x6B64;&#xFF0C;&#x6211;&#x4EEC;&#x5C31;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;&#x4E00;&#x4E2A;tomcat&#x5B89;&#x88C5;&#x76EE;&#x5F55;&#x90E8;&#x7F72;&#x591A;&#x4E2A;tomcat&#x5B9E;&#x4F8B;&#xFF0C;&#x8FD9;&#x6837;&#x7684;&#x597D;&#x5904;&#x5728;&#x4E8E;&#x65B9;&#x4FBF;&#x5347;&#x7EA7;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x5728;&#x4E0D;&#x5F71;&#x54CD;tomcat&#x5B9E;&#x4F8B;&#x7684;&#x524D;&#x63D0;&#x4E0B;&#xFF0C;&#x66FF;&#x6362;&#x6389;CATALINA_HOME&#x6307;&#x5B9A;&#x7684;tomcat&#x5B89;&#x88C5;&#x76EE;&#x5F55;&#x3002;</p>
<center>
<p><img src="http://www.fullstackyang.com/content/images/2018/06/tomcat-dirs.png" alt="Tomcat&#x591A;&#x5B9E;&#x4F8B;&#x5355;&#x5E94;&#x7528;&#x90E8;&#x7F72;&#x65B9;&#x6848;" loading="lazy"></p>
</center>
<h3 id="22serverxml">2.2 &#x4FEE;&#x6539;server.xml</h3>
<p>&#x8FD9;&#x91CC;&#x4E0D;&#x8BE6;&#x7EC6;&#x5206;&#x6790;server.xml&#x4E2D;&#x6BCF;&#x4E00;&#x4E2A;&#x914D;&#x7F6E;&#x9879;&#xFF0C;&#x7F51;&#x4E0A;&#x4E5F;&#x6709;&#x5F88;&#x591A;&#x8FD9;&#x65B9;&#x9762;&#x7684;&#x6587;&#x6863;&#x3002;&#x4E0B;&#x9762;&#x4E3B;&#x8981;&#x8BF4;&#x660E;&#x76D1;&#x542C;&#x7AEF;&#x53E3;&#x548C;Host&#x7684;&#x914D;&#x7F6E;&#x5185;&#x5BB9;&#x3002;</p>
<p>&#x5728;server.xml&#x4E2D;&#x914D;&#x7F6E;&#x4E86;&#x56DB;&#x4E2A;&#x76D1;&#x542C;&#x7AEF;&#x53E3;&#xFF0C;&#x5206;&#x522B;&#x662F;&#xFF1A;</p>
<ul>
<li>Server Port&#xFF1A;&#x8BE5;&#x7AEF;&#x53E3;&#x7528;&#x4E8E;&#x76D1;&#x542C;&#x5173;&#x95ED;tomcat&#x7684;shutdown&#x547D;&#x4EE4;&#xFF0C;&#x9ED8;&#x8BA4;&#x4E3A;8005</li>
<li>Connector Port&#xFF1A;&#x8BE5;&#x7AEF;&#x53E3;&#x7528;&#x4E8E;&#x76D1;&#x542C;HTTP&#x7684;&#x8BF7;&#x6C42;&#xFF0C;&#x9ED8;&#x8BA4;&#x4E3A;8080</li>
<li>AJP Port&#xFF1A;&#x8BE5;&#x7AEF;&#x53E3;&#x7528;&#x4E8E;&#x76D1;&#x542C;AJP&#xFF08; Apache JServ Protocol &#xFF09;&#x534F;&#x8BAE;&#x4E0A;&#x7684;&#x8BF7;&#x6C42;&#xFF0C;&#x901A;&#x5E38;&#x7528;&#x4E8E;&#x6574;&#x5408;Apache Server&#x7B49;&#x5176;&#x4ED6;HTTP&#x670D;&#x52A1;&#x5668;&#xFF0C;&#x9ED8;&#x8BA4;&#x4E3A;8009</li>
<li>Redirect Port&#xFF1A;&#x91CD;&#x5B9A;&#x5411;&#x7AEF;&#x53E3;&#xFF0C;&#x51FA;&#x73B0;&#x5728;Connector&#x914D;&#x7F6E;&#x4E2D;&#xFF0C;&#x5982;&#x679C;&#x8BE5;Connector&#x4EC5;&#x652F;&#x6301;&#x975E;SSL&#x7684;&#x666E;&#x901A;http&#x8BF7;&#x6C42;&#xFF0C;&#x90A3;&#x4E48;&#x8BE5;&#x7AEF;&#x53E3;&#x4F1A;&#x628A;https&#x7684;&#x8BF7;&#x6C42;&#x8F6C;&#x53D1;&#x5230;&#x8FD9;&#x4E2A;Redirect Port&#x6307;&#x5B9A;&#x7684;&#x7AEF;&#x53E3;&#xFF0C;&#x9ED8;&#x8BA4;&#x4E3A;8443</li>
</ul>
<p>&#x53EF;&#x89C1;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x662F;&#x4F7F;&#x7528;AJP&#x534F;&#x8BAE;&#x8FDE;&#x63A5;tomcat&#xFF0C;&#x53EA;&#x9700;&#x8981;&#x4FDD;&#x8BC1;&#x591A;&#x5B9E;&#x4F8B;&#x4E2D;&#x7684;Server Port&#x548C;Connect Port&#x4E0D;&#x540C;&#x5373;&#x53EF;&#x3002;</p>
<p>&#x518D;&#x6765;&#x8BF4;Host&#x914D;&#x7F6E;&#xFF0C;Host&#x5C31;&#x662F;&#x6240;&#x8C13;&#x7684;&#x865A;&#x62DF;&#x4E3B;&#x673A;&#xFF0C;&#x5BF9;&#x5E94;&#x5305;&#x542B;&#x4E86;&#x4E00;&#x4E2A;&#x6216;&#x8005;&#x591A;&#x4E2A;web&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#xFF0C;&#x9ED8;&#x8BA4;&#x7684;Host&#x914D;&#x7F6E;&#x5982;&#x4E0B;</p>
<pre><code>&lt;Host name=&quot;localhost&quot;  appBase=&quot;webapps&quot; unpackWARs=&quot;true&quot; autoDeploy=&quot;true&quot;&gt;
</code></pre>
<p>&#x5176;&#x4E2D;&#xFF1A;</p>
<ul>
<li>name&#xFF1A; &#x865A;&#x62DF;&#x4E3B;&#x673A;&#x7684;&#x540D;&#x79F0;&#xFF0C;&#x4E00;&#x53F0;&#x4E3B;&#x673A;&#x8868;&#x793A;&#x4E86;&#x5B8C;&#x5168;&#x9650;&#x5B9A;&#x7684;&#x57DF;&#x540D;&#x6216;IP&#x5730;&#x5740;&#xFF0C;&#x9ED8;&#x8BA4;&#x4E3A;localhost&#xFF0C;&#x540C;&#x65F6;&#x4E5F;&#x662F;&#x552F;&#x4E00;&#x7684;host&#xFF0C;&#x8FDB;&#x5165;tomcat&#x7684;&#x6240;&#x6709;http&#x8BF7;&#x6C42;&#x90FD;&#x4F1A;&#x6620;&#x5C04;&#x5230;&#x8BE5;&#x4E3B;&#x673A;&#x4E0A;</li>
<li>appBase&#xFF1A;web&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x76EE;&#x5F55;&#x7684;&#x8DEF;&#x5F84;&#xFF0C;&#x53EF;&#x4EE5;&#x662F;CATALINA_HOME&#x7684;&#x76F8;&#x5BF9;&#x8DEF;&#x5F84;&#xFF0C;&#x4E5F;&#x53EF;&#x4EE5;&#x5199;&#x6210;&#x7EDD;&#x5BF9;&#x8DEF;&#x5F84;&#xFF0C;&#x9ED8;&#x8BA4;&#x60C5;&#x51B5;&#x4E0B;&#x4E3A;$CATALINA_HOME/webapps</li>
<li>unpackWARs&#xFF1A; &#x8868;&#x793A;&#x662F;&#x5426;&#x81EA;&#x52A8;&#x89E3;&#x538B;war&#x5305;</li>
<li>autoDeploy&#xFF1A;&#x6240;&#x8C13;&#x7684;&#x70ED;&#x90E8;&#x7F72;&#xFF0C;&#x5373;&#x5728;tomcat&#x6B63;&#x5728;&#x8FD0;&#x884C;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x5982;&#x679C;&#x6709;&#x65B0;&#x7684;war&#x52A0;&#x5165;&#xFF0C;&#x5219;&#x4F1A;&#x7ACB;&#x5373;&#x6267;&#x884C;&#x90E8;&#x7F72;&#x64CD;&#x4F5C;</li>
<li>&#x53E6;&#x5916;&#x518D;&#x4ECB;&#x7ECD;&#x4E00;&#x4E2A;Host&#x4E2D;&#x7684;&#x5C5E;&#x6027;&#x2014;deployOnStartup&#xFF1A;&#x8868;&#x793A;tomcat&#x542F;&#x52A8;&#x65F6;&#x662F;&#x5426;&#x81EA;&#x52A8;&#x90E8;&#x7F72;appBase&#x76EE;&#x5F55;&#x4E0B;&#x6240;&#x6709;&#x7684;Web&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#xFF0C;&#x9ED8;&#x8BA4;&#x4E3A;true&#x3002;&#x8FD9;&#x4E2A;&#x5C5E;&#x6027;&#x548C;autoDeploy&#x4F1A;&#x4EA7;&#x751F;&#x4E24;&#x6B21;&#x90E8;&#x7F72;&#x7684;&#x201C;&#x526F;&#x4F5C;&#x7528;&#x201D;&#xFF1A;&#x4E00;&#x6B21;&#x662F;tomcat&#x542F;&#x52A8;&#x65F6;&#x5C31;&#x5F00;&#x59CB;&#x90E8;&#x7F72;&#xFF0C;&#x7B2C;&#x4E8C;&#x6B21;&#x5C31;&#x662F;autoDeploy&#x5F15;&#x8D77;&#x7684;&#x70ED;&#x90E8;&#x7F72;&#x3002;&#x56E0;&#x6B64;&#x6700;&#x597D;&#x5C06;autoDeploy&#x7F6E;&#x4E3A;false</li>
</ul>
<p>&#x5728;&#x90E8;&#x7F72;&#x591A;&#x5B9E;&#x4F8B;&#x5355;&#x5E94;&#x7528;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x9ED8;&#x8BA4;&#x7684;$CATALINA/webapps&#x4F1A;&#x56E0;&#x4E3A;tomcat&#x5B89;&#x88C5;&#x76EE;&#x5F55;&#x5347;&#x7EA7;&#x4EA7;&#x751F;&#x4E0D;&#x5FC5;&#x8981;&#x7684;&#x9EBB;&#x70E6;&#xFF0C;&#x6211;&#x4EEC;&#x8003;&#x8651;&#x5C06;appBase&#x7684;&#x76EE;&#x5F55;&#x7EDF;&#x4E00;&#x5230;&#x53E6;&#x5916;&#x7684;&#x8DEF;&#x5F84;&#x4E0B;&#x3002;</p>
<p>&#x6700;&#x540E;&#x518D;&#x8BF4;&#x660E;&#x4E00;&#x4E0B;Context&#x7684;&#x914D;&#x7F6E;&#xFF0C;&#x5B83;&#x51FA;&#x73B0;&#x5728;Host&#x914D;&#x7F6E;&#x5185;&#xFF0C;&#x4E00;&#x4E2A;Context&#x7684;&#x914D;&#x7F6E;&#x5C31;&#x4EE3;&#x8868;&#x4E86;&#x4E00;&#x4E2A;web&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#xFF0C;&#x5982;&#x679C;&#x914D;&#x7F6E;&#x591A;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#xFF0C;&#x5C31;&#x9700;&#x8981;&#x5728;Host&#x4E0B;&#x914D;&#x7F6E;&#x591A;&#x4E2A;Context&#xFF0C;&#x4E00;&#x4E2A;&#x7B80;&#x5355;&#x7684;Context&#x914D;&#x7F6E;&#x5982;&#x4E0B;</p>
<pre><code>&lt;Context path=&quot;/some&quot; docBase=&quot;someapp.war&quot; &gt;
</code></pre>
<p>&#x5176;&#x4E2D;:</p>
<ul>
<li>path&#xFF1A;&#x8868;&#x793A;&#x8BBF;&#x95EE;&#x5165;&#x53E3;&#xFF0C;&#x4F8B;&#x5982;&#xFF0C;path=&#x201D;/abc&#x201D;&#xFF0C;&#x5219;&#x8BBF;&#x95EE;localhost:8080/abc&#x65F6;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x8BBF;&#x95EE;&#x8BE5;Context&#x5BF9;&#x5E94;&#x7684;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x3002;&#x5982;&#x679C;path=&#x201D;&#x201D;&#xFF0C;&#x5219;&#x76F4;&#x63A5;&#x7528;localhost:8080&#x5C31;&#x53EF;&#x4EE5;&#x8BBF;&#x95EE;</li>
<li>docBase&#xFF1A;&#x8868;&#x793A;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x7684;&#x89E3;&#x5305;&#x76EE;&#x5F55;&#x6216;&#x8005;war&#x6587;&#x4EF6;&#x8DEF;&#x5F84;&#xFF0C;&#x662F;Host&#x7684;appBase&#x914D;&#x7F6E;&#x76EE;&#x5F55;&#x7684;&#x76F8;&#x5BF9;&#x8DEF;&#x5F84;&#xFF0C;&#x4E5F;&#x53EF;&#x4EE5;&#x662F;&#x76F4;&#x63A5;&#x5199;&#x6210;&#x7EDD;&#x5BF9;&#x8DEF;&#x5F84;&#xFF0C;&#x4F46;&#x662F;&#x4E0D;&#x8981;&#x5C06;appBase&#x7684;&#x503C;&#xFF0C;&#x4F5C;&#x4E3A;docBase&#x914D;&#x7F6E;&#x8DEF;&#x5F84;&#x7684;&#x524D;&#x7F00;&#xFF0C;&#x4F8B;&#x5982;appBase=&#x201D;somedir&#x201D;&#xFF0C;docBase=&#x201D;somedir-someapp.war&#x201D;&#xFF0C;&#x8FD9;&#x6837;&#x7684;&#x914D;&#x7F6E;&#x4F1A;&#x5BFC;&#x81F4;&#x90E8;&#x7F72;&#x9519;&#x8BEF;<br>
&#x901A;&#x8FC7;&#x914D;&#x7F6E;Host&#x7684;appBase&#x548C;Context&#x7684;docBase&#x4E24;&#x4E2A;&#x5C5E;&#x6027;&#xFF0C;&#x53EF;&#x4EE5;&#x5C06;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x7684;&#x6587;&#x4EF6;&#x548C;tomcat&#x76F8;&#x5173;&#x7684;&#x76EE;&#x5F55;&#x8FDB;&#x884C;&#x5206;&#x79BB;&#xFF0C;&#x8FD9;&#x6837;webapps&#x76EE;&#x5F55;&#x4E5F;&#x5C31;&#x6CA1;&#x6709;&#x4F5C;&#x7528;&#x4E86;&#x3002;</li>
</ul>
<p>&#x6700;&#x7EC8;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x5F97;&#x5230;&#x591A;&#x5B9E;&#x4F8B;&#x5355;&#x5E94;&#x7528;&#x90E8;&#x7F72;&#x65B9;&#x6848;&#x7684;&#x6574;&#x4F53;&#x6846;&#x67B6;&#xFF1A;<br>
<img src="http://www.fullstackyang.com/content/images/2018/06/tomcat-instances.png" alt="Tomcat&#x591A;&#x5B9E;&#x4F8B;&#x5355;&#x5E94;&#x7528;&#x90E8;&#x7F72;&#x65B9;&#x6848;" loading="lazy"></p>
<h2 id>&#x4E09;&#x3001;&#x65B9;&#x6848;&#x5B9E;&#x65BD;</h2>
<p>&#x73B0;&#x5728;&#x5047;&#x8BBE;&#x6211;&#x4EEC;&#x6709;&#x4E00;&#x53F0;&#x5DF2;&#x7ECF;&#x914D;&#x7F6E;&#x597D;Java&#x73AF;&#x5883;&#x7684;&#x670D;&#x52A1;&#x5668;&#xFF1A;</p>
<pre><code># export JAVA_HOME=/application/jdk
# export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
# export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar

# java -version
java version &quot;1.8.0_101&quot;
Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)
</code></pre>
<p>&#x53E6;&#x5916;&#x5047;&#x8BBE;&#x4E00;&#x4E2A;&#x5B8C;&#x597D;&#x7684;&#x53EF;&#x4EE5;&#x8FD0;&#x884C;&#x7684;web&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x5DF2;&#x7ECF;&#x6253;&#x5305;&#x6210;some.war&#xFF0C;&#x653E;&#x5728;/data/www&#x76EE;&#x5F55;&#x4E0B;&#xFF0C;&#x5176;&#x4E2D;&#x5305;&#x542B;&#x4E00;&#x4E2A;&#x7B80;&#x5355;&#x7684;index.jsp</p>
<pre><code>&lt;html&gt;
&lt;body&gt;
&lt;h2&gt;Hello World!&lt;/h2&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h3 id="31tomcat">3.1 &#x4E0B;&#x8F7D;&#x5E76;&#x89E3;&#x538B;tomcat</h3>
<pre><code># cd /usr/local
# wget -q http://mirrors.cnnic.cn/apache/tomcat/tomcat-7/v7.0.72/bin/apache-tomcat-7.0.72.tar.gz
# tar zxf apache-tomcat-7.0.72.tar.gz
# ls apache-tomcat-7.0.72
bin &#xA0;conf &#xA0;lib &#xA0;LICENSE &#xA0;logs &#xA0;NOTICE &#xA0;RELEASE-NOTES &#xA0;RUNNING.txt &#xA0;temp &#xA0;webapps &#xA0;work
</code></pre>
<h3 id="32tomcat">3.2 &#x914D;&#x7F6E;tomcat&#x591A;&#x5B9E;&#x4F8B;</h3>
<p>&#x53EF;&#x4EE5;&#x7528;&#x4E00;&#x5C0F;&#x6BB5;&#x811A;&#x672C;&#x6765;&#x5B8C;&#x6210;&#x6279;&#x91CF;&#x521B;&#x5EFA;&#x7684;&#x5DE5;&#x4F5C;</p>
<pre><code>for ((i=1;i&lt;=3;i++))
do
    mkdir /application/tomcat7-$i/{work,temp,conf,logs} -p
    cp -a /application/tomcat7-$i/application/tomcat7-$i &amp;&amp; \
    sed -i 22s@8005@80${i}5@ /application/tomcat7-$i/conf/server.xml // &#x4FEE;&#x6539;tomcat&#x5173;&#x95ED;&#x7AEF;&#x53E3;
    sed -i 71s@8080@808${i}@ /application/tomcat7-$i/conf/server.xml // &#x4FEE;&#x6539;Http&#x76D1;&#x542C;&#x7AEF;&#x53E3;
    sed -i 93s@8009@80${i}9@ /application/tomcat7-$i/conf/server.xml // &#x4FEE;&#x6539;AJP&#x7AEF;&#x53E3;
    sed -i &apos;125s@appBase=&quot;webapps&quot;@appBase=&quot;/data/www&quot;@&apos; /application/tomcat7-$i/conf/server.xml //&#x7EDF;&#x4E00;web&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x7684;&#x8DEF;&#x5F84;
    sed -i &apos;126s@autoDeploy=&quot;true&quot;@autoDeploy=&quot;false&quot;@&apos; /application/tomcat7-$i/conf/server.xml //&#x5173;&#x95ED;&#x81EA;&#x52A8;&#x90E8;&#x7F72;
    sed -i &apos;126a &lt;Context path=&quot;&quot; docBase=&quot;/data/www/some.war&quot; /&gt;&apos; /application/tomcat7-$i/conf/server.xml //&#x914D;&#x7F6E;Context&#x4FE1;&#x606F;&#xFF0C;&#x6307;&#x5411;some.war&#x7684;&#x8DEF;&#x5F84;
done
</code></pre>
<h3 id="33">3.3 &#x521B;&#x5EFA;&#x542F;&#x505C;&#x811A;&#x672C;</h3>
<pre><code>#!/bin/sh

CUR_DIR=`dirname $BASH_SOURCE`
export JAVA_HOME=&quot;/application/jdk&quot;
export CATALINA_BASE=`readlink -f $CUR_DIR`
export CATALINA_HOME=&quot;/usr/local/apache-tomcat-7.0.72&quot;

case $1 in
 start)
 [ -f $CATALINA_HOME/bin/startup.sh ] &amp;&amp; $CATALINA_HOME/bin/startup.sh
 ;;
 stop)
 [ -f $CATALINA_HOME/bin/shutdown.sh ] &amp;&amp; $CATALINA_HOME/bin/shutdown.sh
 ;;
 restart)
 [ -f $CATALINA_HOME/bin/shutdown.sh ] &amp;&amp; $CATALINA_HOME/bin/shutdown.sh &amp;&amp; \
 [ -f $CATALINA_HOME/bin/startup.sh ] &amp;&amp; $CATALINA_HOME/bin/startup.sh
 ;;
 *)
 echo &quot;usage : $0 { start | stop | restart }&quot;
 return 1;
 ;;
esac

return 0
</code></pre>
<p>&#x628A;&#x8BE5;&#x811A;&#x672C;&#x653E;&#x5728;tomcat7-1&#xFF0C;tomcat7-2&#x548C;tomcat7-3&#x76EE;&#x5F55;&#x4E0B;</p>
<p>&#x73B0;&#x5728;&#x6211;&#x4EEC;&#x7684;&#x76EE;&#x5F55;&#x7ED3;&#x6784;&#x5982;&#x4E0B;</p>
<pre><code># ls tomcat7-1 tomcat7-2 tomcat7-3 
tomcat7-1:
conf  logs  temp  tomcat.sh  work

tomcat7-2:
conf  logs  temp  tomcat.sh  work

tomcat7-3:
conf  logs  temp  tomcat.sh  work
</code></pre>
<h3 id="34tomcats">3.4 &#x542F;&#x52A8;tomcats</h3>
<pre><code># cd /application
# . tomcat7-1/tomcat.sh start 
# . tomcat7-2/tomcat.sh start
# . tomcat7-3/tomcat.sh start

# netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name   
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      25757/sshd                
tcp        0      0 :::8029                     :::*                        LISTEN      21225/java          
tcp        0      0 ::ffff:127.0.0.1:8035       :::*                        LISTEN      21186/java          
tcp        0      0 :::8039                     :::*                        LISTEN      21186/java          
tcp        0      0 ::ffff:127.0.0.1:8015       :::*                        LISTEN      21002/java          
tcp        0      0 :::8081                     :::*                        LISTEN      21002/java          
tcp        0      0 :::8082                     :::*                        LISTEN      21225/java          
tcp        0      0 :::8083                     :::*                        LISTEN      21186/java          
tcp        0      0 :::8019                     :::*                        LISTEN      21002/java          
tcp        0      0 :::22                       :::*                        LISTEN      25757/sshd          
tcp        0      0 ::ffff:127.0.0.1:8025       :::*                        LISTEN      21225/java
</code></pre>
<p>&#x53EF;&#x4EE5;&#x770B;&#x5230;8081&#xFF0C;8082&#xFF0C;8083&#x7B49;&#x5176;&#x4ED6;&#x7AEF;&#x53E3;&#x90FD;&#x5DF2;&#x7ECF;&#x542F;&#x52A8;&#xFF0C;&#x73B0;&#x5728;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;curl&#x547D;&#x4EE4;&#x8FDB;&#x884C;&#x8BBF;&#x95EE;</p>
<pre><code># curl localhost:8081
&lt;html&gt;
&lt;body&gt;
&lt;h2&gt;Hello World!&lt;/h2&gt;
&lt;/body&gt;
&lt;/html&gt;

# curl localhost:8082
&lt;html&gt;
&lt;body&gt;
&lt;h2&gt;Hello World!&lt;/h2&gt;
&lt;/body&gt;
&lt;/html&gt;

# curl localhost:8083
&lt;html&gt;
&lt;body&gt;
&lt;h2&gt;Hello World!&lt;/h2&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>&#x5B8C;&#x6210;&#xFF01;</p>
<h2 id>&#x56DB;&#x3001;&#x53C2;&#x8003;&#x6587;&#x732E;</h2>
<ul>
<li>(&#x7F8E;)&#x5E03;&#x91CC;&#x6CF0;&#x6069;, (&#x7F8E;)&#x8FBE;&#x5C14;&#x6587;, &#x5434;&#x8C6A;. Tomcat&#x6743;&#x5A01;&#x6307;&#x5357;[M]. &#x4E2D;&#x56FD;&#x7535;&#x529B;&#x51FA;&#x7248;&#x793E;, 2009.</li>
<li>tomcat&#x5B98;&#x65B9;&#x6587;&#x6863;&#xFF1A;<a href="https://tomcat.apache.org/tomcat-7.0-doc/RUNNING.txt">https://tomcat.apache.org/tomcat-7.0-doc/RUNNING.txt</a></li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[IT从业者的绘图指南(Processon版)]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id>&#x4E00;&#x3001;&#x5F15;&#x8A00;</h2>
<p>&#x4F5C;&#x4E3A;&#x4E00;&#x540D;IT&#x4ECE;&#x4E1A;&#x8005;&#xFF0C;&#x4E0D;&#x4EC5;&#x8981;&#x6709;&#x624E;&#x5B9E;&#x7684;&#x77E5;&#x8BC6;&#x50A8;&#x5907;&#xFF0C;&#x51FA;&#x8272;&#x7684;&#x4E1A;&#x52A1;&#x80FD;&#x529B;&#xFF0C;&#x8FD8;&#x9700;&#x8981;&#x5177;&#x5907;&#x4E00;&#x5B9A;&#x7684;&#x8F6F;&#x5B9E;&#x529B;&#x3002;&#x8F6F;&#x5B9E;&#x529B;&#x4F53;&#x73B0;</p>]]></description><link>http://www.fullstackyang.com/itcong-ye-zhe-de-hui-tu-zhi-nan-processonban/</link><guid isPermaLink="false">624567890d2dd30001909ffe</guid><category><![CDATA[others]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Thu, 18 Aug 2016 14:34:00 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2018/06/27357472.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id>&#x4E00;&#x3001;&#x5F15;&#x8A00;</h2>
<img src="http://www.fullstackyang.com/content/images/2018/06/27357472.jpg" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)"><p>&#x4F5C;&#x4E3A;&#x4E00;&#x540D;IT&#x4ECE;&#x4E1A;&#x8005;&#xFF0C;&#x4E0D;&#x4EC5;&#x8981;&#x6709;&#x624E;&#x5B9E;&#x7684;&#x77E5;&#x8BC6;&#x50A8;&#x5907;&#xFF0C;&#x51FA;&#x8272;&#x7684;&#x4E1A;&#x52A1;&#x80FD;&#x529B;&#xFF0C;&#x8FD8;&#x9700;&#x8981;&#x5177;&#x5907;&#x4E00;&#x5B9A;&#x7684;&#x8F6F;&#x5B9E;&#x529B;&#x3002;&#x8F6F;&#x5B9E;&#x529B;&#x4F53;&#x73B0;&#x5728;&#x5177;&#x4F53;&#x4E8B;&#x52A1;&#x7684;&#x5904;&#x7406;&#x80FD;&#x529B;&#xFF0C;&#x5305;&#x62EC;&#x6C9F;&#x901A;&#xFF0C;&#x534F;&#x4F5C;&#xFF0C;&#x56E2;&#x961F;&#x9886;&#x5BFC;&#xFF0C;&#x95EE;&#x9898;&#x7684;&#x89E3;&#x51B3;&#x65B9;&#x6848;&#x7B49;&#xFF0C;&#x8FD9;&#x4E9B;&#x80FD;&#x529B;&#x5728;&#x5173;&#x952E;&#x65F6;&#x523B;&#x6BD4;&#x786C;&#x6027;&#x7684;&#x6280;&#x672F;&#x6C34;&#x5E73;&#x66F4;&#x80FD;&#x4F53;&#x73B0;&#x4E00;&#x540D;&#x5DE5;&#x7A0B;&#x5E08;&#x7684;&#x4EF7;&#x503C;&#xFF0C;&#x5B83;&#x51B3;&#x5B9A;&#x4E86;IT&#x804C;&#x4E1A;&#x751F;&#x6DAF;&#x7684;&#x9AD8;&#x5EA6;&#x548C;&#x89C6;&#x91CE;&#x3002;</p>
<p>&#x800C;&#x672C;&#x6587;&#x6240;&#x5206;&#x4EAB;&#x7684;&#x7ED8;&#x56FE;&#x80FD;&#x529B;&#xFF0C;&#x4E0E;&#x5176;&#x8BF4;&#x662F;&#x8F6F;&#x5B9E;&#x529B;&#xFF0C;&#x4E0D;&#x59A8;&#x8BF4;&#x662F;&#x57FA;&#x672C;&#x529F;&#x3002;&#x65E0;&#x8BBA;&#x4ECE;&#x4E8B;&#x7684;&#x662F;&#x5F00;&#x53D1;&#x3001;&#x8FD0;&#x7EF4;&#x3001;&#x901A;&#x4FE1;&#xFF0C;&#x751A;&#x81F3;&#x4EA7;&#x54C1;&#x7ECF;&#x7406;&#xFF0C;&#x4EA4;&#x4E92;&#x8BBE;&#x8BA1;&#x3001;&#x8FD0;&#x8425;&#x8FD9;&#x4E9B;&#x6709;&#x4EA4;&#x96C6;&#x7684;&#x5C97;&#x4F4D;&#xFF0C;&#x90FD;&#x4F1A;&#x5728;&#x5DE5;&#x4F5C;&#x4E2D;&#x7528;&#x5230;&#x3002;&#x56E0;&#x4E3A;&#x5728;&#x8BA1;&#x7B97;&#x673A;&#x7684;&#x4E16;&#x754C;&#x91CC;&#xFF0C;&#x5927;&#x591A;&#x6570;&#x573A;&#x666F;&#x90FD;&#x662F;&#x62BD;&#x8C61;&#x7684;&#xFF0C;&#x5F53;&#x6211;&#x4EEC;&#x5728;&#x63CF;&#x8FF0;&#x4ED6;&#x4EEC;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x4E00;&#x5B9A;&#x662F;&#x901A;&#x8FC7;&#x5176;&#x5B9E;&#x73B0;&#x539F;&#x7406;&#x548C;&#x673A;&#x5236;&#xFF0C;&#x62BD;&#x8C61;&#x51FA;&#x4E00;&#x4E2A;&#x884C;&#x4E3A;&#x903B;&#x8F91;&#xFF0C;&#x6700;&#x540E;&#x518D;&#x5177;&#x8C61;&#x5230;&#x4E00;&#x5F20;&#x56FE;&#x3002;&#x60F3;&#x8C61;&#x4E00;&#x4E0B;&#xFF0C;&#x5F53;&#x6211;&#x4EEC;&#x5728;&#x6D4F;&#x89C8;&#x5668;&#x4E2D;&#x8F93;&#x5165;&#x4E86;&#x4E00;&#x4E2A;&#x5730;&#x5740;&#xFF0C;&#x5728;&#x6572;&#x51FB;&#x56DE;&#x8F66;&#x4E4B;&#x540E;&#xFF0C;&#x6240;&#x53D1;&#x751F;&#x7684;&#x4E00;&#x5207;&#x662F;&#x591A;&#x4E48;&#x5730;&#x590D;&#x6742;&#xFF0C;&#x5982;&#x679C;&#x80FD;&#x62CD;&#x6210;&#x7535;&#x5F71;&#xFF0C;&#x90A3;&#x4E48;&#x53EF;&#x4EE5;&#x53D6;&#x540D;&#x53EB;&#x300A;&#x4E00;&#x4E2A;&#x6570;&#x636E;&#x5305;&#x7684;&#x5947;&#x5E7B;&#x6F02;&#x6D41;&#x300B;&#x3002;&#x5982;&#x679C;&#x4F60;&#x80FD;&#x591F;&#x4EE5;&#x5177;&#x8C61;&#x7684;&#x753B;&#x9762;&#x6765;&#x8868;&#x8FF0;&#x4E00;&#x4E2A;&#x8BA1;&#x7B97;&#x673A;&#x4E16;&#x754C;&#x4E2D;&#x53D1;&#x751F;&#x7684;&#x4E00;&#x4E2A;&#x573A;&#x666F;&#xFF0C;&#x90A3;&#x5F88;&#x597D;&#xFF0C;&#x8BF4;&#x660E;&#x4F60;&#x7684;&#x601D;&#x8DEF;&#x6E05;&#x6670;&#xFF0C;&#x5BF9;&#x539F;&#x7406;&#x7684;&#x7406;&#x89E3;&#x975E;&#x5E38;&#x900F;&#x5F7B;&#xFF0C;&#x7136;&#x540E;&#x4F60;&#x8981;&#x505A;&#x7684;&#x5DE5;&#x4F5C;&#x5C31;&#x50CF;&#x5BFC;&#x6F14;&#x521B;&#x4F5C;&#x5206;&#x955C;&#x4E00;&#x6837;&#xFF0C;&#x5C06;&#x5B83;&#x4EEC;&#x4F53;&#x73B0;&#x5728;&#x753B;&#x7EB8;&#x4E0A;&#x3002;</p>
<p>&#x8FD9;&#x662F;&#x4E00;&#x79CD;&#x6240;&#x8C13;&#x62BD;&#x8C61;&#x601D;&#x7EF4;&#x7684;&#x80FD;&#x529B;&#xFF0C;&#x6700;&#x597D;&#x7684;&#x953B;&#x70BC;&#x65B9;&#x5F0F;&#x4E4B;&#x4E00;&#x4FBF;&#x662F;&#x753B;&#x56FE;&#x3002;&#x5F88;&#x591A;&#x65F6;&#x5019;&#xFF0C;&#x6211;&#x4EEC;&#x4F1A;&#x89C9;&#x5F97;&#x8BF4;&#x4E0D;&#x6E05;&#x695A;&#xFF0C;&#x4E00;&#x65E6;&#x4F60;&#x53D1;&#x73B0;&#x8BF4;&#x4E0D;&#x6E05;&#x695A;&#xFF0C;&#x90A3;&#x4E48;&#x6211;&#x4EEC;&#x5C31;&#x53EF;&#x4EE5;&#x7528;&#x753B;&#x56FE;&#x6765;&#x8BF4;&#x660E;&#xFF0C;&#x8FD9;&#x4E9B;&#x56FE;&#x5305;&#x542B;&#x4E86;&#x4F60;&#x60F3;&#x8981;&#x8868;&#x8FBE;&#x7684;&#x601D;&#x60F3;&#x6216;&#x8005;&#x903B;&#x8F91;&#xFF0C;&#x800C;&#x4E0D;&#x662F;&#x4E00;&#x4E2A;&#x753B;&#x5F97;&#x975E;&#x5E38;&#x903C;&#x771F;&#x7684;&#x4E3B;&#x673A;&#x7BB1;&#x3002;&#x56E0;&#x6B64;&#xFF0C;&#x5728;&#x5DE5;&#x4F5C;&#x5B66;&#x4E60;&#x4E2D;&#xFF0C;&#x517B;&#x6210;&#x753B;&#x56FE;&#x7684;&#x4E60;&#x60EF;&#xFF0C;&#x628A;&#x590D;&#x6742;&#x6A21;&#x7CCA;&#x7684;&#x6587;&#x5B57;&#x63CF;&#x8FF0;&#x8F6C;&#x6362;&#x6210;&#x4E00;&#x5F20;&#x6E05;&#x6670;&#x76F4;&#x767D;&#x7684;&#x56FE;&#xFF0C;&#x4E0D;&#x4EC5;&#x53EF;&#x4EE5;&#x964D;&#x4F4E;&#x8BB8;&#x591A;&#x6C9F;&#x901A;&#x7684;&#x6210;&#x672C;&#xFF0C;&#x8FD8;&#x53EF;&#x4EE5;&#x953B;&#x70BC;&#x4E2A;&#x4EBA;&#x7684;&#x62BD;&#x8C61;&#x601D;&#x7EF4;&#x80FD;&#x529B;&#x3002;</p>
<p>&#x4E0B;&#x56FE;&#xFF08;&#x91CD;&#x65B0;&#x7ED8;&#x5236;&#xFF09;&#x53D6;&#x81EA;Jesse James Garrett &#x7684;&#x300A;&#x7528;&#x6237;&#x4F53;&#x9A8C;&#x7684;&#x8981;&#x7D20;&#xFF1A;&#x4EE5;&#x7528;&#x6237;&#x4E3A;&#x4E2D;&#x5FC3;&#x7684;Web&#x8BBE;&#x8BA1;&#x300B;&#x4E00;&#x4E66;&#x4E2D;&#x7684;&#x7528;&#x6237;&#x4F53;&#x9A8C;&#x6A21;&#x578B;&#xFF0C;&#x53EF;&#x4EE5;&#x8BF4;&#x6574;&#x672C;&#x4E66;&#x5C31;&#x662F;&#x56F4;&#x7ED5;&#x8FD9;&#x5F20;&#x56FE;&#x5C55;&#x5F00;&#x8BBA;&#x8FF0;&#x7684;&#xFF0C;&#x662F;&#x5F88;&#x591A;&#x4EA7;&#x54C1;&#x7ECF;&#x7406;&#x7684;&#x5165;&#x95E8;&#x7ECF;&#x5178;&#x4E66;&#x7C4D;&#x3002;&#x4ECE;2000&#x5E74;3&#x6708;&#x521D;&#x6B21;&#x53D1;&#x5E03;&#x5230;&#x7F51;&#x4E0A;&#x4EE5;&#x6765;&#xFF0C;Jesse&#x6240;&#x7ED8;&#x5236;&#x7684;&#x8FD9;&#x4E2A;&#x6A21;&#x578B;&#x5DF2;&#x7ECF;&#x88AB;&#x4E0B;&#x8F7D;&#x4E86;2&#x4E07;&#x591A;&#x6B21;&#x3002;&#x4E8B;&#x5B9E;&#x4E0A;&#xFF0C;&#x7528;&#x6237;&#x4F53;&#x9A8C;&#x662F;&#x4E00;&#x79CD;&#x975E;&#x5E38;&#x62BD;&#x8C61;&#x7684;&#x4E1C;&#x897F;&#xFF0C;&#x6240;&#x8C13;&#x5927;&#x5E08;&#x5C31;&#x662F;&#x5177;&#x5907;&#x8FD9;&#x6837;&#x7684;&#x80FD;&#x529B;&#xFF0C;&#x5C06;&#x6781;&#x4E3A;&#x62BD;&#x8C61;&#x7684;&#x601D;&#x60F3;&#xFF0C;&#x6295;&#x5C04;&#x5230;&#x4E00;&#x4E2A;&#x7B80;&#x5355;&#x7684;&#x4E8C;&#x7EF4;&#x7A7A;&#x95F4;&#x4E0A;&#xFF0C;&#x8868;&#x73B0;&#x4E3A;&#x5177;&#x8C61;&#x7684;&#x56FE;&#x8868;&#xFF0C;&#x4ECE;&#x800C;&#x5F62;&#x6210;&#x5177;&#x6709;&#x903B;&#x8F91;&#x7684;&#x4FE1;&#x606F;&#xFF0C;&#x8FD9;&#x5C31;&#x662F;&#x771F;&#x6B63;&#x610F;&#x4E49;&#x4E0A;&#x7684;&#x6DF1;&#x5165;&#x6D45;&#x51FA;&#x3002;<br>
<img src="/content/images/2018/06/user-experience.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"><br>
&#x90A3;&#x4E48;&#x5F88;&#x591A;&#x4EBA;&#x4F1A;&#x95EE;&#xFF0C;&#x8BF4;&#x4E86;&#x8FD9;&#x4E48;&#x591A;&#xFF0C;&#x7528;&#x4EC0;&#x4E48;&#x5DE5;&#x5177;&#x753B;&#x56FE;&#x6BD4;&#x8F83;&#x597D;&#x7B49;&#x7B49;&#xFF0C;&#x8FD9;&#x91CC;&#x8981;&#x8BF4;&#x660E;&#x7684;&#x662F;&#xFF0C;&#x672C;&#x6587;&#x6240;&#x8981;&#x5206;&#x4EAB;&#x7684;&#x5185;&#x5BB9;&#xFF0C;&#x5E76;&#x4E0D;&#x5C40;&#x9650;&#x4E8E;&#x67D0;&#x4E00;&#x79CD;&#x753B;&#x56FE;&#x7684;&#x5DE5;&#x5177;&#x548C;&#x6280;&#x5DE7;&#xFF0C;&#x5DE5;&#x5177;&#x672C;&#x8EAB;&#x6CA1;&#x6709;&#x4EC0;&#x4E48;&#x9AD8;&#x4F4E;&#x4E4B;&#x5DEE;&#xFF0C;&#x5DEE;&#x522B;&#x5728;&#x4E8E;&#x662F;&#x5426;&#x5177;&#x5907;&#x62BD;&#x8C61;&#x601D;&#x7EF4;&#x7684;&#x80FD;&#x529B;&#xFF0C;&#x5728;&#x4E8E;&#x7ED8;&#x56FE;&#x7684;&#x64CD;&#x4F5C;&#x662F;&#x5426;&#x89C4;&#x8303;&#x9AD8;&#x6548;&#xFF0C;&#x5728;&#x4E8E;&#x662F;&#x5426;&#x7406;&#x89E3;&#x4E8B;&#x52A1;&#x7684;&#x673A;&#x7406;&#xFF0C;&#x5173;&#x6CE8;&#x8FD9;&#x4E9B;&#x624D;&#x80FD;&#x591F;&#x63D0;&#x5347;&#x7ED8;&#x56FE;&#x80FD;&#x529B;&#xFF0C;&#x800C;&#x4E0D;&#x662F;&#x9677;&#x5165;&#x5DE5;&#x5177;&#x4E4B;&#x4E89;&#xFF0C;&#x8FD9;&#x6CA1;&#x6709;&#x4EFB;&#x4F55;&#x610F;&#x4E49;&#xFF0C;&#x5373;&#x4FBF;&#x662F;&#x6700;&#x666E;&#x901A;&#x7684;windows&#x753B;&#x56FE;&#x677F;&#xFF0C;&#x4E00;&#x6837;&#x53EF;&#x4EE5;&#x753B;&#x56FE;&#xFF0C;&#x65E0;&#x975E;&#x56FE;&#x6807;&#x4E0D;&#x591F;&#x6F02;&#x4EAE;&#xFF0C;&#x4F46;&#x6211;&#x4EEC;&#x5E76;&#x4E0D;&#x5728;&#x4E4E;&#x8FD9;&#x4E9B;&#xFF0C;&#x5BF9;&#x4E8E;IT&#x4ECE;&#x4E1A;&#x8005;&#x6765;&#x8BF4;&#xFF0C;&#x5E76;&#x4E0D;&#x9700;&#x8981;&#x89C6;&#x89C9;&#x4E0A;&#x827A;&#x672F;&#x4E0A;&#x7684;&#x7F8E;&#x611F;&#xFF0C;&#x800C;&#x662F;&#x8FD9;&#x5F20;&#x56FE;&#x80CC;&#x540E;&#x627F;&#x8F7D;&#x7684;&#x4FE1;&#x606F;&#x3002;</p>
<p>&#x4E0B;&#x9762;&#x8981;&#x4ECB;&#x7ECD;&#x7684;&#x57FA;&#x672C;&#x662F;&#x5404;&#x4E2A;&#x7ED8;&#x56FE;&#x8F6F;&#x4EF6;&#x90FD;&#x76F8;&#x901A;&#x7684;&#x529F;&#x80FD;&#x7279;&#x6027;&#xFF0C;&#x4F7F;&#x7528;&#x8FD9;&#x4E9B;&#x529F;&#x80FD;&#x53EF;&#x4EE5;&#x63D0;&#x5347;&#x6211;&#x4EEC;&#x7ED8;&#x56FE;&#x7684;&#x6548;&#x7387;&#xFF0C;&#x53E6;&#x5916;&#x8FD8;&#x63D0;&#x51FA;&#x4E86;&#x4E00;&#x4E9B;&#x7ED8;&#x56FE;&#x7684;&#x89C4;&#x8303;&#x5EFA;&#x8BAE;&#xFF0C;&#x4F9B;&#x5927;&#x5BB6;&#x53C2;&#x8003;&#xFF0C;&#x6BD5;&#x7ADF;&#x8FD9;&#x4E0D;&#x662F;&#x4E00;&#x4EFD;&#x7ED8;&#x56FE;&#x8F6F;&#x4EF6;&#x7684;&#x8BF4;&#x660E;&#x4E66;&#x3002;&#x5E0C;&#x671B;&#x5927;&#x5BB6;&#x80FD;&#x591F;&#x4E86;&#x89E3;&#x7ED8;&#x56FE;&#x7684;&#x601D;&#x60F3;&#xFF0C;&#x800C;&#x4E0D;&#x662F;&#x5DE5;&#x5177;&#x672C;&#x8EAB;&#x7684;&#x4F7F;&#x7528;&#x3002;</p>
<h2 id="processon">&#x4E8C;&#x3001;ProcessOn&#x7B80;&#x4ECB;</h2>
<p>&#x672C;&#x6587;&#x6240;&#x4F7F;&#x7528;&#x7684;&#x662F;&#x5728;&#x7EBF;&#x7ED8;&#x56FE;&#x5DE5;&#x5177;&#x2014;&#x2014;ProcessOn&#xFF0C;&#x8FD9;&#x662F;&#x4E00;&#x4E2A;&#x65B9;&#x4FBF;&#x6613;&#x7528;&#x3001;&#x514D;&#x8D39;&#x9AD8;&#x6548;&#x7684;&#x5728;&#x7EBF;&#x4F5C;&#x56FE;&#x5DE5;&#x5177;&#xFF0C;&#x8FD0;&#x7528;&#x5B83;&#x53EF;&#x4EE5;&#x514D;&#x8D39;&#x5236;&#x4F5C;&#x591A;&#x79CD;&#x56FE;&#x3002;</p>
<p>&#x4E4B;&#x6240;&#x4EE5;&#x4F1A;&#x4F7F;&#x7528;&#x8FD9;&#x4E2A;&#x5DE5;&#x5177;&#xFF0C;&#x4E3B;&#x8981;&#x6709;&#x51E0;&#x4E2A;&#x539F;&#x56E0;&#xFF1A;</p>
<ul>
<li>&#x4E00;&#x662F;&#x56E0;&#x4E3A;&#x5B83;&#x662F;&#x4E00;&#x4E2A;&#x5728;&#x7EBF;&#x7684;&#x5DE5;&#x5177;&#xFF0C;&#x81EA;&#x7136;&#x4E5F;&#x5C31;&#x6709;&#x4E86;&#x8DE8;&#x5E73;&#x53F0;&#x7684;&#x7279;&#x6027;&#x3002;&#x4F5C;&#x4E3A;&#x4E00;&#x4E2A;IT&#x4ECE;&#x4E1A;&#x8005;&#xFF0C;&#x5F88;&#x591A;&#x60C5;&#x51B5;&#x4E0B;&#x4F1A;&#x7A7F;&#x68AD;&#x5728;Windows&#xFF0C;Linux&#xFF0C;Mac OS&#x8FD9;&#x4E9B;&#x64CD;&#x4F5C;&#x7CFB;&#x7EDF;&#x4E4B;&#x95F4;&#x5DE5;&#x4F5C;&#xFF0C;&#x800C;&#x5E38;&#x7528;&#x7684;&#x7ED8;&#x56FE;&#x8F6F;&#x4EF6;&#xFF0C;&#x901A;&#x5E38;&#x53EA;&#x80FD;&#x8FD0;&#x884C;&#x5728;Windows&#xFF0C;&#x5F53;&#x7136;Linux&#x548C;Mac OS&#x4E5F;&#x6709;&#x975E;&#x5E38;&#x4E0D;&#x9519;&#x7684;&#x7ED8;&#x56FE;&#x8F6F;&#x4EF6;&#xFF0C;&#x4F46;&#x7EC8;&#x7A76;&#x65E0;&#x6CD5;&#x5B9E;&#x73B0;&#x79FB;&#x52A8;&#x529E;&#x516C;&#x3002;&#x800C;&#x4F5C;&#x4E3A;&#x5728;&#x7EBF;&#x5DE5;&#x5177;&#xFF0C;&#x4E5F;&#x5C31;&#x5C4F;&#x853D;&#x4E86;&#x56E0;&#x4E3A;&#x4E0D;&#x540C;&#x64CD;&#x4F5C;&#x7CFB;&#x7EDF;&#x5E26;&#x6765;&#x7684;&#x9EBB;&#x70E6;&#xFF0C;&#x4F60;&#x53EF;&#x4EE5;&#x65B9;&#x4FBF;&#x5730;&#x5728;&#x5BB6;&#x4E2D;MacBook&#x4E2D;&#x4F7F;&#x7528;&#x5B83;&#x6253;&#x5F00;&#x516C;&#x53F8;&#x4E0B;&#x73ED;&#x524D;&#x753B;&#x7684;&#x4E00;&#x5F20;&#x534A;&#x6210;&#x54C1;&#x56FE;&#xFF0C;&#x7EE7;&#x7EED;&#x5B8C;&#x6210;&#xFF0C;&#x7136;&#x540E;&#x660E;&#x5929;&#x4E0A;&#x73ED;&#x5C31;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x7ED9;&#x9886;&#x5BFC;&#x4F5C;&#x6C47;&#x62A5;&#x4E86;&#x3002;</li>
<li>&#x4E8C;&#x662F;&#x56E0;&#x4E3A;&#x5176;&#x5728;&#x7EBF;&#x5B58;&#x50A8;&#xFF0C;&#x8FD9;&#x4E5F;&#x5F88;&#x91CD;&#x8981;&#xFF0C;&#x53EF;&#x4EE5;&#x907F;&#x514D;&#x4E00;&#x4E9B;&#x60B2;&#x5267;&#x7684;&#x53D1;&#x751F;&#xFF0C;&#x4F8B;&#x5982;&#x8D76;&#x4E86;&#x4E00;&#x665A;&#x4E0A;&#x7684;&#x56FE;&#xFF0C;&#x7A81;&#x7136;&#x65AD;&#x7535;&#xFF0C;&#x84DD;&#x5C4F;&#x4EC0;&#x4E48;&#x7684;&#xFF0C;&#x7136;&#x800C;&#x5E76;&#x6CA1;&#x6709;&#x4FDD;&#x5B58;&#xFF0C;&#x4E0D;&#x5F97;&#x4E0D;&#x6EE1;&#x8179;&#x6028;&#x6C14;&#x5730;&#x91CD;&#x753B;&#x3002;</li>
<li>&#x4E09;&#x662F;&#x56E0;&#x4E3A;&#x5B83;&#x64CD;&#x4F5C;&#x7B80;&#x5355;&#xFF0C;&#x5B83;&#x57FA;&#x672C;&#x5438;&#x53D6;&#x4E86;visio&#x4E4B;&#x7C7B;&#x5E38;&#x7528;&#x7ED8;&#x56FE;&#x8F6F;&#x4EF6;&#x7684;&#x64CD;&#x4F5C;&#x7279;&#x70B9;&#xFF0C;&#x56E0;&#x6B64;&#x5BF9;&#x4E8E;&#x6709;&#x7ED8;&#x56FE;&#x7ECF;&#x9A8C;&#x7684;&#x7528;&#x6237;&#xFF0C;&#x5B66;&#x4E60;&#x6210;&#x672C;&#x51E0;&#x4E4E;&#x4E3A;&#x96F6;&#x3002;</li>
<li>&#x56DB;&#x662F;&#x56E0;&#x4E3A;&#x7ED3;&#x5408;&#x7F51;&#x7EDC;&#x793E;&#x4EA4;&#x7684;&#x7279;&#x6027;&#xFF0C;&#x4E0D;&#x540C;&#x56FE;&#x8868;&#x7684;&#x4F5C;&#x8005;&#x53EF;&#x4EE5;&#x8F7B;&#x677E;&#x5730;&#x5728;&#x5E73;&#x53F0;&#x5206;&#x4EAB;&#x5404;&#x81EA;&#x4F5C;&#x54C1;&#xFF0C;&#x7528;&#x6237;&#x4E5F;&#x53EF;&#x4EE5;&#x65B9;&#x4FBF;&#x5730;&#x5BF9;&#x516C;&#x5F00;&#x7684;&#x4F5C;&#x54C1;&#x8FDB;&#x884C;&#x641C;&#x7D22;&#xFF0C;&#x540C;&#x65F6;&#x8FD8;&#x652F;&#x6301;&#x591A;&#x4EBA;&#x534F;&#x4F5C;&#x7684;&#x529F;&#x80FD;&#xFF0C;&#x9002;&#x5408;&#x56E2;&#x961F;&#x5185;&#x90E8;&#x534F;&#x540C;&#x5DE5;&#x4F5C;</li>
</ul>
<p>&#x5F53;&#x7136;&#xFF0C;&#x8FD9;&#x4E2A;&#x5DE5;&#x5177;&#x4E5F;&#x4E0D;&#x662F;&#x5341;&#x5168;&#x5341;&#x7F8E;&#x7684;&#xFF0C;&#x6BD5;&#x7ADF;&#x662F;2015&#x5E74;&#x624D;&#x4E0A;&#x7EBF;&#x63D0;&#x4F9B;&#x670D;&#x52A1;&#xFF0C;&#x4EA7;&#x54C1;&#x8FD8;&#x5B58;&#x5728;&#x6216;&#x5927;&#x6216;&#x5C0F;&#x7684;&#x4E0D;&#x7A33;&#x5B9A;&#x56E0;&#x7D20;&#xFF0C;&#x5982;&#x4E22;&#x5931;&#x6570;&#x636E;&#xFF08;&#x636E;&#x5176;&#x4ED6;&#x7F51;&#x53CB;&#x53CD;&#x9988;&#x5B58;&#x5728;&#x8FD9;&#x6837;&#x7684;&#x60C5;&#x51B5;&#xFF0C;&#x4E0D;&#x8FC7;&#x7B14;&#x8005;&#x5728;&#x5B9E;&#x9645;&#x4F7F;&#x7528;&#x4E2D;&#x672A;&#x9047;&#x5230;&#x8FC7;&#xFF09;&#xFF0C;&#x83DC;&#x5355;&#x529F;&#x80FD;&#x5361;&#x4F4F;&#xFF0C;&#x56FE;&#x6807;&#x76F8;&#x5BF9;&#x6BD4;&#x8F83;&#x5C11;&#x7B49;&#xFF0C;&#x4E0D;&#x8FC7;&#x8FD9;&#x4E9B;&#x95EE;&#x9898;&#x4E5F;&#x8FD8;&#x5728;&#x53EF;&#x5FCD;&#x53D7;&#x7684;&#x8303;&#x56F4;&#x4E4B;&#x5185;&#x3002;&#x4F5C;&#x4E3A;&#x56FD;&#x5185;&#x514D;&#x8D39;&#x7684;&#x5728;&#x7EBF;&#x7ED8;&#x56FE;&#x5DE5;&#x5177;&#xFF0C;&#x53EF;&#x4EE5;&#x505A;&#x5230;&#x8FD9;&#x822C;&#x5B9E;&#x4E3A;&#x4E0D;&#x6613;&#x3002;</p>
<h2 id>&#x4E09;&#x3001;&#x64CD;&#x4F5C;&#x6280;&#x5DE7;</h2>
<p>&#x5BF9;&#x4E8E;ProcessOn&#x767B;&#x5F55;&#x6CE8;&#x518C;&#x7B49;&#x5176;&#x4ED6;&#x64CD;&#x4F5C;&#xFF0C;&#x8FD9;&#x91CC;&#x4E0D;&#x8FC7;&#x591A;&#x4ECB;&#x7ECD;&#xFF08;&#x8BF4;&#x591A;&#x4E86;&#x5C31;&#x50CF;&#x8F6F;&#x6587;&#xFF09;&#xFF0C;&#x4E0B;&#x9762;&#x4ECB;&#x7ECD;&#x4E00;&#x4E9B;&#x5E38;&#x7528;&#x7684;&#x64CD;&#x4F5C;&#x6280;&#x5DE7;&#xFF0C;&#x8FD9;&#x4E9B;&#x6280;&#x5DE7;&#x901A;&#x5E38;&#x4E5F;&#x9002;&#x7528;&#x4E8E;visio&#x7B49;&#x5176;&#x4ED6;&#x7ED8;&#x56FE;&#x8F6F;&#x4EF6;&#xFF0C;&#x5927;&#x5BB6;&#x53EF;&#x4EE5;&#x81EA;&#x884C;&#x5BF9;&#x5E94;&#x3002;&#x53EF;&#x4EE5;&#x8BF4;&#xFF0C;&#x8FD9;&#x4E9B;&#x6280;&#x5DE7;&#x76F8;&#x5F53;&#x4E8E;&#x7ED8;&#x56FE;&#x6548;&#x7387;&#x7684;&#x50AC;&#x5316;&#x5242;&#xFF0C;&#x53EF;&#x4EE5;&#x8BA9;&#x6211;&#x4EEC;&#x5B9E;&#x9645;&#x7684;&#x7ED8;&#x56FE;&#x5DE5;&#x4F5C;&#x63D0;&#x5347;&#x6548;&#x7387;&#xFF0C;&#x5E76;&#x4E14;&#x5B8C;&#x6210;&#x7684;&#x56FE;&#x53C8;&#x4E0D;&#x5931;&#x7F8E;&#x89C2;&#x548C;&#x4E13;&#x4E1A;&#x3002;</p>
<p>&#x5BF9;&#x4E8E;&#x5DF2;&#x7ECF;&#x638C;&#x63E1;&#x8FD9;&#x4E9B;&#x6280;&#x5DE7;&#x7684;&#x8BFB;&#x8005;&#x53EF;&#x4EE5;&#x8DF3;&#x8FC7;&#x672C;&#x8282;</p>
<h3 id="31">3.1 &#x5E73;&#x5747;&#x5206;&#x5E03;</h3>
<p>&#x5728;&#x5F88;&#x591A;&#x573A;&#x666F;&#x4E0B;&#xFF0C;&#x6211;&#x4EEC;&#x4F1A;&#x753B;&#x4E00;&#x6392;&#xFF0C;&#x6216;&#x8005;&#x4E00;&#x4E32;&#x77E9;&#x5F62;&#x4E4B;&#x7C7B;&#x7684;&#x5143;&#x7D20;&#xFF0C;&#x4F46;&#x662F;&#x7531;&#x4E8E;&#x624B;&#x52A8;&#x62D6;&#x62FD;&#x7684;&#x968F;&#x610F;&#x6027;&#xFF0C;&#x5BFC;&#x81F4;&#x8FD9;&#x4E9B;&#x5143;&#x7D20;&#x7684;&#x95F4;&#x8DDD;&#x4E0D;&#x5C3D;&#x76F8;&#x540C;&#xFF0C;&#x8FD9;&#x65F6;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;&#x56FE;&#x5F62;&#x5206;&#x5E03;&#x7684;&#x529F;&#x80FD;&#xFF0C;&#x5C06;&#x8FD9;&#x4E9B;&#x5143;&#x7D20;&#x8C03;&#x6574;&#x4E3A;&#x76F8;&#x7B49;&#x95F4;&#x8DDD;&#xFF0C;&#x8FD9;&#x6837;&#x5728;&#x5143;&#x7D20;&#x6BD4;&#x8F83;&#x591A;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x53EF;&#x4EE5;&#x4FDD;&#x6301;&#x6574;&#x5E45;&#x56FE;&#x7684;&#x6574;&#x6D01;&#x3002;<br>
<img src="/content/images/2018/06/----.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"><br>
&#x64CD;&#x4F5C;&#x65F6;&#xFF0C;&#x9009;&#x4E2D;&#x5BF9;&#x5E94;&#x7684;&#x5143;&#x7D20;&#xFF0C;&#x7136;&#x540E;&#x9009;&#x62E9;&#x5C4F;&#x5E55;&#x9876;&#x90E8;&#x7684;&#x5DE5;&#x5177;&#x680F;&#x4E2D;&#x7684;&#x201C;&#x6392;&#x5217;&#x201D;&#xFF0C;&#x5E76;&#x9009;&#x62E9;&#x201C;&#x56FE;&#x5F62;&#x5206;&#x5E03;&#x201D;-&gt;&#x201C;&#x5782;&#x76F4;&#x5E73;&#x5747;&#x5206;&#x5E03;&#x201D;<br>
<img src="/content/images/2018/06/fenbu.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"><br>
&#x5BF9;&#x5E94;&#x6709;&#x4E24;&#x79CD;&#x5206;&#x5E03;&#xFF1A;</p>
<ul>
<li>&#x6C34;&#x5E73;&#x5E73;&#x5747;&#x5206;&#x5E03;&#xFF0C;&#x5373;&#x6C34;&#x5E73;&#x65B9;&#x5411;&#x4E0A;&#xFF0C;&#x4F7F;&#x591A;&#x4E2A;&#x5143;&#x7D20;&#x4EE5;&#x76F8;&#x7B49;&#x7684;&#x95F4;&#x8DDD;&#x8FDB;&#x884C;&#x6392;&#x5217;</li>
<li>&#x5782;&#x76F4;&#x5E73;&#x5747;&#x5206;&#x5E03;&#xFF0C;&#x5373;&#x5782;&#x76F4;&#x65B9;&#x5411;&#x4E0A;&#xFF0C;&#x4F7F;&#x591A;&#x4E2A;&#x5143;&#x7D20;&#x4EE5;&#x76F8;&#x7B49;&#x7684;&#x95F4;&#x8DDD;&#x8FDB;&#x884C;&#x6392;&#x5217;</li>
</ul>
<h3 id="32">3.2 &#x5143;&#x7D20;&#x5BF9;&#x9F50;</h3>
<p>&#x5927;&#x591A;&#x6570;&#x7ED8;&#x56FE;&#x8F6F;&#x4EF6;&#x4E2D;&#xFF0C;&#x5728;&#x62D6;&#x52A8;&#x4E00;&#x4E2A;&#x5143;&#x7D20;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x4F1A;&#x81EA;&#x52A8;&#x5730;&#x51FA;&#x73B0;&#x4E00;&#x4E9B;&#x5BF9;&#x9F50;&#x7EBF;&#xFF0C;&#x65B9;&#x4FBF;&#x7528;&#x6237;&#x5C06;&#x5143;&#x7D20;&#x5BF9;&#x9F50;&#x5230;&#x7279;&#x5B9A;&#x7684;&#x4F4D;&#x7F6E;&#xFF0C;&#x4F46;&#x662F;&#x4E00;&#x65E6;&#x5143;&#x7D20;&#x6BD4;&#x8F83;&#x591A;&#xFF0C;&#x62D6;&#x52A8;&#x7684;&#x64CD;&#x4F5C;&#x5C31;&#x6709;&#x70B9;&#x676F;&#x6C34;&#x8F66;&#x85AA;&#x4E86;&#xFF0C;&#x4E8B;&#x5B9E;&#x4E0A;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;&#x5BF9;&#x9F50;&#x7684;&#x529F;&#x80FD;&#x5FEB;&#x901F;&#x5730;&#x8FDB;&#x884C;&#x5143;&#x7D20;&#x5BF9;&#x9F50;&#xFF0C;&#x5982;&#x4E0B;&#x56FE;&#xFF1A;<br>
<img src="/content/images/2018/06/duiqi.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"><br>
&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x5C06;&#x9700;&#x8981;&#x5BF9;&#x9F50;&#x5143;&#x7D20;&#x9009;&#x4E2D;&#xFF0C;&#x7136;&#x540E;&#x53F3;&#x952E;&#xFF08;&#x6216;&#x8005;&#x70B9;&#x51FB;&#x5C4F;&#x5E55;&#x9876;&#x90E8;&#x7684;&#x5DE5;&#x5177;&#x680F;&#x4E2D;&#x7684;&#x201C;&#x6392;&#x5217;&#x201D;&#xFF09;&#xFF0C;&#x5E76;&#x9009;&#x62E9;&#x201C;&#x56FE;&#x5F62;&#x5BF9;&#x9F50;&#x201D;-&gt;&#x201C;&#x5C45;&#x4E2D;&#x5BF9;&#x9F50;&#x201D;<br>
<img src="/content/images/2018/06/-----1.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"><br>
&#x8FD9;&#x4E9B;&#x5BF9;&#x9F50;&#x65B9;&#x5F0F;&#xFF0C;&#x53EF;&#x4EE5;&#x4ECE;&#x5B57;&#x9762;&#x610F;&#x601D;&#x7406;&#x89E3;&#xFF1A;</p>
<ul>
<li>&#x5DE6;&#x5BF9;&#x9F50;&#xFF0C;&#x5373;&#x9009;&#x4E2D;&#x7684;&#x6240;&#x6709;&#x5143;&#x7D20;&#xFF0C;&#x5411;&#x5904;&#x4E8E;&#x5C4F;&#x5E55;&#x6700;&#x5DE6;&#x4FA7;&#x7684;&#x5143;&#x7D20;&#x5BF9;&#x9F50;</li>
<li>&#x5C45;&#x4E2D;&#x5BF9;&#x9F50;&#xFF1A;&#x5373;&#x9009;&#x4E2D;&#x7684;&#x6240;&#x6709;&#x5143;&#x7D20;&#xFF0C;&#x6839;&#x636E;&#x5C4F;&#x5E55;&#x6700;&#x5DE6;&#x4FA7;&#x548C;&#x6700;&#x53F3;&#x4FA7;&#x7684;&#x4F4D;&#x7F6E;&#x8BA1;&#x7B97;&#x5F97;&#x5230;&#x4E2D;&#x7EBF;&#xFF0C;&#x5E76;&#x5411;&#x8BE5;&#x4E2D;&#x7EBF;&#x5BF9;&#x9F50;</li>
<li>&#x53F3;&#x5BF9;&#x9F50;&#xFF0C;&#x5373;&#x9009;&#x4E2D;&#x7684;&#x6240;&#x6709;&#x5143;&#x7D20;&#xFF0C;&#x5411;&#x5904;&#x4E8E;&#x5C4F;&#x5E55;&#x6700;&#x53F3;&#x4FA7;&#x7684;&#x5143;&#x7D20;&#x5BF9;&#x9F50;</li>
<li>&#x9876;&#x7AEF;&#x5BF9;&#x9F50;&#xFF1A;&#x5373;&#x9009;&#x4E2D;&#x7684;&#x6240;&#x6709;&#x5143;&#x7D20;&#xFF0C;&#x5411;&#x5904;&#x4E8E;&#x5C4F;&#x5E55;&#x6700;&#x4E0A;&#x65B9;&#x7684;&#x5143;&#x7D20;&#x5BF9;&#x9F50;</li>
<li>&#x5782;&#x76F4;&#x5C45;&#x4E2D;&#x5BF9;&#x9F50;&#xFF1A;&#x5373;&#x9009;&#x4E2D;&#x7684;&#x6240;&#x6709;&#x5143;&#x7D20;&#xFF0C;&#x6839;&#x636E;&#x5904;&#x4E8E;&#x5C4F;&#x5E55;&#x6700;&#x4E0A;&#x65B9;&#x548C;&#x6700;&#x4E0B;&#x65B9;&#x7684;&#x4F4D;&#x7F6E;&#x8BA1;&#x7B97;&#x5F97;&#x5230;&#x4E2D;&#x7EBF;&#xFF0C;&#x5E76;&#x5411;&#x8BE5;&#x4E2D;&#x7EBF;&#x5BF9;&#x9F50;</li>
<li>&#x5E95;&#x7AEF;&#x5BF9;&#x9F50;&#xFF1A;&#x5373;&#x9009;&#x4E2D;&#x7684;&#x6240;&#x6709;&#x5143;&#x7D20;&#xFF0C;&#x5411;&#x5904;&#x4E8E;&#x5C4F;&#x5E55;&#x6700;&#x4E0B;&#x65B9;&#x7684;&#x5143;&#x7D20;&#x5BF9;&#x9F50;</li>
</ul>
<h3 id="33">3.3 &#x5927;&#x5C0F;&#x63A7;&#x5236;</h3>
<p>&#x6709;&#x65F6;&#x5019;&#xFF0C;&#x6211;&#x4EEC;&#x5728;&#x6846;&#x5185;&#x4F1A;&#x6807;&#x6CE8;&#x4E0A;&#x4E00;&#x4E9B;&#x6587;&#x5B57;&#xFF0C;&#x7531;&#x4E8E;&#x6807;&#x6CE8;&#x7684;&#x6587;&#x5B57;&#x957F;&#x77ED;&#x4E00;&#x6B65;&#xFF0C;&#x5C31;&#x51FA;&#x73B0;&#x6846;&#x672C;&#x8EAB;&#x7684;&#x5BBD;&#x5EA6;&#x4E0D;&#x4E00;&#x81F4;&#xFF0C;&#x4E3A;&#x4E86;&#x4FDD;&#x6301;&#x6574;&#x9F50;&#xFF0C;&#x901A;&#x5E38;&#x5C31;&#x4F1A;&#x5C06;&#x8FD9;&#x4E9B;&#x5143;&#x7D20;&#x5BBD;&#x5EA6;&#xFF08;&#x6216;&#x9AD8;&#x5EA6;&#xFF09;&#x4FDD;&#x6301;&#x7EDF;&#x4E00;&#xFF0C;&#x4E00;&#x822C;&#x64CD;&#x4F5C;&#x5C31;&#x662F;&#x624B;&#x52A8;&#x5730;&#x9010;&#x4E2A;&#x8C03;&#x6574;&#x65B9;&#x6846;&#x5927;&#x5C0F;&#xFF0C;&#x6216;&#x8005;&#x9009;&#x4E2D;&#x4E4B;&#x540E;&#x7EDF;&#x4E00;&#x8C03;&#x6574;&#x9AD8;&#x5BBD;&#x7684;&#x6570;&#x503C;&#xFF0C;&#x5F53;&#x7136;&#x4E5F;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;&#x6279;&#x91CF;&#x64CD;&#x4F5C;&#x7684;&#x65B9;&#x5F0F;<br>
<img src="/content/images/2018/06/size.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"><br>
&#x9009;&#x4E2D;&#x5BF9;&#x5E94;&#x7684;&#x5143;&#x7D20;&#xFF0C;&#x7136;&#x540E;&#x9009;&#x62E9;&#x5C4F;&#x5E55;&#x9876;&#x90E8;&#x7684;&#x5DE5;&#x5177;&#x680F;&#x4E2D;&#x7684;&#x201C;&#x6392;&#x5217;&#x201D;&#xFF0C;&#x5E76;&#x9009;&#x62E9;&#x201C;&#x5339;&#x914D;&#x5927;&#x5C0F;&#x201D;-&gt;&#x201C;&#x5BBD;&#x5EA6;&#x201D;<br>
<img src="/content/images/2018/06/resize.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"><br>
&#x8BF4;&#x660E;&#xFF1A;&#x4E0D;&#x8BBA;&#x662F;&#x8C03;&#x6574;&#x9AD8;&#x5EA6;&#x8FD8;&#x662F;&#x5BBD;&#x5EA6;&#xFF0C;&#x90FD;&#x662F;&#x8C03;&#x6574;&#x4E3A;&#x6240;&#x9009;&#x5143;&#x7D20;&#x4E2D;&#x9AD8;&#x5EA6;&#x6700;&#x5927;&#x6216;&#x5BBD;&#x5EA6;&#x6700;&#x5927;&#x7684;&#x6570;&#x503C;</p>
<h3 id="34z">3.4 Z&#x8F74;&#x6392;&#x5217;</h3>
<p>&#x8FD9;&#x91CC;&#x6240;&#x8C13;&#x201C;Z&#x8F74;&#x201D;&#x7684;&#x6982;&#x5FF5;&#xFF0C;&#x662F;&#x4ECE;CSS&#x4E2D;&#x7684;&#x201C;z-index&#x201D;&#x5C5E;&#x6027;&#x501F;&#x9274;&#x8FC7;&#x6765;&#x7684;&#xFF0C;&#x4EA6;&#x5373;&#x5782;&#x76F4;&#x5C4F;&#x5E55;&#x5411;&#x5916;&#x7684;&#x65B9;&#x5411;&#x3002;</p>
<p>&#x5728;&#x591A;&#x4E2A;&#x5143;&#x7D20;&#x8FDB;&#x884C;&#x7EC4;&#x5408;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x901A;&#x5E38;&#x4F1A;&#x6D89;&#x53CA;&#x5230;&#x524D;&#x540E;&#x906E;&#x6321;&#x7684;&#x95EE;&#x9898;&#xFF0C;&#x8FD9;&#x65F6;&#x5019;&#x9700;&#x8981;&#x7528;&#x5230;z&#x8F74;&#x6392;&#x5217;&#xFF0C;&#x5982;&#x4E0B;&#x56FE;&#x4E2D;&#x7684;&#x5706;&#x73AF;&#xFF0C;&#x5176;&#x4E2D;&#x5C31;&#x662F;&#x7531;&#x4E09;&#x4E2A;&#x5706;&#x5C42;&#x53E0;&#x800C;&#x6210;&#xFF0C;&#x5176;&#x4E2D;&#x6A59;&#x8272;&#x7684;&#x5706;&#x5728;&#x6700;&#x5E95;&#x5C42;&#xFF0C;&#x7EA2;&#x8272;&#x7684;&#x5706;&#x5728;&#x4E2D;&#x95F4;&#xFF0C;&#x767D;&#x8272;&#x7684;&#x5706;&#x5728;&#x6700;&#x9876;&#x5C42;&#x3002;</p>
<p>&#x9ED8;&#x8BA4;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x5143;&#x7D20;&#x7684;z&#x8F74;&#x503C;&#x662F;&#x6839;&#x636E;&#x521B;&#x5EFA;&#x7684;&#x5148;&#x540E;&#x987A;&#x5E8F;&#x51B3;&#x5B9A;&#x5927;&#x5C0F;&#x7684;&#xFF0C;&#x8D8A;&#x662F;&#x540E;&#x521B;&#x5EFA;&#x7684;&#x5143;&#x7D20;&#xFF0C;&#x5176;Z&#x8F74;&#x7684;&#x6570;&#x503C;&#x8D8A;&#x5927;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x80FD;&#x906E;&#x6321;&#x5728;&#x5B83;&#x4E4B;&#x524D;&#x521B;&#x5EFA;&#x7684;&#x5143;&#x7D20;&#x3002;<br>
<img src="/content/images/2018/06/z-index.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"><br>
&#x7ED8;&#x5236;&#x8BE5;&#x56FE;&#x5F62;&#x65F6;&#xFF0C;&#x9996;&#x5148;&#x9700;&#x8981;&#x9009;&#x4E2D;&#x8FD9;3&#x4E2A;&#x5706;&#xFF0C;&#x7136;&#x540E;&#x4F7F;&#x7528;&#x201C;&#x5C45;&#x4E2D;&#x5BF9;&#x9F50;&#x201D;&#x548C;&#x201C;&#x5782;&#x76F4;&#x5C45;&#x4E2D;&#x5BF9;&#x9F50;&#x201D;&#xFF0C;&#x4F7F;&#x5176;&#x6210;&#x4E3A;&#x540C;&#x5FC3;&#x5706;&#xFF0C;&#x5982;&#x679C;&#x6B64;&#x65F6;&#xFF0C;&#x6A59;&#x5706;&#x906E;&#x6321;&#x4F4F;&#x4E86;&#x5176;&#x4ED6;&#x4E24;&#x4E2A;&#x5706;&#xFF0C;&#x5219;&#x70B9;&#x51FB;&#x6A59;&#x5706;&#xFF0C;&#x5E76;&#x9009;&#x62E9;&#x5C4F;&#x5E55;&#x9876;&#x90E8;&#x7684;&#x5DE5;&#x5177;&#x680F;&#x4E2D;&#x7684;&#x201C;&#x6392;&#x5217;&#x201D;&#xFF0C;&#x7136;&#x540E;&#x70B9;&#x51FB;&#x201C;&#x7F6E;&#x4E8E;&#x5E95;&#x5C42;&#x201D;&#xFF0C;&#x4E8E;&#x662F;&#x6A59;&#x5706;&#x5C31;&#x4F1A;&#x88AB;&#x63A8;&#x5230;&#x6700;&#x5E95;&#x5C42;&#xFF0C;&#x63A5;&#x7740;&#x53EF;&#x4EE5;&#x9009;&#x4E2D;&#x7EA2;&#x5706;&#xFF0C;&#x5148;&#x540C;&#x6837;&#x7684;&#x64CD;&#x4F5C;&#x5C06;&#x5B83;&#x7F6E;&#x4E8E;&#x5E95;&#x5C42;&#xFF0C;&#x7136;&#x540E;&#x70B9;&#x51FB;&#x201C;&#x4E0A;&#x79FB;&#x4E00;&#x5C42;&#x201D;&#xFF0C;&#x8FD9;&#x6837;&#x7EA2;&#x5706;&#x5C31;&#x4F1A;&#x53E0;&#x5728;&#x6A59;&#x5706;&#x4E4B;&#x4E0A;&#xFF0C;&#x5982;&#x679C;&#x6B64;&#x65F6;&#x767D;&#x5706;&#x4ECD;&#x7136;&#x6CA1;&#x6709;&#x51FA;&#x73B0;&#x5728;&#x6700;&#x9876;&#x5C42;&#xFF0C;&#x53EF;&#x4EE5;&#x9009;&#x4E2D;&#x5B83;&#xFF0C;&#x70B9;&#x51FB;&#x201C;&#x7F6E;&#x4E8E;&#x9876;&#x5C42;&#x201D;&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x5B8C;&#x6210;&#x4E86;</p>
<center>
<p><img src="/content/images/2018/06/z.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
<h3 id="35">3.5 &#x5206;&#x7EC4;</h3>
<p>&#x5206;&#x7EC4;&#x8FD9;&#x4E2A;&#x529F;&#x80FD;&#x5728;&#x590D;&#x6742;&#x5143;&#x7D20;&#x7EC4;&#x6210;&#x7684;&#x56FE;&#x5F62;&#x4E2D;&#xFF0C;&#x975E;&#x5E38;&#x5B9E;&#x7528;&#xFF0C;&#x5B83;&#x76F8;&#x5F53;&#x4E8E;&#x5C06;&#x67D0;&#x51E0;&#x4E2A;&#x5143;&#x7D20;&#x5C01;&#x88C5;&#x6210;&#x4E3A;&#x4E00;&#x4E2A;&#x7EC4;&#x4EF6;&#xFF0C;&#x4EE5;&#x6574;&#x4F53;&#x7684;&#x65B9;&#x5F0F;&#x8FDB;&#x884C;&#x62D6;&#x62FD;&#xFF0C;&#x65CB;&#x8F6C;&#xFF0C;&#x8FDE;&#x7EBF;&#x7B49;&#x64CD;&#x4F5C;&#xFF0C;&#x5E76;&#x4E14;&#x53EF;&#x4EE5;&#x6709;&#x6548;&#x5730;&#x9632;&#x6B62;&#x610F;&#x5916;&#x62D6;&#x52A8;&#x800C;&#x6253;&#x4E71;&#x5E03;&#x5C40;&#x4E4B;&#x7C7B;&#x7684;&#x8BEF;&#x64CD;&#x4F5C;&#x3002;</p>
<p>&#x4E0B;&#x56FE;&#x662F;&#x8868;&#x793A;&#x8D1F;&#x8F7D;&#x5747;&#x8861;&#x7ED3;&#x6784;&#x7684;&#x4E00;&#x4E2A;&#x7B80;&#x5355;&#x62D3;&#x6251;&#x56FE;&#xFF0C;&#x56FE;&#x4E2D;load balancer &#x8282;&#x70B9;&#x548C;web server&#x7684;&#x8282;&#x70B9;&#xFF0C;&#x662F;&#x7531;3&#x4E2A;&#x5143;&#x7D20;&#x7EC4;&#x6210;&#xFF1A;&#x201C;&#x4E3B;&#x673A;&#x201D;&#xFF0C;&#x201C;&#x56FE;&#x6807;&#x201D;&#x548C;&#x201C;&#x5706;&#x89D2;&#x77E9;&#x5F62;&#x201D;&#x3002;&#x901A;&#x5E38;&#x6211;&#x4EEC;&#x4F1A;&#x628A;&#x8FD9;&#x4E2A;&#x4E09;&#x4E2A;&#x5143;&#x7D20;&#x8FDB;&#x884C;&#x7EC4;&#x5408;&#xFF0C;&#x7136;&#x540E;&#x518D;&#x8FDE;&#x63A5;&#x7EBF;&#x7B49;&#x5176;&#x4ED6;&#x64CD;&#x4F5C;&#xFF0C;&#x8FD9;&#x6837;&#x4E00;&#x65E6;&#x8FD9;&#x4E2A;&#x62D3;&#x6251;&#x56FE;&#x8D8B;&#x4E8E;&#x590D;&#x6742;&#xFF0C;&#x800C;&#x53C8;&#x9700;&#x8981;&#x505A;&#x8C03;&#x6574;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x65B9;&#x4FBF;&#x5730;&#x9009;&#x4E2D;&#x76F8;&#x5173;&#x7684;&#x8282;&#x70B9;&#xFF0C;&#x4E0D;&#x81F3;&#x4E8E;&#x5143;&#x7D20;&#x6F0F;&#x9009;&#x6216;&#x9519;&#x9009;&#x800C;&#x5BFC;&#x81F4;&#x6574;&#x4E2A;&#x5E03;&#x5C40;&#x5931;&#x8D25;&#x3002;</p>
<center>
<p><img src="/content/images/2018/06/group.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
&#x64CD;&#x4F5C;&#x4E5F;&#x975E;&#x5E38;&#x7B80;&#x5355;&#xFF0C;&#x8FD9;&#x6837;&#x9009;&#x4E2D;&#x60F3;&#x8981;&#x7EC4;&#x5408;&#x7684;&#x5143;&#x7D20;&#xFF0C;&#x7136;&#x540E;&#x53F3;&#x952E;&#xFF08;&#x6216;&#x9009;&#x62E9;&#x5C4F;&#x5E55;&#x9876;&#x90E8;&#x7684;&#x5DE5;&#x5177;&#x680F;&#x4E2D;&#x7684;&#x201C;&#x6392;&#x5217;&#x201D;&#xFF09;&#xFF0C;&#x5E76;&#x9009;&#x62E9;&#x201C;&#x7EC4;&#x5408;&#x201D;&#xFF0C;&#x5373;&#x53EF;&#x5B8C;&#x6210;&#x3002;
<center>
<p><img src="/content/images/2018/06/g.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
<h3 id="36">3.6 &#x6846;&#x5185;&#x6587;&#x5B57;&#x5BF9;&#x9F50;</h3>
<p>&#x5728;&#x5F88;&#x591A;&#x6846;&#x56FE;&#x4E2D;&#xFF0C;&#x4E3A;&#x4E86;&#x8868;&#x793A;&#x4E00;&#x4E2A;&#x96C6;&#x5408;&#x7684;&#x6982;&#x5FF5;&#xFF0C;&#x901A;&#x5E38;&#x4F1A;&#x5728;&#x8868;&#x793A;&#x7236;&#x5143;&#x7D20;&#x7684;&#x6846;&#x5185;&#x6807;&#x6CE8;&#x4E0A;&#x96C6;&#x5408;&#x7684;&#x540D;&#x5B57;&#xFF0C;&#x4E0B;&#x56FE;&#x6240;&#x793A;&#x7684;&#x662F;spring&#x6846;&#x67B6;&#x5185;&#x6838;&#x5BB9;&#x5668;&#x7684;&#x7EC4;&#x6210;&#x3002;&#x4E00;&#x822C;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x7236;&#x5143;&#x7D20;&#x5185;&#x7684;&#x6807;&#x6CE8;&#x6587;&#x5B57;&#x4F1A;&#x4F7F;&#x7528;&#x201C;&#x9876;&#x7AEF;&#x5BF9;&#x9F50;&#x201D;&#x7684;&#x65B9;&#x5F0F;&#xFF0C;&#x800C;&#x5B50;&#x5143;&#x7D20;&#x5219;&#x662F;&#x5C45;&#x4E2D;&#xFF0C;&#x8FD9;&#x4E5F;&#x662F;&#x6846;&#x5185;&#x6587;&#x5B57;&#x9ED8;&#x8BA4;&#x7684;&#x5BF9;&#x9F50;&#x65B9;&#x5F0F;&#x3002;</p>
<center>
<p><img src="/content/images/2018/06/spring.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
<p>&#x64CD;&#x4F5C;&#x65F6;&#xFF0C;&#x5148;&#x9009;&#x4E2D;&#x5143;&#x7D20;&#xFF0C;&#x7136;&#x540E;&#x6253;&#x5F00;&#x5C4F;&#x5E55;&#x4E0A;&#x65B9;&#x5DE5;&#x5177;&#x680F;&#x4E2D;&#x7684;&#x201C;&#x5BF9;&#x9F50;&#x201D;&#x83DC;&#x5355;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x9009;&#x62E9;&#x76F8;&#x5E94;&#x7684;&#x5BF9;&#x9F50;&#x65B9;&#x5F0F;&#x3002;</p>
<center>
<p><img src="/content/images/2018/06/-----2.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
&#x5176;&#x4E2D;&#x7B2C;&#x4E00;&#x6392;&#x8868;&#x793A;&#x6C34;&#x5E73;&#x65B9;&#x5411;&#x7684;&#x5BF9;&#x9F50;&#x65B9;&#x5F0F;&#xFF0C;&#x4ECE;&#x5DE6;&#x5F80;&#x53F3;&#x4F9D;&#x6B21;&#x662F;&#xFF1A;&#x5DE6;&#x5BF9;&#x9F50;&#xFF0C;&#x6C34;&#x5E73;&#x5C45;&#x4E2D;&#x5BF9;&#x9F50;&#xFF0C;&#x53F3;&#x5BF9;&#x9F50;&#xFF1B;&#x7B2C;&#x4E8C;&#x6392;&#x8868;&#x793A;&#x5782;&#x76F4;&#x65B9;&#x5411;&#x7684;&#x5BF9;&#x9F50;&#x65B9;&#x5F0F;&#xFF0C;&#x4ECE;&#x5DE6;&#x5F80;&#x53F3;&#x4F9D;&#x6B21;&#x662F;&#xFF1A;&#x9876;&#x7AEF;&#x5BF9;&#x9F50;&#xFF0C;&#x5782;&#x76F4;&#x5C45;&#x4E2D;&#x5BF9;&#x9F50;&#xFF0C;&#x5E95;&#x7AEF;&#x5BF9;&#x9F50;&#x3002;
<h3 id="37">3.7 &#x5FEB;&#x6377;&#x952E;</h3>
<p>&#x70B9;&#x51FB;&#x5C4F;&#x5E55;&#x9876;&#x90E8;&#x7684;&#x5DE5;&#x5177;&#x680F;&#x4E2D;&#x7684;&#x201C;&#x5E2E;&#x52A9;&#x201D;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x67E5;&#x770B;Processon&#x76EE;&#x524D;&#x652F;&#x6301;&#x7684;&#x5FEB;&#x6377;&#x952E;<br>
&#x5176;&#x4E2D;&#xFF0C;&#x9664;&#x4E86;Ctrl+C&#xFF0C;Ctrl+V&#xFF0C;Ctrl+A&#x7B49;&#x5E38;&#x7528;&#x7684;&#x5FEB;&#x6377;&#x952E;&#xFF0C;&#x6211;&#x4EEC;&#x4F1A;&#x7ECF;&#x5E38;&#x4F7F;&#x7528;Ctrl+D&#xFF0C;&#x8BE5;&#x5FEB;&#x6377;&#x952E;&#x76F8;&#x5F53;&#x4E8E;&#x6309;&#x4E86;&#x4E00;&#x6B21;Ctrl+C&#xFF0C;&#x518D;&#x6309;&#x4E00;&#x6B21;Ctrl+V&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x590D;&#x5236;&#x548C;&#x7C98;&#x8D34;&#x4E00;&#x952E;&#x5B8C;&#x6210;&#xFF0C;&#x5728;&#x590D;&#x5236;&#x591A;&#x4E2A;&#x5143;&#x7D20;&#x7684;&#x65F6;&#x5019;&#x975E;&#x5E38;&#x5B9E;&#x7528;&#xFF0C;&#x6548;&#x7387;&#x63D0;&#x5347;&#x4E00;&#x500D;&#x3002;<br>
&#x53E6;&#x5916;&#x7EC4;&#x5408;&#x529F;&#x80FD;Ctrl+G&#xFF0C;&#x63D2;&#x5165;&#x6587;&#x672C;T&#xFF0C;&#x63D2;&#x5165;&#x8FDE;&#x7EBF;L&#xFF0C;&#x7F6E;&#x4E8E;&#x9876;&#x5C42;Ctrl+]&#xFF0C;&#x7F6E;&#x4E8E;&#x5E95;&#x5C42;Ctrl+[&#xFF0C;&#x6309;&#x4F4F;Ctrl&#x7EA6;&#x675F;&#x6BD4;&#x4F8B;&#x8C03;&#x6574;&#x5927;&#x5C0F;&#x4E5F;&#x662F;&#x4F7F;&#x7528;&#x7387;&#x6781;&#x9AD8;&#x7684;&#x5FEB;&#x6377;&#x952E;&#x3002;<br>
&#x6211;&#x4EEC;&#x5728;&#x5B9E;&#x8DF5;&#x8FC7;&#x7A0B;&#xFF0C;&#x4E00;&#x5B9A;&#x8981;&#x591A;&#x4F7F;&#x7528;&#x5FEB;&#x6377;&#x952E;&#x6765;&#x63D0;&#x5347;&#x64CD;&#x4F5C;&#x6548;&#x7387;&#xFF0C;&#x4E0D;&#x8981;&#x5728;&#x5BF9;&#x9F50;&#x6392;&#x5217;&#xFF0C;&#x8C03;&#x6574;&#x5927;&#x5C0F;&#xFF0C;&#x62D6;&#x62FD;&#x5E03;&#x5C40;&#x7B49;&#x64CD;&#x4F5C;&#x4E0A;&#x6D6A;&#x8D39;&#x8FC7;&#x591A;&#x7684;&#x65F6;&#x95F4;&#x3002;</p>
<h3 id="38">3.8 &#x7EFC;&#x5408;&#x6848;&#x4F8B;</h3>
<p>&#x4E0B;&#x9762;&#x4ECB;&#x7ECD;&#x4E00;&#x4E2A;&#x7EFC;&#x5408;&#x6848;&#x4F8B;&#xFF0C;&#x6211;&#x4EEC;&#x5C06;&#x8FD0;&#x7528;&#x4E0A;&#x8FF0;&#x6280;&#x5DE7;&#xFF0C;&#x7ED8;&#x5236;Linux&#x4E2D;&#x7684;awk&#x6570;&#x636E;&#x5904;&#x7406;&#x6A21;&#x578B;&#x793A;&#x610F;&#x56FE;&#xFF0C;&#x5982;&#x4E0B;&#x56FE;&#x6240;&#x793A;&#x3002;&#x4E86;&#x89E3;awk&#x547D;&#x4EE4;&#x7684;&#x4EBA;&#x90FD;&#x77E5;&#x9053;&#xFF0C;awk&#x662F;&#x4EE5;&#x884C;&#x4E3A;&#x5355;&#x4F4D;&#x5904;&#x7406;&#x6570;&#x636E;&#x7684;&#xFF0C;&#x5E76;&#x4E14;&#x53EF;&#x4EE5;&#x6309;&#x7167;&#x6307;&#x5B9A;&#x7684;&#x5206;&#x9694;&#x7B26;&#xFF0C;&#x5C06;&#x6570;&#x636E;&#x5207;&#x5272;&#x6210;&#x591A;&#x5217;&#xFF0C;&#x5176;&#x4E2D;RS&#x4E3A;&#x884C;&#x5206;&#x9694;&#x7B26;&#xFF0C;FS&#x4E3A;&#x5217;&#xFF0C;$+&#x6570;&#x5B57;&#x8868;&#x793A;&#x53D6;&#x5217;&#x3002;</p>
<center>
<p><img src="/content/images/2018/06/awk.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
&#x4E0B;&#x9762;&#x5217;&#x4E3E;&#x51E0;&#x4E2A;&#x91CD;&#x8981;&#x7684;&#x64CD;&#x4F5C;&#x6B65;&#x9AA4;&#xFF1A;
<ul>
<li>&#x7ED8;&#x5236;&#x8868;&#x793A;&#x884C;&#x7684;&#x6A2A;&#x5411;&#x77E9;&#x5F62;<br>
&#x9996;&#x5148;&#x521B;&#x5EFA;5&#x4E2A;&#x77E9;&#x5F62;&#xFF0C;&#x4F7F;&#x7528;&#x590D;&#x7528;&#x5FEB;&#x6377;&#x952E;Ctrl+D&#xFF0C;&#x7136;&#x540E;&#x5168;&#x9009;&#x5B8C;&#x6210;&#x5BF9;&#x9F50;&#x64CD;&#x4F5C;&#xFF0C;&#x63A5;&#x7740;&#x5C06;&#x6700;&#x4E0B;&#x65B9;&#x7684;&#x77E9;&#x5F62;&#xFF0C;&#x62D6;&#x52A8;&#x5230;&#x5408;&#x9002;&#x7684;&#x4F4D;&#x7F6E;&#xFF0C;&#x6700;&#x540E;&#x4F7F;&#x7528;&#x201C;&#x5782;&#x76F4;&#x5E73;&#x5747;&#x5206;&#x5E03;&#x201D;&#x529F;&#x80FD;&#xFF0C;&#x5B8C;&#x6210;&#x3002;<br>
<img src="/content/images/2018/06/1.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></li>
<li>&#x7ED8;&#x5236;&#x8868;&#x793A;&#x5217;&#x7684;&#x5782;&#x76F4;&#x77E9;&#x5F62;<br>
<img src="/content/images/2018/06/awkfs.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></li>
<li>&#x5C06;&#x884C;&#x7F6E;&#x4E8E;&#x5217;&#x4E4B;&#x4E0A;&#xFF0C;&#x4F7F;&#x7528;&#x201C;&#x7F6E;&#x4E8E;&#x5E95;&#x5C42;&#x201D;&#x7684;&#x529F;&#x80FD;&#xFF0C;&#x8FD9;&#x91CC;&#x6700;&#x597D;&#x5C06;&#x5217;&#x7684;&#x5404;&#x4E2A;&#x77E9;&#x5F62;&#x8FDB;&#x884C;&#x5206;&#x7EC4;&#x3002;&#x8FD9;&#x6837;&#xFF0C;&#x5982;&#x679C;&#x89C9;&#x5F97;&#x5E03;&#x5C40;&#x4E0D;&#x662F;&#x7279;&#x522B;&#x5408;&#x9002;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x6BD4;&#x8F83;&#x65B9;&#x4FBF;&#x5730;&#x91CD;&#x65B0;&#x8FDB;&#x884C;&#x6C34;&#x5E73;&#x5206;&#x5E03;&#x3002;</li>
</ul>
<center>
<p><img src="/content/images/2018/06/awk1.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
<ul>
<li>&#x6700;&#x540E;&#x5B8C;&#x6210;&#xFF1A;
<ul>
<li>&#x6807;&#x6CE8;&#x6587;&#x5B57;&#x8BF4;&#x660E;&#xFF0C;&#x5C3D;&#x91CF;&#x4F7F;&#x7528;Ctrl+D&#x8FDB;&#x884C;&#x5143;&#x7D20;&#x7684;&#x590D;&#x7528;</li>
<li>&#x8C03;&#x6574;&#x884C;&#x77E9;&#x5F62;&#x7684;&#x900F;&#x660E;&#x5EA6;</li>
<li>&#x5217;&#x77E9;&#x5F62;&#x4E2D;&#x7684;&#x6587;&#x5B57;&#x4F7F;&#x7528;&#x201C;&#x9876;&#x7AEF;&#x5BF9;&#x9F50;&#x201D;&#x5373;&#x53EF;</li>
</ul>
</li>
</ul>
<center>
<p><img src="/content/images/2018/06/awk.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
## &#x56DB;&#x3001;&#x89C4;&#x8303;&#x5EFA;&#x8BAE;
### 4.1 &#x5927;&#x5C0F;
&#x5728;&#x9ED8;&#x8BA4;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;processon&#x7684;&#x753B;&#x7EB8;&#x6BD4;A4&#x7565;&#x5927;&#xFF0C;&#x5373;1250px*1550px&#xFF0C;&#x4E0D;&#x8FC7;&#x4E5F;&#x53EF;&#x4EE5;&#x6309;&#x7167;&#x9700;&#x8981;&#x8FDB;&#x884C;&#x8C03;&#x6574;&#x3002;&#x5728;&#x7ED8;&#x56FE;&#x65F6;&#xFF0C;&#x6240;&#x6709;&#x7684;&#x5143;&#x7D20;&#x5E94;&#x5F53;&#x5C3D;&#x91CF;&#x5E03;&#x5C40;&#x5728;&#x4E00;&#x5F20;&#x753B;&#x7EB8;&#x4E0A;&#xFF0C;&#x8FD9;&#x6837;&#x7F6E;&#x4E8E;A4&#x5927;&#x5C0F;&#x7684;&#x6587;&#x6863;&#x6216;&#x8005;&#x5BBD;&#x5EA6;&#x4E3A;1000px&#x5DE6;&#x53F3;&#x7684;&#x7F51;&#x9875;&#xFF0C;&#x4E0D;&#x4F1A;&#x663E;&#x5F97;&#x7279;&#x522B;&#x7A81;&#x5140;&#xFF0C;&#x5C3A;&#x5BF8;&#x8FC7;&#x5927;&#xFF0C;&#x4F1A;&#x5BFC;&#x81F4;&#x6574;&#x4F53;&#x6BD4;&#x4F8B;&#x7F29;&#x5C0F;&#x4E4B;&#x540E;&#xFF0C;&#x5C40;&#x90E8;&#x5143;&#x7D20;&#x663E;&#x5F97;&#x8FC7;&#x5C0F;&#xFF0C;&#x770B;&#x4E0D;&#x6E05;&#x695A;&#x3002;
<p>&#x53E6;&#x5916;&#xFF0C;&#x6211;&#x4EEC;&#x5728;&#x751F;&#x6210;&#x76F8;&#x540C;&#x5143;&#x7D20;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x5C3D;&#x91CF;&#x5148;&#x624B;&#x52A8;&#x5730;&#x914D;&#x7F6E;&#x5927;&#x5C0F;&#xFF0C;&#x5E76;&#x4E14;&#x8FD9;&#x4E2A;&#x5927;&#x5C0F;&#x662F;&#x4F60;&#x8BB0;&#x5F97;&#x4F4F;&#x7684;&#xFF0C;&#x7136;&#x540E;&#x4F7F;&#x7528;Ctrl+D&#x8FDB;&#x884C;&#x590D;&#x7528;&#xFF0C;&#x90A3;&#x4E48;&#x5F53;&#x67D0;&#x4E00;&#x4E2A;&#x5143;&#x7D20;&#x88AB;&#x8BEF;&#x62D6;&#x62FD;&#x800C;&#x5BFC;&#x81F4;&#x5927;&#x5C0F;&#x53D1;&#x751F;&#x4E86;&#x53D8;&#x5316;&#x4E4B;&#x540E;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x8FC5;&#x901F;&#x5730;&#x8C03;&#x6574;&#x56DE;&#x6765;&#xFF0C;&#x53E6;&#x5916;&#xFF0C;&#x5982;&#x679C;&#x5728;&#x540E;&#x671F;&#x8FD8;&#x60F3;&#x6DFB;&#x52A0;&#x4E00;&#x4E2A;&#x76F8;&#x540C;&#x5143;&#x7D20;&#xFF0C;&#x90A3;&#x4E48;&#x4E5F;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x914D;&#x7F6E;&#x5BF9;&#x5E94;&#x7684;&#x5927;&#x5C0F;&#x3002;&#x7B80;&#x8A00;&#x4E4B;&#xFF0C;&#x914D;&#x7F6E;&#x5143;&#x7D20;&#x7684;&#x5927;&#x5C0F;&#xFF0C;&#x4F7F;&#x7528;&#x4E00;&#x4E2A;&#x4F60;&#x53EF;&#x4EE5;&#x8BB0;&#x4F4F;&#x7684;&#x6570;&#x503C;&#xFF0C;&#x4ECE;&#x800C;&#x63D0;&#x9AD8;&#x5DE5;&#x4F5C;&#x6548;&#x7387;&#x3002;</p>
<h3 id="42">4.2 &#x5B57;&#x4F53;</h3>
<p>&#x5148;&#x6765;&#x4ECB;&#x7ECD;&#x4E00;&#x4E9B;&#x5173;&#x4E8E;&#x5B57;&#x4F53;&#x7684;&#x80CC;&#x666F;&#x77E5;&#x8BC6;&#xFF1A;</p>
<ul>
<li>&#x901A;&#x5E38;&#xFF0C;&#x5B57;&#x4F53;&#x53EF;&#x4EE5;&#x5206;&#x4E3A;&#x886C;&#x7EBF;&#x4F53;&#x548C;&#x65E0;&#x886C;&#x7EBF;&#x4F53;&#xFF0C;&#x719F;&#x6089;CSS&#x7684;&#x540C;&#x5B66;&#x4E00;&#x5B9A;&#x77E5;&#x9053;&#x8BBE;&#x7F6E;&#x5B57;&#x4F53;&#x65F6;&#x6709;san-serif&#x5C5E;&#x6027;&#xFF0C;san-serif&#x5373;&#x65E0;&#x886C;&#x7EBF;&#x4F53;&#xFF0C;&#x8BCD;&#x6839;serif&#x5373;&#x886C;&#x7EBF;&#x7684;&#x610F;&#x601D;&#x3002;&#x6240;&#x8C13;&#x7684;&#x886C;&#x7EBF;&#xFF0C;&#x5C31;&#x662F;&#x5728;&#x6BCF;&#x4E2A;&#x5B57;&#x7B26;&#x7684;&#x8FB9;&#x7F18;&#x90E8;&#x5206;&#x6709;&#x4E00;&#x5B9A;&#x7684;&#x63CF;&#x8FB9;&#x4FEE;&#x9970;&#x3002;&#x4E3E;&#x4F8B;&#x6765;&#x8BF4;&#xFF0C;&#x4E2D;&#x6587;&#x5B57;&#x4F53;&#x4E2D;&#x7684;&#x201C;&#x5B8B;&#x4F53;&#x201D;&#xFF0C;&#x82F1;&#x6587;&#x5B57;&#x4F53;&#x4E2D;&#x7684;&#x201C;Times New Roma&#x201D;&#x5C31;&#x662F;&#x5178;&#x578B;&#x7684;&#x886C;&#x7EBF;&#x4F53;&#xFF0C;&#x800C;&#x4E2D;&#x6587;&#x5B57;&#x4F53;&#x4E2D;&#x7684;&#x201C;&#x9ED1;&#x4F53;&#x201D;&#xFF0C;&#x82F1;&#x6587;&#x5B57;&#x4F53;&#x4E2D;&#x7684;&#x201C;Arial&#x201D;&#x5C31;&#x662F;&#x5178;&#x578B;&#x7684;&#x65E0;&#x886C;&#x7EBF;&#x4F53;&#x3002;<br>
<img src="/content/images/2018/06/font.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></li>
<li>&#x6309;&#x7167;&#x5B57;&#x7B26;&#x7684;&#x5BBD;&#x5EA6;&#xFF0C;&#x8FD8;&#x53EF;&#x4EE5;&#x5C06;&#x5B57;&#x4F53;&#x5206;&#x4E3A;&#x7B49;&#x5BBD;&#x5B57;&#x4F53;&#x548C;&#x975E;&#x7B49;&#x5BBD;&#x5B57;&#x4F53;&#xFF0C;&#x987E;&#x540D;&#x601D;&#x4E49;&#xFF0C;&#x7B49;&#x5BBD;&#x5B57;&#x4F53;&#x4E5F;&#x5C31;&#x662F;&#x6BCF;&#x4E2A;&#x5B57;&#x7B26;&#x7684;&#x5BBD;&#x5EA6;&#x90FD;&#x76F8;&#x540C;&#x3002;&#x5728;IT&#x9886;&#x57DF;&#xFF0C;&#x4E00;&#x822C;&#x90FD;&#x503E;&#x5411;&#x4E8E;&#x4F7F;&#x7528;&#x7B49;&#x5BBD;&#x5B57;&#x4F53;&#xFF0C;&#x4F8B;&#x5982;&#x5FAE;&#x8F6F;&#x5F00;&#x53D1;&#x7684;Consolas&#x5B57;&#x4F53;&#x5C31;&#x662F;&#x5178;&#x578B;&#x7684;&#x7B49;&#x5BBD;&#x5B57;&#x4F53;&#xFF0C;&#x5B83;&#x88AB;&#x4F7F;&#x7528;&#x5728;windows&#x7684;&#x63A7;&#x5236;&#x53F0;&#x4E2D;&#xFF0C;&#x65B0;&#x7248;&#x672C;eclipse&#x9ED8;&#x8BA4;&#x4E5F;&#x4F7F;&#x7528;&#x8BE5;&#x5B57;&#x4F53;&#xFF08;&#x65E7;&#x7248;&#x672C;&#x9ED8;&#x8BA4;&#x7684;&#x662F;Courier New&#x5B57;&#x4F53;&#xFF09;&#x3002;&#x4ECE;&#x4E0B;&#x9762;&#x7684;&#x5BF9;&#x6BD4;&#x4E2D;&#xFF0C;&#x53EF;&#x4EE5;&#x5F88;&#x6E05;&#x695A;&#x5730;&#x770B;&#x5230;&#x7B49;&#x5BBD;&#x5B57;&#x4F53;&#x548C;&#x975E;&#x7B49;&#x5BBD;&#x5B57;&#x4F53;&#x7684;&#x5DEE;&#x522B;&#x3002;<br>
<img src="/content/images/2018/06/monospace.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"><br>
&#x4E00;&#x822C;&#x6765;&#x8BF4;&#xFF0C;&#x7531;&#x4E8E;&#x886C;&#x7EBF;&#x4F53;&#x5177;&#x6709;&#x7B14;&#x753B;&#x4E0A;&#x7684;&#x4FEE;&#x9970;&#xFF0C;&#x4F7F;&#x5F97;&#x611F;&#x5B98;&#x4E0A;&#x5B57;&#x7B26;&#x4E4B;&#x95F4;&#x6709;&#x4E00;&#x5B9A;&#x7684;&#x8FDE;&#x7EED;&#x6027;&#xFF0C;&#x8FD9;&#x6837;&#x5BF9;&#x4E8E;&#x5927;&#x6BB5;&#x7684;&#x6587;&#x5B57;&#x5C31;&#x6BD4;&#x8F83;&#x65B9;&#x4FBF;&#x6A2A;&#x5411;&#x9605;&#x8BFB;&#xFF0C;&#x8FD9;&#x4E5F;&#x5C31;&#x662F;&#x6211;&#x4EEC;&#x7684;&#x8BFE;&#x672C;&#xFF0C;&#x62A5;&#x7EB8;&#x7B49;&#x8BFB;&#x7269;&#x4F7F;&#x7528;&#x5B8B;&#x4F53;&#x8FDB;&#x884C;&#x5370;&#x5237;&#x7684;&#x539F;&#x56E0;&#x4E4B;&#x4E00;&#xFF0C;&#x800C;&#x65E0;&#x886C;&#x7EBF;&#x4F53;&#x66F4;&#x7B26;&#x5408;&#x73B0;&#x4EE3;&#x7F8E;&#x5B66;&#x4ECE;&#x7B80;&#x7684;&#x89C2;&#x5FF5;&#xFF0C;&#x4E5F;&#x6BD4;&#x8F83;&#x9002;&#x5408;&#x4F5C;&#x4E3A;&#x6807;&#x8BED;&#x6765;&#x5370;&#x5237;&#xFF0C;&#x4F8B;&#x5982;&#x6302;&#x7740;&#x7684;&#x5927;&#x7EA2;&#x6A2A;&#x5E45;&#x901A;&#x5E38;&#x5C31;&#x662F;&#x7528;&#x9ED1;&#x4F53;&#x6765;&#x5370;&#x5237;&#x7684;&#x3002;</li>
</ul>
<p>&#x6211;&#x4EEC;&#x5728;&#x7ED8;&#x56FE;&#x7684;&#x8FC7;&#x7A0B;&#x4E2D;&#xFF0C;&#x5E76;&#x4E0D;&#x9700;&#x8981;&#x5927;&#x6BB5;&#x7684;&#x6587;&#x5B57;&#xFF0C;&#x56E0;&#x6B64;&#x5EFA;&#x8BAE;&#x5C3D;&#x91CF;&#x4F7F;&#x7528;&#x540C;&#x4E00;&#x79CD;&#x65E0;&#x886C;&#x7EBF;&#x4F53;&#xFF0C;&#x5E76;&#x4E14;&#x9664;&#x4E86;&#x6807;&#x9898;&#x90E8;&#x5206;&#x7B49;&#x8FDB;&#x884C;&#x7279;&#x6B8A;&#x5927;&#x5C0F;&#x5904;&#x7406;&#x7684;&#x5B57;&#x4F53;&#xFF0C;&#x5176;&#x4ED6;&#x5143;&#x7D20;&#x7684;&#x6587;&#x5B57;&#x90FD;&#x7EDF;&#x4E00;&#x5B57;&#x53F7;&#x3002;&#x5728;processon&#x63D0;&#x4F9B;&#x7684;&#x5B57;&#x4F53;&#x4E2D;&#xFF0C;&#x7B14;&#x8005;&#x5EFA;&#x8BAE;&#x7EDF;&#x4E00;&#x4F7F;&#x7528;&#x201C;&#x5FAE;&#x8F6F;&#x96C5;&#x9ED1;&#x201D;&#x5B57;&#x4F53;&#xFF0C;&#x5B57;&#x53F7;&#x5927;&#x5C0F;&#x4E3A;14px&#xFF0C;&#x5E76;&#x4E14;&#x52A0;&#x7C97;&#x3002;&#x8FD9;&#x6837;&#x53EF;&#x4EE5;&#x4F7F;&#x5F97;&#x5BFC;&#x51FA;&#x7684;&#x56FE;&#x7247;&#xFF0C;&#x7C98;&#x8D34;&#x5728;word&#x7B49;&#x6587;&#x6863;&#x4E2D;&#x65F6;&#x663E;&#x5F97;&#x6BD4;&#x8F83;&#x548C;&#x8C10;&#x3002;</p>
<p>&#x5982;&#x679C;&#x6211;&#x4EEC;&#x8981;&#x5728;&#x56FE;&#x4E2D;&#x5F15;&#x5165;&#x4EE3;&#x7801;&#x6216;&#x914D;&#x7F6E;&#x6587;&#x4EF6;&#x7B49;&#x4E13;&#x4E1A;&#x6027;&#x7684;&#x5185;&#x5BB9;&#xFF0C;&#x5219;&#x5C3D;&#x91CF;&#x4F7F;&#x7528;&#x7B49;&#x5BBD;&#x5B57;&#x4F53;&#xFF0C;&#x4EE5;&#x4FDD;&#x8BC1;&#x5185;&#x5BB9;&#x6392;&#x7248;&#x7684;&#x6574;&#x9F50;&#x6027;&#xFF0C;&#x8FD9;&#x91CC;&#x5EFA;&#x8BAE;&#x4F7F;&#x7528;Lucida Console&#xFF0C;&#x56E0;&#x4E3A;&#x5B83;&#x65E2;&#x662F;&#x7B49;&#x5BBD;&#x5B57;&#x4F53;&#xFF0C;&#x53C8;&#x662F;&#x65E0;&#x886C;&#x7EBF;&#x5B57;&#x4F53;&#x3002;</p>
<h3 id="43">4.3 &#x914D;&#x8272;</h3>
<p>&#x6BD5;&#x7ADF;&#x7B14;&#x8005;&#x4E0D;&#x662F;&#x5B66;&#x8BBE;&#x8BA1;&#x6216;&#x7F8E;&#x672F;&#x51FA;&#x8EAB;&#xFF0C;&#x8C08;&#x4E0D;&#x4E0A;&#x4E13;&#x4E1A;&#x89D2;&#x5EA6;&#x7684;&#x7F8E;&#x5B66;&#x914D;&#x8272;&#x65B9;&#x6848;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x5F15;&#x7528;&#x7F51;&#x7EDC;&#x4E0A;&#x4E00;&#x7BC7;&#x5173;&#x4E8E;&#x4E2D;&#x56FD;&#x8857;&#x5934;&#x5E7F;&#x544A;&#x724C;&#x8BBE;&#x8BA1;&#x7684;&#x6587;&#x7AE0;&#xFF0C;&#x4EE5;&#x6B64;&#x501F;&#x9274;&#x5BF9;&#x989C;&#x8272;&#x7684;&#x8FD0;&#x7528;&#x65B9;&#x6CD5;</p>
<center>
<blockquote>
<p><img src="/content/images/2018/06/cqfd-300x242.jpg" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"><br>
&#x7D20;&#x6750;&#x6765;&#x6E90;&#x5FAE;&#x535A;&#x300A;<a href="http://weibo.com/ttarticle/p/show?id=2309403993629365534797">&#x4E2D;&#x56FD;&#x7684;&#x62DB;&#x724C;&#x4E3A;&#x4EC0;&#x4E48;&#x8FD9;&#x4E48;&#x4E11;&#xFF5C;&#x5927;&#x8C61;&#x516C;&#x4F1A;</a>&#x300B;</p>
</blockquote>
</center>
&#x4E0A;&#x56FE;&#x5C31;&#x662F;&#x5145;&#x65A5;&#x5404;&#x4E2A;&#x57CE;&#x5E02;&#x8857;&#x5934;&#x7684;&#x5E7F;&#x544A;&#x724C;&#xFF0C;&#x9AD8;&#x7EAF;&#x5EA6;&#x7684;&#x5927;&#x7EA2;&#x8272;&#x80CC;&#x666F;&#xFF0C;&#x9AD8;&#x7EAF;&#x5EA6;&#x989C;&#x8272;&#x7684;&#x5B57;&#x4F53;&#xFF0C;&#x4E14;&#x6CA1;&#x6709;&#x5145;&#x5206;&#x7559;&#x767D;&#xFF0C;&#x4E0D;&#x540C;&#x7684;&#x8272;&#x5F69;&#x5360;&#x636E;&#x76F8;&#x4F3C;&#x7684;&#x9762;&#x79EF;&#xFF0C;&#x76F8;&#x6BD4;&#x4E4B;&#x4E0B;&#xFF0C;&#x4E0B;&#x56FE;&#x7684;&#x6392;&#x7248;&#x91C7;&#x7528;&#x7684;&#x662F;&#x4F4E;&#x7EAF;&#x5EA6;&#x7684;&#x6697;&#x8272;&#xFF0C;&#x4EE5;&#x53CA;&#x5145;&#x5206;&#x7684;&#x7559;&#x767D;&#xFF0C;&#x6863;&#x6B21;&#x660E;&#x663E;&#x9AD8;&#x4E86;&#x5F88;&#x591A;&#xFF0C;&#x8FD9;&#x5C31;&#x662F;&#x901A;&#x5E38;&#x8BB2;&#x7684;&#x201C;&#x7D20;&#x8272;&#x5BA1;&#x7F8E;&#x201D;&#xFF0C;&#x6709;&#x65F6;&#x5019;&#x6211;&#x4EEC;&#x4F1A;&#x79F0;&#x4E4B;&#x4E3A;&#x201C;&#x5C0F;&#x6E05;&#x65B0;&#x201D;&#xFF0C;&#x7C7B;&#x4F3C;&#x4E8E;&#x5B9C;&#x5BB6;&#x7ED9;&#x4EBA;&#x4EEC;&#x7684;&#x5370;&#x8C61;&#x3002;
<p>&#x7ED8;&#x56FE;&#x4E2D;&#x4F7F;&#x7528;&#x989C;&#x8272;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x5EFA;&#x8BAE;&#x4E0D;&#x8981;&#x8FC7;&#x4E8E;&#x8FFD;&#x6C42;&#x9AD8;&#x9971;&#x548C;&#x5EA6;&#x548C;&#x9C9C;&#x8273;&#x7684;&#x8272;&#x5F69;&#xFF0C;&#x800C;&#x662F;&#x91C7;&#x7528;&#x4F4E;&#x7EAF;&#x5EA6;&#x548C;&#x5145;&#x5206;&#x7684;&#x7559;&#x767D;&#x3002;&#x8FD9;&#x4E00;&#x70B9;&#xFF0C;processon&#x7684;&#x8C03;&#x8272;&#x677F;&#x4E5F;&#x7ED9;&#x51FA;&#x975E;&#x5E38;&#x597D;&#x7684;&#x793A;&#x8303;&#x3002;</p>
<center>
<p><img src="/content/images/2018/06/webcolor.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
### 4.4 &#x6700;&#x5C0F;&#x5316;&#x539F;&#x5219;
&#x5728;&#x8FD0;&#x7EF4;&#x7684;&#x5DE5;&#x4F5C;&#x4E2D;&#xFF0C;&#x6709;&#x4E00;&#x4E2A;&#x91CD;&#x8981;&#x7684;&#x6307;&#x5BFC;&#x601D;&#x60F3;&#xFF0C;&#x5373;&#x201C;&#x6700;&#x5C0F;&#x5316;&#x539F;&#x5219;&#x201D;&#xFF0C;&#x4F8B;&#x5982;&#x6700;&#x5C0F;&#x5316;&#x5B89;&#x88C5;&#x64CD;&#x4F5C;&#x7CFB;&#x7EDF;&#xFF0C;&#x6700;&#x5C0F;&#x5316;&#x542F;&#x52A8;&#x670D;&#x52A1;&#xFF0C;&#x6700;&#x5C0F;&#x5316;&#x5B89;&#x5168;&#x6743;&#x9650;&#x7B49;&#x7B49;&#x3002;&#x540C;&#x6837;&#xFF0C;&#x6211;&#x4EEC;&#x4E5F;&#x53EF;&#x4EE5;&#x628A;&#x8FD9;&#x4E2A;&#x601D;&#x60F3;&#x5F15;&#x5165;&#x5230;&#x7ED8;&#x56FE;&#x7684;&#x5B9E;&#x8DF5;&#x4E2D;&#x6765;&#xFF0C;&#x4E3B;&#x8981;&#x4F53;&#x73B0;&#x5728;&#x4E00;&#x4E0B;&#x51E0;&#x70B9;&#xFF1A;
<ul>
<li>&#x4E00;&#x4E2A;&#x65B9;&#x5757;&#xFF0C;&#x9664;&#x4E86;&#x5305;&#x542B;&#x6587;&#x5B57;&#x548C;&#x8DB3;&#x591F;&#x7559;&#x767D;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x5E94;&#x8BE5;&#x4FDD;&#x6301;&#x5728;&#x6700;&#x5C0F;&#x7684;&#x5C3A;&#x5BF8;&#xFF0C;&#x800C;&#x4E0D;&#x5E94;&#x8BE5;&#x6BEB;&#x65E0;&#x903B;&#x8F91;&#x5730;&#x6269;&#x5927;&#xFF0C;&#x5EFA;&#x8BAE;&#x56DB;&#x4E2A;&#x65B9;&#x5411;&#x4E0A;&#x7684;&#x7559;&#x767D;&#x5927;&#x7EA6;&#x4FDD;&#x6301;&#x5728;5px&#x5DE6;&#x53F3;&#xFF1B;</li>
<li>&#x5143;&#x7D20;&#x4E4B;&#x95F4;&#x8FDE;&#x7EBF;&#xFF0C;&#x9664;&#x4E86;&#x5728;&#x8FDE;&#x7EED;&#x4E0A;&#x6807;&#x6CE8;&#x8DB3;&#x591F;&#x7684;&#x6587;&#x5B57;&#xFF0C;&#x5C31;&#x5E94;&#x8BE5;&#x4FDD;&#x6301;&#x7684;&#x5728;&#x6700;&#x77ED;&#x7684;&#x957F;&#x5EA6;&#xFF1B;</li>
<li>&#x76F8;&#x90BB;&#x7684;&#x5143;&#x7D20;&#x4E4B;&#x95F4;&#xFF0C;&#x4E5F;&#x5E94;&#x8BE5;&#x4FDD;&#x6301;&#x5728;&#x6700;&#x5C0F;&#x7684;&#x95F4;&#x9694;&#x4E4B;&#x5185;&#xFF0C;&#x4E0D;&#x5E94;&#x8BE5;&#x8FC7;&#x5927;&#xFF0C;&#x5927;&#x7EA6;&#x5728;5px-20px&#x4E4B;&#x95F4;&#xFF1B;</li>
<li>&#x6574;&#x4F53;&#x6BD4;&#x4F8B;&#x4FDD;&#x6301;&#x5728;&#x6700;&#x5C0F;&#xFF0C;&#x4E0D;&#x5E94;&#x8BE5;&#x7559;&#x6709;&#x5927;&#x9762;&#x79EF;&#x7684;&#x7A7A;&#x767D;&#xFF0C;&#x4F46;&#x4E5F;&#x4E0D;&#x5E94;&#x8FC7;&#x4E8E;&#x62E5;&#x6324;&#xFF0C;&#x7559;&#x6709;&#x9002;&#x5F53;&#x7A7A;&#x95F4;&#xFF0C;&#x53EF;&#x4EE5;&#x8BA9;&#x6574;&#x4F53;&#x5177;&#x6709;&#x547C;&#x5438;&#x5C5E;&#x6027;&#xFF0C;&#x4E0D;&#x4F1A;&#x8BA9;&#x4EBA;&#x89C9;&#x5F97;&#x201C;&#x5BC6;&#x4E0D;&#x900F;&#x98CE;&#x201D;&#xFF1B;</li>
</ul>
<h2 id>&#x4E94;&#x3001;&#x5B9E;&#x6218;</h2>
<p>&#x56E0;&#x4E3A;IT&#x7EC6;&#x5206;&#x9886;&#x57DF;&#x5185;&#x6709;&#x7740;&#x975E;&#x5E38;&#x591A;&#x7684;&#x4E13;&#x4E1A;&#x56FE;&#x8868;&#xFF0C;&#x4F46;&#x7B14;&#x8005;&#x77E5;&#x8BC6;&#x8FB9;&#x754C;&#x6709;&#x9650;&#xFF0C;&#x6240;&#x4EE5;&#x4E0B;&#x9762;&#x7740;&#x91CD;&#x4ECB;&#x7ECD;&#x4E24;&#x79CD;&#x901A;&#x7528;&#x6027;&#x6BD4;&#x8F83;&#x9AD8;&#x7684;&#x56FE;&#xFF1A;&#x57FA;&#x672C;&#x6D41;&#x7A0B;&#x56FE;&#x548C;&#x7CFB;&#x7EDF;&#x62D3;&#x6251;&#x56FE;</p>
<h3 id="51">5.1 &#x57FA;&#x672C;&#x6D41;&#x7A0B;&#x56FE;</h3>
<p>&#x6709;&#x5173;&#x6D41;&#x7A0B;&#x56FE;&#x7684;&#x6982;&#x5FF5;&#xFF0C;&#x6700;&#x65E9;&#x662F;&#x5728;&#x8F6F;&#x4EF6;&#x5DE5;&#x7A0B;&#x4E2D;&#x63A5;&#x89E6;&#x5230;&#x7684;&#x7A0B;&#x5E8F;&#x6D41;&#x7A0B;&#x56FE;&#xFF0C;&#x65E9;&#x671F;&#xFF0C;&#x6D41;&#x7A0B;&#x56FE;&#x76EE;&#x7684;&#x5C31;&#x662F;&#x63CF;&#x8FF0;&#x7A0B;&#x5E8F;&#x7684;&#x6267;&#x884C;&#x8FC7;&#x7A0B;&#xFF0C;&#x4E00;&#x76F4;&#x4EE5;&#x6765;&#x5C31;&#x662F;&#x8F6F;&#x4EF6;&#x8BBE;&#x8BA1;&#x7684;&#x91CD;&#x8981;&#x5DE5;&#x5177;&#xFF0C;&#x968F;&#x7740;&#x4F7F;&#x7528;&#x8005;&#x589E;&#x591A;&#xFF0C;&#x6D41;&#x7A0B;&#x56FE;&#x7684;&#x6982;&#x5FF5;&#x4E5F;&#x4E0D;&#x518D;&#x9650;&#x5236;&#x4E8E;&#x8F6F;&#x4EF6;&#x8BBE;&#x8BA1;&#xFF0C;&#x53EA;&#x8981;&#x6D89;&#x53CA;&#x6709;&#x5173;&#x6D41;&#x7A0B;&#x7684;&#x4EFB;&#x4F55;&#x573A;&#x666F;&#xFF0C;&#x6211;&#x4EEC;&#x90FD;&#x53EF;&#x4EE5;&#x7528;&#x6D41;&#x7A0B;&#x56FE;&#x6765;&#x8868;&#x793A;&#x3002;</p>
<p>&#x8FD9;&#x91CC;&#x6240;&#x8C13;&#x7684;&#x57FA;&#x672C;&#x6D41;&#x7A0B;&#x56FE;&#xFF0C;&#x662F;&#x76F8;&#x5BF9;&#x4E8E;&#x5176;&#x4ED6;&#x6D41;&#x7A0B;&#x56FE;&#x6765;&#x8BF4;&#x7684;&#x3002;&#x8FD9;&#x91CC;&#x7B80;&#x5355;&#x4ECB;&#x7ECD;&#x4E00;&#x4E0B;&#x6CF3;&#x9053;&#x56FE;&#xFF0C;&#x4E0B;&#x56FE;&#x6240;&#x793A;&#xFF0C;&#x6CF3;&#x9053;&#x56FE;&#x5305;&#x542B;&#x4E86;&#x6D41;&#x7A0B;&#x4E2D;&#x6BCF;&#x4E00;&#x4E2A;&#x6B65;&#x9AA4;&#x5BF9;&#x5E94;&#x7684;&#x76F8;&#x5173;&#x5355;&#x4F4D;&#xFF0C;&#x5176;&#x4E2D;&#x5355;&#x4F4D;&#x53EF;&#x4EE5;&#x662F;&#x90E8;&#x95E8;&#xFF0C;&#x4E5F;&#x53EF;&#x4EE5;&#x662F;&#x804C;&#x4F4D;&#x7B49;&#xFF0C;&#x6CF3;&#x9053;&#x56FE;&#x53EF;&#x4EE5;&#x5F88;&#x597D;&#x5730;&#x8868;&#x73B0;&#x4E86;&#x4E00;&#x4E2A;&#x6D41;&#x7A0B;&#x4E2D;&#x4E0D;&#x540C;&#x7684;&#x804C;&#x80FD;&#x5206;&#x5DE5;&#xFF0C;&#x4EE5;&#x53CA;&#x534F;&#x4F5C;&#x7684;&#x903B;&#x8F91;&#x5173;&#x7CFB;&#xFF0C;&#x662F;&#x9879;&#x76EE;&#x7BA1;&#x7406;&#x8005;&#x5236;&#x5B9A;&#x9879;&#x76EE;&#x8BA1;&#x5212;&#x7684;&#x5E38;&#x7528;&#x5DE5;&#x5177;&#x3002;</p>
<center>
<p><img src="/content/images/2018/06/---.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
<h4 id="511">5.1.1 &#x5E38;&#x7528;&#x7B26;&#x53F7;</h4>
<p>&#x4E0B;&#x9762;&#x6574;&#x7406;&#x4E86;&#x57FA;&#x672C;&#x6D41;&#x7A0B;&#x56FE;&#x5E38;&#x7528;&#x7684;&#x7B26;&#x53F7;&#x56FE;&#x793A;&#xFF0C;&#x638C;&#x63E1;&#x4EE5;&#x4E0B;10&#x4E2A;&#x8DB3;&#x591F;&#x5E94;&#x4ED8;99%&#x7684;&#x6D41;&#x7A0B;&#x56FE;&#xFF0C;&#x5176;&#x4E2D;&#x6700;&#x5E38;&#x7528;&#x4E5F;&#x5C31;&#x662F;&#x7B2C;&#x4E00;&#x884C;&#x7684;&#x7B26;&#x53F7;&#xFF1A;</p>
<ul>
<li>&#x5F00;&#x59CB;&#x548C;&#x7ED3;&#x675F;&#x7528;&#x5706;&#x5F27;&#x77E9;&#x5F62;&#x8868;&#x793A;</li>
<li>&#x5904;&#x7406;&#x8FC7;&#x7A0B;&#x7528;&#x77E9;&#x5F62;&#x8868;&#x793A;</li>
<li>&#x5206;&#x652F;&#x5224;&#x65AD;&#x7528;&#x83F1;&#x5F62;&#x8868;&#x793A;</li>
<li>&#x5143;&#x7D20;&#x4E4B;&#x95F4;&#x7528;&#x5E26;&#x7BAD;&#x5934;&#x7684;&#x7EBF;&#x8FDE;&#x63A5;</li>
</ul>
<center>
<p><img src="/content/images/2018/06/flow.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
<h4 id="512">5.1.2 &#x57FA;&#x672C;&#x7ED3;&#x6784;</h4>
<p>&#x4E86;&#x89E3;&#x4E86;&#x5E38;&#x7528;&#x7B26;&#x53F7;&#x4E4B;&#x540E;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x753B;&#x51FA;&#x6D41;&#x7A0B;&#x56FE;&#x4E2D;&#x7684;&#x4E09;&#x4E2A;&#x57FA;&#x672C;&#x7ED3;&#x6784;&#xFF0C;&#x5373;&#x987A;&#x5E8F;&#x7ED3;&#x6784;&#xFF0C;&#x5206;&#x652F;&#x7ED3;&#x6784;&#x548C;&#x5FAA;&#x73AF;&#x7ED3;&#x6784;&#xFF1A;</p>
<ul>
<li>&#x987A;&#x5E8F;&#x7ED3;&#x6784;&#xFF1A;&#x4E5F;&#x662F;&#x6700;&#x7B80;&#x5355;&#x7684;&#x7ED3;&#x6784;&#xFF0C;&#x5373;&#x6309;&#x7167;&#x4E8B;&#x52A1;&#x7684;&#x987A;&#x5E8F;&#x4F9D;&#x6B21;&#x6267;&#x884C;</li>
<li>&#x5206;&#x652F;&#x7ED3;&#x6784;&#xFF1A;&#x6D41;&#x7A0B;&#x4E2D;&#x4F1A;&#x8FDB;&#x884C;&#x6761;&#x4EF6;&#x7684;&#x5224;&#x65AD;&#xFF0C;&#x6839;&#x636E;&#x4E0D;&#x540C;&#x7684;&#x5224;&#x65AD;&#x7ED3;&#x679C;&#x91C7;&#x53D6;&#x4E0D;&#x540C;&#x7684;&#x5904;&#x7406;&#xFF0C;&#x4F8B;&#x5982;&#x542F;&#x52A8;&#x670D;&#x52A1;&#x65F6;&#xFF0C;&#x5148;&#x68C0;&#x67E5;pid&#x6587;&#x4EF6;&#x662F;&#x5426;&#x5B58;&#x5728;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x5B58;&#x5728;&#xFF0C;&#x5219;&#x542F;&#x52A8;&#x670D;&#x52A1;&#xFF0C;&#x5426;&#x5219;&#x62A5;&#x9519;</li>
<li>&#x5FAA;&#x73AF;&#x7ED3;&#x6784;&#xFF1A;&#x5F53;&#x6761;&#x4EF6;&#x4E0D;&#x88AB;&#x6EE1;&#x8DB3;&#x65F6;&#xFF0C;&#x91CD;&#x590D;&#x6267;&#x884C;&#x540C;&#x4E00;&#x4E2A;&#xFF08;&#x6216;&#x51E0;&#x4E2A;&#xFF09;&#x5904;&#x7406;&#xFF0C;&#x4F8B;&#x5982;&#x5E38;&#x4F1A;&#x88AB;&#x7528;&#x4E8E;&#x904D;&#x5386;&#x6570;&#x7EC4;&#x7B49;&#x64CD;&#x4F5C;</li>
</ul>
<center>
<p><img src="/content/images/2018/06/basic3.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
&#x4E8B;&#x5B9E;&#x4E0A;&#xFF0C;&#x6D41;&#x7A0B;&#x56FE;&#x5C31;&#x662F;&#x7531;&#x8FD9;&#x4E09;&#x79CD;&#x57FA;&#x672C;&#x7684;&#x7ED3;&#x6784;&#xFF0C;&#x6839;&#x636E;&#x5B9E;&#x9645;&#x4E1A;&#x52A1;&#x60C5;&#x51B5;&#xFF0C;&#x76F8;&#x4E92;&#x7EC4;&#x5408;&#x800C;&#x6210;&#x3002;&#x6211;&#x4EEC;&#x5728;&#x7ED8;&#x5236;&#x6D41;&#x7A0B;&#x56FE;&#xFF0C;&#x9996;&#x5148;&#x5C31;&#x662F;&#x8981;&#x786E;&#x5B9A;&#x6240;&#x8981;&#x63CF;&#x8FF0;&#x7684;&#x4E1A;&#x52A1;&#x5B9E;&#x9645;&#x7684;&#x6D41;&#x7A0B;&#x903B;&#x8F91;&#xFF0C;&#x7136;&#x540E;&#x63A8;&#x6572;&#x6BCF;&#x4E2A;&#x6B65;&#x9AA4;&#x7684;&#x6267;&#x884C;&#xFF0C;&#x662F;&#x5426;&#x5B58;&#x5728;&#x5206;&#x652F;&#x548C;&#x5FAA;&#x73AF;&#xFF0C;&#x76EE;&#x7684;&#x5C31;&#x662F;&#x8981;&#x9605;&#x8BFB;&#x6D41;&#x7A0B;&#x56FE;&#x7684;&#x4EBA;&#x4E00;&#x76EE;&#x4E86;&#x7136;&#xFF0C;&#x8FC5;&#x901F;&#x5730;&#x7406;&#x89E3;&#x6D41;&#x7A0B;&#x7684;&#x6BCF;&#x4E2A;&#x73AF;&#x8282;&#x3002;
<h4 id="513">5.1.3 &#x6D41;&#x7A0B;&#x56FE;&#x6848;&#x4F8B;</h4>
<p>&#x4E0B;&#x9762;&#x6211;&#x4EEC;&#x4EE5;&#x201C;&#x8D85;&#x5E02;&#x8D2D;&#x7269;&#x201D;&#x4E3A;&#x6848;&#x4F8B;&#xFF0C;&#x7EFC;&#x5408;&#x8FD0;&#x7528;&#x4E00;&#x4E0B;&#x4E0A;&#x8FF0;3&#x4E2A;&#x57FA;&#x672C;&#x7ED3;&#x6784;&#x3002;</p>
<p>&#x5982;&#x56FE;&#xFF0C;&#x5176;&#x4E2D;&#x8D2D;&#x7269;&#x662F;&#x4E00;&#x4E2A;&#x5FAA;&#x73AF;&#x7ED3;&#x6784;&#xFF0C;&#x5982;&#x679C;&#x8D2D;&#x7269;&#x6E05;&#x5355;&#x4E0A;&#x7684;&#x7269;&#x54C1;&#x8FD8;&#x6CA1;&#x6709;&#x4E70;&#x5168;&#xFF0C;&#x5219;&#x7EE7;&#x7EED;&#x8D2D;&#x4E70;&#x7269;&#x54C1;&#xFF0C;&#x5426;&#x5219;&#x5C31;&#x53EF;&#x4EE5;&#x53BB;&#x6536;&#x94F6;&#x53F0;&#x7ED3;&#x7B97;&#x4E86;&#xFF0C;&#x800C;&#x652F;&#x4ED8;&#x73AF;&#x8282;&#x5C31;&#x662F;&#x4E00;&#x4E2A;&#x5206;&#x652F;&#x7ED3;&#x6784;&#xFF0C;&#x5982;&#x679C;&#x73B0;&#x91D1;&#x8DB3;&#x591F;&#x7684;&#x8BDD;&#xFF0C;&#x5C31;&#x9009;&#x62E9;&#x7528;&#x73B0;&#x91D1;&#x652F;&#x4ED8;&#xFF0C;&#x5426;&#x5219;&#x5C31;&#x4F7F;&#x7528;&#x624B;&#x673A;&#x7684;APP&#x652F;&#x4ED8;&#x3002;</p>
<center>
<p><img src="/content/images/2018/06/flowexample.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
&#x50CF;&#x8FD9;&#x6837;&#x7684;&#x6D41;&#x7A0B;&#xFF0C;&#x6211;&#x4EEC;&#x5728;&#x5DE5;&#x4F5C;&#x548C;&#x5B66;&#x4E60;&#x4E2D;&#x8FD8;&#x662F;&#x6709;&#x975E;&#x5E38;&#x591A;&#x7684;&#x5B9E;&#x6218;&#x6848;&#x4F8B;&#x7684;&#xFF0C;&#x4F8B;&#x5982;&#x90E8;&#x7F72;&#x670D;&#x52A1;&#xFF0C;&#x5B89;&#x88C5;&#x8F6F;&#x4EF6;&#x7B49;&#x7B49;&#xFF0C;&#x5728;&#x6574;&#x4E2A;&#x6D41;&#x7A0B;&#x4E2D;&#xFF0C;&#x4E00;&#x5B9A;&#x662F;&#x4F1A;&#x51FA;&#x73B0;&#x5404;&#x79CD;&#x95EE;&#x9898;&#xFF0C;&#x90A3;&#x4E48;&#x5BF9;&#x4E8E;&#x5404;&#x79CD;&#x5F02;&#x5E38;&#x7684;&#x5904;&#x7406;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x7528;&#x4E00;&#x4E2A;&#x5206;&#x652F;&#x7ED3;&#x6784;&#x6765;&#x8868;&#x793A;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x8BD5;&#x7740;&#x628A;&#x5DE5;&#x4F5C;&#x9047;&#x5230;&#x7684;&#x95EE;&#x9898;&#x548C;&#x6392;&#x67E5;&#x8FC7;&#x7A0B;&#xFF0C;&#x901A;&#x8FC7;&#x6D41;&#x7A0B;&#x56FE;&#x7684;&#x65B9;&#x5F0F;&#x843D;&#x5B9E;&#x5230;&#x6587;&#x6863;&#x4E2D;&#xFF0C;&#x90A3;&#x4E48;&#x957F;&#x4E45;&#x4E0B;&#x6765;&#xFF0C;&#x5BF9;&#x4E8E;&#x7ECF;&#x9A8C;&#x7684;&#x79EF;&#x7D2F;&#x4F1A;&#x8D77;&#x5230;&#x975E;&#x5E38;&#x5927;&#x7684;&#x5E2E;&#x52A9;&#x4F5C;&#x7528;&#x3002;
<h3 id="52">5.2 &#x7CFB;&#x7EDF;&#x62D3;&#x6251;&#x56FE;</h3>
<p>&#x8FD9;&#x91CC;&#x5206;&#x4EAB;&#x7684;&#x7CFB;&#x7EDF;&#x62D3;&#x6251;&#x56FE;&#xFF0C;&#x4E3B;&#x8981;&#x662F;&#x6307;&#x96C6;&#x7FA4;&#x67B6;&#x6784;&#x56FE;&#xFF0C;&#x5BF9;&#x4E8E;&#x5176;&#x4ED6;&#x62D3;&#x6251;&#x56FE;&#xFF0C;&#x4ECE;&#x7ED8;&#x56FE;&#x7684;&#x89D2;&#x5EA6;&#x6765;&#x8BF4;&#xFF0C;&#x672C;&#x8D28;&#x4E0A;&#x662F;&#x4E00;&#x6837;&#x7684;&#xFF0C;&#x53EF;&#x4EE5;&#x878D;&#x4F1A;&#x8D2F;&#x901A;&#x3002;</p>
<p>&#x4E0B;&#x9762;&#x8FD8;&#x662F;&#x4EE5;&#x4E00;&#x4E2A;&#x6848;&#x4F8B;&#x6765;&#x5206;&#x4EAB;&#x4E00;&#x4E9B;&#x7B14;&#x8005;&#x6D45;&#x8584;&#x7684;&#x7ECF;&#x9A8C;&#xFF0C;&#x5982;&#x56FE;&#xFF0C;&#x8FD9;&#x662F;&#x4E00;&#x4E2A;&#x7ECF;&#x5178;&#x7684;&#x4E2D;&#x5C0F;&#x89C4;&#x6A21;web&#x96C6;&#x7FA4;&#x67B6;&#x6784;&#xFF08;&#x53C2;&#x8003;&#x81EA;&#x300A;&#x8DDF;&#x8001;&#x7537;&#x5B69;&#x5B66;Linux&#x8FD0;&#x7EF4;&#xFF1A;web&#x96C6;&#x7FA4;&#x5B9E;&#x6218;&#x300B;&#xFF09;&#xFF0C;&#x5305;&#x62EC;&#x8D1F;&#x8F7D;&#x5747;&#x8861;&#xFF0C;web&#x670D;&#x52A1;&#xFF0C;&#x6570;&#x636E;&#x5E93;&#x4E3B;&#x4ECE;&#x590D;&#x5236;&#xFF0C;&#x8BFB;&#x5199;&#x5206;&#x79BB;&#xFF0C;&#x7F51;&#x7EDC;&#x6587;&#x4EF6;&#x7CFB;&#x7EDF;&#xFF0C;&#x6587;&#x4EF6;&#x5907;&#x4EFD;&#xFF0C;&#x6279;&#x91CF;&#x7BA1;&#x7406;&#xFF0C;yum&#x4ED3;&#x5E93;&#x7B49;&#x8BF8;&#x591A;&#x5355;&#x5143;&#x3002;<br>
<img src="/content/images/2018/06/topo.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
<h4 id="521">5.2.1 &#x65B9;&#x6848;&#x89C4;&#x5212;</h4>
<p>&#x9996;&#x5148;&#x5728;&#x65B0;&#x5EFA;&#x4E00;&#x5F20;&#x7A7A;&#x767D;&#x753B;&#x7EB8;&#x4E4B;&#x524D;&#xFF0C;&#x6211;&#x4EEC;&#x5E94;&#x8BE5;&#x5BF9;&#x5F53;&#x524D;&#x8FD9;&#x4E2A;&#x7CFB;&#x7EDF;&#x67B6;&#x6784;&#x6709;&#x5145;&#x5206;&#x4E86;&#x89E3;&#xFF0C;&#x4E0D;&#x8BBA;&#x4F60;&#x662F;&#x5426;&#x5DF2;&#x7ECF;&#x5B9E;&#x73B0;&#x4E86;&#x8FD9;&#x4E2A;&#x67B6;&#x6784;&#xFF0C;&#x90FD;&#x81F3;&#x5C11;&#x6709;&#x4E00;&#x4E2A;&#x65B9;&#x6848;&#x89C4;&#x5212;&#xFF0C;&#x65B9;&#x6848;&#x63CF;&#x8FF0;&#x4E86;&#x8FD9;&#x4E2A;&#x7CFB;&#x7EDF;&#x5E94;&#x8BE5;&#x8981;&#x5B8C;&#x6210;&#x7684;&#x54EA;&#x4E9B;&#x529F;&#x80FD;&#xFF0C;&#x4EE5;&#x53CA;&#x4E3A;&#x4E86;&#x5B8C;&#x6210;&#x8FD9;&#x4E9B;&#x529F;&#x80FD;&#xFF0C;&#x9700;&#x8981;&#x63D0;&#x4F9B;&#x54EA;&#x4E9B;&#x57FA;&#x7840;&#x7684;&#x670D;&#x52A1;&#x7B49;&#xFF0C;&#x53E6;&#x5916;&#x8FD8;&#x5E94;&#x5F53;&#x5305;&#x542B;&#x670D;&#x52A1;&#x5668;&#x89C4;&#x5212;&#x8868;&#xFF0C;&#x7528;&#x6765;&#x8BF4;&#x660E;&#x4E3A;&#x4E86;&#x5B8C;&#x6210;&#x8FD9;&#x4E2A;&#x7CFB;&#x7EDF;&#xFF0C;&#x81F3;&#x5C11;&#x9700;&#x8981;&#x54EA;&#x4E9B;&#x670D;&#x52A1;&#x5668;&#xFF0C;&#x8FD9;&#x4E9B;&#x670D;&#x52A1;&#x5668;&#x63D0;&#x4F9B;&#x54EA;&#x4E9B;&#x670D;&#x52A1;&#x7B49;&#x4FE1;&#x606F;&#x3002;</p>
<h4 id="522">5.2.2 &#x6A21;&#x5757;&#x5206;&#x5272;</h4>
<p>&#x5728;&#x786E;&#x5B9A;&#x65B9;&#x6848;&#x4E4B;&#x540E;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x5BF9;&#x7CFB;&#x7EDF;&#x4E2D;&#x7684;&#x5404;&#x4E2A;&#x6A21;&#x5757;&#x8FDB;&#x884C;&#x5206;&#x5272;&#xFF0C;&#x8FD9;&#x4E2A;&#x8FC7;&#x7A0B;&#x4E0E;&#x8F6F;&#x4EF6;&#x8BBE;&#x8BA1;&#x7684;&#x6A21;&#x5757;&#x8BBE;&#x8BA1;&#x6BD4;&#x8F83;&#x76F8;&#x4F3C;&#xFF0C;&#x5148;&#x786E;&#x5B9A;&#x529F;&#x80FD;&#x6A21;&#x5757;&#xFF0C;&#x5148;&#x4E0D;&#x7BA1;&#x8FD9;&#x4E2A;&#x529F;&#x80FD;&#x6A21;&#x5757;&#x5982;&#x4F55;&#x5B9E;&#x73B0;&#xFF0C;&#x53EA;&#x8981;&#x786E;&#x5B9A;&#x4ED6;&#x5728;&#x7CFB;&#x7EDF;&#x67B6;&#x6784;&#x4E2D;&#x7684;&#x4F4D;&#x7F6E;&#x548C;&#x4F5C;&#x7528;&#xFF0C;&#x4EE5;&#x53CA;&#x63D0;&#x4F9B;&#x670D;&#x52A1;&#x7684;&#x65B9;&#x5F0F;&#xFF0C;&#x6570;&#x636E;&#x7684;&#x6D41;&#x5411;&#x7B49;&#x3002;&#x8FD9;&#x4E9B;&#x786E;&#x5B9A;&#x4E4B;&#x540E;&#xFF0C;&#x6574;&#x4E2A;&#x7CFB;&#x7EDF;&#x7684;&#x6846;&#x67B6;&#x5C31;&#x8BBE;&#x8BA1;&#x5B8C;&#x6210;&#x4E86;&#x3002;&#x5982;&#x56FE;&#xFF0C;&#x6211;&#x4EEC;&#x62BD;&#x8C61;&#x51FA;&#x4E86;&#x51E0;&#x4E2A;&#x6A21;&#x5757;&#xFF1A;&#x8D1F;&#x8F7D;&#x5747;&#x8861;&#xFF0C;web&#x670D;&#x52A1;&#xFF0C;&#x6570;&#x636E;&#x5E93;&#xFF0C;&#x6587;&#x4EF6;&#x5B58;&#x50A8;&#xFF0C;&#x4EE5;&#x53CA;&#x7BA1;&#x7406;&#x4E94;&#x4E2A;&#x6A21;&#x5757;&#x3002;&#x8FD9;&#x4E9B;&#x6A21;&#x5757;&#x5C31;&#x53EF;&#x4EE5;&#x5B9E;&#x73B0;&#x4E00;&#x4E2A;&#x57FA;&#x672C;&#x7684;web&#x670D;&#x52A1;&#x89E3;&#x51B3;&#x65B9;&#x6848;&#x4E86;&#x3002;</p>
<center>
<p><img src="/content/images/2018/06/module.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
&#x4E00;&#x822C;&#x6765;&#x8BF4;&#xFF0C;&#x6BCF;&#x4E2A;&#x6A21;&#x5757;&#x5185;&#x90E8;&#xFF0C;&#x53EF;&#x4EE5;&#x6839;&#x636E;&#x4E0D;&#x540C;&#x9700;&#x6C42;&#x548C;&#x8D44;&#x6E90;&#xFF0C;&#x5B9E;&#x73B0;&#x4E0D;&#x540C;&#x7684;&#x65B9;&#x6848;&#xFF1A;
<ul>
<li>&#x8D1F;&#x8F7D;&#x5747;&#x8861;&#x53EF;&#x4EE5;&#x7531;nginx&#xFF0C;lvs&#x6216;&#x8005;&#x786C;&#x4EF6;&#x7B49;&#x5B9E;&#x73B0;&#xFF1B;</li>
<li>web&#x670D;&#x52A1;&#x6839;&#x636E;&#x5F00;&#x53D1;&#x8BED;&#x8A00;&#x7684;&#x7279;&#x6027;&#x5B9E;&#x73B0;&#x4E0D;&#x540C;web&#x5BB9;&#x5668;&#xFF0C;&#x5982;apache+tomcat&#xFF0C;nginx+php&#x7B49;&#xFF1B;</li>
<li>&#x6570;&#x636E;&#x5E93;&#x7684;&#x5B9E;&#x73B0;&#x5C31;&#x66F4;&#x591A;&#x4E86;&#xFF0C;&#x4F20;&#x7EDF;&#x7684;&#x5173;&#x7CFB;&#x578B;&#x6570;&#x636E;&#x5E93;&#x548C;NoSQL&#x6570;&#x636E;&#x5E93;&#x4EA7;&#x54C1;&#xFF0C;&#x751A;&#x81F3;&#x8FD8;&#x53EF;&#x4EE5;&#x5B9E;&#x73B0;&#x5229;&#x7528;redis&#xFF0C;memcached&#x7B49;&#x5B9E;&#x73B0;&#x7F13;&#x5B58;&#xFF1B;</li>
<li>&#x6587;&#x4EF6;&#x5B58;&#x50A8;&#xFF0C;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;GlusterFS&#x7B49;&#x5404;&#x79CD;&#x5206;&#x5E03;&#x5F0F;&#x6587;&#x4EF6;&#x7CFB;&#x7EDF;&#x5B9E;&#x73B0;&#xFF1B;</li>
<li>&#x7BA1;&#x7406;&#x6A21;&#x5757;&#x7684;&#x529F;&#x80FD;&#x6BD4;&#x8F83;&#x591A;&#xFF0C;&#x4F8B;&#x5982;&#x5B89;&#x88C5;&#xFF0C;&#x90E8;&#x7F72;&#xFF0C;&#x76D1;&#x63A7;&#x7B49;&#xFF0C;&#x5BF9;&#x5E94;&#x6709;&#x591A;&#x79CD;&#x5B9E;&#x73B0;&#x65B9;&#x5F0F;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x4E00;&#x4E00;&#x5217;&#x4E3E;&#x4E86;&#xFF1B;</li>
</ul>
<p>&#x4F46;&#x4E0D;&#x7BA1;&#x5982;&#x4F55;&#x5B9E;&#x73B0;&#xFF0C;&#x4EE5;&#x540E;&#x5373;&#x4FBF;&#x6A21;&#x5757;&#x5185;&#x90E8;&#x8FDB;&#x884C;&#x8C03;&#x6574;&#xFF0C;&#x5927;&#x7684;&#x6846;&#x67B6;&#x4ECD;&#x7136;&#x4E0D;&#x53D8;&#x3002;&#x56E0;&#x6B64;&#x5728;&#x7ED8;&#x56FE;&#x65F6;&#xFF0C;&#x6846;&#x67B6;&#x7684;&#x786E;&#x5B9A;&#x5C24;&#x4E3A;&#x91CD;&#x8981;&#xFF0C;&#x4E5F;&#x662F;&#x6211;&#x4EEC;&#x7740;&#x624B;&#x7ED8;&#x5236;&#x67B6;&#x6784;&#x56FE;&#x7684;&#x5173;&#x952E;&#x4E00;&#x6B65;&#x3002;</p>
<h4 id="523">5.2.3 &#x8282;&#x70B9;&#x8BBE;&#x8BA1;</h4>
<p>&#x63A5;&#x4E0B;&#x6765;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x8BBE;&#x8BA1;&#x6A21;&#x5757;&#x5185;&#x90E8;&#x7684;&#x5B9E;&#x73B0;&#x4E86;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;&#x5404;&#x7C7B;&#x7684;&#x56FE;&#x6807;&#x7ED8;&#x5236;&#x4E0D;&#x540C;&#x670D;&#x52A1;&#x7684;&#x8282;&#x70B9;&#x3002;processon&#x63D0;&#x4F9B;&#x7684;&#x56FE;&#x6807;&#x5E76;&#x6CA1;&#x6709;MS visio&#x4E2D;&#x7684;&#x4E30;&#x5BCC;&#xFF0C;&#x4F46;&#x4E5F;&#x8DB3;&#x591F;&#x4F7F;&#x7528;&#x4E86;&#x3002;</p>
<p>&#x7B14;&#x8005;&#x7684;&#x505A;&#x6CD5;&#x662F;&#xFF0C;&#x4F7F;&#x7528;&#x201C;&#x670D;&#x52A1;&#x5668;&#x201D;&#x56FE;&#x6807;+&#x201C;&#x529F;&#x80FD;&#x201D;&#x56FE;&#x6807;+&#x5706;&#x89D2;&#x77E9;&#x5F62;&#x7EC4;&#x5408;&#x6210;&#x4E00;&#x4E2A;&#x8282;&#x70B9;&#xFF08;&#x5982;&#x4E0A;&#x9762;3.5&#x5C0F;&#x8282;&#x4E2D;&#x770B;&#x5230;&#x7684;&#x90A3;&#x4E2A;&#x56FE;&#xFF09;&#x3002;&#x4E4B;&#x6240;&#x4EE5;&#x8981;&#x7528;&#x5706;&#x89D2;&#x77E9;&#x5F62;&#x8FDB;&#x884C;&#x5305;&#x88F9;&#xFF0C;&#x4E00;&#x65B9;&#x9762;&#x4E3A;&#x4E86;&#x65B9;&#x4FBF;&#x8F93;&#x5165;&#x6587;&#x5B57;&#x6807;&#x6CE8;&#xFF0C;&#x66F4;&#x91CD;&#x8981;&#x7684;&#x4E00;&#x70B9;&#x662F;&#x5728;&#x67B6;&#x6784;&#x6BD4;&#x8F83;&#x590D;&#x6742;&#xFF0C;&#x8FDE;&#x63A5;&#x7EBF;&#x6BD4;&#x8F83;&#x591A;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x77E9;&#x5F62;&#x7684;&#x8FB9;&#x53EF;&#x4EE5;&#x8FDE;&#x63A5;&#x66F4;&#x591A;&#x7684;&#x7EBF;&#xFF0C;&#x800C;&#x5982;&#x679C;&#x76F4;&#x63A5;&#x8FDE;&#x63A5;&#x670D;&#x52A1;&#x5668;&#x7684;&#x56FE;&#x6807;&#xFF0C;&#x4F1A;&#x663E;&#x5F97;&#x975E;&#x5E38;&#x6742;&#x4E71;&#xFF0C;&#x6709;&#x65F6;&#x5019;&#x4E5F;&#x4F1A;&#x906E;&#x6321;&#x6587;&#x5B57;&#x6807;&#x6CE8;&#x3002;</p>
<center>
<p><img src="/content/images/2018/06/node-group.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
</center>
&#x201C;&#x670D;&#x52A1;&#x5668;&#x201D;&#x548C;&#x201C;&#x529F;&#x80FD;&#x201D;&#x56FE;&#x6807;&#xFF0C;&#x5728;processon&#x7ED8;&#x56FE;&#x754C;&#x9762;&#x53F3;&#x4E0B;&#x89D2;&#x201C;&#x66F4;&#x591A;&#x56FE;&#x5F62;&#x201D;&#x4E2D;&#x7684;&#x7F51;&#x7EDC;&#x62D3;&#x6251;&#x56FE;&#x4E0B;&#x53EF;&#x4EE5;&#x627E;&#x5230;&#xFF0C;&#x5206;&#x522B;&#x5728;network&#x548C;Azure&#x5B50;&#x76EE;&#x5F55;&#xFF08;&#x8FD9;&#x4E2A;Azure&#x5C31;&#x662F;&#x5FAE;&#x8F6F;&#x7684;&#x4E91;&#xFF0C;&#x53E6;&#x5916;&#x4E5F;&#x6709;aws&#x7684;&#x56FE;&#x6807;&#xFF0C;&#x4F46;&#x662F;&#x4E0D;&#x592A;&#x770B;&#x5F97;&#x61C2;-_-||&#xFF09;
<p>&#x7ED8;&#x5236;&#x5404;&#x4E2A;&#x8282;&#x70B9;&#x65F6;&#xFF0C;&#x5C3D;&#x91CF;&#x4F7F;&#x7528;Ctrl+D&#x8FDB;&#x884C;&#x590D;&#x7528;&#x3002;&#x5BF9;&#x4E8E;&#x201C;&#x529F;&#x80FD;&#x201D;&#x56FE;&#x6807;&#xFF0C;&#x7531;&#x4E8E;&#x9ED8;&#x8BA4;&#x7684;&#x56FE;&#x6807;&#x6BD4;&#x8F83;&#x5927;&#xFF0C;&#x5728;&#x8C03;&#x6574;&#x5927;&#x5C0F;&#x65F6;&#x53EF;&#x4EE5;&#x6309;&#x4F4F;Ctrl&#x952E;&#x8FDB;&#x884C;&#x62D6;&#x62FD;&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x8FD9;&#x6837;&#x53EF;&#x4EE5;&#x4FDD;&#x6301;&#x56FE;&#x6807;&#x7684;&#x5927;&#x5C0F;&#x6BD4;&#x4F8B;&#xFF0C;&#x5C31;&#x4E0D;&#x4F1A;&#x5931;&#x771F;&#x4E86;&#x3002;</p>
<h4 id="524">5.2.4 &#x8FDE;&#x7EBF;&#x8C03;&#x6574;</h4>
<p>&#x5F53;&#x6211;&#x4EEC;&#x9700;&#x8981;&#x5C06;&#x6BCF;&#x4E2A;&#x8282;&#x70B9;&#x8FDE;&#x63A5;&#x8D77;&#x6765;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x52A1;&#x5FC5;&#x8BB0;&#x5F97;&#x5BF9;&#x8282;&#x70B9;&#x8FDB;&#x884C;&#x5206;&#x7EC4;&#x64CD;&#x4F5C;&#xFF0C;&#x4E0D;&#x7136;&#x4E00;&#x65E6;&#x7F6E;&#x4E8E;&#x5927;&#x6846;&#x67B6;&#x4E4B;&#x5185;&#xFF0C;&#x518D;&#x60F3;&#x9009;&#x62E9;&#x8FD9;&#x4E2A;&#x8282;&#x70B9;&#xFF0C;&#x6216;&#x8005;&#x518D;&#x6B21;&#x6DFB;&#x52A0;&#x8FDE;&#x7EBF;&#x64CD;&#x4F5C;&#x5C31;&#x975E;&#x5E38;&#x9EBB;&#x70E6;&#x3002;&#x6BD4;&#x8F83;&#x9057;&#x61BE;&#x7684;&#x662F;processon&#x7684;&#x5206;&#x7EC4;&#x529F;&#x80FD;&#x6BD4;&#x8F83;&#x5355;&#x8584;&#xFF0C;&#x5F53;&#x6211;&#x4EEC;&#x5C06;&#x4E00;&#x4E2A;&#x5206;&#x7EC4;&#x4F5C;&#x4E3A;&#x4E00;&#x4E2A;&#x5143;&#x7D20;&#x4E0E;&#x5176;&#x4ED6;&#x7684;&#x5143;&#x7D20;&#x518D;&#x6B21;&#x5206;&#x7EC4;&#x65F6;&#xFF0C;&#x539F;&#x6765;&#x7684;&#x5206;&#x7EC4;&#x5C31;&#x4F1A;&#x64A4;&#x9500;&#x6389;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x8BF4;&#x5206;&#x7EC4;&#x4E0D;&#x5177;&#x6709;&#x5D4C;&#x5957;&#x7684;&#x7279;&#x6027;&#xFF0C;&#x8FD9;&#x548C;MS visio&#x4E0D;&#x592A;&#x4E00;&#x6837;&#xFF0C;&#x6240;&#x4EE5;&#x5728;&#x5206;&#x7EC4;&#x64CD;&#x4F5C;&#x65F6;&#xFF0C;&#x6700;&#x597D;&#x7684;&#x65B9;&#x5F0F;&#x5C31;&#x662F;&#x5355;&#x4E2A;&#x8282;&#x70B9;&#x5206;&#x7EC4;&#x3002;</p>
<p>&#x5206;&#x7EC4;&#x4E4B;&#x540E;&#xFF0C;&#x8282;&#x70B9;&#x4E2D;&#x7684;&#x4E09;&#x4E2A;&#x5143;&#x7D20;&#x5C31;&#x4F5C;&#x4E3A;&#x4E00;&#x4E2A;&#x6574;&#x4F53;&#xFF0C;&#x6B64;&#x65F6;&#x518D;&#x4E0E;&#x5176;&#x4ED6;&#x8282;&#x70B9;&#x8FDB;&#x884C;&#x76F8;&#x8FDE;&#xFF0C;&#x8FDE;&#x63A5;&#x65F6;&#x4E5F;&#x52A1;&#x5FC5;&#x8FDE;&#x63A5;&#x5230;&#x5BF9;&#x65B9;&#x7684;&#x8FB9;&#x4E0A;&#xFF0C;&#x8FD9;&#x6837;&#x5728;&#x62D6;&#x52A8;&#x65F6;&#x5C31;&#x53EF;&#x4EE5;&#x8DDF;&#x7740;&#x4E00;&#x8D77;&#x52A8;&#x3002;&#x9488;&#x5BF9;&#x91CD;&#x8981;&#x8282;&#x70B9;&#x8FDE;&#x7EBF;&#xFF0C;&#x9700;&#x8981;&#x8FDB;&#x884C;&#x4E00;&#x5B9A;&#x7684;&#x6587;&#x5B57;&#x6807;&#x6CE8;&#xFF0C;&#x8BF4;&#x660E;&#x5176;&#x610F;&#x4E49;&#x3002;<br>
<img src="/content/images/2018/06/line.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
<h4 id="525">5.2.5 &#x6574;&#x4F53;&#x8C03;&#x6574;</h4>
<p>&#x8FD9;&#x91CC;&#x5C31;&#x9700;&#x8981;&#x5E94;&#x7528;&#x6700;&#x5C0F;&#x5316;&#x539F;&#x5219;&#x8FDB;&#x884C;&#x8C03;&#x6574;&#x3002;&#x5728;&#x8BBE;&#x8BA1;&#x8282;&#x70B9;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x4E3A;&#x4E86;&#x80FD;&#x591F;&#x5305;&#x542B;&#x5404;&#x4E2A;&#x8282;&#x70B9;&#xFF0C;&#x901A;&#x5E38;&#x4F1A;&#x628A;&#x5927;&#x6846;&#x8C03;&#x6574;&#x5230;&#x6BD4;&#x8F83;&#x5927;&#x7684;&#x5C3A;&#x5BF8;&#xFF0C;&#x4E0D;&#x81F3;&#x4E8E;&#x5F71;&#x54CD;&#x8282;&#x70B9;&#x7684;&#x62D6;&#x62FD;&#xFF0C;&#x800C;&#x5F53;&#x6A21;&#x5757;&#x5185;&#x90E8;&#x5B8C;&#x6210;&#x4E4B;&#x540E;&#xFF0C;&#x5C31;&#x8981;&#x5C06;&#x6574;&#x5E45;&#x56FE;&#x7684;&#x6BD4;&#x4F8B;&#x8C03;&#x6574;&#x5230;&#x5408;&#x9002;&#x7684;&#x5927;&#x5C0F;&#xFF0C;&#x53BB;&#x6389;&#x65E0;&#x610F;&#x4E49;&#x7684;&#x7A7A;&#x767D;&#xFF0C;&#x4F7F;&#x5F97;&#x5E03;&#x5C40;&#x8D8B;&#x4E8E;&#x7D27;&#x51D1;&#x5408;&#x7406;&#x3002;</p>
<p>&#x7136;&#x540E;&#x53BB;&#x6389;&#x6846;&#x67B6;&#x4E4B;&#x95F4;&#x7684;&#x8FDE;&#x7EBF;&#xFF0C;&#x5C06;&#x63D0;&#x4F9B;&#x670D;&#x52A1;&#x7684;&#x8282;&#x70B9;&#x548C;&#x4F7F;&#x7528;&#x670D;&#x52A1;&#x7684;&#x8282;&#x70B9;&#x76F4;&#x63A5;&#x76F8;&#x8FDE;&#xFF0C;&#x7531;&#x4E8E;&#x7BA1;&#x7406;&#x4E2D;&#x7684;&#x8282;&#x70B9;&#x4E0E;&#x5176;&#x4ED6;&#x8282;&#x70B9;&#x90FD;&#x9700;&#x8981;&#x8FDE;&#x63A5;&#xFF0C;&#x5982;&#x679C;&#x753B;&#x7EBF;&#x5C31;&#x663E;&#x5F97;&#x6BD4;&#x8F83;&#x51CC;&#x4E71;&#xFF0C;&#x5E76;&#x4E14;&#x8FDE;&#x7EBF;&#x7684;&#x610F;&#x4E49;&#x4E0D;&#x5927;&#xFF0C;&#x6545;&#x800C;&#x7701;&#x53BB;&#x3002;<br>
<img src="/content/images/2018/06/condensed.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"><br>
&#x6700;&#x540E;&#x518D;&#x52A0;&#x4E0A;&#x4E00;&#x4E9B;&#x4FEE;&#x9970;&#xFF0C;&#x4EE5;&#x53CA;&#x5916;&#x90E8;&#x7684;&#x8C03;&#x7528;&#x60C5;&#x51B5;&#xFF0C;&#x5C31;&#x5B8C;&#x6210;&#x4E86;&#x6574;&#x4E2A;&#x7CFB;&#x7EDF;&#x67B6;&#x6784;&#x56FE;&#x3002;<br>
<img src="/content/images/2018/06/topo.png" alt="IT&#x4ECE;&#x4E1A;&#x8005;&#x7684;&#x7ED8;&#x56FE;&#x6307;&#x5357;(Processon&#x7248;)" loading="lazy"></p>
<h2 id>&#x516D;&#x3001;&#x603B;&#x7ED3;</h2>
<p>&#x672C;&#x6587;&#x4E3B;&#x8981;&#x5206;&#x4EAB;&#x4E86;&#x4EE5;&#x4E0B;&#x51E0;&#x70B9;</p>
<ul>
<li>&#x4ECB;&#x7ECD;&#x4E86;&#x7ED8;&#x56FE;&#x4F5C;&#x4E3A;IT&#x4ECE;&#x4E1A;&#x4EBA;&#x5458;&#x8F6F;&#x5B9E;&#x529B;&#x7684;&#x91CD;&#x8981;&#x6027;&#xFF0C;&#x4EE5;&#x53CA;&#x7ED8;&#x56FE;&#x5728;&#x65E5;&#x5E38;&#x5DE5;&#x4F5C;&#x4E2D;&#x7684;&#x91CD;&#x8981;&#x4F5C;&#x7528;</li>
<li>&#x7ED8;&#x56FE;&#x5DE5;&#x5177;processon&#x4E2D;&#x5404;&#x4E2A;&#x529F;&#x80FD;&#x7279;&#x6027;&#x548C;&#x4F7F;&#x7528;&#x6280;&#x5DE7;&#xFF0C;&#x4E3B;&#x8981;&#x6709;&#x5206;&#x5E03;&#xFF0C;&#x5BF9;&#x9F50;&#xFF0C;z&#x8F74;&#x6392;&#x5217;&#xFF0C;&#x5FEB;&#x6377;&#x952E;&#x7B49;</li>
<li>&#x63D0;&#x51FA;&#x4E86;&#x4E00;&#x4E9B;&#x7ED8;&#x56FE;&#x7684;&#x89C4;&#x8303;&#x5EFA;&#x8BAE;&#xFF0C;&#x5305;&#x62EC;&#x5927;&#x5C0F;&#xFF0C;&#x5B57;&#x4F53;&#xFF0C;&#x989C;&#x8272;&#xFF0C;&#x6700;&#x5C0F;&#x5316;&#x539F;&#x5219;&#xFF0C;&#x5747;&#x662F;&#x4F53;&#x73B0;&#x5728;&#x7EC6;&#x8282;&#x4E0A;&#xFF0C;&#x4E0D;&#x8FC7;&#xFF0C;&#x8FD9;&#x4E9B;&#x7EC6;&#x8282;&#x6700;&#x7EC8;&#x4F1A;&#x5F71;&#x54CD;&#x5230;&#x6574;&#x4F53;&#x7684;&#x8D28;&#x611F;</li>
<li>&#x6D41;&#x7A0B;&#x56FE;&#x548C;&#x7CFB;&#x7EDF;&#x62D3;&#x6251;&#x56FE;&#x7684;&#x7ED8;&#x5236;&#x8981;&#x9886;&#x548C;&#x7ECF;&#x9A8C;&#x3002;</li>
<li>&#x7ED8;&#x56FE;&#x662F;&#x62BD;&#x8C61;&#x601D;&#x7EF4;&#x80FD;&#x529B;&#x7684;&#x57F9;&#x517B;&#x65B9;&#x5F0F;&#x4E4B;&#x4E00;</li>
<li>&#x6D41;&#x7A0B;&#x56FE;&#x7684;&#x5E38;&#x7528;&#x7B26;&#x53F7;&#xFF0C;&#x57FA;&#x672C;&#x7ED3;&#x6784;&#xFF0C;&#x4EE5;&#x53CA;&#x5B9E;&#x6218;&#x8FD0;&#x7528;</li>
<li>&#x4EE5;web&#x96C6;&#x7FA4;&#x67B6;&#x6784;&#x4E3A;&#x6848;&#x4F8B;&#x4ECB;&#x7ECD;&#x4E86;&#x7ED8;&#x5236;&#x7CFB;&#x7EDF;&#x62D3;&#x6251;&#x56FE;&#x7684;&#x6B65;&#x9AA4;</li>
<li>&#x4E00;&#x70B9;&#x5FAE;&#x8584;&#x7684;&#x7ECF;&#x9A8C;&#x5206;&#x4EAB;&#xFF0C;&#x5E0C;&#x671B;&#x53EF;&#x4EE5;&#x5E2E;&#x52A9;&#x5230;&#x90A3;&#x4E9B;&#x4E0D;&#x4E60;&#x60EF;&#x753B;&#x56FE;&#xFF0C;&#x6216;&#x8005;&#x60F3;&#x753B;&#x597D;&#x56FE;&#x5374;&#x5728;&#x753B;&#x56FE;&#x5404;&#x79CD;&#x64CD;&#x4F5C;&#x4E0A;&#x8017;&#x8D39;&#x8FC7;&#x591A;&#x7CBE;&#x529B;&#x7684;&#x5C0F;&#x4F19;&#x4F34;&#x4EEC;&#x3002;</li>
</ul>
<h2 id>&#x4E03;&#x3001;&#x53C2;&#x8003;&#x8D44;&#x6599;</h2>
<ul>
<li>Jesse James Garrett. &#x7528;&#x6237;&#x4F53;&#x9A8C;&#x7684;&#x8981;&#x7D20;:&#x4EE5;&#x7528;&#x6237;&#x4E3A;&#x4E2D;&#x5FC3;&#x7684;Web&#x8BBE;&#x8BA1;. &#x673A;&#x68B0;&#x5DE5;&#x4E1A;&#x51FA;&#x7248;&#x793E;, 2007.</li>
<li>&#x9EA6;&#x514B;&#x97E6;&#x5FB7;. &#x8D85;&#x8D8A;&#x5E73;&#x51E1;&#x7684;&#x5E73;&#x9762;&#x8BBE;&#x8BA1; &#x7248;&#x5F0F;&#x8BBE;&#x8BA1;&#x539F;&#x7406;&#x4E0E;&#x5E94;&#x7528;. &#x4EBA;&#x6C11;&#x90AE;&#x7535;&#x51FA;&#x7248;&#x793E;, 2010.</li>
<li>&#x5927;&#x8C61;&#x516C;&#x793E;. &#x4E2D;&#x56FD;&#x7684;&#x62DB;&#x724C;&#x4E3A;&#x4EC0;&#x4E48;&#x8FD9;&#x4E48;&#x4E11;. <a href="http://weibo.com/ttarticle/p/show?id=2309403993629365534797">http://weibo.com/ttarticle/p/show?id=2309403993629365534797</a>,  2016.</li>
<li>&#x5F20;&#x6D77;&#x85E9;. &#x8F6F;&#x4EF6;&#x5DE5;&#x7A0B;&#x5BFC;&#x8BBA;[M]. &#x6E05;&#x534E;&#x5927;&#x5B66;&#x51FA;&#x7248;&#x793E;, 2003.</li>
<li>&#x8001;&#x7537;&#x5B69;. &#x8DDF;&#x8001;&#x7537;&#x5B69;&#x5B66;Linux&#x8FD0;&#x7EF4;:Web&#x96C6;&#x7FA4;&#x5B9E;&#x6218;. &#x673A;&#x68B0;&#x5DE5;&#x4E1A;&#x51FA;&#x7248;&#x793E;, 2016.</li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[MySQL和B树的那些事]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id>&#x96F6;&#x3001;&#x94FA;&#x57AB;</h2>
<p>&#x5728;&#x4ECB;&#x7ECD;B&#x6811;&#x4E4B;&#x524D;&#xFF0C;&#x5148;&#x6765;&#x770B;&#x53E6;&#x4E00;&#x68F5;&#x795E;&#x5947;&#x7684;&#x6811;&#x2014;&#x2014;&#x4E8C;&#x53C9;&#x6392;&#x5E8F;&#x6811;&#xFF08;Binary Sort Tree&#xFF09;&#xFF0C;&#x9996;&#x5148;&#x5B83;&#x662F;&#x4E00;&#x68F5;&#x6811;&#xFF0C;&#x201C;&#x4E8C;&#x53C9;&#x201D;&#x8FD9;&#x4E2A;&#x63CF;</p>]]></description><link>http://www.fullstackyang.com/mysqlhe-bshu-de-na-xie-shi/</link><guid isPermaLink="false">624567890d2dd30001909ffd</guid><category><![CDATA[database]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Thu, 11 Aug 2016 14:24:00 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2018/06/logs-19.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id>&#x96F6;&#x3001;&#x94FA;&#x57AB;</h2>
<img src="http://www.fullstackyang.com/content/images/2018/06/logs-19.png" alt="MySQL&#x548C;B&#x6811;&#x7684;&#x90A3;&#x4E9B;&#x4E8B;"><p>&#x5728;&#x4ECB;&#x7ECD;B&#x6811;&#x4E4B;&#x524D;&#xFF0C;&#x5148;&#x6765;&#x770B;&#x53E6;&#x4E00;&#x68F5;&#x795E;&#x5947;&#x7684;&#x6811;&#x2014;&#x2014;&#x4E8C;&#x53C9;&#x6392;&#x5E8F;&#x6811;&#xFF08;Binary Sort Tree&#xFF09;&#xFF0C;&#x9996;&#x5148;&#x5B83;&#x662F;&#x4E00;&#x68F5;&#x6811;&#xFF0C;&#x201C;&#x4E8C;&#x53C9;&#x201D;&#x8FD9;&#x4E2A;&#x63CF;&#x8FF0;&#x5DF2;&#x7ECF;&#x5F88;&#x660E;&#x663E;&#x4E86;&#xFF0C;&#x5C31;&#x662F;&#x6811;&#x4E0A;&#x7684;&#x4E00;&#x6839;&#x6811;&#x679D;&#x5F00;&#x4E24;&#x4E2A;&#x53C9;&#xFF0C;&#x4E8E;&#x662F;&#x9012;&#x5F52;&#x4E0B;&#x6765;&#x5C31;&#x662F;&#x4E8C;&#x53C9;&#x6811;&#x4E86;&#xFF08;&#x4E0B;&#x56FE;&#x6240;&#x793A;&#xFF09;&#xFF0C;&#x800C;&#x8FD9;&#x68F5;&#x6811;&#x4E0A;&#x7684;&#x8282;&#x70B9;&#x662F;&#x5DF2;&#x7ECF;&#x6392;&#x597D;&#x5E8F;&#x7684;&#xFF0C;&#x5177;&#x4F53;&#x7684;&#x6392;&#x5E8F;&#x89C4;&#x5219;&#x5982;&#x4E0B;&#xFF1A;</p>
<ul>
<li>&#x82E5;&#x5DE6;&#x5B50;&#x6811;&#x4E0D;&#x7A7A;&#xFF0C;&#x5219;&#x5DE6;&#x5B50;&#x6811;&#x4E0A;&#x6240;&#x6709;&#x8282;&#x70B9;&#x7684;&#x503C;&#x5747;&#x5C0F;&#x4E8E;&#x5B83;&#x7684;&#x6839;&#x8282;&#x70B9;&#x7684;&#x503C;</li>
<li>&#x82E5;&#x53F3;&#x5B50;&#x6811;&#x4E0D;&#x7A7A;&#xFF0C;&#x5219;&#x53F3;&#x5B57;&#x6570;&#x4E0A;&#x6240;&#x6709;&#x8282;&#x70B9;&#x7684;&#x503C;&#x5747;&#x5927;&#x4E8E;&#x5B83;&#x7684;&#x6839;&#x8282;&#x70B9;&#x7684;&#x503C;</li>
<li>&#x5B83;&#x7684;&#x5DE6;&#x3001;&#x53F3;&#x5B50;&#x6811;&#x4E5F;&#x5206;&#x522B;&#x4E3A;&#x4E8C;&#x53C9;&#x6392;&#x5E8F;&#x6570;&#xFF08;&#x9012;&#x5F52;&#x5B9A;&#x4E49;&#xFF09;<br>
<img src="/content/images/2018/06/bst.png" alt="MySQL&#x548C;B&#x6811;&#x7684;&#x90A3;&#x4E9B;&#x4E8B;" loading="lazy"></li>
</ul>
<p>&#x4ECE;&#x56FE;&#x4E2D;&#x53EF;&#x4EE5;&#x770B;&#x51FA;&#xFF0C;&#x4E8C;&#x53C9;&#x6392;&#x5E8F;&#x6811;&#x7EC4;&#x7EC7;&#x6570;&#x636E;&#x65F6;&#xFF0C;&#x7528;&#x4E8E;&#x67E5;&#x627E;&#x662F;&#x6BD4;&#x8F83;&#x65B9;&#x4FBF;&#x7684;&#xFF0C;&#x56E0;&#x4E3A;&#x6BCF;&#x6B21;&#x7ECF;&#x8FC7;&#x4E00;&#x6B21;&#x8282;&#x70B9;&#x65F6;&#xFF0C;&#x6700;&#x591A;&#x53EF;&#x4EE5;&#x51CF;&#x5C11;&#x4E00;&#x534A;&#x7684;&#x53EF;&#x80FD;&#xFF0C;&#x4E0D;&#x8FC7;&#x6781;&#x7AEF;&#x60C5;&#x51B5;&#x4F1A;&#x51FA;&#x73B0;&#x6240;&#x6709;&#x8282;&#x70B9;&#x90FD;&#x4F4D;&#x4E8E;&#x540C;&#x4E00;&#x4FA7;&#xFF0C;&#x76F4;&#x89C2;&#x4E0A;&#x770B;&#x5C31;&#x662F;&#x4E00;&#x6761;&#x76F4;&#x7EBF;&#xFF0C;&#x90A3;&#x4E48;&#x8FD9;&#x79CD;&#x67E5;&#x8BE2;&#x7684;&#x6548;&#x7387;&#x5C31;&#x6BD4;&#x8F83;&#x4F4E;&#x4E86;&#xFF0C;&#x56E0;&#x6B64;&#x9700;&#x8981;&#x5BF9;&#x4E8C;&#x53C9;&#x6811;&#x5DE6;&#x53F3;&#x5B50;&#x6811;&#x7684;&#x9AD8;&#x5EA6;&#x8FDB;&#x884C;&#x5E73;&#x8861;&#x5316;&#x5904;&#x7406;&#xFF0C;&#x4E8E;&#x662F;&#x5C31;&#x6709;&#x4E86;&#x5E73;&#x8861;&#x4E8C;&#x53C9;&#x6811;&#xFF08;Balenced Binary Tree&#xFF09;&#xFF0C;&#x6240;&#x8C13;&#x201C;&#x5E73;&#x8861;&#x201D;&#xFF0C;&#x8BF4;&#x7684;&#x662F;&#x8FD9;&#x68F5;&#x6811;&#x7684;&#x5404;&#x4E2A;&#x5206;&#x652F;&#x7684;&#x9AD8;&#x5EA6;&#x662F;&#x5747;&#x5300;&#x7684;&#xFF0C;&#x5B83;&#x7684;&#x5DE6;&#x5B50;&#x6811;&#x548C;&#x53F3;&#x5B50;&#x6811;&#x7684;&#x9AD8;&#x5EA6;&#x4E4B;&#x5DEE;&#x7EDD;&#x5BF9;&#x503C;&#x5C0F;&#x4E8E;1&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x4E0D;&#x4F1A;&#x51FA;&#x73B0;&#x4E00;&#x6761;&#x652F;&#x8DEF;&#x7279;&#x522B;&#x957F;&#x7684;&#x60C5;&#x51B5;&#x3002;&#x4E8E;&#x662F;&#xFF0C;&#x5728;&#x8FD9;&#x6837;&#x7684;&#x5E73;&#x8861;&#x6811;&#x4E2D;&#x8FDB;&#x884C;&#x67E5;&#x627E;&#x65F6;&#xFF0C;&#x603B;&#x5171;&#x6BD4;&#x8F83;&#x8282;&#x70B9;&#x7684;&#x6B21;&#x6570;&#x4E0D;&#x8D85;&#x8FC7;&#x6811;&#x7684;&#x9AD8;&#x5EA6;&#xFF0C;&#x8FD9;&#x5C31;&#x786E;&#x4FDD;&#x4E86;&#x67E5;&#x8BE2;&#x7684;&#x6548;&#x7387;&#xFF08;&#x65F6;&#x95F4;&#x590D;&#x6742;&#x5EA6;&#x4E3A;O(logn)&#xFF09;</p>
<h2 id="b">&#x4E00;&#x3001;B&#x6811;&#x7684;&#x8D77;&#x6E90;</h2>
<p>B&#x6811;&#xFF0C;&#x6700;&#x65E9;&#x662F;&#x7531;&#x5FB7;&#x56FD;&#x8BA1;&#x7B97;&#x673A;&#x79D1;&#x5B66;&#x5BB6;Rudolf Bayer&#x7B49;&#x4EBA;&#x4E8E;1972&#x5E74;&#x5728;&#x8BBA;&#x6587; &#x300A;Organization and Maintenance of Large Ordered Indexes&#x300B;&#x63D0;&#x51FA;&#x7684;&#xFF0C;&#x4E0D;&#x8FC7;&#x6211;&#x53BB;&#x770B;&#x4E86;&#x770B;&#x539F;&#x6587;&#xFF0C;&#x53D1;&#x73B0;&#x4F5C;&#x8005;&#x4E5F;&#x6CA1;&#x6709;&#x89E3;&#x91CA;&#x4E3A;&#x4EC0;&#x4E48;&#x5C31;&#x53EB;B-trees&#x4E86;&#xFF0C;&#x6240;&#x4EE5;&#x628A;B&#x6811;&#x7684;B&#xFF0C;&#x7B80;&#x5355;&#x5730;&#x89E3;&#x91CA;&#x4E3A;Balanced&#x6216;&#x8005;Binary&#x90FD;&#x4E0D;&#x662F;&#x7279;&#x522B;&#x4E25;&#x8C28;&#xFF0C;&#x4E5F;&#x8BB8;&#x4F5C;&#x8005;&#x5C31;&#x662F;&#x53D6;&#x5176;&#x540D;&#x5B57;Bayer&#x7684;&#x9996;&#x5B57;&#x6BCD;&#x547D;&#x540D;&#x7684;&#x4E5F;&#x8BF4;&#x4E0D;&#x5B9A;&#x554A;&#x2026;&#x2026;</p>
<h2 id="b">&#x4E8C;&#x3001;B&#x6811;&#x957F;&#x5565;&#x6837;</h2>
<p>&#x8FD8;&#x662F;&#x76F4;&#x63A5;&#x770B;&#x56FE;&#x6BD4;&#x8F83;&#x6E05;&#x695A;&#xFF0C;&#x56FE;&#x4E2D;&#x6240;&#x793A;&#xFF0C;B&#x6811;&#x4E8B;&#x5B9E;&#x4E0A;&#x662F;&#x4E00;&#x79CD;&#x5E73;&#x8861;&#x7684;&#x591A;&#x53C9;&#x67E5;&#x627E;&#x6811;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x8BF4;&#x6700;&#x591A;&#x53EF;&#x4EE5;&#x5F00;m&#x4E2A;&#x53C9;&#xFF08;m&gt;=2&#xFF09;&#xFF0C;&#x6211;&#x4EEC;&#x79F0;&#x4E4B;&#x4E3A;m&#x9636;b&#x6811;&#xFF0C;&#x4E3A;&#x4E86;&#x4F53;&#x73B0;&#x672C;&#x535A;&#x5BA2;&#x7684;&#x826F;&#x5FC3;&#x4E4B;&#x5904;&#xFF0C;&#x4E0D;&#x540C;&#x4E8E;&#x5176;&#x4ED6;&#x5730;&#x65B9;&#x90FD;&#x80FD;&#x770B;&#x5230;2&#x9636;B&#x6811;&#xFF0C;&#x8FD9;&#x91CC;&#x7279;&#x610F;&#x753B;&#x4E86;&#x4E00;&#x68F5;5&#x9636;B&#x6811; &#x3002;<br>
<img src="/content/images/2018/06/btree.png" alt="MySQL&#x548C;B&#x6811;&#x7684;&#x90A3;&#x4E9B;&#x4E8B;" loading="lazy"><br>
&#x603B;&#x7684;&#x6765;&#x8BF4;&#xFF0C;m&#x9636;B&#x6811;&#x6EE1;&#x8DB3;&#x4EE5;&#x4E0B;&#x6761;&#x4EF6;&#xFF1A;</p>
<ul>
<li>&#x6BCF;&#x4E2A;&#x8282;&#x70B9;&#x81F3;&#x591A;&#x53EF;&#x4EE5;&#x62E5;&#x6709;m&#x68F5;&#x5B50;&#x6811;</li>
<li>&#x6839;&#x8282;&#x70B9;&#xFF0C;&#x53EA;&#x6709;&#x81F3;&#x5C11;&#x6709;2&#x4E2A;&#x8282;&#x70B9;&#xFF08;&#x8981;&#x4E48;&#x6781;&#x7AEF;&#x60C5;&#x51B5;&#xFF0C;&#x5C31;&#x662F;&#x4E00;&#x68F5;&#x6811;&#x5C31;&#x4E00;&#x4E2A;&#x6839;&#x8282;&#x70B9;&#xFF0C;&#x5355;&#x7EC6;&#x80DE;&#x751F;&#x7269;&#xFF0C;&#x5373;&#x662F;&#x6839;&#xFF0C;&#x4E5F;&#x662F;&#x53F6;&#xFF0C;&#x4E5F;&#x662F;&#x6811;)&#x3002;</li>
<li>&#x975E;&#x6839;&#x975E;&#x53F6;&#x7684;&#x8282;&#x70B9;&#x81F3;&#x5C11;&#x6709;&#x7684;Ceil(m/2)&#x4E2A;&#x5B50;&#x6811;(Ceil&#x8868;&#x793A;&#x5411;&#x4E0A;&#x53D6;&#x6574;&#xFF0C;&#x56FE;&#x4E2D;5&#x9636;B&#x6811;&#xFF0C;&#x6BCF;&#x4E2A;&#x8282;&#x70B9;&#x81F3;&#x5C11;&#x6709;3&#x4E2A;&#x5B50;&#x6811;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x81F3;&#x5C11;&#x6709;3&#x4E2A;&#x53C9;)</li>
<li>&#x975E;&#x53F6;&#x8282;&#x70B9;&#x4E2D;&#x7684;&#x4FE1;&#x606F;&#x5305;&#x62EC;[n,A0,K1,A1,K2,A2,&#x2026;,Kn,An]&#xFF0C;&#xFF0C;&#x5176;&#x4E2D;n&#x8868;&#x793A;&#x8BE5;&#x8282;&#x70B9;&#x4E2D;&#x4FDD;&#x5B58;&#x7684;&#x5173;&#x952E;&#x5B57;&#x4E2A;&#x6570;&#xFF0C;K&#x4E3A;&#x5173;&#x952E;&#x5B57;&#x4E14;Ki&lt;Ki+1&#xFF0C;A&#x4E3A;&#x6307;&#x5411;&#x5B50;&#x6811;&#x6839;&#x8282;&#x70B9;&#x7684;&#x6307;&#x9488;</li>
<li>&#x4ECE;&#x6839;&#x5230;&#x53F6;&#x5B50;&#x7684;&#x6BCF;&#x4E00;&#x6761;&#x8DEF;&#x5F84;&#x90FD;&#x6709;&#x76F8;&#x540C;&#x7684;&#x957F;&#x5EA6;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x8BF4;&#xFF0C;&#x53F6;&#x5B50;&#x8282;&#x5728;&#x76F8;&#x540C;&#x7684;&#x5C42;&#xFF0C;&#x5E76;&#x4E14;&#x8FD9;&#x4E9B;&#x8282;&#x70B9;&#x4E0D;&#x5E26;&#x4FE1;&#x606F;&#xFF0C;&#x5B9E;&#x9645;&#x4E0A;&#x8FD9;&#x4E9B;&#x8282;&#x70B9;&#x5C31;&#x8868;&#x793A;&#x627E;&#x4E0D;&#x5230;&#x6307;&#x5B9A;&#x7684;&#x503C;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x6307;&#x5411;&#x8FD9;&#x4E9B;&#x8282;&#x70B9;&#x7684;&#x6307;&#x9488;&#x4E3A;&#x7A7A;<br>
B&#x6811;&#x7684;&#x67E5;&#x8BE2;&#x8FC7;&#x7A0B;&#x548C;&#x4E8C;&#x53C9;&#x6392;&#x5E8F;&#x6811;&#x6BD4;&#x8F83;&#x7C7B;&#x4F3C;&#xFF0C;&#x4ECE;&#x6839;&#x8282;&#x70B9;&#x4F9D;&#x6B21;&#x6BD4;&#x8F83;&#x6BCF;&#x4E2A;&#x7ED3;&#x70B9;&#xFF0C;&#x56E0;&#x4E3A;&#x6BCF;&#x4E2A;&#x8282;&#x70B9;&#x4E2D;&#x7684;&#x5173;&#x952E;&#x5B57;&#x548C;&#x5DE6;&#x53F3;&#x5B50;&#x6811;&#x90FD;&#x662F;&#x6709;&#x5E8F;&#x7684;&#xFF0C;&#x6240;&#x4EE5;&#x53EA;&#x8981;&#x6BD4;&#x8F83;&#x8282;&#x70B9;&#x4E2D;&#x7684;&#x5173;&#x952E;&#x5B57;&#xFF0C;&#x6216;&#x8005;&#x6CBF;&#x7740;&#x6307;&#x9488;&#x5C31;&#x80FD;&#x5F88;&#x5FEB;&#x5730;&#x627E;&#x5230;&#x6307;&#x5B9A;&#x7684;&#x5173;&#x952E;&#x5B57;&#xFF0C;&#x5982;&#x679C;&#x67E5;&#x627E;&#x5931;&#x8D25;&#xFF0C;&#x5219;&#x4F1A;&#x8FD4;&#x56DE;&#x53F6;&#x5B50;&#x8282;&#x70B9;&#xFF0C;&#x5373;&#x7A7A;&#x6307;&#x9488;&#x3002;</li>
</ul>
<p>&#x4F8B;&#x5982;&#x67E5;&#x8BE2;&#x56FE;&#x4E2D;&#x5B57;&#x6BCD;&#x8868;&#x4E2D;&#x7684;K</p>
<ol>
<li>&#x4ECE;&#x6839;&#x8282;&#x70B9;P&#x5F00;&#x59CB;&#xFF0C;K&#x7684;&#x4F4D;&#x7F6E;&#x5728;P&#x4E4B;&#x524D;&#xFF0C;&#x8FDB;&#x5165;&#x5DE6;&#x4FA7;&#x6307;&#x9488;</li>
<li>&#x5DE6;&#x5B50;&#x6811;&#x4E2D;&#xFF0C;&#x4F9D;&#x6B21;&#x6BD4;&#x8F83;C&#x3001;F&#x3001;J&#x3001;M&#xFF0C;&#x53D1;&#x73B0;K&#x5728;J&#x548C;M&#x4E4B;&#x95F4;</li>
<li>&#x6CBF;&#x7740;J&#x548C;M&#x4E4B;&#x95F4;&#x7684;&#x6307;&#x9488;&#xFF0C;&#x7EE7;&#x7EED;&#x8BBF;&#x95EE;&#x5B50;&#x6811;&#xFF0C;&#x5E76;&#x4F9D;&#x6B21;&#x8FDB;&#x884C;&#x6BD4;&#x8F83;&#xFF0C;&#x53D1;&#x73B0;&#x7B2C;&#x4E00;&#x4E2A;&#x5173;&#x952E;&#x5B57;K&#x5373;&#x4E3A;&#x6307;&#x5B9A;&#x67E5;&#x627E;&#x7684;&#x503C;</li>
</ol>
<h2 id="plusb">&#x4E09;&#x3001;Plus&#x7248;&#x2014;&#x2014;B+&#x6811;</h2>
<p>&#x4F5C;&#x4E3A;B&#x6811;&#x7684;&#x52A0;&#x5F3A;&#x7248;&#xFF0C;B+&#x6811;&#x4E0E;B&#x6811;&#x7684;&#x5DEE;&#x5F02;&#x5728;&#x4E8E;</p>
<ul>
<li>&#x6709;n&#x68F5;&#x5B50;&#x6811;&#x7684;&#x8282;&#x70B9;&#x542B;&#x6709;n&#x4E2A;&#x5173;&#x952E;&#x5B57;&#xFF08;&#x4E5F;&#x6709;&#x8BA4;&#x4E3A;&#x662F;n-1&#x4E2A;&#x5173;&#x952E;&#x5B57;&#xFF09;</li>
<li>&#x6240;&#x6709;&#x7684;&#x53F6;&#x5B50;&#x8282;&#x70B9;&#x5305;&#x542B;&#x4E86;&#x5168;&#x90E8;&#x7684;&#x5173;&#x952E;&#x5B57;&#xFF0C;&#x53CA;&#x6307;&#x5411;&#x542B;&#x8FD9;&#x4E9B;&#x5173;&#x952E;&#x5B57;&#x8BB0;&#x5F55;&#x7684;&#x6307;&#x9488;&#xFF0C;&#x4E14;&#x53F6;&#x5B50;&#x8282;&#x70B9;&#x672C;&#x8EAB;&#x6839;&#x636E;&#x5173;&#x952E;&#x5B57;&#x81EA;&#x5C0F;&#x800C;&#x5927;&#x987A;&#x5E8F;&#x8FDE;&#x63A5;</li>
<li>&#x975E;&#x53F6;&#x5B50;&#x8282;&#x70B9;&#x53EF;&#x4EE5;&#x770B;&#x6210;&#x7D22;&#x5F15;&#x90E8;&#x5206;&#xFF0C;&#x8282;&#x70B9;&#x4E2D;&#x4EC5;&#x542B;&#x6709;&#x5176;&#x5B50;&#x6811;&#xFF08;&#x6839;&#x8282;&#x70B9;&#xFF09;&#x4E2D;&#x7684;&#x6700;&#x5927;&#xFF08;&#x6216;&#x6700;&#x5C0F;&#xFF09;&#x5173;&#x952E;&#x5B57;<br>
<img src="/content/images/2018/06/B.png" alt="MySQL&#x548C;B&#x6811;&#x7684;&#x90A3;&#x4E9B;&#x4E8B;" loading="lazy"></li>
</ul>
<h2 id="mysqlb">&#x56DB;&#x3001;MySQL&#x662F;&#x5982;&#x4F55;&#x4F7F;&#x7528;B&#x6811;&#x7684;</h2>
<p>&#x8BF4;&#x660E;&#xFF1A;&#x4E8B;&#x5B9E;&#x4E0A;&#xFF0C;&#x5728;MySQL&#x6570;&#x636E;&#x5E93;&#x4E2D;&#xFF0C;&#x8BF8;&#x591A;&#x5B58;&#x50A8;&#x5F15;&#x64CE;&#x4F7F;&#x7528;&#x7684;&#x662F;B+&#x6811;&#xFF0C;&#x5373;&#x4FBF;&#x5176;&#x540D;&#x5B57;&#x770B;&#x4E0A;&#x53BB;&#x662F;BTREE&#x3002;</p>
<h4 id="41innodb">4.1 innodb&#x7684;&#x7D22;&#x5F15;&#x673A;&#x5236;</h4>
<p>&#x5148;&#x4EE5;innodb&#x5B58;&#x50A8;&#x5F15;&#x64CE;&#x4E3A;&#x4F8B;&#xFF0C;&#x8BF4;&#x660E;innodb&#x5F15;&#x64CE;&#x662F;&#x5982;&#x4F55;&#x5229;&#x7528;B+&#x6811;&#x5EFA;&#x7ACB;&#x7D22;&#x5F15;&#x7684;</p>
<p>&#x9996;&#x5148;&#x521B;&#x5EFA;&#x4E00;&#x5F20;&#x8868;&#xFF1A;zodiac&#xFF0C;&#x5E76;&#x63D2;&#x5165;&#x4E00;&#x4E9B;&#x6570;&#x636E;</p>
<pre><code>CREATE TABLE `zodiac` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` char(4) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `index_name` (`name`)
); 

insert zodiac(id,name) values(1,&apos;&#x9F20;&apos;);
insert zodiac(id,name) values(2,&apos;&#x725B;&apos;);
insert zodiac(id,name) values(3,&apos;&#x864E;&apos;);
insert zodiac(id,name) values(4,&apos;&#x5154;&apos;);
insert zodiac(id,name) values(5,&apos;&#x9F99;&apos;);
insert zodiac(id,name) values(6,&apos;&#x86C7;&apos;);
insert zodiac(id,name) values(7,&apos;&#x9A6C;&apos;);
insert zodiac(id,name) values(8,&apos;&#x7F8A;&apos;);
insert zodiac(id,name) values(9,&apos;&#x7334;&apos;);
insert zodiac(id,name) values(10,&apos;&#x9E21;&apos;);
insert zodiac(id,name) values(11,&apos;&#x72D7;&apos;);
insert zodiac(id,name) values(12,&apos;&#x732A;&apos;);
</code></pre>
<p>&#x5BF9;&#x4E8E;innodb&#x6765;&#x8BF4;&#xFF0C;&#x53EA;&#x6709;&#x4E00;&#x4E2A;&#x6570;&#x636E;&#x6587;&#x4EF6;&#xFF0C;&#x8FD9;&#x4E2A;&#x6570;&#x636E;&#x6587;&#x4EF6;&#x672C;&#x8EAB;&#x5C31;&#x662F;&#x7528;B+&#x6811;&#x5F62;&#x5F0F;&#x7EC4;&#x7EC7;&#xFF0C;B+&#x6811;&#x6BCF;&#x4E2A;&#x8282;&#x70B9;&#x7684;&#x5173;&#x952E;&#x5B57;&#x5C31;&#x662F;&#x8868;&#x7684;&#x4E3B;&#x952E;&#xFF0C;&#x56E0;&#x6B64;innode&#x7684;&#x6570;&#x636E;&#x6587;&#x4EF6;&#x672C;&#x8EAB;&#x5C31;&#x662F;&#x4E3B;&#x7D22;&#x5F15;&#x6587;&#x4EF6;&#xFF0C;&#x5982;&#x4E0B;&#x56FE;&#x6240;&#x793A;&#xFF0C;&#x4E3B;&#x7D22;&#x5F15;&#x4E2D;&#x7684;&#x53F6;&#x5B50;&#x9875;&#xFF08;leaf page&#xFF09;&#x5305;&#x542B;&#x4E86;&#x6570;&#x636E;&#x8BB0;&#x5F55;&#xFF0C;&#x4F46;&#x975E;&#x53F6;&#x5B50;&#x8282;&#x70B9;&#x53EA;&#x5305;&#x542B;&#x4E86;&#x4E3B;&#x952E;&#xFF0C;&#x672F;&#x8BED;&#x201C;&#x805A;&#x7C07;&#x201D;&#x8868;&#x793A;&#x6570;&#x636E;&#x884C;&#x548C;&#x76F8;&#x90BB;&#x7684;&#x952E;&#x503C;&#x7D27;&#x51D1;&#x5730;&#x5B58;&#x50A8;&#x5728;&#x4E00;&#x8D77;&#xFF0C;&#x56E0;&#x6B64;&#x8FD9;&#x79CD;&#x7D22;&#x5F15;&#x88AB;&#x79F0;&#x4E3A;&#x805A;&#x7C07;&#x7D22;&#x5F15;&#xFF0C;&#x6216;&#x805A;&#x96C6;&#x7D22;&#x5F15;&#x3002;&#x8FD9;&#x79CD;&#x7D22;&#x5F15;&#x65B9;&#x5F0F;&#xFF0C;&#x53EF;&#x4EE5;&#x63D0;&#x9AD8;&#x6570;&#x636E;&#x8BBF;&#x95EE;&#x7684;&#x901F;&#x5EA6;&#xFF0C;&#x56E0;&#x4E3A;&#x7D22;&#x5F15;&#x548C;&#x6570;&#x636E;&#x662F;&#x4FDD;&#x5B58;&#x5728;&#x540C;&#x4E00;&#x68F5;B&#x6811;&#x4E4B;&#x4E2D;&#xFF0C;&#x4ECE;&#x805A;&#x7C07;&#x7D22;&#x5F15;&#x4E2D;&#x83B7;&#x53D6;&#x6570;&#x636E;&#x901A;&#x5E38;&#x6BD4;&#x5728;&#x975E;&#x805A;&#x7C07;&#x7D22;&#x5F15;&#x4E2D;&#x8981;&#x6765;&#x5F97;&#x5FEB;&#x3002;</p>
<p>&#x6240;&#x4EE5;&#x53EF;&#x4EE5;&#x8BF4;&#xFF0C;innodb&#x7684;&#x6570;&#x636E;&#x6587;&#x4EF6;&#x662F;&#x4F9D;&#x9760;&#x4E3B;&#x952E;&#x7EC4;&#x7EC7;&#x8D77;&#x6765;&#x7684;&#xFF0C;&#x8FD9;&#x4E5F;&#x5C31;&#x662F;&#x4E3A;&#x4EC0;&#x4E48;innodb&#x5F15;&#x64CE;&#x4E0B;&#x521B;&#x5EFA;&#x7684;&#x8868;&#xFF0C;&#x5FC5;&#x987B;&#x6307;&#x5B9A;&#x4E3B;&#x952E;&#x7684;&#x539F;&#x56E0;&#xFF0C;&#x5982;&#x679C;&#x6CA1;&#x6709;&#x663E;&#x5F0F;&#x6307;&#x5B9A;&#x4E3B;&#x952E;&#xFF0C;innodb&#x5F15;&#x64CE;&#x4ECD;&#x7136;&#x4F1A;&#x5BF9;&#x8BE5;&#x8868;&#x9690;&#x5F0F;&#x5730;&#x5B9A;&#x4E49;&#x4E00;&#x4E2A;&#x4E3B;&#x952E;&#x4F5C;&#x4E3A;&#x805A;&#x7C07;&#x7D22;&#x5F15;&#x3002;<br>
<img src="/content/images/2018/06/Innodbprimary.png" alt="MySQL&#x548C;B&#x6811;&#x7684;&#x90A3;&#x4E9B;&#x4E8B;" loading="lazy"><br>
&#x540C;&#x6837;innodb&#x7684;&#x8F85;&#x52A9;&#x7D22;&#x5F15;&#xFF0C;&#x5982;&#x4E0B;&#x56FE;&#x6240;&#x793A;&#xFF0C;&#x5047;&#x8BBE;&#x8FD9;&#x4E9B;&#x5B57;&#x7B26;&#x662F;&#x6309;&#x7167;&#x751F;&#x8096;&#x7684;&#x987A;&#x5E8F;&#x6392;&#x5217;&#x7684;&#xFF08;&#x5176;&#x5B9E;&#x6211;&#x4E5F;&#x4E0D;&#x77E5;&#x9053;&#x5177;&#x4F53;&#x600E;&#x4E48;&#x5B9E;&#x73B0;&#xFF0C;&#x4E0D;&#x8981;&#x5728;&#x610F;&#x8FD9;&#x4E9B;&#x7EC6;&#x8282;&#xFF0C;&#x5C31;&#x662F;&#x4E3E;&#x4E2A;&#x4F8B;&#x5B50;&#xFF09;&#xFF0C;&#x5176;&#x53F6;&#x5B50;&#x8282;&#x70B9;&#x4E2D;&#x4E5F;&#x5305;&#x542B;&#x4E86;&#x8BB0;&#x5F55;&#x7684;&#x4E3B;&#x952E;&#xFF0C;&#x56E0;&#x6B64;innodb&#x5F15;&#x64CE;&#x5728;&#x67E5;&#x8BE2;&#x8F85;&#x52A9;&#x7D22;&#x5F15;&#x7684;&#x65F6;&#x5019;&#x4F1A;&#x67E5;&#x8BE2;&#x4E24;&#x6B21;&#xFF0C;&#x9996;&#x5148;&#x901A;&#x8FC7;&#x8F85;&#x52A9;&#x7D22;&#x5F15;&#x5F97;&#x5230;&#x4E3B;&#x952E;&#x503C;&#xFF0C;&#x7136;&#x540E;&#x518D;&#x67E5;&#x8BE2;&#x4E3B;&#x7D22;&#x5F15;&#xFF0C;&#x7565;&#x5FAE;&#x6709;&#x70B9;&#x5570;&#x55E6;&#x3002;&#x3002;&#x3002;<br>
<img src="/content/images/2018/06/innodbsecondary.png" alt="MySQL&#x548C;B&#x6811;&#x7684;&#x90A3;&#x4E9B;&#x4E8B;" loading="lazy"></p>
<h4 id="42myisam">4.2 MyISAM&#x7684;&#x7D22;&#x5F15;&#x673A;&#x5236;</h4>
<p>MyISAM&#x5F15;&#x64CE;&#x540C;&#x6837;&#x4E5F;&#x4F7F;&#x7528;B+&#x6811;&#x7EC4;&#x7EC7;&#x7D22;&#x5F15;&#xFF0C;&#x5982;&#x4E0B;&#x56FE;&#x6240;&#x793A;&#xFF0C;&#x5047;&#x8BBE;&#x6211;&#x4EEC;&#x7684;&#x6570;&#x636E;&#x4E0D;&#x662F;&#x6309;&#x7167;&#x4E4B;&#x524D;&#x7684;&#x987A;&#x5E8F;&#x63D2;&#x5165;&#x7684;&#xFF0C;&#x800C;&#x662F;&#x6309;&#x7167;&#x56FE;&#x4E2D;&#x7684;&#x662F;&#x987A;&#x5E8F;&#x63D2;&#x5165;&#x8868;&#xFF0C;&#x53EF;&#x4EE5;&#x770B;&#x5230;MyISAM&#x5F15;&#x64CE;&#x4E0B;&#xFF0C;B+&#x6811;&#x53F6;&#x5B50;&#x8282;&#x70B9;&#x4E2D;&#x5305;&#x542B;&#x7684;&#x662F;&#x6570;&#x636E;&#x8BB0;&#x5F55;&#x7684;&#x5730;&#x5740;&#xFF08;&#x53EF;&#x4EE5;&#x7B80;&#x5355;&#x7406;&#x89E3;&#x4E3A;&#x201C;&#x884C;&#x53F7;&#x201D;&#xFF09;&#xFF0C;&#x800C;MyISAM&#x7684;&#x8F85;&#x52A9;&#x7D22;&#x5F15;&#x5728;&#x7ED3;&#x6784;&#x4E0A;&#x548C;&#x4E3B;&#x7D22;&#x5F15;&#x6CA1;&#x6709;&#x672C;&#x8D28;&#x7684;&#x533A;&#x522B;&#xFF0C;&#x540C;&#x6837;&#x5176;&#x53F6;&#x5B50;&#x8282;&#x70B9;&#x4E5F;&#x5305;&#x542B;&#x4E86;&#x6570;&#x636E;&#x8BB0;&#x5F55;&#x7684;&#x5730;&#x5740;&#xFF0C;&#x7A0D;&#x5FAE;&#x4E0D;&#x540C;&#x7684;&#x662F;&#x8F85;&#x52A9;&#x7D22;&#x5F15;&#x7684;&#x5173;&#x952E;&#x5B57;&#x662F;&#x5141;&#x8BB8;&#x91CD;&#x590D;<br>
<img src="/content/images/2018/06/myisamprimary.png" alt="MySQL&#x548C;B&#x6811;&#x7684;&#x90A3;&#x4E9B;&#x4E8B;" loading="lazy"><br>
<img src="/content/images/2018/06/myisamsecondary.png" alt="MySQL&#x548C;B&#x6811;&#x7684;&#x90A3;&#x4E9B;&#x4E8B;" loading="lazy"></p>
<h2 id>&#x4E94;&#x3001;&#x7B80;&#x5355;&#x5BF9;&#x6BD4;</h2>
<ol>
<li>Innodb&#x8F85;&#x52A9;&#x7D22;&#x5F15;&#x7684;&#x53F6;&#x5B50;&#x8282;&#x70B9;&#x5B58;&#x50A8;&#x7684;&#x4E0D;&#x662F;&#x5730;&#x5740;&#xFF0C;&#x800C;&#x662F;&#x4E3B;&#x952E;&#x503C;&#xFF0C;&#x8FD9;&#x6837;&#x7684;&#x7B56;&#x7565;&#x51CF;&#x5C11;&#x4E86;&#x5F53;&#x51FA;&#x73B0;&#x884C;&#x79FB;&#x52A8;&#x6216;&#x8005;&#x6570;&#x636E;&#x9875;&#x5206;&#x88C2;&#x65F6;&#x8F85;&#x52A9;&#x7D22;&#x5F15;&#x7684;&#x7EF4;&#x62A4;&#x5DE5;&#x4F5C;&#xFF0C;&#x867D;&#x7136;&#x4F7F;&#x7528;&#x4E3B;&#x952E;&#x503C;&#x5F53;&#x4F5C;&#x6307;&#x9488;&#x4F1A;&#x8BA9;&#x8F85;&#x52A9;&#x7D22;&#x5F15;&#x5360;&#x7528;&#x66F4;&#x591A;&#x7A7A;&#x95F4;&#xFF0C;&#x4F46;&#x597D;&#x5904;&#x662F;&#xFF0C;Innodb&#x5728;&#x79FB;&#x52A8;&#x884C;&#x65F6;&#x65E0;&#x9700;&#x66F4;&#x65B0;&#x8F85;&#x52A9;&#x7D22;&#x5F15;&#x4E2D;&#x7684;&#x4E3B;&#x952E;&#x503C;&#xFF0C;&#x800C;MyISAM&#x9700;&#x8981;&#x8C03;&#x6574;&#x5176;&#x53F6;&#x5B50;&#x8282;&#x70B9;&#x4E2D;&#x7684;&#x5730;&#x5740;</li>
<li>innodb&#x5F15;&#x64CE;&#x4E0B;&#xFF0C;&#x6570;&#x636E;&#x8BB0;&#x5F55;&#x662F;&#x4FDD;&#x5B58;&#x5728;B+&#x6811;&#x7684;&#x53F6;&#x5B50;&#x8282;&#x70B9;&#xFF08;&#x5927;&#x5C0F;&#x76F8;&#x5F53;&#x4E8E;&#x78C1;&#x76D8;&#x4E0A;&#x7684;&#x9875;&#xFF09;&#x4E0A;&#xFF0C;&#x5F53;&#x63D2;&#x5165;&#x65B0;&#x7684;&#x6570;&#x636E;&#x65F6;&#xFF0C;&#x5982;&#x679C;&#x4E3B;&#x952E;&#x7684;&#x503C;&#x662F;&#x6709;&#x5E8F;&#x7684;&#xFF0C;&#x5B83;&#x4F1A;&#x628A;&#x6BCF;&#x4E00;&#x6761;&#x8BB0;&#x5F55;&#x90FD;&#x5B58;&#x50A8;&#x5728;&#x4E0A;&#x4E00;&#x6761;&#x8BB0;&#x5F55;&#x7684;&#x540E;&#x9762;&#xFF0C;&#x4F46;&#x662F;&#x5982;&#x679C;&#x4E3B;&#x952E;&#x4F7F;&#x7528;&#x7684;&#x662F;&#x65E0;&#x5E8F;&#x7684;&#x6570;&#x503C;&#xFF0C;&#x4F8B;&#x5982;UUID&#xFF0C;&#x8FD9;&#x6837;&#x5728;&#x63D2;&#x5165;&#x6570;&#x636E;&#x65F6;Innodb&#x65E0;&#x6CD5;&#x7B80;&#x5355;&#x5730;&#x628A;&#x65B0;&#x7684;&#x6570;&#x636E;&#x63D2;&#x5165;&#x5230;&#x6700;&#x540E;&#xFF0C;&#x800C;&#x662F;&#x9700;&#x8981;&#x4E3A;&#x8FD9;&#x6761;&#x6570;&#x636E;&#x5BFB;&#x627E;&#x5408;&#x9002;&#x7684;&#x4F4D;&#x7F6E;&#xFF0C;&#x8FD9;&#x5C31;&#x989D;&#x5916;&#x589E;&#x52A0;&#x4E86;&#x5DE5;&#x4F5C;&#xFF0C;&#x8FD9;&#x5C31;&#x662F;innodb&#x5F15;&#x64CE;&#x5199;&#x5165;&#x6027;&#x80FD;&#x8981;&#x7565;&#x5DEE;&#x4E8E;MyISAM&#x7684;&#x539F;&#x56E0;&#x4E4B;&#x4E00;</li>
</ol>
<p>Innodb&#x548C;MyISAM&#x7D22;&#x5F15;&#x7684;&#x62BD;&#x8C61;&#x56FE;<br>
<img src="/content/images/2018/06/innodb_myisam.png" alt="MySQL&#x548C;B&#x6811;&#x7684;&#x90A3;&#x4E9B;&#x4E8B;" loading="lazy"></p>
<h2 id>&#x516D;&#x3001;&#x53C2;&#x8003;&#x6587;&#x732E;</h2>
<p>Bayer, R.; McCreight, E. (1972), &#x201C;Organization and Maintenance of Large Ordered Indexes&#x201D; (PDF), Acta Informatica, 1 (3): 173&#x2013;189<br>
<a href="http://www.minet.uni-jena.de/dbis/lehre/ws2005/dbs1/Bayer_hist.pdf">http://www.minet.uni-jena.de/dbis/lehre/ws2005/dbs1/Bayer_hist.pdf</a></p>
<p>&#x4E25;&#x851A;&#x654F;, &#x5434;&#x4F1F;&#x6C11;. &#x6570;&#x636E;&#x7ED3;&#x6784;: C &#x8BED;&#x8A00;&#x7248;[M]. &#x6E05;&#x534E;&#x5927;&#x5B66;&#x51FA;&#x7248;&#x793E;&#x6709;&#x9650;&#x516C;&#x53F8;, 2002.<br>
<a href="http://cs.ecust.edu.cn/snwei/studypc/jsjdl/data/sjjgc.pdf">http://cs.ecust.edu.cn/snwei/studypc/jsjdl/data/sjjgc.pdf</a></p>
<p>Schwartz B, Zaitsev P, Tkachenko V. High performance MySQL: Optimization, backups, and replication[M]. &#x201D; O&#x2019;Reilly Media, Inc.&#x201D;, 2012.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[MySQL主从复制快速部署技巧]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="mysqldumpmasterdata">&#x4E00;&#x3001;mysqldump &#x2013;master-data&#x53C2;&#x6570;&#x4ECB;&#x7ECD;</h2>
<p>MySQL&#x4E3B;&#x4ECE;&#x590D;&#x5236;&#x539F;&#x7406;&#x56FE;<br>
<img src="http://www.fullstackyang.com/content/images/2018/06/mysql-------.png" alt="mysql-------" loading="lazy"><br>
&#x6309;&#x7167;mysql&#x6700;&#x7ECF;&#x5178;&#x7684;&#x90E8;&#x7F72;&#x4E3B;&#x4ECE;&#x590D;&#x5236;&#x7684;&#x65B9;&#x5F0F;&#xFF0C;&#x5FC5;&#x987B;&#x8981;&#x7ECF;&#x8FC7;&#x9501;&#x8868;&#xFF0C;&#x518D;&#x5BFC;&#x51FA;&#x5168;&#x5907;&#x6570;&#x636E;&#xFF0C;</p>]]></description><link>http://www.fullstackyang.com/mysqlzhu-cong-fu-zhi-kuai-su-bu-shu-ji-qiao/</link><guid isPermaLink="false">624567890d2dd30001909ffc</guid><category><![CDATA[database]]></category><category><![CDATA[arch]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Wed, 03 Aug 2016 14:15:00 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2018/06/MySQL-replication-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="mysqldumpmasterdata">&#x4E00;&#x3001;mysqldump &#x2013;master-data&#x53C2;&#x6570;&#x4ECB;&#x7ECD;</h2>
<img src="http://www.fullstackyang.com/content/images/2018/06/MySQL-replication-1.jpg" alt="MySQL&#x4E3B;&#x4ECE;&#x590D;&#x5236;&#x5FEB;&#x901F;&#x90E8;&#x7F72;&#x6280;&#x5DE7;"><p>MySQL&#x4E3B;&#x4ECE;&#x590D;&#x5236;&#x539F;&#x7406;&#x56FE;<br>
<img src="http://www.fullstackyang.com/content/images/2018/06/mysql-------.png" alt="MySQL&#x4E3B;&#x4ECE;&#x590D;&#x5236;&#x5FEB;&#x901F;&#x90E8;&#x7F72;&#x6280;&#x5DE7;" loading="lazy"><br>
&#x6309;&#x7167;mysql&#x6700;&#x7ECF;&#x5178;&#x7684;&#x90E8;&#x7F72;&#x4E3B;&#x4ECE;&#x590D;&#x5236;&#x7684;&#x65B9;&#x5F0F;&#xFF0C;&#x5FC5;&#x987B;&#x8981;&#x7ECF;&#x8FC7;&#x9501;&#x8868;&#xFF0C;&#x518D;&#x5BFC;&#x51FA;&#x5168;&#x5907;&#x6570;&#x636E;&#xFF0C;&#x6700;&#x540E;&#x518D;&#x89E3;&#x9501;&#x7684;&#x6B65;&#x9AA4;&#xFF0C;&#x8FD9;&#x6837;&#x7684;&#x64CD;&#x4F5C;&#x7565;&#x663E;&#x7E41;&#x7410;</p>
<p>&#x4E8B;&#x5B9E;&#x4E0A;mysqldump&#x547D;&#x4EE4;&#x4E2D;&#x63D0;&#x4F9B;&#x4E86;&#x4E00;&#x4E2A;&#x6BD4;&#x8F83;&#x65B9;&#x4FBF;&#x7684;&#x53C2;&#x6570;&#xFF0C;&#x5373;&#x2013;master-data<br>
&#x4E0B;&#x9762;&#x5185;&#x5BB9;&#x6765;&#x81EA;&#x5B98;&#x65B9;&#x624B;&#x518C;&#xFF1A;</p>
<blockquote>
<p>It causes the dump output to include a CHANGE MASTER TO statement that indicates the binary log coordinates (file name and position) of the dumped server. These are the master server coordinates from which the slave should start replicating after you load the dump file into the slave.</p>
</blockquote>
<p>&#x4E5F;&#x5C31;&#x662F;&#x8BF4;&#xFF0C;&#x8FD9;&#x4E2A;&#x53C2;&#x6570;&#x4F1A;&#x5F53;&#x524D;binlog&#x6587;&#x4EF6;&#x540D;&#x548C;&#x4F4D;&#x7F6E;&#x4E00;&#x5E76;&#x8F93;&#x51FA;&#x5230;&#x6587;&#x4EF6;&#xFF0C;&#x8FD9;&#x5C31;&#x65B9;&#x4FBF;&#x6211;&#x4EEC;&#x5728;&#x4ECE;&#x5E93;&#x4E0A;&#x6062;&#x590D;&#x6570;&#x636E;&#x65F6;&#xFF0C;&#x4E0D;&#x7528;&#x518D;&#x4EBA;&#x5DE5;&#x6838;&#x5BF9;binlog&#x5750;&#x6807;&#xFF0C;&#x540C;&#x65F6;dump&#x6570;&#x636E;&#x65F6;&#x8FD8;&#x4F1A;&#x6253;&#x5F00;&#x5168;&#x5C40;&#x7684;&#x8BFB;&#x9501;&#xFF08;&#x76F8;&#x5F53;&#x4E8E;&#x2013;lock-all-tables&#xFF0C;-x&#xFF09;&#xFF0C;&#x53EF;&#x4EE5;&#x8BF4;&#x2013;master-data&#x53C2;&#x6570;&#x5C31;&#x662F;&#x4E3A;&#x4E86;&#x90E8;&#x7F72;&#x4ECE;&#x5E93;&#x800C;&#x8BBE;&#x8BA1;&#x7684;</p>
<h2 id>&#x4E8C;&#x3001;&#x64CD;&#x4F5C;&#x8FC7;&#x7A0B;</h2>
<h4 id="1binlogserverid">1. &#x786E;&#x8BA4;&#x4E3B;&#x5E93;&#x5F00;&#x542F;binlog&#x529F;&#x80FD;&#xFF0C;&#x5E76;&#x4FDD;&#x8BC1;server-id&#x5404;&#x4E0D;&#x76F8;&#x540C;</h4>
<h4 id="2mysqldump">2. mysqldump&#x547D;&#x4EE4;&#x5BF9;&#x4E3B;&#x5E93;&#x7684;&#x6570;&#x636E;&#x8FDB;&#x884C;&#x5168;&#x5907;</h4>
<pre><code># mysqldump -uroot -p -A -B --events --master-data=1|gzip &gt;/server/backup/mysql_bak_master_data_$(date +%F).sql.gz
</code></pre>
<h4 id="3">3.&#x5C06;&#x5907;&#x4EFD;&#x6587;&#x4EF6;&#x8FC1;&#x79FB;&#x5230;&#x4ECE;&#x5E93;&#x670D;&#x52A1;&#x5668;</h4>
<h4 id="4changemasterto">4.&#x4ECE;&#x5E93;&#x6267;&#x884C;change master to&#x2026;&#x547D;&#x4EE4;</h4>
<pre><code>mysql&gt; change master to
&gt; master_host=&apos;172.16.1.52&apos;,
&gt; master_port=3306,
&gt; master_user=&apos;rep&apos;,
&gt; master_password=&apos;password&apos;;
</code></pre>
<blockquote>
<p>&#x8BF4;&#x660E;&#xFF1A;change master &#x547D;&#x4EE4;&#x9700;&#x8981;&#x5728;&#x4E0B;&#x9762;&#x7684;&#x6062;&#x590D;&#x6570;&#x636E;&#x6B65;&#x9AA4;&#x4E4B;&#x524D;&#x6267;&#x884C;&#xFF0C;&#x5426;&#x5219;&#x7531;master-data=1&#x4EA7;&#x751F;&#x7684;change master&#x8BED;&#x53E5;&#x5199;&#x5165;master.info&#x7684;&#x5185;&#x5BB9;&#x4F1A;&#x88AB;&#x624B;&#x52A8;&#x6267;&#x884C;change master&#x540E;&#x4FEE;&#x6539;&#xFF0C;&#x4EA6;&#x5373;&#xFF0C;&#x5148;&#x6062;&#x590D;&#x6570;&#x636E;&#x65F6;&#xFF0C;master.info&#x547D;&#x4EE4;&#x5199;&#x5165;binlog&#x7684;&#x5750;&#x6807;&#xFF0C;&#x63A5;&#x7740;&#x518D;&#x624B;&#x52A8;&#x6267;&#x884C;change master to&#x914D;&#x7F6E;&#x4E3B;&#x5E93;&#x5730;&#x5740;&#xFF0C;&#x8D26;&#x53F7;&#x7B49;&#x4FE1;&#x606F;&#x65F6;&#xFF0C;&#x5C31;&#x4F1A;&#x628A;master.info&#x7684;&#x5185;&#x5BB9;&#x8986;&#x76D6;&#x6389;&#xFF0C;&#x4ECE;&#x800C;&#x4E22;&#x5931;&#x4E86;binlog&#x5750;&#x6807;&#x4FE1;&#x606F;</p>
</blockquote>
<h4 id="5">5.&#x4ECE;&#x5E93;&#x4E0A;&#x6062;&#x590D;&#x6570;&#x636E;</h4>
<pre><code># cd /server/backup
# gzip -d mysql_bak_master_data_2016-08-04.sql.gz
# mysql -uroot -p &lt;/server/backup/mysql_bak_master_data_2016-08-04.sql
# cat /data/3308/data/master.info 
18
mysql-bin.000003
2503
172.16.1.52
rep
password
3306
60
0





0
1800.000

0
</code></pre>
<h4 id="6">6. &#x4ECE;&#x5E93;&#x542F;&#x52A8;&#x590D;&#x5236;</h4>
<pre><code># mysql -uroot -p -e &quot;start slave;&quot;
# mysql -uroot -p -e &quot;show slave status \G;&quot;
*************************** 1. row ***************************
 Slave_IO_State: Waiting for master to send event
 Master_Host: 172.16.1.52
 Master_User: rep
 Master_Port: 3306
 Connect_Retry: 60
 Master_Log_File: mysql-bin.000003
 Read_Master_Log_Pos: 2503
 Relay_Log_File: relay-bin.000002
 Relay_Log_Pos: 253
 Relay_Master_Log_File: mysql-bin.000003
 Slave_IO_Running: Yes
 Slave_SQL_Running: Yes
&#x2026;&#x2026;
 Seconds_Behind_Master: 0
&#x2026;&#x2026;
</code></pre>
<blockquote>
<p>&#x8BF4;&#x660E;&#xFF1A;&#x5982;&#x679C;start slave&#x542F;&#x52A8;&#x590D;&#x5236;&#x5931;&#x8D25;&#xFF0C;&#x5219;&#x4F7F;&#x7528;reset slave all&#x547D;&#x4EE4;&#x6E05;&#x7A7A;&#x6240;&#x6709;&#x7684;&#x4ECE;&#x5E93;&#x8FDE;&#x63A5;&#x53C2;&#x6570;&#xFF0C;&#x7136;&#x540E;&#x518D;&#x6309;&#x7167;&#x4E0A;&#x8FF0;&#x6B65;&#x9AA4;&#x6267;&#x884C;&#x4E00;&#x6B21;&#x5373;&#x53EF;</p>
</blockquote>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[MySQL数据库增量数据恢复案例]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id>&#x4E00;&#x3001;&#x573A;&#x666F;&#x6982;&#x8FF0;</h2>
<ol>
<li>MySQL&#x6570;&#x636E;&#x5E93;&#x6BCF;&#x65E5;&#x96F6;&#x70B9;&#x81EA;&#x52A8;&#x5168;&#x5907;</li>
<li>&#x67D0;&#x5929;&#x4E0A;&#x5348;10&#x70B9;&#xFF0C;&#x5C0F;&#x660E;&#x83AB;&#x540D;&#x5176;&#x5999;&#x5730;drop&#x4E86;&#x4E00;&#x4E2A;&#x6570;&#x636E;&#x5E93;</li>
<li>&#x6211;&#x4EEC;&#x9700;&#x8981;&#x901A;&#x8FC7;&#x5168;&#x5907;&#x7684;&#x6570;&#x636E;</li></ol>]]></description><link>http://www.fullstackyang.com/mysqlshu-ju-ku-zeng-liang-shu-ju-hui-fu-an-li/</link><guid isPermaLink="false">624567890d2dd30001909ffb</guid><category><![CDATA[database]]></category><category><![CDATA[ops]]></category><dc:creator><![CDATA[yangyang]]></dc:creator><pubDate>Tue, 02 Aug 2016 13:39:00 GMT</pubDate><media:content url="http://www.fullstackyang.com/content/images/2018/06/immersus_media_james_prola_mysql_mascot_rebound_shark_01_1x.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id>&#x4E00;&#x3001;&#x573A;&#x666F;&#x6982;&#x8FF0;</h2>
<ol>
<li>MySQL&#x6570;&#x636E;&#x5E93;&#x6BCF;&#x65E5;&#x96F6;&#x70B9;&#x81EA;&#x52A8;&#x5168;&#x5907;</li>
<li>&#x67D0;&#x5929;&#x4E0A;&#x5348;10&#x70B9;&#xFF0C;&#x5C0F;&#x660E;&#x83AB;&#x540D;&#x5176;&#x5999;&#x5730;drop&#x4E86;&#x4E00;&#x4E2A;&#x6570;&#x636E;&#x5E93;</li>
<li>&#x6211;&#x4EEC;&#x9700;&#x8981;&#x901A;&#x8FC7;&#x5168;&#x5907;&#x7684;&#x6570;&#x636E;&#x6587;&#x4EF6;&#xFF0C;&#x4EE5;&#x53CA;&#x589E;&#x91CF;&#x7684;binlog&#x6587;&#x4EF6;&#x8FDB;&#x884C;&#x6570;&#x636E;&#x6062;&#x590D;</li>
</ol>
<h2 id>&#x4E8C;&#x3001;&#x4E3B;&#x8981;&#x601D;&#x60F3;</h2>
<ol>
<li>&#x5229;&#x7528;&#x5168;&#x5907;&#x7684;sql&#x6587;&#x4EF6;&#x4E2D;&#x8BB0;&#x5F55;&#x7684;CHANGE MASTER&#x8BED;&#x53E5;&#xFF0C;binlog&#x6587;&#x4EF6;&#x53CA;&#x5176;&#x4F4D;&#x7F6E;&#x70B9;&#x4FE1;&#x606F;&#xFF0C;&#x627E;&#x51FA;binlog&#x6587;&#x4EF6;&#x589E;&#x91CF;&#x7684;&#x90E8;&#x5206;</li>
<li>&#x7528;mysqlbinlog&#x547D;&#x4EE4;&#x5C06;&#x4E0A;&#x8FF0;&#x7684;binlog&#x6587;&#x4EF6;&#x5BFC;&#x51FA;&#x4E3A;sql&#x6587;&#x4EF6;&#xFF0C;&#x5E76;&#x5254;&#x9664;&#x5176;&#x4E2D;&#x7684;drop&#x8BED;&#x53E5;</li>
<li>&#x901A;&#x8FC7;&#x5168;&#x5907;&#x6587;&#x4EF6;&#x548C;&#x589E;&#x91CF;binlog&#x6587;&#x4EF6;&#x7684;&#x5BFC;&#x51FA;sql&#x6587;&#x4EF6;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x6062;&#x590D;&#x5230;&#x5B8C;&#x6574;&#x7684;&#x6570;&#x636E;</li>
</ol>
<h2 id>&#x4E09;&#x3001;&#x8FC7;&#x7A0B;&#x793A;&#x610F;&#x56FE;</h2>
<img src="http://www.fullstackyang.com/content/images/2018/06/immersus_media_james_prola_mysql_mascot_rebound_shark_01_1x.jpg" alt="MySQL&#x6570;&#x636E;&#x5E93;&#x589E;&#x91CF;&#x6570;&#x636E;&#x6062;&#x590D;&#x6848;&#x4F8B;"><p><img src="/content/images/2018/06/QQ--20160802163433.png" alt="MySQL&#x6570;&#x636E;&#x5E93;&#x589E;&#x91CF;&#x6570;&#x636E;&#x6062;&#x590D;&#x6848;&#x4F8B;" loading="lazy"></p>
<h2 id>&#x56DB;&#x3001;&#x64CD;&#x4F5C;&#x8FC7;&#x7A0B;</h2>
<h4 id="1">1. &#x6A21;&#x62DF;&#x6570;&#x636E;</h4>
<pre><code>CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` char(20) NOT NULL,
  `age` tinyint(2) NOT NULL DEFAULT &apos;0&apos;,
  PRIMARY KEY (`id`),
  KEY `index_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 

mysql&gt; insert student values(1,&apos;zhangsan&apos;,20); 
mysql&gt; insert student values(2,&apos;lisi&apos;,21); 
mysql&gt; insert student values(3,&apos;wangwu&apos;,22);
</code></pre>
<h4 id="2">2. &#x5168;&#x5907;&#x547D;&#x4EE4;</h4>
<pre><code># mysqldump -uroot -p -B -F -R -x --master-data=2 test|gzip &gt;/server/backup/test_$(date +%F).sql.gz

&#x53C2;&#x6570;&#x8BF4;&#x660E;&#xFF1A;
-B &#x6307;&#x5B9A;&#x6570;&#x636E;&#x5E93;
-F &#x5237;&#x65B0;&#x65E5;&#x5FD7;
-R &#x5907;&#x4EFD;&#x5B58;&#x50A8;&#x8FC7;&#x7A0B;&#x7B49;
-x &#x9501;&#x8868;
--master-data &#x5728;&#x5907;&#x4EFD;&#x8BED;&#x53E5;&#x91CC;&#x6DFB;&#x52A0;CHANGE MASTER&#x8BED;&#x53E5;&#x4EE5;&#x53CA;binlog&#x6587;&#x4EF6;&#x53CA;&#x4F4D;&#x7F6E;&#x70B9;&#x4FE1;&#x606F;
</code></pre>
<h4 id="3">3. &#x7EE7;&#x7EED;&#x63D2;&#x5165;&#x6570;&#x636E;</h4>
<pre><code>mysql&gt; insert student values(6,&apos;xiaoming&apos;,20);
 
mysql&gt; insert student values(6,&apos;xiaohong&apos;,20); 

&#x6B64;&#x65F6;&#x8BEF;&#x64CD;&#x4F5C;&#xFF0C;&#x5220;&#x9664;&#x4E86;test&#x6570;&#x636E;&#x5E93;
mysql&gt; drop database test;
</code></pre>
<p>&#x6B64;&#x65F6;&#xFF0C;&#x5168;&#x5907;&#x4E4B;&#x540E;&#x5230;&#x8BEF;&#x64CD;&#x4F5C;&#x65F6;&#x523B;&#x4E4B;&#x95F4;&#xFF0C;&#x7528;&#x6237;&#x5199;&#x5165;&#x7684;&#x6570;&#x636E;&#x5728;binlog&#x4E2D;&#xFF0C;&#x9700;&#x8981;&#x6062;&#x590D;&#x51FA;&#x6765;</p>
<h4 id="4binlog">4. &#x67E5;&#x770B;&#x5168;&#x5907;&#x4E4B;&#x540E;&#x65B0;&#x589E;&#x7684;binlog&#x6587;&#x4EF6;</h4>
<pre><code># cd /server/backup/
# ls
test_2016-08-02.sql.gz
# gzip -d test_2016-08-02.sql.gz 
# grep CHANGE test_2016-08-02.sql 
-- CHANGE MASTER TO MASTER_LOG_FILE=&apos;mysql-bin.000003&apos;, MASTER_LOG_POS=107;
</code></pre>
<p>&#x8FD9;&#x662F;&#x5168;&#x5907;&#x65F6;&#x523B;&#x7684;binlog&#x6587;&#x4EF6;&#x4F4D;&#x7F6E;&#xFF0C;&#x5373;mysql-bin.000003&#x7684;107&#x884C;&#xFF0C;&#x56E0;&#x6B64;&#x5728;&#x8BE5;&#x6587;&#x4EF6;&#x4E4B;&#x524D;&#x7684;binlog&#x6587;&#x4EF6;&#x4E2D;&#x7684;&#x6570;&#x636E;&#x90FD;&#x5DF2;&#x7ECF;&#x5305;&#x542B;&#x5728;&#x8FD9;&#x4E2A;&#x5168;&#x5907;&#x7684;sql&#x6587;&#x4EF6;&#x4E2D;&#x4E86;</p>
<h4 id="5binlogsqldrop">5. &#x79FB;&#x52A8;binlog&#x6587;&#x4EF6;&#xFF0C;&#x5E76;&#x8BFB;&#x53D6;sql&#xFF0C;&#x5254;&#x9664;&#x5176;&#x4E2D;&#x7684;drop&#x8BED;&#x53E5;</h4>
<pre><code># cp /data/3306/mysql-bin.000003 /server/backup/
# mysqlbinlog -d test mysql-bin.000003 &gt;003bin.sql
# &#x7528;vim&#x7F16;&#x8F91;&#x6587;&#x4EF6;&#xFF0C;&#x5254;&#x9664;drop&#x8BED;&#x53E5;
</code></pre>
<p>&#x5728;&#x6062;&#x590D;&#x5168;&#x5907;&#x6570;&#x636E;&#x4E4B;&#x524D;&#x5FC5;&#x987B;&#x5C06;&#x8BE5;binlog&#x6587;&#x4EF6;&#x79FB;&#x51FA;&#xFF0C;&#x5426;&#x5219;&#x6062;&#x590D;&#x8FC7;&#x7A0B;&#x4E2D;&#xFF0C;&#x4F1A;&#x7EE7;&#x7EED;&#x5199;&#x5165;&#x8BED;&#x53E5;&#x5230;binlog&#xFF0C;&#x6700;&#x7EC8;&#x5BFC;&#x81F4;&#x589E;&#x91CF;&#x6062;&#x590D;&#x6570;&#x636E;&#x90E8;&#x5206;&#x53D8;&#x5F97;&#x6BD4;&#x8F83;&#x6DF7;&#x4E71;</p>
<h4 id="6">6. &#x6062;&#x590D;&#x6570;&#x636E;</h4>
<pre><code># mysql -uroot -p &lt;test_2016-08-02.sql 
# mysql -uroot -p -e &quot;select * from test.student;&quot;
+----+----------+-----+
| id | name     | age |
+----+----------+-----+
|  1 | zhangsan |  20 |
|  2 | lisi     |  21 |
|  3 | wangwu   |  22 |
+----+----------+-----+
//&#x6B64;&#x65F6;&#x6062;&#x590D;&#x4E86;&#x5168;&#x5907;&#x65F6;&#x523B;&#x7684;&#x6570;&#x636E;
//&#x7136;&#x540E;&#x4F7F;&#x7528;003bin.sql&#x6587;&#x4EF6;&#x6062;&#x590D;&#x5168;&#x5907;&#x65F6;&#x523B;&#x5230;&#x5220;&#x9664;&#x6570;&#x636E;&#x5E93;&#x4E4B;&#x95F4;&#xFF0C;&#x65B0;&#x589E;&#x7684;&#x6570;&#x636E;
# mysql -uroot -p test&lt;003bin.sql &lt;-&#x9700;&#x8981;&#x6307;&#x5B9A;&#x6062;&#x590D;&#x7684;&#x6570;&#x636E;&#x5E93;
# mysql -uroot -p -e &quot;select * from test.student;&quot;
+----+----------+-----+
| id | name     | age |
+----+----------+-----+
|  1 | zhangsan |  20 |
|  2 | lisi     |  20 |
|  3 | wangwu   |  20 |
|  4 | xiaoming |  20 | 
|  5 | xiaohong |  20 |
+----+----------+-----+
&#x5B8C;&#x6210;
</code></pre>
<h2 id>&#x4E94;&#x3001;&#x5C0F;&#x7ED3;</h2>
<ul>
<li>&#x9002;&#x5408;&#x4EBA;&#x4E3A;SQL&#x8BED;&#x53E5;&#x9020;&#x6210;&#x7684;&#x8BEF;&#x64CD;&#x4F5C;&#x6216;&#x8005;&#x6CA1;&#x6709;&#x4E3B;&#x4ECE;&#x590D;&#x5236;&#x7B49;&#x7684;&#x70ED;&#x5907;&#x60C5;&#x51B5;&#x5B95;&#x673A;&#x65F6;&#x7684;&#x4FEE;&#x590D;</li>
<li>&#x6062;&#x590D;&#x6761;&#x4EF6;&#x8981;&#x5168;&#x5907;&#x548C;&#x589E;&#x91CF;&#x7684;&#x6240;&#x6709;&#x6570;&#x636E;</li>
<li>&#x6062;&#x590D;&#x65F6;&#x5EFA;&#x8BAE;&#x5BF9;&#x5916;&#x505C;&#x6B62;&#x66F4;&#x65B0;&#xFF0C;&#x5373;&#x7981;&#x6B62;&#x66F4;&#x65B0;&#x6570;&#x636E;&#x5E93;</li>
<li>&#x5148;&#x6062;&#x590D;&#x5168;&#x91CF;&#xFF0C;&#x7136;&#x540E;&#x628A;&#x5168;&#x5907;&#x65F6;&#x523B;&#x70B9;&#x4EE5;&#x540E;&#x7684;&#x589E;&#x91CF;&#x65E5;&#x5FD7;&#xFF0C;&#x6309;&#x987A;&#x5E8F;&#x6062;&#x590D;&#x6210;SQL&#x6587;&#x4EF6;&#xFF0C;&#x7136;&#x540E;&#x628A;&#x6587;&#x4EF6;&#x4E2D;&#x6709;&#x95EE;&#x9898;&#x7684;SQL&#x8BED;&#x53E5;&#x5220;&#x9664;&#xFF08;&#x4E5F;&#x53EF;&#x901A;&#x8FC7;&#x65F6;&#x95F4;&#x548C;&#x4F4D;&#x7F6E;&#x70B9;&#xFF09;&#xFF0C;&#x518D;&#x6062;&#x590D;&#x5230;&#x6570;&#x636E;&#x5E93;</li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>