<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Zhihang&#39;s Blog</title>
    <link>https://zhihang.org/</link>
    <description>Recent content on Zhihang&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-cn</language>
    <managingEditor>akynazh@gmail.com (zhihang)</managingEditor>
    <webMaster>akynazh@gmail.com (zhihang)</webMaster>
    <lastBuildDate>Fri, 05 Sep 2025 01:07:44 +0800</lastBuildDate><atom:link href="https://zhihang.org/index.xml" rel="self" type="application/rss+xml" />
      
      <item>
        <title>个人快捷键记忆表</title>
        <link>https://zhihang.org/posts/personal-shortcut-key-configuration-record/</link>
        <pubDate>Fri, 05 Sep 2025 01:07:44 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>personal-shortcut-key-configuration-record</guid>
        <description>&lt;h2 id=&#34;preface&#34;&gt;Preface&lt;/h2&gt;
&lt;p&gt;MacOS &amp;amp; Windows Shortcuts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#preface&#34;&gt;Preface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#macos-shortcuts&#34;&gt;MacOS Shortcuts&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#cmd--cmd--shift&#34;&gt;CMD &amp;gt;&amp;gt; CMD + SHIFT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#alt&#34;&gt;ALT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#windows-shortcuts&#34;&gt;Windows Shortcuts&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#ctrl--ctrl--shift&#34;&gt;CTRL &amp;gt;&amp;gt; CTRL + SHIFT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#win&#34;&gt;WIN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#fn&#34;&gt;FN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#autohotkey&#34;&gt;AutoHotkey&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#app_windows_switch&#34;&gt;app_windows_switch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#chrome_duplicate_tab&#34;&gt;chrome_duplicate_tab&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;macos-shortcuts&#34;&gt;MacOS Shortcuts&lt;/h2&gt;
&lt;h3 id=&#34;cmd--cmd--shift&#34;&gt;CMD &amp;raquo; CMD + SHIFT&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Func&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Config&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;`&lt;/td&gt;
&lt;td&gt;Move Focus To Next Window&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Zoom Out&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;Zoom In&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tab&lt;/td&gt;
&lt;td&gt;Switch Apps&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q&lt;/td&gt;
&lt;td&gt;Quit App&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;W&lt;/td&gt;
&lt;td&gt;Close&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;Translate &amp;raquo; Translate(OCR)&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;Pot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;Replace, Refresh&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;td&gt;New Tab&lt;/td&gt;
&lt;td&gt;Browser&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Everything&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;U&lt;/td&gt;
&lt;td&gt;Usage&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I&lt;/td&gt;
&lt;td&gt;Insert Code&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;Optimize&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P&lt;/td&gt;
&lt;td&gt;Snipaste &amp;raquo; System Screenshot&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;Snipaste, Settings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[&lt;/td&gt;
&lt;td&gt;Fold &amp;raquo; Fold All&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;]&lt;/td&gt;
&lt;td&gt;Unfold &amp;raquo; Unfold All&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\&lt;/td&gt;
&lt;td&gt;Terminal&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S&lt;/td&gt;
&lt;td&gt;Save&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;Duplicate Tab, Split Right&lt;/td&gt;
&lt;td&gt;Browser, IDE&lt;/td&gt;
&lt;td&gt;Settings, IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;Find&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G&lt;/td&gt;
&lt;td&gt;Globally Find&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H&lt;/td&gt;
&lt;td&gt;Hide&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;J&lt;/td&gt;
&lt;td&gt;Execute&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;K&lt;/td&gt;
&lt;td&gt;Debug&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L&lt;/td&gt;
&lt;td&gt;Line&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&#39;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Undo &amp;raquo; Redo&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;Cut&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;Copy&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V&lt;/td&gt;
&lt;td&gt;Paste &amp;raquo; Paste As Plain Text&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;Refactor&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;td&gt;New Window&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;td&gt;Minimize&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;,&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;Comment&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Space&lt;/td&gt;
&lt;td&gt;Search&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RK&lt;/td&gt;
&lt;td&gt;Forward&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LK&lt;/td&gt;
&lt;td&gt;Backward&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UK&lt;/td&gt;
&lt;td&gt;Debug: Step Over&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DK&lt;/td&gt;
&lt;td&gt;Debug: Step Into&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;alt&#34;&gt;ALT&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Func&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Config&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RK&lt;/td&gt;
&lt;td&gt;Window Right Half&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;Rectangle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LK&lt;/td&gt;
&lt;td&gt;Window Left Half&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;Rectangle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UK&lt;/td&gt;
&lt;td&gt;Window Maximize&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;Rectangle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DK&lt;/td&gt;
&lt;td&gt;Window Almost&lt;/td&gt;
&lt;td&gt;Maximize ALL&lt;/td&gt;
&lt;td&gt;Rectangle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V&lt;/td&gt;
&lt;td&gt;Pasteboard&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;Clipy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;windows-shortcuts&#34;&gt;Windows Shortcuts&lt;/h2&gt;
&lt;h3 id=&#34;ctrl--ctrl--shift&#34;&gt;CTRL &amp;raquo; CTRL + SHIFT&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Func&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Config&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;`&lt;/td&gt;
&lt;td&gt;Move Focus To Next Window&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;AutoHotkey&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Zoom Out&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;Zoom In&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tab&lt;/td&gt;
&lt;td&gt;Switch Apps&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;PowerToys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q&lt;/td&gt;
&lt;td&gt;Quit App&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;PowerToys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;W&lt;/td&gt;
&lt;td&gt;Close&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;Translate &amp;raquo; Translate(OCR)&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;Pot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;Replace, Refresh&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;td&gt;New Tab&lt;/td&gt;
&lt;td&gt;Browser&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Everything&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;U&lt;/td&gt;
&lt;td&gt;Usage&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I&lt;/td&gt;
&lt;td&gt;Insert Code&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;Optimize&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P&lt;/td&gt;
&lt;td&gt;Snipaste &amp;raquo; System Screenshot&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;Snipaste, Game Bar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[&lt;/td&gt;
&lt;td&gt;Fold &amp;raquo; Fold All&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;]&lt;/td&gt;
&lt;td&gt;Unfold &amp;raquo; Unfold All&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\&lt;/td&gt;
&lt;td&gt;Terminal&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S&lt;/td&gt;
&lt;td&gt;Save&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;Duplicate Tab, Split Right&lt;/td&gt;
&lt;td&gt;Browser, IDE&lt;/td&gt;
&lt;td&gt;AutoHotkey, IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;Find&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G&lt;/td&gt;
&lt;td&gt;Globally Find&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H&lt;/td&gt;
&lt;td&gt;Hide&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;PowerToys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;J&lt;/td&gt;
&lt;td&gt;Execute&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;K&lt;/td&gt;
&lt;td&gt;Debug&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L&lt;/td&gt;
&lt;td&gt;Line&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&#39;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Undo &amp;raquo; Redo&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;Cut&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;Copy&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V&lt;/td&gt;
&lt;td&gt;Paste &amp;raquo; Paste As Plain Text&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;Refactor&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;td&gt;New Window&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;td&gt;Minimize&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;PowerToys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;,&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;Comment&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Space&lt;/td&gt;
&lt;td&gt;Search&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;PowerToys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RK&lt;/td&gt;
&lt;td&gt;Forward&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LK&lt;/td&gt;
&lt;td&gt;Backward&lt;/td&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UK&lt;/td&gt;
&lt;td&gt;Debug: Step Over&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DK&lt;/td&gt;
&lt;td&gt;Debug: Step Into&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;td&gt;IDE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;win&#34;&gt;WIN&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Func&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RK&lt;/td&gt;
&lt;td&gt;Window Right Half&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LK&lt;/td&gt;
&lt;td&gt;Window Left Half&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UK&lt;/td&gt;
&lt;td&gt;Window Maximize&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DK&lt;/td&gt;
&lt;td&gt;Window Almost Maximize&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;V&lt;/td&gt;
&lt;td&gt;Pasteboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L&lt;/td&gt;
&lt;td&gt;Lock Screen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;Execute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;Quick Links&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G&lt;/td&gt;
&lt;td&gt;Game Bar&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;fn&#34;&gt;FN&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Func&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;F2&lt;/td&gt;
&lt;td&gt;Rename&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F5&lt;/td&gt;
&lt;td&gt;Refresh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F11&lt;/td&gt;
&lt;td&gt;Full Screen&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;autohotkey&#34;&gt;AutoHotkey&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Install AutoHotkey;&lt;/li&gt;
&lt;li&gt;Edit script;&lt;/li&gt;
&lt;li&gt;Put script to startup folder(&lt;code&gt;CMD+R &amp;gt;&amp;gt; shell:startup&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;app_windows_switch&#34;&gt;app_windows_switch&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;#Requires AutoHotkey v2.0
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;^`::
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;{
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    win_id := WinActive(&amp;#34;A&amp;#34;)
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    win_class := WinGetClass(&amp;#34;A&amp;#34;)
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    active_process_name := WinGetProcessName(&amp;#34;A&amp;#34;)
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    ; We have to be extra careful about explorer.exe since that process is responsible for more than file explorer
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    if (active_process_name = &amp;#34;explorer.exe&amp;#34;)
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        win_list := WinGetList(&amp;#34;ahk_exe&amp;#34; active_process_name &amp;#34; ahk_class&amp;#34; win_class)
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    else
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        win_list := WinGetList(&amp;#34;ahk_exe&amp;#34; active_process_name)
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    ; Calculate index of next window. Since activating a window puts it at the top of the list, we have to take from the bottom.
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    next_window_i := win_list.Length
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    next_window_id := win_list[next_window_i]
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    ; Activate the next window and send it to the top.
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    WinMoveTop(&amp;#34;ahk_id&amp;#34; next_window_id)
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;    WinActivate(&amp;#34;ahk_id&amp;#34; next_window_id)
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;chrome_duplicate_tab&#34;&gt;chrome_duplicate_tab&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;#IfWinActive ahk_exe chrome.exe
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;^d:: ; Ctrl + D 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;Send, ^l ; url
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;Send, ^c ; copy
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;Send, ^t ; new tab
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;Send, ^v ; paste url
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;Send, {Enter} ; open
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;return
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;#IfWinActive
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      </item>
      
    
      
      <item>
        <title>服务器被入侵后的急救记录</title>
        <link>https://zhihang.org/posts/emergency-records-after-server-intrusion/</link>
        <pubDate>Sat, 10 May 2025 17:11:29 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>emergency-records-after-server-intrusion</guid>
        <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;记录一次服务器被入侵后的急救记录。第一次遇上服务器被入侵的事，觉得惊吓、紧张又有趣，一开始手足无措，依靠 AI 和社区相关博客，顺利处理完成，也得到了很重要的经验教训。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%89%8D%E8%A8%80&#34;&gt;前言&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8F%91%E7%8E%B0%E9%97%AE%E9%A2%98&#34;&gt;发现问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%87%8D%E7%BD%AE%E5%AF%86%E7%A0%81&#34;&gt;重置密码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B8%85%E9%99%A4%E7%97%85%E6%AF%92&#34;&gt;清除病毒&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%A3%80%E6%9F%A5%E5%90%8E%E9%97%A8&#34;&gt;检查后门&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BB%8F%E9%AA%8C%E6%95%99%E8%AE%AD&#34;&gt;经验教训&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;发现问题&#34;&gt;发现问题&lt;/h2&gt;
&lt;p&gt;最近发现服务器的部分服务明显卡顿，使用 top 命令观察进程：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;top -c 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;PID  USER PR  NI  VIRT RES    SHR S  %CPU  %MEM     TIME+ COMMAND
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;4135357&lt;/span&gt; root &lt;span style=&#34;color:#b48ead&#34;&gt;30&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;723224&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;146032&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;   S   99.9 30.9  462:10.61 /root/.local/start/xmrig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个名为 xmrig 的进程 CPU 占用经常达到 99%，查询得知 xmrig 是一个加密货币挖矿程序，通常用于挖掘 Monero (XMR)。可见服务器已经被入侵，被用来进行非法挖矿，这类攻击称为“加密劫持”（Cryptojacking）。这个入侵者以 root 身份执行了程序，因此要么是 root 密码在某些地方泄露了，要么是自己通过 root 跑的服务代码有病毒，当然也有可能单纯是密码被穷举出来了。&lt;/p&gt;
&lt;p&gt;回忆后发现很久之前使用了通过 AppStore 下载的某些手机服务器管理软件管理这个服务器，在软件上输入了服务器账密，很大可能被某个软件的开发者泄漏了。&lt;/p&gt;
&lt;p&gt;以后要非常小心不要在任何无法保证数据安全的地方输入密码，也尽量不要使用 root 账户登录 Linux 服务器。另外即使是 AppStore 下载的软件，可能也是不安全的，最好还是使用经过社区验证过的开源软件。&lt;/p&gt;
&lt;p&gt;如果是密码泄露，那值得庆幸的是，入侵者并没有直接修改掉原始密码，或者很明显地破坏我的服务器。但是从另一个角度看，这确实让我在短时间内无法发现自己的服务器被入侵了，挖坑病毒在服务器上跑了快一个月了！之后最好得加一个服务器监控告警程序在服务器上面。&lt;/p&gt;
&lt;p&gt;如果不是密码泄露的问题，那就是某些代码有病毒，这个比较难发现，只能在清理完病毒后持续观察了。&lt;/p&gt;
&lt;p&gt;继续通过 top 命令观察进程，发现还有另外一个怪异的进程，CPU 占用也经常达到 99%：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;PID USER PR  NI  VIRT RES    SHR S  %CPU  %MEM     TIME+ COMMAND
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;518&lt;/span&gt; root &lt;span style=&#34;color:#b48ead&#34;&gt;20&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;10808&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;208&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;204&lt;/span&gt; S 99.9 0.0 2:42.28 arpd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在正常情况下，arpd 是 Linux 上的一个合法工具，作用是缓存 ARP 表项以减少 ARP 请求，也可用于 ARP 代理，属于 iputils 套件。&lt;/p&gt;
&lt;p&gt;个人怀疑 arqd 是否会消耗这么多资源，AI 也认为合法的 arpd 几乎不应该消耗这么多资源，可能是伪装成合法程序的恶意进程（命名为 arpd 来掩盖身份）。&lt;/p&gt;
&lt;h2 id=&#34;重置密码&#34;&gt;重置密码&lt;/h2&gt;
&lt;p&gt;发现密码泄漏，必须马上重置密码，防止被远程自动程序继续入侵。&lt;/p&gt;
&lt;p&gt;首先修改 root 密码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;passwd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;检查公钥列表：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;cat /root/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;发现确实有陌生的密钥，立马删除。&lt;/p&gt;
&lt;p&gt;查看是否有其他陌生用户：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;cut -d: -f1 /etc/passwd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;并没有发现。如果有，删除掉。&lt;/p&gt;
&lt;p&gt;检查哪些用户有登录权限：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;grep -vE &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;(/false|/nologin)&amp;#39;&lt;/span&gt; /etc/passwd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;没有发现陌生用户。如果有，删除掉。&lt;/p&gt;
&lt;p&gt;如果服务器上某些文件包含了密码明文，需要及时重置，这里省略。&lt;/p&gt;
&lt;h2 id=&#34;清除病毒&#34;&gt;清除病毒&lt;/h2&gt;
&lt;p&gt;首先删除掉 xmrig 二进制执行文件，然后再 kill 掉 xmrig 进程：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;rm /root/.local/start/xmrig
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;kill&lt;/span&gt; -9 &lt;span style=&#34;color:#b48ead&#34;&gt;4135357&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;直接 kill 会无效，因为有自启动的病毒程序在运行，所以一定要先删除 xmrig 执行文件。&lt;/p&gt;
&lt;p&gt;接着检查 arpd 执行文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;dpkg -S /usr/sbin/arpd
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# iproute2: /usr/sbin/arpd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;说明 arpd 文件确实来自于系统的官方软件包 iproute2，这在形式上是合法的。&lt;/p&gt;
&lt;p&gt;即使它来自官方包，arpd 正常情况下几乎不会运行、也不会占用接近 100% 的 CPU。这行为极不正常，仍可能有二进制被替换或篡改的风险，攻击者可能保留了原有包元数据，但替换了实际文件内容，仅靠 dpkg -S 输出无法确认安全性。&lt;/p&gt;
&lt;p&gt;还是直接重新安装 arpd：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;apt-get install --reinstall iproute2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样会用官方版本覆盖掉现在的 arpd。&lt;/p&gt;
&lt;p&gt;接着 top 持续观察，发现已经基本正常，舒服了。&lt;/p&gt;
&lt;h2 id=&#34;检查后门&#34;&gt;检查后门&lt;/h2&gt;
&lt;p&gt;现在还不能松懈，继续检查病毒是否留有后门，比如某些自动程序可能会自动下载 xmrig 并执行。&lt;/p&gt;
&lt;p&gt;检查相关启动文件是否有问题：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# .*shrc&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# .*profile&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# /etc/rc.local&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;find /root /home -type f &lt;span style=&#34;color:#ebcb8b&#34;&gt;\(&lt;/span&gt; -name &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;.bashrc&amp;#34;&lt;/span&gt; -o -name &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;.profile&amp;#34;&lt;/span&gt; -o -name &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;.zprofile&amp;#34;&lt;/span&gt; -o -name &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;.zshrc&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\)&lt;/span&gt; -exec grep -i xmrig &lt;span style=&#34;color:#81a1c1&#34;&gt;{}&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;cat /etc/rc.local &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; grep xmrig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;检查是否有可疑的服务：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;systemctl list-units --type&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;service &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; grep xmrig
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# grep -r xmrig /etc/systemd/system&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;发现有一个陌生服务 “thenorth.service”:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;ExecStart=/root/.local/start/xmrig -c /root/.local/start/config.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可见 thenorth.service 就是攻击者伪装的 systemd 服务，执行的是 xmrig 挖矿程序。虽然 xmrig 执行文件已经删除了，但是这里还是将其删除：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;systemctl disable thenorth.service
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;rm /etc/systemd/system/thenorth.service
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;systemctl daemon-reload
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 如果删除文件后，服务仍然显示存在，可以尝试清除所有 systemd 的缓存，并强制更新其配置：&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# systemctl reset-failed &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;检查定时任务：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;crontab -l &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; grep xmrig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述步骤可能考虑不到所有地方，因此也许无法根除病毒，所以需要持续观察。&lt;/p&gt;
&lt;h2 id=&#34;经验教训&#34;&gt;经验教训&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;不要在任何无法保证数据安全的地方输入密码；&lt;/li&gt;
&lt;li&gt;尽量不要使用 root 账户登录服务器；&lt;/li&gt;
&lt;li&gt;禁用密码登录服务器，只认公钥：&lt;code&gt;PasswordAuthentication no&lt;/code&gt;，防止密码被穷举；&lt;/li&gt;
&lt;li&gt;尽量使用经过社区验证的开源软件；&lt;/li&gt;
&lt;li&gt;设置服务器监控程序，及时告警；&lt;/li&gt;
&lt;li&gt;要非常清楚自己服务器上跑的任何一个服务，最好列个清单；&lt;/li&gt;
&lt;li&gt;最好不要在服务器上面放置过于重要或私密的东西。&lt;/li&gt;
&lt;/ol&gt;
</description>
      </item>
      
    
      
      <item>
        <title>分布式系统理论知识整理</title>
        <link>https://zhihang.org/posts/summary-of-distributed-system-theory-and-practical-experience/</link>
        <pubDate>Wed, 12 Feb 2025 23:44:09 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>summary-of-distributed-system-theory-and-practical-experience</guid>
        <description>&lt;h2 id=&#34;toc&#34;&gt;TOC&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#toc&#34;&gt;TOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#cap-%E5%AE%9A%E7%90%86&#34;&gt;CAP 定理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%80%E8%87%B4%E6%80%A7%E5%8D%8F%E8%AE%AE&#34;&gt;一致性协议&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#2pc&#34;&gt;2PC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#3pc&#34;&gt;3PC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#raft&#34;&gt;Raft&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#raft-%E6%A6%82%E8%BF%B0&#34;&gt;Raft 概述&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#raft-%E8%8A%82%E7%82%B9%E8%A7%92%E8%89%B2&#34;&gt;Raft 节点角色&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#raft-%E9%80%89%E4%B8%BE%E8%BF%87%E7%A8%8B&#34;&gt;Raft 选举过程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#raft-%E4%B8%8E-paxos-%E7%9A%84%E5%8C%BA%E5%88%AB&#34;&gt;Raft 与 Paxos 的区别&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#paxos&#34;&gt;Paxos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#quorum-based-replication&#34;&gt;Quorum-Based Replication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81&#34;&gt;分布式锁&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E4%BA%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AE%9E%E7%8E%B0%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81&#34;&gt;基于数据库实现分布式锁&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E4%BA%8E-redis-%E5%AE%9E%E7%8E%B0%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81&#34;&gt;基于 Redis 实现分布式锁&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E4%BA%8E-zookeeper-%E5%AE%9E%E7%8E%B0%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81&#34;&gt;基于 Zookeeper 实现分布式锁&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%86%E5%B8%83%E5%BC%8F-id&#34;&gt;分布式 ID&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1&#34;&gt;分布式事务&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%80%9D%E6%83%B3&#34;&gt;基本思想&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#seata&#34;&gt;Seata&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;cap-定理&#34;&gt;CAP 定理&lt;/h2&gt;
&lt;p&gt;CAP 定理指出对于一个分布式计算系统来说，不可能同时满足以下三点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;一致性（Consistency）：同一时间所有节点返回的数据都是一致的&lt;/li&gt;
&lt;li&gt;可用性（Availability）：每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据&lt;/li&gt;
&lt;li&gt;分区容错性（Partition Tolerance）：发生网络分区时（即节点之间无法通信），大部分分布式系统都不能在时限内达成数据一致性。所以在分布式系统中 P 是一定该发生的，那么 A 和 C 我们只能选择一个&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;一致性协议&#34;&gt;一致性协议&lt;/h2&gt;
&lt;p&gt;分布式一致性具体可以分为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;强一致性：是分布式系统中的一个一致性保证，它确保了系统中的所有副本始终保持一致，无论客户端请求在哪个节点处理，系统中的所有节点都能看到相同的数据。&lt;/li&gt;
&lt;li&gt;最终一致性：与强一致性不同，最终一致性允许系统在某些时刻存在短暂的不一致，直到系统最终达到一致性。它通常用于高可用性要求较高的系统（如某些 NoSQL 数据库）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;CAP 定理定义了分布式系统中的一致性、可用性和分区容忍性之间的权衡。在实际系统设计中，需要根据需求做出选择。2PC、3PC 和 Paxos 等协议提供了实现这些需求的具体方法。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2PC&lt;/strong&gt; 适用于强一致性的场景，但在网络分区时可能会面临不可用的问题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3PC&lt;/strong&gt; 是对 2PC 的改进，力图在保证一致性的同时减少因网络分区导致的系统不可用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Raft&lt;/strong&gt; 是一种分布式一致性算法，旨在通过简化 Paxos 算法的理解和实现，提供一种易于理解和实现的一致性协议。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Paxos&lt;/strong&gt; 提供了一种强一致性的分布式协议，适用于高容错性和一致性要求的系统，但在分区发生时可能会牺牲可用性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quorum-Based Replication&lt;/strong&gt; 是一种用于在分布式系统中确保数据一致性和高可用性的策略。通过设置写和读操作所需的 Quorum（法定人数），系统能够容忍部分节点的失败或延迟，确保数据在最终一致的状态下达到各个副本节点。它适用于高可用性要求较高的场景，如 NoSQL 数据库、分布式存储系统 和 缓存系统。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;2pc&#34;&gt;2PC&lt;/h2&gt;
&lt;p&gt;2PC（Two-Phase Commit）是分布式事务中的一致性协议，保证分布式系统中事务的原子性（即事务要么全部成功，要么全部失败）。2PC 由两个阶段组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;第一阶段（准备阶段）&lt;/strong&gt;：协调者向所有参与者发送“准备提交”请求，参与者要么同意提交事务，要么拒绝。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第二阶段（提交阶段）&lt;/strong&gt;：如果所有参与者都同意提交，协调者发送“提交”命令；如果有任何一个参与者拒绝，协调者发送“回滚”命令。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2PC 与 CAP 的关系&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 2PC 中，协调者需要等待所有参与者的回应才能决定事务是否提交。如果出现网络分区或某个节点宕机，可能无法确定事务状态，导致系统不可用。因此，2PC 在分区发生时可能会牺牲可用性来保证一致性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;3pc&#34;&gt;3PC&lt;/h2&gt;
&lt;p&gt;3PC（Three-Phase Commit）是 2PC 的改进版本，旨在解决 2PC 在面对网络分区和节点崩溃时的阻塞问题。3PC 在 2PC 的基础上增加了一个预提交阶段，以避免事务阻塞。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;第一阶段（准备阶段）&lt;/strong&gt;：协调者向参与者发送“准备提交”请求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第二阶段（预提交阶段）&lt;/strong&gt;：协调者向所有参与者发送“预提交”命令，参与者确认并准备提交。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第三阶段（提交阶段）&lt;/strong&gt;：协调者向所有参与者发送“提交”命令。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为何需要预提交？在 2PC (Two-Phase Commit) 中，如果在第一阶段（准备阶段）和第二阶段（提交阶段）之间发生故障（如网络分区或某个参与者宕机），就会导致协议阻塞，无法完成事务。这是因为没有机制来确保在没有足够信息的情况下做出最终决策。3PC 通过引入一个“预提交阶段”来避免这一问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果协调者在第一阶段和第二阶段之间崩溃，参与者已经在“预提交”阶段保存了事务的状态（但未完全提交），因此系统可以在恢复后继续执行，而不需要等待所有节点的反馈来决定事务的最终状态。&lt;/li&gt;
&lt;li&gt;预提交确保了在第二阶段开始时，参与者已经做好提交准备，减少了事务最终不一致的风险。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;raft&#34;&gt;Raft&lt;/h2&gt;
&lt;h3 id=&#34;raft-概述&#34;&gt;Raft 概述&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Raft&lt;/strong&gt; 是一种分布式一致性算法，旨在通过简化 Paxos 算法的理解和实现，提供一种易于理解和实现的一致性协议。Raft 主要用于 &lt;strong&gt;分布式日志复制&lt;/strong&gt;，它保证了在一个分布式系统中，所有的节点都能达成一致，尤其在一个节点故障或系统出现网络分区的情况下，仍能确保数据的一致性和系统的高可用性。&lt;/p&gt;
&lt;p&gt;Raft 算法通过将一致性问题分为三个子问题来简化理解：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;领导选举&lt;/strong&gt;（Leader Election）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;日志复制&lt;/strong&gt;（Log Replication）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全性&lt;/strong&gt;（Safety）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;raft-节点角色&#34;&gt;Raft 节点角色&lt;/h3&gt;
&lt;p&gt;Raft 协议中的节点有三种角色：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Leader&lt;/strong&gt;：负责处理所有客户端请求，并将它们记录到日志中。所有日志条目都会通过 Leader 进行复制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Follower&lt;/strong&gt;：被动节点，接收来自 Leader 的日志条目，并执行日志条目中的操作。大部分节点在 Raft 集群启动时都是 Follower。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Candidate&lt;/strong&gt;：当 Follower 在一段时间内没有接收到 Leader 的心跳（即 Leader 没有按时发送心跳信号），它将变成 Candidate，发起选举来选举新的 Leader。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个节点维护一份日志，记录了系统的状态变更。Raft 通过复制日志来确保系统的一致性。日志中的每个条目都包括一个索引和一个日志条目内容。&lt;/p&gt;
&lt;h3 id=&#34;raft-选举过程&#34;&gt;Raft 选举过程&lt;/h3&gt;
&lt;p&gt;在 Raft 中，当集群启动时，所有节点最初是 Follower。如果在 &lt;strong&gt;选举超时&lt;/strong&gt;（即 Follower 一段时间内没有接收到 Leader 的心跳，这个时间各 Follower 随机），它会变成 Candidate，并发起选举。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Candidate 会向其他节点请求投票。如果大多数节点投票给它，它就会成为新的 Leader。&lt;/li&gt;
&lt;li&gt;一旦 Leader 被选举出来，它开始向 Follower 节点复制日志条目。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;raft-与-paxos-的区别&#34;&gt;Raft 与 Paxos 的区别&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;简洁性&lt;/strong&gt;：Raft 的设计目标之一就是简化实现和理解，相比于 Paxos，Raft 的概念更直观，易于理解和实现。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leader 优先&lt;/strong&gt;：Raft 通过 Leader 来集中处理所有请求，这样在性能和效率上相对更优，而 Paxos 通过多轮投票机制来达成一致，可能更加复杂。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;日志复制&lt;/strong&gt;：Raft 强调日志复制，所有操作都通过 Leader 日志进行传递，确保数据一致性；Paxos 不直接处理日志复制问题，它关注的是如何在分布式系统中进行一致性的决策。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;paxos&#34;&gt;Paxos&lt;/h2&gt;
&lt;p&gt;Paxos 是一种用于保证分布式系统中一致性的算法。它通过提议和投票机制确保系统中的多个副本最终达成一致。Paxos 可以在网络分区和节点崩溃的情况下达成一致决策，适用于高可用性和一致性要求的系统。&lt;/p&gt;
&lt;p&gt;Paxos 的选举过程并不像传统的领导选举那样明确，而是通过多个阶段（Prepare、Promise、Propose 和 Accept）达成一致。Paxos 保证，尽管会有多个提案同时存在，但最终会有一个值被选中，且达成一致的提案是唯一的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提案者提出提案并请求投票。&lt;/li&gt;
&lt;li&gt;接受者通过承诺和投票来决定是否接受提案。&lt;/li&gt;
&lt;li&gt;学习者最终会了解到哪一个提案被选为一致的决策。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Paxos 是一种容错机制，能够在分布式系统中保证数据一致性，即使在部分节点失败或网络分区的情况下，最终也能达成一致的选举结果。&lt;/p&gt;
&lt;h2 id=&#34;quorum-based-replication&#34;&gt;Quorum-Based Replication&lt;/h2&gt;
&lt;p&gt;Quorum-Based Replication 是一种用于分布式系统中实现数据一致性的策略，尤其是在高可用性和容错性要求较高的系统中，如 NoSQL 数据库（如 Cassandra 和 Riak）和分布式存储系统。它通过设置读和写的 Quorum（法定人数）来保证数据在多个副本间的最终一致性。&lt;/p&gt;
&lt;p&gt;在分布式系统中，数据通常会被复制到多个节点上。Quorum-based replication 通过定义 读（read） 和 写（write） 操作所需的最小确认节点数来确保一致性。在每个操作中，系统会在特定数量的节点上执行并确认操作，只有当足够的节点同意时，操作才会被认为是成功的。&lt;/p&gt;
&lt;p&gt;主要概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quorum：一个操作需要的最小节点数。通常，写操作和读操作会使用不同的 Quorum 大小来确保一致性。&lt;/li&gt;
&lt;li&gt;写 Quorum (W)：执行写操作时，需要在至少 W 个节点上完成写操作才能算作成功。&lt;/li&gt;
&lt;li&gt;读 Quorum (R)：执行读操作时，需要从至少 R 个节点获取数据才能返回结果。&lt;/li&gt;
&lt;li&gt;副本数 (N)：数据在系统中被复制的副本数，通常是指每个数据的副本存储在多少个节点上。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;工作原理：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;写操作：当进行写操作时，数据会被写入到至少 W 个节点。如果系统的副本数为 N，那么 W 必须大于 N/2，即写操作必须在超过半数的节点上成功写入才能认为是成功。&lt;/li&gt;
&lt;li&gt;读操作：当进行读操作时，系统会从至少 R 个节点中读取数据。如果在这些节点中存在不同版本的数据，系统会通过版本号、时间戳或其他方式来解决冲突并保证数据一致。&lt;/li&gt;
&lt;li&gt;一致性保证：为了保证一致性，通常有一个要求：W + R &amp;gt; N。这个条件保证了在读写操作之间，至少有一个节点是重叠的（即包含了最新的数据）。例如，如果在写操作时写入了 W 个节点，那么当执行读操作时，至少会从 R 个节点中读取到数据，这样可以避免读取到过时的数据。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;分布式锁&#34;&gt;分布式锁&lt;/h2&gt;
&lt;p&gt;分布式锁是一种用于保证在分布式系统中，同一时间只有一个服务或线程可以访问共享资源的机制，防止不同节点上的并发操作产生数据不一致或其他冲突。由于分布式系统中，多个服务实例通常会并发访问同一资源，因此需要一种机制来确保在某些时刻，只有一个实例能对资源进行操作。&lt;/p&gt;
&lt;h3 id=&#34;基于数据库实现分布式锁&#34;&gt;基于数据库实现分布式锁&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;悲观锁：&lt;code&gt;select ... for update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;乐观锁：版本号递增（CAS）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;基于-redis-实现分布式锁&#34;&gt;基于 Redis 实现分布式锁&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;初始化锁的时候，使用 &lt;code&gt;setnx k v&lt;/code&gt;，并使用 expire 命令为锁添加一个超时时间，超过该时间则自动释放锁，锁的 value 值为一个随机生成的 UUID，通过此在释放锁的时候进行判断;&lt;/li&gt;
&lt;li&gt;获取锁的时候设置一个获取的超时时间，若超过这个时间则放弃获取锁;&lt;/li&gt;
&lt;li&gt;释放锁的时候，通过 UUID 判断是不是该锁，若是该锁，则执行 delete 进行锁释放。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;基于-zookeeper-实现分布式锁&#34;&gt;基于 Zookeeper 实现分布式锁&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;创建一个目录 mylock；&lt;/li&gt;
&lt;li&gt;线程 A 想获取锁就在 mylock 目录下创建临时顺序节点；&lt;/li&gt;
&lt;li&gt;获取 mylock 目录下所有的子节点，然后获取比自己小的兄弟节点，如果不存在，则说明当前线程顺序号最小，获得锁；&lt;/li&gt;
&lt;li&gt;线程 B 获取所有节点，判断自己不是最小节点，设置监听比自己次小的节点；&lt;/li&gt;
&lt;li&gt;线程 A 处理完，删除自己的节点，线程 B 监听到变更事件，判断自己是不是最小的节点，如果是则获得锁。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;分布式-id&#34;&gt;分布式 ID&lt;/h2&gt;
&lt;p&gt;分布式 ID 是指在分布式系统中，生成的标识符（ID）具有全局唯一性，能够在多个节点或服务之间保证不重复，并且通常是高效、顺序的。分布式 ID 的生成通常需要满足以下几个要求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全局唯一性：每个 ID 必须在整个分布式系统中唯一，不会发生重复。&lt;/li&gt;
&lt;li&gt;高效性：生成 ID 的速度必须足够快，不会成为系统的瓶颈。&lt;/li&gt;
&lt;li&gt;顺序性（可选）：有些场景可能需要 ID 按时间递增（有序），以便在数据库中按顺序存储。&lt;/li&gt;
&lt;li&gt;分布式系统兼容性：在多个节点、服务实例之间，ID 的生成方式应具有良好的兼容性，避免产生冲突。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现方案：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;雪花算法&lt;/li&gt;
&lt;li&gt;UUID&lt;/li&gt;
&lt;li&gt;数据库自增 ID + 分布式锁&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;雪花算法（Snowflake Algorithm）是由 Twitter 提出的分布式唯一 ID 生成算法，旨在解决在分布式系统中生成 &lt;strong&gt;全局唯一且递增&lt;/strong&gt; 的 ID 问题。它通过结合时间戳、机器标识、序列号等信息，生成一个 64 位的 ID，确保高并发环境下的唯一性和顺序性。&lt;/p&gt;
&lt;p&gt;雪花算法生成的 ID 是一个 64 位的整数，通常分成以下几个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;符号位（1 bit）：始终为 0，保证生成的 ID 是正数。&lt;/li&gt;
&lt;li&gt;时间戳（41 bits）：41 位时间戳，表示自某个纪元以来的毫秒数，支持约 69 年 的时间范围。&lt;/li&gt;
&lt;li&gt;机器 ID（10 bits）：10 位机器标识，支持最多 1024 台机器。可以根据需要分为数据中心 ID 和机器 ID。&lt;/li&gt;
&lt;li&gt;序列号（12 bits）：在同一毫秒内，支持生成 最多 4096 个唯一 ID，保证 ID 的唯一性和高并发。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;雪花算法的时钟回拨问题：由于雪花算法依赖时间戳生成 ID，如果机器的系统时钟发生回拨（如 NTP 同步或系统时间调整），可能会导致 ID 冲突或顺序错误。优化：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;通过记录上次生成的时间戳，在时钟回拨时暂停 ID 生成，直到时钟恢复到正确的时间。&lt;/li&gt;
&lt;li&gt;增加时间戳回拨检测机制，例如通过记录时间戳的最大值，避免出现回拨导致的冲突。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;分布式事务&#34;&gt;分布式事务&lt;/h2&gt;
&lt;h3 id=&#34;基本思想&#34;&gt;基本思想&lt;/h3&gt;
&lt;p&gt;​分布式系统会把一个应用系统拆分为可独立部署的多个服务，各个服务的事务会操作各自的数据库，因此需要服务与服务之间远程协作才能完成事务操作。这种分布式系统环境下由不同的服务之间通过网络远程协作完成事务称之为&lt;strong&gt;分布式事务&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;例如用户下一个订单，需要首先创建订单，然后删减库存，接着扣除用户的金钱，最后完成订单。这个过程中，每个操作都可以作为一个微服务，每个微服务操作对应的数据库，而各个数据库可能分布在不同机器上，那么分布式事务就产生了，我们要确保一个事务被正确地处理，必须解决好分布式事务的数据提交与回滚。&lt;/p&gt;
&lt;h3 id=&#34;seata&#34;&gt;Seata&lt;/h3&gt;
&lt;p&gt;Seata 是一款开源的分布式事务解决方案，致力于提供高性能和简单易用的分布式事务服务。在 Seata 中，分布式事务的执行过程通常涉及三个主要角色：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TC (Transaction Coordinator)：事务协调者，维护全局和分支事务的状态，驱动&lt;strong&gt;全局事务&lt;/strong&gt;提交或回滚。&lt;/li&gt;
&lt;li&gt;TM (Transaction Manager)：事务管理器，定义&lt;strong&gt;全局事务的范围&lt;/strong&gt;：开始全局事务、提交或回滚全局事务。&lt;/li&gt;
&lt;li&gt;RM (Resource Manager)：资源管理器，管理分支事务处理的资源，与 TC 交谈以注册分支事务和报告分支事务的状态，并驱动&lt;strong&gt;分支事务&lt;/strong&gt;提交或回滚。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Seata 使用 2PC 协议来保证分布式事务的 &lt;strong&gt;原子性&lt;/strong&gt; 和 &lt;strong&gt;一致性&lt;/strong&gt;，确保在多个服务间的操作要么全部成功（提交），要么全部失败（回滚）。&lt;/p&gt;
&lt;p&gt;在 Seata 中，分布式事务的执行流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;TM 开启分布式事务（TM 向 TC 注册全局事务记录）；&lt;/li&gt;
&lt;li&gt;按业务场景，编排数据库、服务等事务内资源（RM 向 TC 汇报资源准备状态 ）；&lt;/li&gt;
&lt;li&gt;TM 结束分布式事务，事务一阶段结束（TM 通知 TC 提交/回滚分布式事务）；&lt;/li&gt;
&lt;li&gt;TC 汇总事务信息，决定分布式事务是提交还是回滚；&lt;/li&gt;
&lt;li&gt;TC 通知所有 RM 提交/回滚 资源，事务二阶段结束；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;为什么不使用 Raft？在分布式事务中，Seata 更注重事务的一致性和原子性，并且其主要目标是让事务能够在分布式环境中进行有效的协调和管理。Raft 更多地关注在分布式系统中如何处理节点故障、保证一致性和日志同步，而 Seata 更侧重于事务的 隔离性 和 原子性。Seata 的事务协调 更适合使用类似 2PC 或 TCC 这种高效的协议，而 Raft 的复杂性和实现方式对于事务管理来说可能不够合适。&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>走进音乐的世界</title>
        <link>https://zhihang.org/posts/recording-and-reflection-on-music-theory/</link>
        <pubDate>Fri, 06 Dec 2024 17:22:27 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>recording-and-reflection-on-music-theory</guid>
        <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;这里记录一切和音乐相关的知识和信息，欢迎走进音乐的世界。&lt;/p&gt;
&lt;p&gt;这篇博客将会持续更新下去。另外部分内容由于篇幅较长或其它原因，独立成一篇新的文章：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://zhihang.org/posts/appreciation-collection-of-classical-music-works&#34;&gt;古典音乐作品鉴赏集&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://zhihang.org/posts/record-of-music-format-and-track-splitting-issues&#34;&gt;音乐格式和分轨问题记录&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://zhihang.org/posts/record-of-knowledge-related-to-classical-music&#34;&gt;古典音乐重要知识整理&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;内容导览：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%89%8D%E8%A8%80&#34;&gt;前言&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%A3%B0%E9%9F%B3&#34;&gt;声音&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%9F%B3%E7%AC%A6&#34;&gt;音符&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%9F%B3%E4%B9%90&#34;&gt;音乐&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%8A%82%E5%A5%8F&#34;&gt;节奏&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B9%90%E9%9F%B3%E4%BD%93%E7%B3%BB&#34;&gt;乐音体系&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%AB%E5%BA%A6&#34;&gt;八度&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%9F%B3%E5%90%8D%E5%92%8C%E5%94%B1%E5%90%8D&#34;&gt;音名和唱名&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8D%8A%E9%9F%B3%E4%B8%8E%E5%8D%81%E4%BA%8C%E5%B9%B3%E5%9D%87%E5%BE%8B&#34;&gt;半音与十二平均律&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%9F%B3%E7%BB%84&#34;&gt;音组&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%A7%91%E5%AD%A6%E9%9F%B3%E9%AB%98%E8%AE%B0%E5%8F%B7%E6%B3%95&#34;&gt;科学音高记号法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BA%A5%E5%A7%86%E9%9C%8D%E5%85%B9%E9%9F%B3%E9%AB%98%E8%AE%B0%E5%8F%B7%E6%B3%95&#34;&gt;亥姆霍兹音高记号法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%9F%B3%E4%B9%90%E8%AE%B0%E8%B0%B1%E6%B3%95&#34;&gt;音乐记谱法&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BA%94%E7%BA%BF%E8%B0%B1&#34;&gt;五线谱&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%AE%80%E8%B0%B1&#34;&gt;简谱&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%AD%E7%BA%BF%E8%B0%B1&#34;&gt;六线谱&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9B%9B%E7%BA%BF%E8%B0%B1&#34;&gt;四线谱&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%9F%B3%E7%A8%8B&#34;&gt;音程&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%87%AA%E7%84%B6%E9%9F%B3%E7%A8%8B&#34;&gt;自然音程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8F%98%E5%8C%96%E9%9F%B3%E7%A8%8B&#34;&gt;变化音程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8D%8F%E5%92%8C%E9%9F%B3&#34;&gt;协和音&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%9F%B3%E7%A8%8B%E8%BD%AC%E4%BD%8D&#34;&gt;音程转位&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%92%8C%E5%BC%A6&#34;&gt;和弦&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%92%8C%E5%BC%A6%E7%B1%BB%E5%9E%8B&#34;&gt;和弦类型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%92%8C%E5%BC%A6%E8%BD%AC%E4%BD%8D&#34;&gt;和弦转位&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%B0%83%E5%BC%8F%E4%BD%93%E7%B3%BB&#34;&gt;调式体系&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5&#34;&gt;基本概念&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%A4%A7%E5%B0%8F%E8%B0%83&#34;&gt;大小调&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%94%AE%E7%9B%98%E4%B9%90%E5%99%A8&#34;&gt;键盘乐器&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%92%A2%E7%90%B4&#34;&gt;钢琴&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%A4%A7%E9%94%AE%E7%90%B4&#34;&gt;大键琴&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%94%B5%E5%AD%90%E7%90%B4&#34;&gt;电子琴&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%AE%A1%E9%A3%8E%E7%90%B4&#34;&gt;管风琴&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%BC%A6%E4%B9%90%E5%99%A8&#34;&gt;弦乐器&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%90%89%E4%BB%96&#34;&gt;吉他&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%A0%87%E5%87%86%E5%AE%9A%E5%BC%A6&#34;&gt;标准定弦&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%AB%E5%A4%A7%E5%90%89%E4%BB%96%E5%92%8C%E5%BC%A6&#34;&gt;八大吉他和弦&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%B4%9D%E6%96%AF&#34;&gt;贝斯&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%B0%8F%E6%8F%90%E7%90%B4&#34;&gt;小提琴&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BD%8E%E9%9F%B3%E6%8F%90%E7%90%B4&#34;&gt;低音提琴&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%A4%A7%E6%8F%90%E7%90%B4&#34;&gt;大提琴&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reference&#34;&gt;Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;声音&#34;&gt;声音&lt;/h2&gt;
&lt;p&gt;我们常用音调，响度，音长和音色等来形容声音。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;音调（音高，Pitch）&lt;/strong&gt; 的高低决定于发声体振动的频率，声源1秒钟内振动的次数叫频率，它反映振动的快慢，频率高，物体振动快。频率高，音调高。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;空气柱越短，音调越高，反之越低&lt;/li&gt;
&lt;li&gt;琴弦越紧，音调越高，反之越低&lt;/li&gt;
&lt;li&gt;琴弦越细，音调越高，反之越低&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在吉他中，六弦最粗，所以音调最低，而一弦最细，所以音调最高。通过调弦，即转动吉他上方六个旋钮，可以调节琴弦的松紧程度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;响度（音强，loudness）&lt;/strong&gt; 反映声音的大小，响度的大小与振幅有关，还与离声源距离有关，越远声音越弱。弹琴所用的力度越大，响度就越大。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;音长（时值，Note value）&lt;/strong&gt;，是指声音的长短，它决定于发音体振动时间的久暂。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;音色（音品，Timbre）&lt;/strong&gt;，是发声体的不同而造成的，我们可以根据音色不同，从而区别不同的声音。&lt;/p&gt;
&lt;p&gt;吉他跟钢琴都能发出同一个音高，但它们的听感是不一样的。吉他有吉他的音色，各种乐器都有自己的音色，每个人嗓音也是一个独一无二的音色。&lt;/p&gt;
&lt;p&gt;乐器演奏出的音符并非只有一个音高频率，而是有一组频率。基频是这组音音高最低的频率，通常把基频定义为 &lt;strong&gt;音符的音高&lt;/strong&gt;。而其他的高频则遵循一个规律，它们的频率都是基频的 &lt;strong&gt;正整数倍&lt;/strong&gt;，这些高频叫做 &lt;strong&gt;泛音&lt;/strong&gt;。基频和其他高频之间的关系决定着乐器的音色。&lt;/p&gt;
&lt;p&gt;对于振动有规律，具有明显基频和泛音，能分辨出音高的声音叫做 &lt;strong&gt;乐音（Musical tone）&lt;/strong&gt;。而对于振动没有规律无法清晰分辨基频泛音的声音则叫做 &lt;strong&gt;噪音（Noise）&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;音符&#34;&gt;音符&lt;/h2&gt;
&lt;p&gt;音乐中的单词就叫做 &lt;strong&gt;音符（Note）&lt;/strong&gt;，而 &lt;strong&gt;旋律&lt;/strong&gt;就是由音符的组织出来的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;音符时值&lt;/strong&gt; 也称为音符值或音值，在乐谱中用来表达各音符之间的相对持续时间。与音符时值持续相等时间的无声状态，则是由各种不同的 &lt;strong&gt;休止符&lt;/strong&gt; 来表达。&lt;strong&gt;附点音符&lt;/strong&gt; 时长则是前面音符的一半。&lt;/p&gt;
&lt;p&gt;四分音符为一拍，全音符则为四拍，对应有休止符，表示停顿。这里要注意音符的时长是相对的。&lt;/p&gt;
&lt;p&gt;常用音符时值如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1732727507956.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;常用休止符如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1732727966248.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;对于一首曲子，首先可以定义它每分钟有多少拍，然后才能得到一拍的时长，不同曲子一拍的时长有差异，也因此给人的感觉不一样。&lt;/p&gt;
&lt;h2 id=&#34;音乐&#34;&gt;音乐&lt;/h2&gt;
&lt;p&gt;音乐的三要素是 &lt;strong&gt;节奏（Rhythm）、和声（Harmony）、旋律（Melody）&lt;/strong&gt;。三要素之间的结合方式叫做 &lt;strong&gt;织体（Texture）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这是几种常见的音乐织体：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单调音乐：由一根旋律线单独进行的音乐织体。&lt;/li&gt;
&lt;li&gt;复调音乐：由多个独立的旋律线并行构成的织体。&lt;/li&gt;
&lt;li&gt;支音音乐：所有乐器声部都在演奏和模仿同一个旋律构成的织体。&lt;/li&gt;
&lt;li&gt;主调音乐：由一条旋律线配以和声进行来构成的织体。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;节奏&#34;&gt;节奏&lt;/h2&gt;
&lt;p&gt;节奏是由有规律或无规律的脉冲、音符（或声音）和静音组成的一种模式。&lt;/p&gt;
&lt;p&gt;音符本身的音值对节奏有影响，这体现在每种拍子的强弱规律。比如四二拍的每小节中音符的强弱规律是“强弱”，四三拍则是“强弱弱”。拍子可以组成为复拍，比如两个四二拍组成四四拍，强弱规律是“强、弱、次强、弱”。通过“&amp;gt;”来标记强音。&lt;/p&gt;
&lt;p&gt;音符的排列型式对节奏有重要影响，也就是节奏型。比如切分音、连音。&lt;/p&gt;
&lt;p&gt;切分音，指的是改变乐曲中强拍上出现重音的规律，使弱拍或强拍弱部分的音，因时值延长而成为重音。中间音的长，两边音的短，中间音是重音：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1734246992730.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;对音符进行分拍可以得到连音。对一个音符进行划分的规则如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1734243718619.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;比如要对一个二分音符进行五等分，就是使用二次分拍的进行四等分，也就得到八分音符，使用八分音符来书写五连音。&lt;/p&gt;
&lt;p&gt;有些节奏型是常见的，比如前十六后八、前八后十六、三连音、无连音，可以对其迅速做出反应。&lt;/p&gt;
&lt;h2 id=&#34;乐音体系&#34;&gt;乐音体系&lt;/h2&gt;
&lt;h3 id=&#34;八度&#34;&gt;八度&lt;/h3&gt;
&lt;p&gt;我们可以用唱名 Do[1] Re[2] Mi[3] Fa[4] Sol[5] La[6] Ti[7] Do[8] 唱出歌曲的旋律，“[]” 中的数字就是 &lt;strong&gt;音级（Degree ）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我们以 Do[1] 到 Do[1] 为一度，Do[1] 到 Re[2] 为二度，以此类推。于是从 Do[1] 到上面 Do[8] 之间音高上的距离(&lt;strong&gt;音程，Interval&lt;/strong&gt;)就叫做 &lt;strong&gt;八度（Octave）&lt;/strong&gt;，因此说 Do[8] 比 Do[1] 高了一个八度。&lt;/p&gt;
&lt;h3 id=&#34;音名和唱名&#34;&gt;音名和唱名&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;音名&lt;/strong&gt;：用 C，D，E，F，G，A，B 来标记基本音级的，叫做音名，它们表示一定的音高，比如 C4 即是中央 C 音高。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;唱名&lt;/strong&gt;：与 C，D，E，F，G，A，B 对应的唱名用 do、re、mi、fa、so、la、si 来作为 &lt;strong&gt;音级&lt;/strong&gt; 名称，但注意 do 并不能用于指代 C，只有在 C 调下可以这么认为，D 调下则 do 用 D 来唱。后文具体进行解释。&lt;/p&gt;
&lt;p&gt;在 C 大调中，音阶的音符是没有任何升降符号的，所有音符都是自然音符。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C（主音，do）&lt;/li&gt;
&lt;li&gt;D（大二度，re）&lt;/li&gt;
&lt;li&gt;E（大三度，mi）&lt;/li&gt;
&lt;li&gt;F（纯四度，fa）&lt;/li&gt;
&lt;li&gt;G（纯五度，so）&lt;/li&gt;
&lt;li&gt;A（大六度，la）&lt;/li&gt;
&lt;li&gt;B（大七度，si）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 C 小调中，音阶的音符会有不同的排列，因为小调音阶有一些特定的音程变化。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C（主音，do）&lt;/li&gt;
&lt;li&gt;D（大二度，re）&lt;/li&gt;
&lt;li&gt;E♭（小三度，mi）&lt;/li&gt;
&lt;li&gt;F（纯四度，fa）&lt;/li&gt;
&lt;li&gt;G（纯五度，so）&lt;/li&gt;
&lt;li&gt;A♭（小六度，la）&lt;/li&gt;
&lt;li&gt;B♭（小七度，si）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 D 大调中，音符的关系会有所不同，因为 D 大调的音阶是基于 D 音开始的。D 大调的音阶包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;D（主音，do）&lt;/li&gt;
&lt;li&gt;E（大二度，re）&lt;/li&gt;
&lt;li&gt;F#（大三度，mi）&lt;/li&gt;
&lt;li&gt;G（纯四度，fa）&lt;/li&gt;
&lt;li&gt;A（纯五度，so）&lt;/li&gt;
&lt;li&gt;B（大六度，la）&lt;/li&gt;
&lt;li&gt;C#（大七度，si）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在吉他中，从六弦到一弦（即从最粗的弦到最细的弦），音名依次为 EADGBE。标准调弦下音高为（吉他正面方向）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 弦: E4（约 329.63 Hz）&lt;/li&gt;
&lt;li&gt;2 弦: B3（约 246.94 Hz）&lt;/li&gt;
&lt;li&gt;3 弦: G3（约 196.00 Hz）&lt;/li&gt;
&lt;li&gt;4 弦: D3（约 146.83 Hz）&lt;/li&gt;
&lt;li&gt;5 弦: A2（约 110.00 Hz）&lt;/li&gt;
&lt;li&gt;6 弦: E2（约 82.41 Hz）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在吉他上，音高是通过弦的振动和按压琴格的位置来决定的。每根弦和每个品格都有固定的音高。按下吉他的品格（即指板上的位置）会改变弦的振动长度，从而改变音高。每按下一个品格，音高上升一个半音。比如，按下 6 弦的 1 品，音高从 E2 变为 F2。&lt;/p&gt;
&lt;p&gt;如果想在吉他上弹奏 C 大调，可以从 5 弦的 3 品开始弹，即从 A2 升高 3 个半音到 C3（A2 到 B2 相隔一个全音，B2 到 C3 相隔一个半音）。&lt;/p&gt;
&lt;h3 id=&#34;半音与十二平均律&#34;&gt;半音与十二平均律&lt;/h3&gt;
&lt;p&gt;在乐音体系中，音高关系最小的计量单位叫 &lt;strong&gt;半音（Semitone）&lt;/strong&gt;，两个半音就是一个全音。&lt;/p&gt;
&lt;p&gt;在 C，D，E，F，G，A，B，C 中，&lt;strong&gt;EF 和 BC&lt;/strong&gt; 之间相差一个半音，其它相邻音相差一个全音。&lt;/p&gt;
&lt;p&gt;在吉他中，相邻两个品格之间相差半音。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;十二平均律（Equal temperament）&lt;/strong&gt;，或平均律, 是将八度的二倍音程等比例地划分为十二份的定律方式。它让每一个临近的音在音程上都是同样的倍数关系。这每一个音和主音 Do[1] 组成的音程的倍数关系分别是 $2^{n/12}$，n=0到12。&lt;/p&gt;
&lt;p&gt;当 n=12，倍数正好是 &lt;strong&gt;二倍&lt;/strong&gt; 即纯八度，它对应的音名和当 n=0 时纯一度上的音是一样的。所以去掉 12，从 0 数到 11 正好产生十二个不一样的音名。&lt;/p&gt;
&lt;p&gt;对于 C 大调，如果是以国际标准音 &lt;strong&gt;A-la-440HZ&lt;/strong&gt; 为准，通过十二平均律可以计算出各个音的频率（单位：HZ）为：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;C#/Db&lt;/th&gt;
&lt;th&gt;D&lt;/th&gt;
&lt;th&gt;D#/Eb&lt;/th&gt;
&lt;th&gt;E&lt;/th&gt;
&lt;th&gt;F&lt;/th&gt;
&lt;th&gt;F#/Gb&lt;/th&gt;
&lt;th&gt;G&lt;/th&gt;
&lt;th&gt;G#/Ab&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;A#/Bb&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;261.6&lt;/td&gt;
&lt;td&gt;277.2&lt;/td&gt;
&lt;td&gt;293.7&lt;/td&gt;
&lt;td&gt;311.1&lt;/td&gt;
&lt;td&gt;329.6&lt;/td&gt;
&lt;td&gt;349.2&lt;/td&gt;
&lt;td&gt;370.0&lt;/td&gt;
&lt;td&gt;392.0&lt;/td&gt;
&lt;td&gt;415.3&lt;/td&gt;
&lt;td&gt;440.0&lt;/td&gt;
&lt;td&gt;466.2&lt;/td&gt;
&lt;td&gt;493.9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;可以看出，根据十二平均律分出了 12 个音，每个音之间相差的频率大小就是一个半音的大小。&lt;/p&gt;
&lt;h3 id=&#34;音组&#34;&gt;音组&lt;/h3&gt;
&lt;p&gt;不同八度的音名如果都长一样会造成误解，因此有必要用不同的标记以示区分。&lt;/p&gt;
&lt;p&gt;音高的标记国际上通用两套体系：&lt;strong&gt;科学音高记号法&lt;/strong&gt; 与 &lt;strong&gt;亥姆霍兹音高记号法&lt;/strong&gt;。&lt;/p&gt;
&lt;h4 id=&#34;科学音高记号法&#34;&gt;科学音高记号法&lt;/h4&gt;
&lt;p&gt;我们把从 C 开始的一个八度设定为一个音组，音组中的音名用大写英文字母 CDEFGAB 和升降符号标记。每个音组都把 C 作为音组的第一个音，B 作为音组的最后一个音。&lt;/p&gt;
&lt;p&gt;人耳的听力极限在 &lt;strong&gt;20Hz - 20,000Hz&lt;/strong&gt; 左右，随年龄稍有衰减。这个频率区间跨度大约在十个八度，所以使用十一个音组就能完全将人耳听力范围涵盖在内。&lt;/p&gt;
&lt;p&gt;于是，我们可以用数字 0-10 来标记这十一个音组。最低一个的音组对应数字 0，最高一个对应数字 10。&lt;/p&gt;
&lt;p&gt;在标记音高时，音名的大写字母在前，数字在后。&lt;/p&gt;
&lt;p&gt;中央 C 标记为 &lt;strong&gt;C4&lt;/strong&gt;，标准音高 A440 记为 A4，这两个音都落在 4 号音组中。&lt;/p&gt;
&lt;p&gt;最低一个 0 号音组中的 C 是 16.35Hz，标记为 C0。这个音组的最后一个音是 B0，由 B0 升高一个半音可以得到下一个音组中的第一个音 C1。&lt;/p&gt;
&lt;p&gt;最高的一个 10 号音组中，B 的频率在 31608Hz，标记为 B10。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1706239299755.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h4 id=&#34;亥姆霍兹音高记号法&#34;&gt;亥姆霍兹音高记号法&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1734248009815.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;在钢琴正中央的一组音级（包括基本音级和变化音级的十二个音级&amp;ndash;从 C 到 B）叫做“&lt;strong&gt;小字一组&lt;/strong&gt;”。用小写字母 c、d、e、f、g、a、b 来表示，并在其右上方标记出阿拉伯数字 1。如：c1、d1、e1、f1、g1、a1、b1。&lt;/p&gt;
&lt;p&gt;比小字一组高的音组由低到高分别定名为“小字二组” &amp;hellip;&amp;hellip; “小字六组”等等。并在其右下方用阿拉伯数字 1 或 2、3、4。如小字三组的 D 就标记为 d3。&lt;/p&gt;
&lt;p&gt;比小字一组低的音组由高到低分别定名为“小字组”，“大字组”、“大字一组”、“大字二组”、“大字三组”、“大字四组”等等。&lt;/p&gt;
&lt;p&gt;其中大字组的音用大写字母 C、D、E、F、G、A、B 来表示，并在其右下方用阿拉伯数字 1 或 2、3、4。如大字二组的 D 就标记为 D2。&lt;/p&gt;
&lt;h2 id=&#34;音乐记谱法&#34;&gt;音乐记谱法&lt;/h2&gt;
&lt;h3 id=&#34;五线谱&#34;&gt;五线谱&lt;/h3&gt;
&lt;p&gt;五线谱上的四三拍分数标记，是从下往上读的，表示以四分音符为基本拍，每小节有三拍，实际上表示每个小节的时值是三个四分音符的总时值，所以并不是只采用四分音符表示。&lt;/p&gt;
&lt;p&gt;五线谱有五条线，最下面为一线，一线二线间为一间，一线往下为下加一间、下加一线，五线往上为上加一间、上加一线，可以一直加，每个线或间标识一个音高。&lt;/p&gt;
&lt;p&gt;谱号是五线谱中的一个符号，用来表示乐谱中不同位置的音高。谱号通常是一个音名字母的变体，放在五线谱中的某个位置上，表示该位置上的音高。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1734249119990.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;如下图所示，从二线开始画高音谱号，那么二线即为 G4 音，一间即为 F4，一线即为 E4，下加一间即为 D4，下加一线即为中央 C4 了：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1734248922968.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;不同乐器适用不同谱号。现今的有音高乐器通常只会使用高音、中音、次中音和低音谱表四种谱表，圆号、小提琴、吉他等常使用高音谱表，长号、大提琴、低音提琴等常使用低音谱表，中提琴、大提琴等常使用中音谱表，大提琴、长号等常使用次中音谱表。&lt;/p&gt;
&lt;p&gt;五线谱中会使用很多额外的标记来注释某段拍子应该如何演奏，比如：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/Snipaste_2024-12-15_16-06-44.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;标记音符的强度及其变化：用 f 表示“强”，p 表示“弱”。mf 为中强，ff 为极强，fff 为最强，sf 为突强，&amp;quot;&amp;lt;cresc.&amp;quot; 表示渐强。&lt;/p&gt;
&lt;p&gt;标记演奏的情感：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cantabile：如歌的&lt;/li&gt;
&lt;li&gt;Dolce：柔和甜美的&lt;/li&gt;
&lt;li&gt;Leggiero：轻快的&lt;/li&gt;
&lt;li&gt;Agitato：充满激情的&lt;/li&gt;
&lt;li&gt;Grandioso：壮观宏伟的&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;标记演奏的整体速度：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presto - 急板（168-200 bpm）&lt;/li&gt;
&lt;li&gt;Vivace - 活泼的（~140 bpm）&lt;/li&gt;
&lt;li&gt;Allegro assai - 颇快的&lt;/li&gt;
&lt;li&gt;Allegro - 快板（120-168 bpm）&lt;/li&gt;
&lt;li&gt;Allegro Moderato - 适度、中速的快板&lt;/li&gt;
&lt;li&gt;Allegretto - 小快板（104-112 bpm）&lt;/li&gt;
&lt;li&gt;Moderato - 中板（90-115 bpm）&lt;/li&gt;
&lt;li&gt;Andantino - 小行板（比行板稍快）&lt;/li&gt;
&lt;li&gt;Andante - 行板（76-108 bpm）&lt;/li&gt;
&lt;li&gt;Adagietto - 小柔板/颇慢&lt;/li&gt;
&lt;li&gt;Adagio - 柔板（66-76 bpm）&lt;/li&gt;
&lt;li&gt;Largo - 广板（40-60 bpm）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;若加了 Molto，则表示“非常”，用来加强速度或力度的指示。例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Molto Allegro: 比普通的 Allegro 更快。&lt;/li&gt;
&lt;li&gt;Molto Adagio: 比普通的 Adagio 更轻柔。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体的速度增加没有固定的数量，因为它依赖于演奏者的诠释和乐曲的风格。通常来说，它表示要在原有的基础上更为明显地表现出速度或力度的变化。&lt;/p&gt;
&lt;p&gt;装饰音是一种用来装饰音符的音。装饰音可以加强音乐的旋律和节奏感。通常装饰音会附在音符上很快地演奏。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1744614558676.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;具体演奏方法可以参考：&lt;a href=&#34;https://zhuanlan.zhihu.com/p/528726886&#34;&gt;装饰音演奏大法&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在学习弹奏哥德堡变奏曲中，我发现巴洛克时期的装饰音写法有所不同，如下图五线谱所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1744616157468.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;查找百科可以找到巴洛克时期装饰音的具体写法和演奏方法：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/%E5%B7%B4%E6%B4%9B%E5%85%8B%E6%97%B6%E6%9C%9F%E8%A3%85%E9%A5%B0%E9%9F%B3.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;简谱&#34;&gt;简谱&lt;/h3&gt;
&lt;p&gt;简谱为记谱法之一，因主要以数字作表达，亦称为数字谱。&lt;/p&gt;
&lt;p&gt;简谱起源于十八世纪的法国，后经德国人改良，遂成今日之貌。简谱若与五线谱合并显示，则称为“简五谱”。&lt;/p&gt;
&lt;p&gt;在简谱中，使用 1-7 代表各个音符，例如 1 表示 do，2 表示 re，以此类推。至于 1 具体代表那个音，乐谱中会有具体的表示，比如是一首 G 大调的作品，那么可能会写为 “1=G 3/4”，表示 1 为 G 音（通常为 G4），以四分音符为一拍，每小节三拍子。&lt;/p&gt;
&lt;p&gt;对于音高，如果是高一个八度，就会在数字上方加上一点。如果是低一个八度，就会数字下方加上一点。在中间的那一个八度就什么也不用加。依此类推，如果要再高一个八度，就在上方垂直加上两点。如下所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1739114584890.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;对于音长，通常只有数字的是四分音符。数字下加一条横线，就可令四分音符的长度减半，即成为八分音符，依此类推。在数字后面加一条横线则变成二分音符，依此类推。此外，休止符用“0”来表示。&lt;/p&gt;
&lt;h3 id=&#34;六线谱&#34;&gt;六线谱&lt;/h3&gt;
&lt;p&gt;六线谱是世界上通用的一种专为吉他设计的记谱方法，它的基本结构是由六根间隔相等的线组成，六根线分别代表吉他上的六根弦，最下面的一条线，代表吉他的第六根弦。&lt;/p&gt;
&lt;p&gt;六线谱可以表示两手演奏的位置和动作（即指法），属于记录指法的乐谱。六线谱不记录音的高低，但与简谱或五线谱结合对照起来使用时非常方便，既能表示音高，又能表示指法。&lt;/p&gt;
&lt;h3 id=&#34;四线谱&#34;&gt;四线谱&lt;/h3&gt;
&lt;p&gt;四线谱有三种，一种是精简“五线谱”，一种是尤克里里专用谱，还有就是贝斯专用谱。在音乐创作当中使用较为广泛。&lt;/p&gt;
&lt;p&gt;十一世纪时，修道士圭多·达雷左首创四线谱。&lt;/p&gt;
&lt;p&gt;四线谱可以精确地记录音高，以便歌手准确演唱。四线谱也是贝斯专用谱。还有一种是精简“五线谱”。&lt;/p&gt;
&lt;h2 id=&#34;音程&#34;&gt;音程&lt;/h2&gt;
&lt;p&gt;音程指的是一个乐音体系中，两个音之间的高低关系。两个音可以有前后顺序，即旋律音程，也可以同时发声，即和声音程。较低的音称为根音或下方音，较高的音称为冠音或上方音。&lt;/p&gt;
&lt;h3 id=&#34;自然音程&#34;&gt;自然音程&lt;/h3&gt;
&lt;p&gt;在采用五度相生律的自然大调中，任意两个音之间的音程可以按照度数和音程系数归为十四种。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1734864904928.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;度数指的是两个音之间包含的基本音名或唱名的数量（含自身）。例如，do－fa 的度数是四度，包含了 do、re、mi、fa 四个唱名；do－do1 的度数是八度。&lt;/p&gt;
&lt;p&gt;“纯”音程是基于简单频率比和高度谐和性而定义的，主要包括一度、四度、五度和八度。这些音程在音乐体系中具有基础性作用。其他音程因其复杂性或功能多样性，被归类为“大”、“小”、“增”、“减”，而没有“纯”的概念。这种分类反映了音程在音乐实践和理论中的不同角色和功能。&lt;/p&gt;
&lt;p&gt;根据对照表可以轻松计算得到音程，比如增四度，对于 sol，我们首先根据四度音程 re-mi-fa-sol，找到了 re，这相差音数为 1+0.5+1=2.5，则为纯四度，为了得增四度，将 re 降半音或者 sol 升半音即可：(b)re-sol / re-(#)sol。&lt;/p&gt;
&lt;h3 id=&#34;变化音程&#34;&gt;变化音程&lt;/h3&gt;
&lt;p&gt;根据自然音程，变化音数，可以得到变化音程。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1734873188893.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;具体增减关系：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1734873738167.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;协和音&#34;&gt;协和音&lt;/h3&gt;
&lt;p&gt;在音乐范畴中，协和与不协和指的是将和弦或旋律的悦耳程度进行分类与描述的一种方式。通常意义上来讲，协和的声音常与甜美、放松、愉悦、可接受等情感相联系；而不协和则常与刺耳、紧张、不愉快、不可接受和伤心等情感相联系。&lt;/p&gt;
&lt;p&gt;在古典音乐的对位法中，协和与不协和往往按照以下的方式进行区分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;完全协和（德语：vollkommene Konsonanzen）：纯一度、纯八度、纯四度、纯五度。&lt;/li&gt;
&lt;li&gt;不完全协和（德语：unvollkommene Konsonanzen）：大三度、小三度、大六度、小六度。&lt;/li&gt;
&lt;li&gt;不协和：大二度、小二度、大七度、小七度，增四度或减五度。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而在爵士乐中，对于协和与不协和则有不同的定义：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;一级协和（德语：primäre Konsonanzen）：大三度、小三度、大六度与小六度；&lt;/li&gt;
&lt;li&gt;次级协和（德语：sekundäre Konsonanzen）：纯一度、纯八度、纯四度和纯五度；&lt;/li&gt;
&lt;li&gt;轻微不协和（德语：milde Disssonanzen）：增二度、增五度、增四度、小七度和大二度；&lt;/li&gt;
&lt;li&gt;不协和（德语：Disssonanzen）：小二度、大七度和小九度；&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;音程转位&#34;&gt;音程转位&lt;/h3&gt;
&lt;p&gt;在音程中，把某个音程的根音向上提高八度，或者把它的冠音降低八度，也就是将音程的根音与冠音的位置进行相互调换，这种就称为音程转位。&lt;/p&gt;
&lt;p&gt;为方便称呼，转位之前的音程会被称为原位音程，而转位之后的音程会被称为转位音程。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1734875446857.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;和弦&#34;&gt;和弦&lt;/h2&gt;
&lt;p&gt;现代音乐概念里面，由 &lt;strong&gt;多个不同的音高&lt;/strong&gt; 同时发声就形成 &lt;strong&gt;和声&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三个或三个音以上&lt;/strong&gt; 的和声就叫做 &lt;strong&gt;和弦（Chord）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;和弦原意是指弦线。在音乐理论里，是指组合在一起的两个以上不同音高的音。在欧洲古典音乐及受其影响的音乐风格里，更多时候是指三个或以上的音高组合，而两个音高的组合则以音程来描述。&lt;/p&gt;
&lt;p&gt;和弦的组成音，可分开演奏，亦可同时演奏。分开演奏的，称为分解和弦。&lt;/p&gt;
&lt;h3 id=&#34;和弦类型&#34;&gt;和弦类型&lt;/h3&gt;
&lt;p&gt;和弦的结构类型很多，如果按照组成音的多寡来区分，和弦可以分为三和弦（triads）、七和弦（sevenths）及九和弦（ninths）等。&lt;/p&gt;
&lt;p&gt;三和弦是由三个音组成，从最低音到最高音依次叫根音、三音和五音。七和弦是由四个音组成，九和弦则由五个音组成。&lt;/p&gt;
&lt;p&gt;这些和弦又可用音程结构来细分，例如三和弦可以分为大和弦（major chord）、小和弦（minor chord）、增和弦（augmented chord）、减和弦（diminished chord）四种形态。他们的构成规律如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/a.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;和弦转位&#34;&gt;和弦转位&lt;/h3&gt;
&lt;p&gt;和弦通过转位形成转位和弦。一个和弦中除根音以外的音作为最低音，则称为转位和弦。&lt;/p&gt;
&lt;p&gt;如果和弦是 C，那么和弦音有三个：C、E、G。一般来说，低音当然是以 C 为中心来演奏的，这是基本形式，而不是围绕 E 或 G 弹奏。这就是转位。&lt;/p&gt;
&lt;p&gt;在古典系统理论中，三音作为低音的形式被称为第一转位，低音用五音的形式被称为第二转位，没有转位的叫做基本型。&lt;/p&gt;
&lt;p&gt;转位的形式可以用来控制歌曲的稳定性，或创造一个平滑移动的低音线。&lt;/p&gt;
&lt;h2 id=&#34;调式体系&#34;&gt;调式体系&lt;/h2&gt;
&lt;h3 id=&#34;基本概念&#34;&gt;基本概念&lt;/h3&gt;
&lt;p&gt;音阶的类型叫做 &lt;strong&gt;调式(mode)&lt;/strong&gt;。一个音阶是按泛音列或音排列，并因其规律形成循环的一系列音符。八度中选取任意一组音，它们的音高 &lt;strong&gt;由低到高&lt;/strong&gt; 依次排列就能组成一条音阶。&lt;/p&gt;
&lt;p&gt;像钢琴键盘白键这样，一个双全音群和一个三个全音的群，两个群由&lt;strong&gt;半音&lt;/strong&gt;衔接在一起，这样组成的音阶就叫做 &lt;strong&gt;自然音阶（Diatonic scale）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在音乐理论中，稳定音和不稳定音是指音阶中不同音级的稳定性，即它们在调性中的作用。稳定音是指音阶中相对稳定、不需要解决的音，它们是和弦的构成音，在音乐中听起来稳定、安定，通常可以停留较长时间。稳定音通常是 1、3、5 级音，这三个音构成了主和弦。不稳定音是在调性中听起来不安定，通常需要向稳定音解决的音。它们通常是音阶中的 2、4、6、7 级音。&lt;/p&gt;
&lt;h3 id=&#34;大小调&#34;&gt;大小调&lt;/h3&gt;
&lt;p&gt;自然音阶有七个不同的音，因此属于七声音阶。自然音阶有七种调式，各自拥有独特的气质。其中大小调是最常用的 2 种。大调音阶的音程向上以 &lt;strong&gt;全全半全全全半&lt;/strong&gt; 排列，用大调写的音乐一般给人的感觉或轻松舒缓或积极阳光。小调音阶的音程向上以 &lt;strong&gt;全半全全半全全&lt;/strong&gt; 排列，小调音乐带有忧郁哀伤的气质。&lt;/p&gt;
&lt;p&gt;对于 C 大调，就是以 C 为主音，以大调作为调式。组成的音有 C、D、E、F、G、A、B 及 C。C 大调是一个没有升号和降号的调。A 小调与 C 大调是关系大小调，它们共用相同的调号，也就是没有升降号。&lt;/p&gt;
&lt;p&gt;将 C 大调移高一个纯五度就是以 G 为主音的 G 大调。G 大调音阶为：G - A - B - C - D - E - F# - G，有了一个升号。如下图，在五线谱中，G 大调表示为在高音谱号右侧写一个升号：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1739115235010.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;键盘乐器&#34;&gt;键盘乐器&lt;/h2&gt;
&lt;h3 id=&#34;钢琴&#34;&gt;钢琴&lt;/h3&gt;
&lt;p&gt;传统钢琴（如立式钢琴和三角钢琴）是机械乐器，通过敲击琴键触发锤子敲打弦，产生声音。每个琴键都有一个相应的弦，弦的震动通过琴体放大，形成音响。这种声音具有自然的音色、共鸣和音质变化。传统钢琴需要定期调音和保养，尤其是对于三角钢琴，每年需要至少调音一次，以保证音色和音准的准确。&lt;/p&gt;
&lt;p&gt;电钢琴是通过电子发声的乐器，通常没有像传统钢琴那样的弦，而是模拟或数字化音频生成声音。电钢琴的音色可以是多种多样的，包括钢琴音、电子合成音、管风琴音等。电钢琴通常不需要调音。&lt;/p&gt;
&lt;p&gt;关于踏板：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;右踏板（延音踏板）：延长所有音符的持续时间，增加音符之间的连贯性。踩下踏板后，所有音符的消音器抬起，音符持续发声。&lt;/li&gt;
&lt;li&gt;左踏板（弱音踏板）：减弱音量并改变音色，使音符显得更加柔和。踩下踏板后，使琴槌击打弦的面积变小，音量减弱。&lt;/li&gt;
&lt;li&gt;中踏板（延音加强踏板）：只延长特定音符的持续时间，允许在演奏时保持某些音符的持续而不影响其他音符。踩下踏板后，只延长已按下音符的持续时间，其他音符不受影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;大键琴&#34;&gt;大键琴&lt;/h3&gt;
&lt;p&gt;大键琴（Harpsichord）是一种古老的键盘乐器，属于弦乐器家族。它在巴洛克时期尤其重要，广泛用于古典音乐中，尤其是巴赫、亨德尔、维瓦尔第等作曲家的作品中。&lt;/p&gt;
&lt;p&gt;大键琴的外形与钢琴相似，通常有一个较大的、扁平的琴身和琴键。它通常有两组或更多的键盘，每组键盘都有一定数量的琴键。与钢琴不同，大键琴的弦是通过拨片（plectrum）来激发的，而不是通过锤子敲击弦。这种结构使得大键琴的音色与钢琴有很大的不同。&lt;/p&gt;
&lt;p&gt;当按下大键琴的琴键时，键下的拨片会拨动对应弦的振动，产生声音。由于没有打击弦的机制，大键琴的声音相对钢琴来说更为尖锐、明亮且较为“平”。大键琴的声音不能通过力度变化来调节。即按下琴键的力度不会影响音量或音色的变化，这与钢琴的触感和声音变化机制是不同的。&lt;/p&gt;
&lt;p&gt;大键琴的演奏不能像钢琴一样通过击打力度来变化音量，因此大键琴演奏者需要使用快速的指法技巧和精准的手指控制来达到不同的音效。大键琴通常需要演奏者在旋律中加入许多装饰音，如倚音、琶音、快速音符变化等，这些技巧使得大键琴的演奏富有表现力。&lt;/p&gt;
&lt;h3 id=&#34;电子琴&#34;&gt;电子琴&lt;/h3&gt;
&lt;p&gt;Yamaha psr-e383 电子琴的一些使用记录：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;61 键&lt;/li&gt;
&lt;li&gt;屏幕虽然显示了 C3，但实际上的音高是 C4&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.yamaha.com.cn/products/show/3047/#d282990&#34;&gt;视频说明书&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.yamaha.com.cn/products/show/3047/#d282990&#34;&gt;资料下载&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;没有踏板&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;管风琴&#34;&gt;管风琴&lt;/h3&gt;
&lt;p&gt;管风琴（Organ）是一种历史悠久的键盘乐器，以其巨大的音响和丰富的音色著称，常常出现在教堂、音乐厅以及大型演奏会中。它是古典音乐、宗教音乐和某些现代音乐演奏中不可或缺的乐器。管风琴的声音通过空气流动通过管道产生，这些管道根据不同的长度、材质和形状可以产生各种音色。&lt;/p&gt;
&lt;h2 id=&#34;弦乐器&#34;&gt;弦乐器&lt;/h2&gt;
&lt;h3 id=&#34;吉他&#34;&gt;吉他&lt;/h3&gt;
&lt;h4 id=&#34;标准定弦&#34;&gt;标准定弦&lt;/h4&gt;
&lt;p&gt;标准定弦是六弦吉他最常用的定弦法。若无变格定弦的具体说明，则标准定弦是默认的。它包括以下音符:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;E2-A2-D3-G3-B3-E4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1735194431475.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;这里就采用了科学音高记号法，字母表示音名，数字表示所在八度。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;弦&lt;/th&gt;
&lt;th&gt;频率&lt;/th&gt;
&lt;th&gt;科学记谱法音高&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 (E)&lt;/td&gt;
&lt;td&gt;329.63 Hz&lt;/td&gt;
&lt;td&gt;E4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 (B)&lt;/td&gt;
&lt;td&gt;246.94 Hz&lt;/td&gt;
&lt;td&gt;B3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3 (G)&lt;/td&gt;
&lt;td&gt;196.00 Hz&lt;/td&gt;
&lt;td&gt;G3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 (D)&lt;/td&gt;
&lt;td&gt;146.83 Hz&lt;/td&gt;
&lt;td&gt;D3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 (A)&lt;/td&gt;
&lt;td&gt;110.00 Hz&lt;/td&gt;
&lt;td&gt;A2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6 (E)&lt;/td&gt;
&lt;td&gt;82.41 Hz&lt;/td&gt;
&lt;td&gt;E2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id=&#34;八大吉他和弦&#34;&gt;八大吉他和弦&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/recording-and-reflection-on-music-theory/image/1738467571576.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;按弦注意事项：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;按的位置要尽量接近下方琴桁（Fret）。&lt;/li&gt;
&lt;li&gt;使用指尖按弦，并且关节呈弯曲状态，而大拇指保持放松。&lt;/li&gt;
&lt;li&gt;确保没有闷住／碰触邻弦，每条该发出声音的弦都有正常运作。&lt;/li&gt;
&lt;li&gt;每天花点时间练习和弦之间的转换过程，进步速度会很快。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;贝斯&#34;&gt;贝斯&lt;/h3&gt;
&lt;p&gt;贝斯(低音吉他)&lt;/p&gt;
&lt;h3 id=&#34;小提琴&#34;&gt;小提琴&lt;/h3&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h3 id=&#34;低音提琴&#34;&gt;低音提琴&lt;/h3&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h3 id=&#34;大提琴&#34;&gt;大提琴&lt;/h3&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ohmusictheory.com/&#34;&gt;oh music theory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://zh.wikipedia.org/wiki/Wikipedia:%E9%A6%96%E9%A1%B5&#34;&gt;维基百科&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.icourse163.org/course/CCOM-1003681001&#34;&gt;中央音乐学院：音乐奥秘解码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://music-theory.aizcutei.com&#34;&gt;自由派音乐理论&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>音乐格式和分轨问题记录</title>
        <link>https://zhihang.org/posts/record-of-music-format-and-track-splitting-issues/</link>
        <pubDate>Fri, 22 Nov 2024 14:43:20 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>record-of-music-format-and-track-splitting-issues</guid>
        <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;实体音乐媒介有黑胶唱片、磁带、光存储介质等。光存储介质主要包括 CD(Compact Disc)、DVD(Digital Versatile Disc)，SACD(Super Audio CD)，BD(Blu-ray Disc) 等。&lt;/p&gt;
&lt;p&gt;随着技术进步，数字化音乐出现，主要包括各种格式的音乐数字文件和各种平台所提供的流媒体服务。&lt;/p&gt;
&lt;p&gt;作为一个音乐爱好者，我觉得了解各种音乐格式还是很有必要的。特别是作为 Apple Music 使用者，就更有意义了。Apple Music 支持导入音乐和编辑专辑，很适合做一个自己的音乐库。虽然我已经是 Apple Music 美区用户，曲库已经相当完善，但还是有一些特别想听的音乐找不到，比如最近想听 Clannad 的 OST 是没有的，古典音乐某些演奏家的演奏版本是找不到的。&lt;/p&gt;
&lt;p&gt;因此，少部分音乐我还是得通过其他手段获取，这时候了解各种音乐格式就很有意义了，同时还需要了解一些分轨技术，以更好地享用和收藏整轨音乐包。&lt;/p&gt;
&lt;h2 id=&#34;常见音乐格式&#34;&gt;常见音乐格式&lt;/h2&gt;
&lt;p&gt;数字音乐有很多音乐格式，如 mp3、flac、wav、m4a 等，下面做一个记录。&lt;/p&gt;
&lt;h3 id=&#34;mp3mpeg-audio-layer-3&#34;&gt;MP3(MPEG Audio Layer-3)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;MPEG Audio Layer-3&lt;/strong&gt; 是音频压缩技术的全称，&lt;strong&gt;MPEG&lt;/strong&gt; 是 &lt;strong&gt;Moving Picture Experts Group&lt;/strong&gt; 的缩写，即&lt;strong&gt;动态图像专家组&lt;/strong&gt;，它是一个国际标准化组织下的工作组，负责制定音频和视频压缩的国际标准。&lt;strong&gt;Layer&lt;/strong&gt; 可以理解为同一标准中针对不同场景的压缩级别，Layer-3 相对 1 和 2 压缩效率和音质更好。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;压缩方式&lt;/strong&gt;：有损压缩（Lossy Compression）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;音质&lt;/strong&gt;：通过移除人耳不易察觉的声音信息减小文件大小，音质受码率（bitrate）影响。
&lt;ul&gt;
&lt;li&gt;常见码率：128 kbps（中等）、192 kbps（良好）、320 kbps（接近无损）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件大小&lt;/strong&gt;：小，适合节省存储空间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;兼容性&lt;/strong&gt;：几乎所有设备和软件都支持。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：流媒体、便携式音乐设备、普通聆听。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;flacfree-lossless-audio-codec&#34;&gt;FLAC(Free Lossless Audio Codec)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;压缩方式&lt;/strong&gt;：无损压缩（Lossless Compression）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;音质&lt;/strong&gt;：保留录音的完整音频数据，音质与原始录音一致。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件大小&lt;/strong&gt;：比 WAV 小（约原文件的 50-70%），但比 MP3 大很多。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;兼容性&lt;/strong&gt;：现代播放器和设备广泛支持（如 VLC、Foobar2000、Hi-Fi 音响）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：高品质音乐收藏、发烧友、高端音响设备。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;优缺点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优点：高音质，文件支持标签（如专辑封面、艺术家信息）。&lt;/li&gt;
&lt;li&gt;缺点：文件较大，兼容性不如 MP3。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;wavwaveform-audio-file-format&#34;&gt;WAV(Waveform Audio File Format)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;压缩方式&lt;/strong&gt;：未压缩或无损（Uncompressed or Lossless）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;音质&lt;/strong&gt;：最接近原始录音，极高音质。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件大小&lt;/strong&gt;：非常大（约 10 MB/分钟）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;兼容性&lt;/strong&gt;：专业音频设备和软件支持良好。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：录音、编辑、母带制作、专业音频工程。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;优缺点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优点：音质最佳，无任何压缩损失。&lt;/li&gt;
&lt;li&gt;缺点：文件巨大，不适合普通存储或便携设备。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;m4ampeg-4-audio&#34;&gt;M4A(MPEG-4 Audio)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;压缩方式&lt;/strong&gt;：有两种版本
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AAC（Advanced Audio Coding）&lt;/strong&gt;：有损压缩。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ALAC（Apple Lossless Audio Codec）&lt;/strong&gt;：无损压缩。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;音质&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;AAC 音质优于 MP3（同码率下）。&lt;/li&gt;
&lt;li&gt;ALAC 提供与 FLAC 类似的无损音质。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件大小&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;AAC 比 MP3 小。&lt;/li&gt;
&lt;li&gt;ALAC 比 WAV 小但大于 MP3。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;兼容性&lt;/strong&gt;：苹果生态系统支持最佳（如 iTunes、iPhone），大多数现代播放器也兼容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;/strong&gt;：流媒体（AAC）、高品质收藏（ALAC）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;优缺点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优点：AAC 高效，ALAC 高音质，苹果用户友好。&lt;/li&gt;
&lt;li&gt;缺点：ALAC 在非苹果设备上的支持较 FLAC 少。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;其他常见格式&#34;&gt;其他常见格式&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OGG（Ogg Vorbis）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开源有损格式，音质优于 MP3（同码率）。&lt;/li&gt;
&lt;li&gt;常用于游戏、Spotify 等流媒体。&lt;/li&gt;
&lt;li&gt;缺点：兼容性较差。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AIFF（Audio Interchange File Format）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;苹果开发的未压缩格式，与 WAV 类似，音质无损。&lt;/li&gt;
&lt;li&gt;用途：专业音频编辑，苹果生态友好。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DSD（Direct Stream Digital）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;超高分辨率无损格式，常用于 SACD。&lt;/li&gt;
&lt;li&gt;文件巨大，仅限高端设备支持。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;APE（Monkey&amp;rsquo;s Audio）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高效无损格式，文件比 FLAC 小，但兼容性差。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;选择建议&#34;&gt;选择建议&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;流媒体/普通听众&lt;/strong&gt;：MP3、AAC（M4A）更适合，兼顾音质和文件大小。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;音乐发烧友&lt;/strong&gt;：FLAC 或 ALAC 提供高音质，适合高端设备和收藏。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;音频编辑&lt;/strong&gt;：WAV 和 AIFF 更适合，因其保留了原始录音的所有细节。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件空间有限&lt;/strong&gt;：MP3 或 AAC（M4A）优先，文件小且易兼容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高分辨率音频&lt;/strong&gt;：DSD 或 FLAC 是最佳选择。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;整轨和分轨&#34;&gt;整轨和分轨&lt;/h2&gt;
&lt;p&gt;我在处理一些 OST(Original Soundtrack，原声音乐) 包时，发现里面通常包含许多文件，cue、flac、ape 等音频文件和一些图片。这里关键在于 cue 文件。&lt;/p&gt;
&lt;p&gt;cue 文件是一个文本文件，存储了音频文件的 &lt;strong&gt;分轨(Split Tracks)&lt;/strong&gt; 信息，包括每个音轨的起始时间、曲目名称、艺术家等元数据。也就是说只要存在 cue，那么对应的音频文件(flac、ape 等)就是一个 &lt;strong&gt;整轨(Single Track)&lt;/strong&gt; 音频。比如下面一个实例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;PERFORMER &amp;#34;KEY&amp;#34;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;TITLE &amp;#34;CLANNAD ORIGINAL SOUNDTRACK&amp;#34;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;FILE &amp;#34;KSLA-0012.ape&amp;#34; WAVE
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;  TRACK 01 AUDIO
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    TITLE &amp;#34;汐&amp;#34;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    PERFORMER &amp;#34;戸越 まごめ&amp;#34;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    FLAGS DCP
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    INDEX 01 00:00:00
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;  TRACK 02 AUDIO
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    TITLE &amp;#34;幻想&amp;#34;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    PERFORMER &amp;#34;戸越 まごめ&amp;#34;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    FLAGS DCP
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    INDEX 01 01:08:00
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;  ...
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;  TRACK 19 AUDIO
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    TITLE &amp;#34;月の位相&amp;#34;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    PERFORMER &amp;#34;折戸 伸治&amp;#34;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    FLAGS DCP
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    INDEX 01 64:42:00
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;  TRACK 20 AUDIO
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;    TITLE &amp;#34;無間&amp;#34;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;    PERFORMER &amp;#34;折戸 伸治&amp;#34;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;    FLAGS DCP
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;    INDEX 01 68:34:00
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个 Clannad OST 描述了详细的音频信息，对于头部信息：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;PERFORMER &amp;ldquo;KEY&amp;rdquo;&lt;/strong&gt;：这表示专辑的表演者是 &amp;ldquo;KEY&amp;rdquo;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TITLE &amp;ldquo;CLANNAD ORIGINAL SOUNDTRACK&amp;rdquo;&lt;/strong&gt;：这是专辑的标题，指明这是 &amp;ldquo;CLANNAD 原声带&amp;rdquo;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FILE &amp;ldquo;KSLA-0012.ape&amp;rdquo; WAVE&lt;/strong&gt;：这表示音频文件的名称为 &amp;ldquo;KSLA-0012.ape&amp;rdquo;，并且文件格式为 WAV 或兼容 WAV 的格式。虽然文件扩展名是 &lt;code&gt;.ape&lt;/code&gt;，可能是无损音频格式 APE 的文件，但在 &lt;code&gt;.cue&lt;/code&gt; 文件中通常会使用 WAV 来表示音频格式。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;从 TRACK 开始，就是每首音乐的具体信息，比如 TRACK 01:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TITLE &amp;ldquo;汐&amp;rdquo;&lt;/strong&gt;：这是第一轨的标题，名为 &amp;ldquo;汐&amp;rdquo;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PERFORMER &amp;ldquo;戸越 まごめ&amp;rdquo;&lt;/strong&gt;：演唱者为 &amp;ldquo;戸越 まごめ&amp;rdquo;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FLAGS DCP&lt;/strong&gt;：标记此轨为 &amp;ldquo;Disc-at-Once&amp;rdquo; 刻录模式，意味着此轨与其他音轨之间没有间隙。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;INDEX 01 00:00:00&lt;/strong&gt;：第一轨从 00:00:00（即 0 秒）开始播放。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;通过-xld-完成分轨&#34;&gt;通过 XLD 完成分轨&lt;/h2&gt;
&lt;p&gt;在 Mac 上可以通过 xld 完成音频分轨、转换等操作，xld 支持 gui 和 cmd，下面通过 cmd 进行示范。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;下载 XLD&lt;/li&gt;
&lt;li&gt;将 &amp;ldquo;XLD.app&amp;rdquo; 安装到 &amp;ldquo;/Applications/XLD.app&amp;rdquo;&lt;/li&gt;
&lt;li&gt;设置 xld 命令如下：&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;xld&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    XLD_APP&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/Applications/XLD.app&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;XLD_APP&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;/Contents/MacOS/XLD&amp;#34;&lt;/span&gt; --cmdline &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$@&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后即可快乐食用 xld 咯！&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;mkdir &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;./Clannad OST 0012&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# -c 指定 cue -o 指定输出目录（需要存在） -f 指定输出格式（默认 wav）最后跟上整轨音频文件&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;xld -c &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;KSLA-0012.cue&amp;#34;&lt;/span&gt; -o &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;./Clannad OST 0012&amp;#34;&lt;/span&gt; -f alac &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;KSLA-0012.ape&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一些注意事项：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如遇乱码问题，先将 cue 文件保存为 utf8 后再操作即可。&lt;/li&gt;
&lt;li&gt;格式则建议采用 alac，相比 wav 更小但音质无异，flac 也可但是无法导入 apple music。&lt;/li&gt;
&lt;li&gt;输出的文件夹导入 apple music 后，专辑名称不是文件夹名而是 cue 头信息中的 TITLE&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;PLUS: 通过 XLD 进行音频转换：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;xld -f alac だんご大家族.flac
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;chatgpt.com&#34;&gt;ChatGPT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://tmkk.undo.jp/xld/index_e.html&#34;&gt;XLD OFFICIAL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
    
      
      <item>
        <title>缓存重要知识整理</title>
        <link>https://zhihang.org/posts/cache-related-knowledge-organization/</link>
        <pubDate>Mon, 14 Oct 2024 01:48:44 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>cache-related-knowledge-organization</guid>
        <description>&lt;h2 id=&#34;toc&#34;&gt;TOC&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#toc&#34;&gt;TOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BC%93%E5%AD%98%E5%88%86%E7%B1%BB&#34;&gt;缓存分类&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#redis&#34;&gt;Redis&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BA%BF%E7%A8%8B%E6%A8%A1%E5%9E%8B&#34;&gt;线程模型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%80%9A%E4%BF%A1%E6%B5%81%E7%A8%8B&#34;&gt;通信流程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%BF%87%E6%9C%9F%E5%88%A0%E9%99%A4%E7%AD%96%E7%95%A5&#34;&gt;过期删除策略&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%BB%E4%BB%8E%E6%9E%B6%E6%9E%84&#34;&gt;主从架构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%9B%86%E7%BE%A4%E6%A8%A1%E5%BC%8F&#34;&gt;集群模式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84&#34;&gt;数据结构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C&#34;&gt;基本操作&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BA%8B%E5%8A%A1&#34;&gt;事务&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8F%91%E5%B8%83%E5%92%8C%E8%AE%A2%E9%98%85&#34;&gt;发布和订阅&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%8C%81%E4%B9%85%E5%8C%96%E6%9C%BA%E5%88%B6&#34;&gt;持久化机制&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#rdb-%E6%8C%81%E4%B9%85%E5%8C%96&#34;&gt;RDB 持久化&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#aof-%E6%8C%81%E4%B9%85%E5%8C%96&#34;&gt;AOF 持久化&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#redis-%E5%A4%A7-key-%E9%97%AE%E9%A2%98&#34;&gt;Redis 大 key 问题&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BC%93%E5%AD%98%E8%BF%87%E6%9C%9F%E7%AD%96%E7%95%A5&#34;&gt;缓存过期策略&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BC%93%E5%AD%98%E9%97%AE%E9%A2%98&#34;&gt;缓存问题&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9%E5%AE%95%E6%9C%BA&#34;&gt;缓存雪崩（宕机）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BC%93%E5%AD%98%E7%A9%BF%E9%80%8F%E7%BB%95%E8%BF%87&#34;&gt;缓存穿透（绕过）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BC%93%E5%AD%98%E5%A4%B1%E6%95%88&#34;&gt;缓存失效&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%B9%B6%E5%8F%91%E7%AB%9E%E4%BA%89%E9%97%AE%E9%A2%98&#34;&gt;并发竞争问题&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BC%93%E5%AD%98%E4%B8%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%80%E8%87%B4%E6%80%A7%E9%97%AE%E9%A2%98&#34;&gt;缓存与数据库一致性问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reference&#34;&gt;Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;缓存分类&#34;&gt;缓存分类&lt;/h2&gt;
&lt;p&gt;缓存可分为本地缓存和分布式缓存：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本地缓存&lt;/strong&gt;：指的是在应用中的缓存组件，其最大的优点是应用和 cache 是在同一个进程内部，请求缓存非常快速，没有过多的网络开销等，在单应用不需要集群支持或者集群情况下各节点无需互相通知的场景下使用本地缓存较合适；同时，它的缺点也是应为缓存跟应用程序耦合，多个应用程序无法直接的共享缓存，各应用或集群的各节点都需要维护自己的单独缓存，对内存是一种浪费。常见的本地缓存有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ehcache&lt;/li&gt;
&lt;li&gt;Guava Cache&lt;/li&gt;
&lt;li&gt;Caffeine&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Caffeine 是基于 JAVA8 的高性能缓存库。并且在 Spring5 (Springboot 2.x) 后，Spring 官方放弃了 Guava，而使用了性能更优秀的 Caffeine 作为默认缓存组件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;分布式缓存&lt;/strong&gt;：指的是与应用分离的缓存组件或服务，其最大的优点是自身就是一个独立的应用，与本地应用隔离，多个应用可直接的共享缓存。常见的分布式缓存有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;Memcached&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Memcached 不支持灾难恢复，对分布式支持不如 Redis，已经基本被 Redis 取代，下面着重记录 Redis 相关要点。&lt;/p&gt;
&lt;h2 id=&#34;redis&#34;&gt;Redis&lt;/h2&gt;
&lt;h3 id=&#34;线程模型&#34;&gt;线程模型&lt;/h3&gt;
&lt;p&gt;Redis 内部使用文件事件处理器 file event handler ，这个文件事件处理器是单线程的，所以 Redis 才叫做单线程的模型。它采用 IO 多路复用机制同时监听多个 socket，将产生事件的 socket 压入内存队列中，事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。&lt;/p&gt;
&lt;p&gt;文件事件处理器的结构包含 4 个部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多个 socket&lt;/li&gt;
&lt;li&gt;IO 多路复用程序&lt;/li&gt;
&lt;li&gt;文件事件分派器&lt;/li&gt;
&lt;li&gt;事件处理器（连接应答处理器、命令请求处理器、命令回复处理器）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;单线程模型效率高的原因:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;纯内存操作&lt;/li&gt;
&lt;li&gt;核心是基于非阻塞的 IO 多路复用机制&lt;/li&gt;
&lt;li&gt;单线程反而避免了多线程的频繁上下文切换问题，预防了多线程可能产生的竞争问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Redis 6.0 开始引入多线程，Redis 在有些方面，单线程已经不具有优势了。因为读写网络的 Read/Write 系统调用在 Redis 执行期间占用了大部分 CPU 时间，如果把网络读写做成多线程的方式对性能会有很大提升。&lt;/p&gt;
&lt;p&gt;Redis 的多线程部分&lt;strong&gt;只是用来处理网络数据的读写和协议解析&lt;/strong&gt;，执行命令仍然是单线程。&lt;/p&gt;
&lt;h3 id=&#34;通信流程&#34;&gt;通信流程&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/cache-related-knowledge-organization/image/1731381439143.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;多个 socket 可能会并发产生不同的操作，每个操作对应不同的文件事件，但是 IO 多路复用程序会监听多个 socket，会将产生事件的 socket 放入队列中排队，事件分派器每次从队列中取出一个 socket，根据 socket 的事件类型交给对应的事件处理器进行处理。&lt;/p&gt;
&lt;h3 id=&#34;过期删除策略&#34;&gt;过期删除策略&lt;/h3&gt;
&lt;p&gt;Redis 使用的过期删除策略是「惰性删除+定期删除」，删除的对象是已过期的 key。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/cache-related-knowledge-organization/image/1693649039266.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;内存淘汰策略是解决内存过大的问题，当 Redis 的运行内存超过最大运行内存时，就会触发内存淘汰策略，Redis 4.0 之后共实现了 8 种内存淘汰策略，我也对这 8 种的策略进行分类，如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/cache-related-knowledge-organization/image/1693649068416.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;主从架构&#34;&gt;主从架构&lt;/h3&gt;
&lt;p&gt;主从(master-slave)架构，一主多从实现高并发，主节点负责写，并且将数据复制到其它的 slave 节点，从节点负责读。所有的读请求全部走从节点。Redis 在主从的基础上通过哨兵机制切换主从实现高可用。&lt;/p&gt;
&lt;p&gt;主从复制流程大致是，初次连接全量复制，通过 RDB 快照 + 增量复制机制完成，如果复制过程中断线也会采用增量复制完成（可通过 heartbeat 机制确认连接情况）。&lt;/p&gt;
&lt;p&gt;哨兵机制大致是，哨兵监控 master，如果一个哨兵觉得 master 宕机了，则是主观宕机(sdown)，超过 quorum 个认为这是客观宕机(odown)，此时选举出新 master 候选人，这个人得到 majority 个哨兵的认可就可以成为 master。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;quorum 的计算公式为：quorum = (哨兵节点数/2) + 1&lt;/li&gt;
&lt;li&gt;majority 是选举机制中的一个值，可以理解为选票，majority &amp;gt;= quorum 并且 majority &amp;gt; 哨兵数量的一半&lt;/li&gt;
&lt;li&gt;选举机制中，候选者是判断哪个节点下线的哨兵，候选者投给自己，其他人投给收到的第一个申请的人&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关于选举机制带来的“脑裂”问题，其实就是出现 2 个 master，原 master 因为网络问题脱离，而其他人开始选新 master，后来原 master 恢复，导致出现 2 个 master。原 master 未进行主从切换复制数据，清空数据并成为 slave，导致丢失数据。通过限制 master 的 slave 个数大于 0 和延迟时间不超一定时间即可避免这个问题。&lt;/p&gt;
&lt;h3 id=&#34;集群模式&#34;&gt;集群模式&lt;/h3&gt;
&lt;p&gt;Redis cluster，主要是针对海量数据+高并发+高可用的场景。Redis cluster 支撑 N 个 Redis master node，每个 master node 都可以挂载多个 slave node。&lt;/p&gt;
&lt;p&gt;集群模式下，各个 master 存储不同的数据，采用一致性哈希算法来计算 key 的目标 master。具体来说，Redis 集群通过一致性哈希和槽（slot）机制来管理和定位键。&lt;/p&gt;
&lt;p&gt;Redis 集群将整个键空间分为 16384 个槽。每个键通过 CRC16 算法计算哈希值，然后对 16384 取模，决定其属于哪个槽。集群中的每个 master 负责若干个槽。&lt;/p&gt;
&lt;p&gt;对于普通的哈希算法，一旦其中一个 master 挂了，将会影响其他大多 master 的哈希，导致大量 key 需要重新分布，采用一致性哈希，可以将影响降低到单个 master，一致性哈希还采用了虚拟节点的方法，实现 key 的均匀分布：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/cache-related-knowledge-organization/image/1731400145088.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;数据结构&#34;&gt;数据结构&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;String: SDS，基于 C 字符串的动态长度可变字符串。&lt;/li&gt;
&lt;li&gt;List: QuickList(LinkedList+ZipList)&lt;/li&gt;
&lt;li&gt;Set: HashTable/IntSet。如果一个集合只包含整数值元素，且元素数量少于 512 个时，会使用 Intset。&lt;/li&gt;
&lt;li&gt;Hash: HashTable/ZipList。如果保存的所有键值对的键和值的字符串长度都小于 64 字节且数量小于 512 个则采用 ZipList。&lt;/li&gt;
&lt;li&gt;Zset: ZipList/SkipList+Dict。当 Zset 保存的键值对数量少于 128 个且每个元素的长度小于 64 字节时使用 ZipList，否则使用 SkipList。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SDS 对 c 原始 char 数组的改进:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;支持扩容&lt;/li&gt;
&lt;li&gt;包含长度 len，获取长度复杂度 O(1)&lt;/li&gt;
&lt;li&gt;空间预分配&lt;/li&gt;
&lt;li&gt;惰性空间释放&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;惰性空间释放用于优化 SDS 的字符串缩短操作： 当 SDS 的 API 需要缩短 SDS 保存的字符串时， 程序并不立即使用内存重分配来回收缩短后多出来的字节， 而是使用 free 属性将这些字节的数量记录起来， 并等待将来使用。&lt;/p&gt;
&lt;h3 id=&#34;基本操作&#34;&gt;基本操作&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 启动 redis&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;redis-server
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 连接到本地 redis:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;redis-cli
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 连接到远程 redis:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;redis-cli -h host -p port -a password
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 获取配置&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;config get 配置名
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 配置&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;config &lt;span style=&#34;color:#81a1c1&#34;&gt;set&lt;/span&gt; 配置名 值
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 获取密码&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;config get requirepass
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 设置密码&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;config &lt;span style=&#34;color:#81a1c1&#34;&gt;set&lt;/span&gt; requirepass &lt;span style=&#34;color:#b48ead&#34;&gt;12345&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 进行密码验证&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;auth &lt;span style=&#34;color:#b48ead&#34;&gt;12345&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;OK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ps: 如果重启服务密码会失效, 通过修改配置文件可以解决:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# /etc/redis/redis.conf&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;requirepass ${password}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以后通过下面命令启动服务，这样就可以在服务开启时同时指定密码。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;redis-server redis.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# string:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;127.0.0.1:6379&amp;gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;set&lt;/span&gt; mkey sos
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;OK
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;127.0.0.1:6379&amp;gt; get mkey
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;sos&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;127.0.0.1:6379&amp;gt; del mkey
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;integer&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;127.0.0.1:6379&amp;gt; get mkey
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;nil&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# list:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;lpush clist redis
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;lpush clist mysql
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;lrange clist &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;100&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# hash:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# mkeys: 接偶数个参数，一一对应。&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;127.0.0.1:6379&amp;gt; hmset mkeys A a B b C c
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;OK
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;127.0.0.1:6379&amp;gt; hget mkeys B
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# set:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;127.0.0.1:6379&amp;gt; sadd mkey &lt;span style=&#34;color:#b48ead&#34;&gt;123&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;integer&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;127.0.0.1:6379&amp;gt; sadd mkey &lt;span style=&#34;color:#b48ead&#34;&gt;123&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;integer&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;127.0.0.1:6379&amp;gt; smembers mkey
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;123&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# zset(sorted_set):&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 根据分数和字典序进行排序，同分数下比较字典序，不同分数时，分数越低越靠前。&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# ... {分数} {键值}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;127.0.0.1:6379&amp;gt; zadd zs &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; ak
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;integer&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;127.0.0.1:6379&amp;gt; zadd zs &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; to
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;integer&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;127.0.0.1:6379&amp;gt; zrangebyscore zs &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;100&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ak&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;2&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;to&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;127.0.0.1:6379&amp;gt; zadd zs &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt; pp
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;38&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;integer&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;39&lt;/span&gt;127.0.0.1:6379&amp;gt; zrangebyscore zs &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;100&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;40&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;pp&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;41&lt;/span&gt;2&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ak&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;42&lt;/span&gt;3&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;to&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;43&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;44&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 涉及批量获取和删除操作的, 线上不建议使用。&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;45&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 批量删除匹配到的 key&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;46&lt;/span&gt;redis-cli keys &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;user-*&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; xargs redis-cli del
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;47&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 如果设置了密码:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;48&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# redis-cli -a &amp;#34;pwd&amp;#34; keys &amp;#34;user-*&amp;#34; | xargs redis-cli -a &amp;#34;pwd&amp;#34; del&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;49&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;50&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 批量获取匹配到的 key 对应的 value&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;51&lt;/span&gt;redis-cli keys user-* &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; xargs redis-cli mget
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;52&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;53&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 根据pattern获取key&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;54&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# - * 代表匹配任意字符&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;55&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# - ? 代表匹配一个字符&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;56&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# - [] 代表匹配部分字符，例如[1,3]代表匹配1和3，而[1-10]代表匹配1到10的任意数字。&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;57&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# - x 转移字符，例如要匹配星号，问号需要转义的字符&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;58&lt;/span&gt;keys &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;pattern&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;59&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;## e.g.&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;60&lt;/span&gt;127.0.0.1:6379&amp;gt; keys m*
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;61&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;mkeys&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;62&lt;/span&gt;2&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;mkey&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;63&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;64&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 获取key数量&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;65&lt;/span&gt;127.0.0.1:6379&amp;gt; dbsize
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;66&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;67&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 删除所有数据库所有key&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;68&lt;/span&gt;127.0.0.1:6379&amp;gt; flushall
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;69&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 删除当前数据库所有key&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;70&lt;/span&gt;127.0.0.1:6379&amp;gt; flushdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;事务&#34;&gt;事务&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;127.0.0.1:6379&amp;gt; multi &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 开启事务&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;OK
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;127.0.0.1:6379&amp;gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;set&lt;/span&gt; book java
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;QUEUED
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;127.0.0.1:6379&amp;gt; get book
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;QUEUED
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;127.0.0.1:6379&amp;gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;exec&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 执行事务&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; OK
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;2&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;java&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;127.0.0.1:6379&amp;gt; get book
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;java&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;127.0.0.1:6379&amp;gt; multi
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;OK
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;127.0.0.1:6379&amp;gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;set&lt;/span&gt; name peter
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;QUEUED
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;127.0.0.1:6379&amp;gt; discard &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 取消事务&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;OK
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;127.0.0.1:6379&amp;gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;exec&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;error&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; ERR EXEC without MULTI
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;127.0.0.1:6379&amp;gt; get name
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;nil&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;发布和订阅&#34;&gt;发布和订阅&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;127.0.0.1:6379&amp;gt; subscribe news
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;Reading messages... &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;press Ctrl-C to quit&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;subscribe&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;2&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;news&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;3&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;integer&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 另一个 redis 连接下&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;127.0.0.1:6379&amp;gt; publish news &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;integer&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;127.0.0.1:6379&amp;gt; publish news &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;world&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;integer&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在前一个 redis-cli 中可接收到订阅的消息：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;127.0.0.1:6379&amp;gt; subscribe news
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;Reading messages... &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;press Ctrl-C to quit&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;subscribe&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;2&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;news&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;3&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;integer&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;2&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;news&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;3&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;2&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;news&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;3&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;world&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;持久化机制&#34;&gt;持久化机制&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;RDB：RDB 持久化机制，是对 Redis 中的数据执行周期性的持久化。&lt;/li&gt;
&lt;li&gt;AOF：AOF 机制对每条写入命令作为日志，以 append-only 的模式写入一个日志文件中，在 Redis 重启的时候，可以通过回放 AOF 日志中的写入指令来重新构建整个数据集。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Redis 支持同时开启开启两种持久化方式，用 AOF 来保证数据不丢失，作为数据恢复的第一选择；用 RDB 来做不同程度的冷备，在 AOF 文件都丢失或损坏不可用的时候，还可以使用 RDB 来进行快速的数据恢复。&lt;/p&gt;
&lt;h4 id=&#34;rdb-持久化&#34;&gt;RDB 持久化&lt;/h4&gt;
&lt;p&gt;RDB(Redis DataBase), 中文名为快照/内存快照，RDB 持久化是把当前进程数据生成快照保存到磁盘上的过程。触发 rdb 持久化的方式有 2 种，分别是手动触发和自动触发。&lt;/p&gt;
&lt;p&gt;手动触发：save &amp;amp; bgsave：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;save：阻塞当前 Redis 服务器，直到 RDB 过程完成为止&lt;/li&gt;
&lt;li&gt;bgsave：Redis 进程执行 fork 操作创建子进程，RDB 持久化过程由子进程负责，完成后自动结束。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;自动触发：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置：redis.conf 中配置 save m n，即在 m 秒内有 n 次修改时，自动触发 bgsave 生成 rdb 文件&lt;/li&gt;
&lt;li&gt;主从复制时，从节点要从主节点进行全量复制时也会触发 bgsave 操作，生成当时的快照发送到从节点&lt;/li&gt;
&lt;li&gt;执行 debug reload 命令重新加载 redis 时也会触发 bgsave 操作&lt;/li&gt;
&lt;li&gt;默认情况下执行 shutdown 命令时，如果没有开启 aof 持久化，那么也会触发 bgsave 操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;RDB 持久化时如何保证数据一致性？&lt;/p&gt;
&lt;p&gt;RDB 中的核心思路是 Copy-on-Write，来保证在进行快照操作的这段时间，需要压缩写入磁盘上的数据在内存中不会发生变化。在正常的快照操作中，一方面 Redis 主进程会 fork 一个新的快照进程专门来做这个事情，这样保证了 Redis 服务不会停止对客户端包括写请求在内的任何响应。另一方面这段时间发生的数据变化会以副本的方式存放在另一个新的内存区域，待快照操作结束后才会同步到原来的内存区域。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/cache-related-knowledge-organization/image/1692936457085.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h4 id=&#34;aof-持久化&#34;&gt;AOF 持久化&lt;/h4&gt;
&lt;p&gt;Redis 是“写后”日志，Redis 先执行命令，把数据写入内存，然后才记录日志。日志里记录的是 Redis 收到的每一条命令，这些命令是以文本形式保存。&lt;/p&gt;
&lt;p&gt;AOF 持久化过程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;命令追加：服务器在执行完一个写命令之后，会以协议格式将被执行的写命令追加到服务器的 aof_buf 缓冲区&lt;/li&gt;
&lt;li&gt;文件写入和同步：有三种策略如下&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/cache-related-knowledge-organization/image/1692939970057.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;AOF 重写机制：&lt;/p&gt;
&lt;p&gt;AOF 持久化会记录每个写命令到 AOF 文件，随着时间越来越长，AOF 文件会变得越来越大。如果不加以控制，会对 Redis 服务器，甚至对操作系统造成影响，而且 AOF 文件越大，数据恢复也越慢。为了解决 AOF 文件体积膨胀的问题，Redis 提供 AOF 文件重写机制来对 AOF 文件进行“瘦身”。&lt;/p&gt;
&lt;p&gt;实例：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/cache-related-knowledge-organization/image/1692940164613.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;操作过程：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/cache-related-knowledge-organization/image/1692940315829.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;redis-大-key-问题&#34;&gt;Redis 大 key 问题&lt;/h3&gt;
&lt;p&gt;定位大 key:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/cache-related-knowledge-organization/image/1692858084512.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;ps: &lt;code&gt;redis-cli --bigkeys&lt;/code&gt; 以遍历的方式分析 Redis 实例中的所有 Key，并返回整体统计信息与每个数据类型中 Top 前几的大 Key。&lt;/p&gt;
&lt;p&gt;删除或优化大 key:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/cache-related-knowledge-organization/image/1692858065059.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;缓存过期策略&#34;&gt;缓存过期策略&lt;/h2&gt;
&lt;p&gt;缓存的存储空间有限制，当缓存空间被用满时，如何保证在稳定服务的同时有效提升命中率？这就由缓存清空策略来处理，设计适合自身数据特征的清空策略能有效提升命中率。常见的一般策略有：&lt;/p&gt;
&lt;p&gt;FIFO(first in first out)：&lt;/p&gt;
&lt;p&gt;先进先出策略，最先进入缓存的数据在缓存空间不够的情况下（超出最大元素限制）会被优先被清除掉，以腾出新的空间接受新的数据。策略算法主要比较缓存元素的创建时间。在数据实效性要求场景下可选择该类策略，优先保障最新数据可用。&lt;/p&gt;
&lt;p&gt;LFU(less frequently used)：&lt;/p&gt;
&lt;p&gt;最少使用策略，无论是否过期，根据元素的被使用次数判断，清除使用次数较少的元素释放空间。策略算法主要比较元素的hitCount（命中次数）。在保证高频数据有效性场景下，可选择这类策略。&lt;/p&gt;
&lt;p&gt;LRU(least recently used)：&lt;/p&gt;
&lt;p&gt;最近最少使用策略，无论是否过期，根据元素最后一次被使用的时间戳，清除最远使用时间戳的元素释放空间。策略算法主要比较元素最近一次被get使用时间。在热点数据场景下较适用，优先保证热点数据的有效性。&lt;/p&gt;
&lt;p&gt;除此之外，还有一些简单策略比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根据过期时间判断，清理过期时间最长的元素；&lt;/li&gt;
&lt;li&gt;根据过期时间判断，清理最近要过期的元素；&lt;/li&gt;
&lt;li&gt;随机清理；&lt;/li&gt;
&lt;li&gt;根据关键字（或元素内容）长短清理等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Redis 过期策略是：定期删除+惰性删除。&lt;/p&gt;
&lt;p&gt;定期删除，指的是 Redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key，检查其是否过期，如果过期就删除。&lt;/p&gt;
&lt;p&gt;惰性删除，就是在获取 key 的时候，如果此时 key 已经过期，就删除，不会返回任何东西。&lt;/p&gt;
&lt;p&gt;如果定期删除漏掉了很多过期 key，然后你也没及时去查，也就没走惰性删除，此时大量过期 key 堆积在内存里，导致 Redis 内存块耗尽了，所以还需要走内存淘汰机制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;noeviction: 当内存不足以容纳新写入数据时，新写入操作会报错；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;allkeys-lru&lt;/strong&gt;：当内存不足以容纳新写入数据时，在键空间中，移除最近最少使用的 key（这个是最常用的）。&lt;/li&gt;
&lt;li&gt;allkeys-random：当内存不足以容纳新写入数据时，在键空间中，随机移除某个 key；&lt;/li&gt;
&lt;li&gt;volatile-lru：当内存不足以容纳新写入数据时，在设置了过期时间的键空间中，移除最近最少使用的 key。&lt;/li&gt;
&lt;li&gt;volatile-random：当内存不足以容纳新写入数据时，在设置了过期时间的键空间中，随机移除某个 key。&lt;/li&gt;
&lt;li&gt;volatile-ttl：当内存不足以容纳新写入数据时，在设置了过期时间的键空间中，有更早过期时间的 key 优先移除。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;手写 LRU，很简单，指定好最大容量，使用 python 的有序字典即可，获取 key 时重新入典，放 key 时如果存在则重新入典，如果满了就移除最空闲数据。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;collections&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;LRUCache&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;def&lt;/span&gt; __init__&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;self&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; capacity&lt;span style=&#34;color:#eceff4&#34;&gt;):&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;capacity &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; capacity
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;queue &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; collections&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;OrderedDict&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;get&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;self&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; key&lt;span style=&#34;color:#eceff4&#34;&gt;):&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; key &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;in&lt;/span&gt; self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;queue&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;queue&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;pop&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;key&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;queue&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;key&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; value
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;queue&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;key&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;put&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;self&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; key&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; value&lt;span style=&#34;color:#eceff4&#34;&gt;):&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; key &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;in&lt;/span&gt; self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;queue&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;            self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;queue&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;pop&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;key&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;elif&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;len&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;queue&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;items&lt;span style=&#34;color:#eceff4&#34;&gt;())&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;capacity&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;            self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;queue&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;popitem&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;last&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;False&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;        self&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;queue&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;key&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;缓存问题&#34;&gt;缓存问题&lt;/h2&gt;
&lt;h3 id=&#34;缓存雪崩宕机&#34;&gt;缓存雪崩（宕机）&lt;/h3&gt;
&lt;p&gt;缓存系统宕机，大量请求打到数据库上。&lt;/p&gt;
&lt;p&gt;解决方案如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事前：Redis 高可用，主从+哨兵，Redis cluster，避免全盘崩溃。&lt;/li&gt;
&lt;li&gt;事中：本地 ehcache 缓存 + hystrix 限流&amp;amp;降级，避免 MySQL 被打死。&lt;/li&gt;
&lt;li&gt;事后：Redis 持久化，一旦重启，自动从磁盘上加载数据，快速恢复缓存数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;缓存穿透绕过&#34;&gt;缓存穿透（绕过）&lt;/h3&gt;
&lt;p&gt;安全攻击，利用某些数据值的特点，大量请求一定不在数据库中的数据，导致缓存无法生成一直请求数据库。&lt;/p&gt;
&lt;p&gt;数据保密，空值缓存保护，布隆过滤器拦截等方式来解决。&lt;/p&gt;
&lt;p&gt;关于布隆过滤器：&lt;/p&gt;
&lt;p&gt;布隆过滤器是一个很长的二进制向量和一系列随机映射函数，用于检索一个元素是否在一个集合中。其基本工作原理如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;初始化：创建一个大小为 m 的位数组，所有位初始化为 0。并准备多个哈希函数（通常为 k 个），每个哈希函数将输入映射为位数组的一个位置。&lt;/li&gt;
&lt;li&gt;添加元素：
&lt;ul&gt;
&lt;li&gt;对每个待插入的元素，使用 k 个哈希函数分别计算出该元素的 k 个位置。&lt;/li&gt;
&lt;li&gt;将这些位置对应的位数组中的值设置为 1。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;查询元素：
&lt;ul&gt;
&lt;li&gt;对于查询的元素，同样使用 k 个哈希函数计算出 k 个位置。&lt;/li&gt;
&lt;li&gt;检查这些位置的位数组值：
&lt;ul&gt;
&lt;li&gt;如果所有这些位置的值都是 1，则该元素 可能 在集合中。&lt;/li&gt;
&lt;li&gt;如果任意一个位置的值是 0，则该元素 肯定不在 集合中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;它的空间效率和查询时间都远远超过一般的算法，但是有一定的误判率 （函数返回 true , 意味着元素可能存在，函数返回 false ，元素必定不存在），这是 k 个位置的哈希冲突导致的。&lt;/p&gt;
&lt;p&gt;布隆过滤器的四个核心属性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;k :  哈希函数个数&lt;/li&gt;
&lt;li&gt;m : 位数组长度&lt;/li&gt;
&lt;li&gt;n :  插入的元素个数&lt;/li&gt;
&lt;li&gt;p :  误判率&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;布隆过滤器无法删除元素，但我们可以通过计数布隆过滤器和定时重新构建布隆过滤器两种方案实现删除元素的效果。&lt;/p&gt;
&lt;p&gt;使用场景：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/cache-related-knowledge-organization/image/1692632968544.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;缓存失效&#34;&gt;缓存失效&lt;/h3&gt;
&lt;p&gt;缓存失效（击穿），就是说某个 key 非常热点，访问非常频繁，处于集中式高并发访问的情况，当这个 key 在失效的瞬间，大量的请求就击穿了缓存，直接请求数据库。&lt;/p&gt;
&lt;p&gt;不同场景下的解决方式可如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若缓存的数据是基本不会发生更新的，则可尝试将该热点数据设置为永不过期。&lt;/li&gt;
&lt;li&gt;若缓存的数据更新不频繁，且缓存刷新的整个流程耗时较少的情况下，则可采用互斥锁以保证仅少量的请求能请求数据库并重新构建缓存，其余线程则在锁释放后能访问到新缓存。&lt;/li&gt;
&lt;li&gt;若缓存的数据更新频繁或者在缓存刷新的流程耗时较长的情况下，可以利用定时线程在缓存过期前主动地重新构建缓存或者延后缓存的过期时间，以保证所有的请求能一直访问到对应的缓存。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;并发竞争问题&#34;&gt;并发竞争问题&lt;/h3&gt;
&lt;p&gt;多个实例要更新同一个 key，可以采用分布式锁来解决竞争问题。&lt;/p&gt;
&lt;p&gt;可以基于 zookeeper 实现分布式锁。每个系统通过 zookeeper 获取分布式锁，确保同一时间，只能有一个系统实例在操作某个 key，别人都不允许读和写。&lt;/p&gt;
&lt;h2 id=&#34;缓存与数据库一致性问题&#34;&gt;缓存与数据库一致性问题&lt;/h2&gt;
&lt;p&gt;先删缓存，后更新数据库，延时再删缓存。&lt;/p&gt;
&lt;p&gt;问题一、延迟多久？&lt;/p&gt;
&lt;p&gt;一般建议：延迟 300ms ~ 1s 左右。&lt;/p&gt;
&lt;p&gt;延迟时间的本质是为了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;等待数据库更新完成&lt;/li&gt;
&lt;li&gt;尽量覆盖掉在此期间被误写回缓存的脏数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;推荐做法是根据你数据库的平均写入耗时 + 预估并发访问风险时间来确定，如果数据库写操作耗时 ≈ 150ms，建议延迟 500ms 左右。如果是高并发写系统，甚至可以用 异步线程 + 延迟队列/定时任务 来做第二次删除，避免主线程阻塞&lt;/p&gt;
&lt;p&gt;问题二、是先删缓存还是先更新数据库？&lt;/p&gt;
&lt;p&gt;一定是：先删缓存，再更新数据库！&lt;/p&gt;
&lt;p&gt;原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果你先更新数据库再删缓存，并发读请求可能读到新数据但旧缓存还在，导致数据库数据被旧缓存“污染”。&lt;/li&gt;
&lt;li&gt;而“先删缓存”即使发生并发读，最多就是读不到数据，从数据库再读一遍，不会出错，只是慢一点。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://doocs.github.io/advanced-java/#/docs/high-concurrency/redis-master-slave&#34;&gt;advanced-java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://tech.meituan.com/2017/03/17/cache-about.html&#34;&gt;美团技术团队:缓存那些事&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>大数据重要知识整理</title>
        <link>https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/</link>
        <pubDate>Thu, 22 Aug 2024 23:46:46 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>summary-of-knowledge-and-practices-related-to-big-data</guid>
        <description>&lt;h2 id=&#34;toc&#34;&gt;TOC&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#toc&#34;&gt;TOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#preface&#34;&gt;Preface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#nouns&#34;&gt;Nouns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hadoop&#34;&gt;Hadoop&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#hdfs&#34;&gt;HDFS&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5&#34;&gt;基本概念&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%87%87%E7%94%A8%E6%93%8D%E4%BD%9C&#34;&gt;采用操作&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%AB%98%E5%8F%AF%E7%94%A8%E5%8E%9F%E7%90%86&#34;&gt;高可用原理&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mapreduce&#34;&gt;MapReduce&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#yarn&#34;&gt;YARN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#spark&#34;&gt;Spark&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5-1&#34;&gt;基本概念&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C&#34;&gt;基本操作&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%B0%83%E4%BC%98%E5%8E%9F%E5%88%99&#34;&gt;调优原则&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#flink&#34;&gt;Flink&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5-2&#34;&gt;基本概念&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E8%B7%B5%E6%B5%8B%E8%AF%95&#34;&gt;实践测试&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#state&#34;&gt;State&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#checkpoint-%E6%9C%BA%E5%88%B6&#34;&gt;Checkpoint 机制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%80%E8%87%B4%E6%80%A7&#34;&gt;一致性&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%B9%B6%E8%A1%8C%E5%BA%A6&#34;&gt;并行度&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8F%8D%E5%8E%8B%E6%9C%BA%E5%88%B6&#34;&gt;反压机制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%89%E7%A7%8D%E6%97%B6%E9%97%B4%E8%AF%AD%E4%B9%89&#34;&gt;三种时间语义&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#lsm&#34;&gt;LSM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#kafka&#34;&gt;Kafka&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hive&#34;&gt;Hive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hbase&#34;&gt;HBase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#paimon&#34;&gt;Paimon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hudi&#34;&gt;Hudi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#clickhouse&#34;&gt;ClickHouse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mpp&#34;&gt;MPP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#starrocks&#34;&gt;StarRocks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#bitmap&#34;&gt;BitMap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#blogs&#34;&gt;Blogs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reference&#34;&gt;Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;preface&#34;&gt;Preface&lt;/h2&gt;
&lt;p&gt;最近在负责 ShopeePay 大数据处理相关的工作，发现对大数据相关知识认识还不够，只凭大学相关课程显然差的远，在一些技术设计上存在一定问题。同时在 Shopee 对账项目中也了解到大数据领域包括 paimon 在内的流批统一相关的前沿技术，知之甚少，需要恶补一下。&lt;/p&gt;
&lt;p&gt;这里将对大数据相关的知识做一个整理汇总，主要包括 Hadoop、Spark、Flink、Kafka 等组件的重要概念、架构、基础用法，此外还简单记录了在 Shopee DataStudio 中的 Best Practice。后面持续补充更多应用场景、踩过的坑和更多原理性的知识。&lt;/p&gt;
&lt;h2 id=&#34;nouns&#34;&gt;Nouns&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;SLA(Service-Level Agreement)：服务等级协议，指的是系统服务提供者对客户的一个服务承诺，用于衡量大型“分布式“系统是否健康的协议。&lt;/li&gt;
&lt;li&gt;OLAP(Online Analytical Processing)：联机分析处理，主要用途是分析聚合数据。&lt;/li&gt;
&lt;li&gt;OLTP(Online Transaction Processing)：联机事务处理，主要用途是处理数据库事务。&lt;/li&gt;
&lt;li&gt;HTAP(Hybrid Transactional/Analytical Processing)：混合事务/分析处理。&lt;/li&gt;
&lt;li&gt;DQC(Data Quality Control)：数据质量监控，对数据库里的数据质量进行质量管理的工具。&lt;/li&gt;
&lt;li&gt;SPM(Shopping Page Mark)：导购页面标记，是电商业务为内外站提供的一套跟踪成交效果数据的解决方案，根据 SPM 效果指标和数据可以得到 PV、UV、CVR 等数据。SPM 编码是用来跟踪界面模块位置的编码，标准编码由 4 段组成，采用 a.b.c.d 段格式。&lt;/li&gt;
&lt;li&gt;PV(Page View)：页面浏览量。&lt;/li&gt;
&lt;li&gt;UV(Unique Visitors)：独立访客。&lt;/li&gt;
&lt;li&gt;GMV(Gross Merchandise Volume)：商品交易总额。&lt;/li&gt;
&lt;li&gt;CVR(Conversions Rates)：转化率，网站转化率=进行了相应的动作的访问量/总访问量。&lt;/li&gt;
&lt;li&gt;KYC(Know Your Customer)：意思是充分了解你的客户，是指在服务商和客户进行业务往来之前或期间核实客户身份的过程。&lt;/li&gt;
&lt;li&gt;ETL(Extract-Transform-Load)：用于描述将数据从来源端经过抽取、转换、加载到目的端的过程。&lt;/li&gt;
&lt;li&gt;ODS(Operation Data Store)：数据运营层，是数据准备区。数据源中的数据经过 ETL 过程之后进入本层。&lt;/li&gt;
&lt;li&gt;DW(Data Warehouse)：数据仓库。数据仓库从上到下可以分为三个层：DWD、DWM、DWS。&lt;/li&gt;
&lt;li&gt;DWD(Data Warehouse Details)：数据细节层，该层是业务层和数据仓库的隔离层，对 ODS 数据层做一些数据的清洗和规范化的操作。&lt;/li&gt;
&lt;li&gt;DWM(Data Warehouse Middle)：数据中间层，对通用的核心维度进行聚合操作，算出相应的统计指标。&lt;/li&gt;
&lt;li&gt;DWS(Data Warehouse Service)：数据服务层，基于 DWM 上的基础数据，整合汇总成分析某一个主题域的数据服务层，一般是宽表，用于提供后续的业务查询，OLAP 分析，数据分发等。&lt;/li&gt;
&lt;li&gt;ADS(Application Data Service)：数据应用层，出报表，该层主要是提供给数据产品和数据分析使用的数据。&lt;/li&gt;
&lt;li&gt;FT(Fact Table)：事实表是指存储有事实记录的表，比如系统日志、销售记录等。&lt;/li&gt;
&lt;li&gt;DIM(Dimension Table)：维度表，是与事实表相对应的一种表，它保存了维度的属性值，可以跟事实表做关联，相当于将事实表上经常重复出现的属性抽取、规范出来用一张表进行管理。&lt;/li&gt;
&lt;li&gt;WT(Wide Table)：指字段比较多的数据库表。通常是指业务主体相关的指标、纬度、属性关联在一起的一张数据库表。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;hadoop&#34;&gt;Hadoop&lt;/h2&gt;
&lt;p&gt;Apache Hadoop 软件是一个开源框架，支持使用简单的编程模型跨计算机集群对大型数据集进行分布式存储和处理。它的核心模块分为存储和计算模块，前者被称为 HDFS，后者即 MapReduce 计算模型。&lt;/p&gt;
&lt;h3 id=&#34;hdfs&#34;&gt;HDFS&lt;/h3&gt;
&lt;h4 id=&#34;基本概念&#34;&gt;基本概念&lt;/h4&gt;
&lt;p&gt;HDFS，即 Hadoop 分布式文件系统，它具有高容错、高吞吐量等特性，可以部署在低成本的硬件上。&lt;/p&gt;
&lt;p&gt;HDFS 遵循&lt;strong&gt;主从架构&lt;/strong&gt;，由单个 NameNode(NN) 和多个 DataNode(DN) 组成。NameNode 负责执行有关文件系统命名空间的操作，还负责集群元数据的存储，记录着文件中各个数据块的位置信息。DataNode 负责提供来自文件系统客户端的读写请求，执行块的创建，删除等操作。&lt;/p&gt;
&lt;p&gt;HDFS 提供了&lt;strong&gt;数据复制&lt;/strong&gt;机制。HDFS 将每一个文件存储为一系列块，每个块由多个&lt;strong&gt;副本&lt;/strong&gt;来保证容错，块的大小和复制因子可以自行配置（默认情况下，块大小是 128M，默认复制因子是 3）。&lt;/p&gt;
&lt;p&gt;HDFS 提供了数据完整性校验机制来保证数据的完整性，创建 HDFS 文件时会计算文件每个块的校验和并将其存储在同一 HDFS 命名空间下。HDFS 还通过心跳机制和重新复制机制来确保 DataNode 的可用性。&lt;/p&gt;
&lt;h4 id=&#34;采用操作&#34;&gt;采用操作&lt;/h4&gt;
&lt;p&gt;HDFS 采用 Shell 操作总结：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 显示当前目录结构&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;hadoop fs -ls  &amp;lt;path&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 创建目录&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;hadoop fs -mkdir  &amp;lt;path&amp;gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 删除文件&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;hadoop fs -rm  &amp;lt;path&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 递归删除目录和文件&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;hadoop fs -rm -R  &amp;lt;path&amp;gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 从本地加载文件到 HDFS&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;hadoop fs -put  &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;localsrc&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;dst&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 从 HDFS 导出文件到本地&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;hadoop fs -get  &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;dst&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;localsrc&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 查看文件内容&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;hadoop fs -cat  &amp;lt;path&amp;gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 拷贝文件&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;hadoop fs -cp &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;src&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;dst&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 移动文件&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;hadoop fs -mv &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;src&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;dst&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 统计当前目录下各文件大小 &lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# + 默认单位字节  &lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# + -s : 显示所有文件大小总和，&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# + -h : 将以更友好的方式显示文件大小（例如 64.0m 而不是 67108864）&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;hadoop fs -du  &amp;lt;path&amp;gt;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;高可用原理&#34;&gt;高可用原理&lt;/h4&gt;
&lt;p&gt;HDFS 的 HA，指的是在一个集群中存在多个 NameNode，分别运行在独立的物理节点上。在任何时间点，只有一个 NameNode 是处于 Active 状态，其它的是处于  Standby状态。 Active NameNode（简写为 Active NN）负责所有的客户端的操作，而 Standby NameNode（简写为 Standby NN）用来同步 Active NameNode 的状态信息，以提供快速的故障恢复能力。&lt;/p&gt;
&lt;h3 id=&#34;mapreduce&#34;&gt;MapReduce&lt;/h3&gt;
&lt;p&gt;MapReduce 是一个分布式计算框架，它的处理流程如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1724124052168.png&#34; loading=&#34;lazy&#34; alt=&#34;MapReduce&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;其中 splitting 和 shuffing 操作都是由框架实现的，需要我们自己编程实现的只有 mapping 和 reducing，这也就是 MapReduce 这个称呼的来源。&lt;/p&gt;
&lt;p&gt;从上面流程中可以看到在 Mapping 到 Shuffling 的过程中存在大量的数据传输，可以使用 Combiner 在传输之前进行一个本地化的 Reduce 操作，降低数据传输量完成优化。注意这个优化手段需要注意是否影响最终结果，比如本地 Reduce 计算平均数将导致最终结果的错误。&lt;/p&gt;
&lt;p&gt;还有一个重要的概念是 Partitioner，可以理解成分类器，将 map 的输出按照 key 值的不同分别分给对应的 reducer，默认的使用的是 HashPartitioner，对 key 值进行哈希散列并对 numReduceTasks 取余，可以自定义，比如按照单词分类，一个 java 示例如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;CustomPartitioner&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;extends&lt;/span&gt; Partitioner&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Text&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; IntWritable&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getPartition&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Text text&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; IntWritable intWritable&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; numPartitions&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; WordCountDataUtils&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;WORD_LIST&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;indexOf&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;text&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;toString&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;yarn&#34;&gt;YARN&lt;/h3&gt;
&lt;p&gt;Apache YARN (Yet Another Resource Negotiator) 是 hadoop 2.0 引入的集群资源管理系统。用户可以将各种服务框架部署在 YARN 上，由 YARN 进行统一地管理和资源分配。&lt;/p&gt;
&lt;p&gt;YARN 主要组件如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ResourceManager：整个集群资源的主要协调者和管理者，负责给用户提交的所有应用程序分配资源；&lt;/li&gt;
&lt;li&gt;NodeManager：YARN 集群中的每个具体节点的管理者。主要负责该节点内所有容器的生命周期的管理，监视资源和跟踪节点健康。&lt;/li&gt;
&lt;li&gt;ApplicationMaster：在用户提交一个应用程序时，YARN 会启动一个轻量级的进程 ApplicationMaster。它负责协调来自 ResourceManager 的资源，并通过 NodeManager 监视容器内资源的使用情况，同时还负责任务的监控与容错。&lt;/li&gt;
&lt;li&gt;Container：Container 是 YARN 中的资源抽象，它封装了某个节点上的多维度资源，如内存、CPU、磁盘、网络等。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;YARN 工作原理大致如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1724125567321.png&#34; loading=&#34;lazy&#34; alt=&#34;YARN&#34;  /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Client 提交作业到 YARN 上；&lt;/li&gt;
&lt;li&gt;Resource Manager 选择一个 Node Manager，启动一个 Container 并运行 Application Master 实例；&lt;/li&gt;
&lt;li&gt;ApplicationMaster 根据实际需要向 Resource Manager 请求更多的 Container 资源；&lt;/li&gt;
&lt;li&gt;ApplicationMaster 通过获取到的 Container 资源执行分布式计算。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;spark&#34;&gt;Spark&lt;/h2&gt;
&lt;h3 id=&#34;基本概念-1&#34;&gt;基本概念&lt;/h3&gt;
&lt;p&gt;Spark 基于 Spark Core 扩展了四个核心组件，分别用于满足不同领域的计算需求:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1724036863585.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;Spark 最基本的数据抽象是 &lt;code&gt;RDD&lt;/code&gt;，全称为 Resilient Distributed Datasets（弹性分布式数据集），它是只读的、分区记录的集合，支持并行操作，可以由外部数据集或其他 RDD 转换而来。一个 RDD 由一个或者多个分区（Partitions）组成。&lt;/p&gt;
&lt;p&gt;RDD 的一个重要特性是&lt;strong&gt;血缘关系&lt;/strong&gt;。RDD 会保存彼此间的依赖关系，RDD 的每次转换都会生成一个新的依赖关系，这种 RDD 之间的依赖关系就像流水线一样。在部分分区数据丢失后，可以通过这种依赖关系重新计算丢失的分区数据，而不是对 RDD 的所有分区进行重新计算。RDD 血缘关系的依赖分为窄依赖和宽依赖。窄依赖是指父 RDD 的每个分区都只被子 RDD 的一个分区所使用，宽依赖是指父 RDD 的每个分区都被多个子 RDD 的分区所依赖。&lt;/p&gt;
&lt;h3 id=&#34;基本操作&#34;&gt;基本操作&lt;/h3&gt;
&lt;p&gt;Spark 安装：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# INSTALL&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;wget https://dlcdn.apache.org/spark/spark-3.5.2/spark-3.5.2-bin-hadoop3.tgz
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;tar -zxvf https://dlcdn.apache.org/spark/spark-3.5.2/spark-3.5.2-bin-hadoop3.tgz
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;export&lt;/span&gt; SPARK_HOME&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;xxx/spark-3.5.2-bin-hadoop3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;export&lt;/span&gt; PATH&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$SPARK_HOME&lt;span style=&#34;color:#a3be8c&#34;&gt;/bin:&lt;/span&gt;$PATH&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Spark 简单示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# TEST&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;spark-shell
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;...
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;Spark context Web UI available at http://10.53.32.147:4040
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;Spark context available as &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;sc&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;master &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; local&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;*&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;, app id &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; local-1724038257910&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;.
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;Spark session available as &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;spark&amp;#39;&lt;/span&gt;.
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;...
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# test map&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&amp;gt; sc.parallelize&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;List&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;1,2,3&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt;.map&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;_ * 10&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;.foreach&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;println&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# test flapMap&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&amp;gt; sc.parallelize&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;List&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;spark flume spark&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hadoop flume hive&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt;.flatMap&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;line &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&amp;gt; line.split&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt;.map&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;word&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&amp;gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;word,1&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt;.reduceByKey&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;_+_&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;.foreach&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;println&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# test intersection&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&amp;gt; sc.parallelize&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;List&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;1, 2, 4, 5&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt;.intersection&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;sc.parallelize&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;List&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;2, 4, 5, 6&lt;span style=&#34;color:#81a1c1&#34;&gt;)))&lt;/span&gt;.foreach&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;println&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# test sortByKey&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&amp;gt; sc.parallelize&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;List&lt;span style=&#34;color:#81a1c1&#34;&gt;((&lt;/span&gt;100, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hadoop&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;, &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;90, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;spark&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;, &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;120, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;storm&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)))&lt;/span&gt;.sortByKey&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;ascending &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;.foreach&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;println&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Spark SQL 是 Spark 中的一个子模块，主要用于操作结构化数据，能够将 SQL 查询与 Spark 程序无缝混合，允许您使用 SQL 或 DataFrame API 对结构化数据进行查询。&lt;/p&gt;
&lt;p&gt;为了支持结构化数据的处理，Spark SQL 提供了新的数据结构 DataFrame。DataFrame 是一个由具名列组成的数据集。如果你想使用函数式编程或者数据是非结构化的 (比如流媒体或者字符流)，则使用 RDDs，否则出于性能上的考虑，应优先使用 DataFrame。Dataset 也是分布式的数据集合，在 Spark 1.6 版本被引入，它集成了 RDD 和 DataFrame 的优点。&lt;/p&gt;
&lt;p&gt;一个简单的左外连接示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;empDF&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;join&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;deptDF&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; joinExpression&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;left_outer&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;show&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;spark&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;sql&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;SELECT * FROM emp LEFT OUTER JOIN dept ON emp.deptno = dept.deptno&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;show&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Spark Streaming 是 Spark 的一个子模块，用于快速构建可扩展，高吞吐量，高容错的流处理程序。具有良好的容错性，Spark Streaming 支持快速从失败中恢复丢失的操作状态，能够和 Spark 其他模块无缝集成，将流处理与批处理完美结合，Spark Streaming 可以从多种数据源读取数据，也支持自定义数据源。&lt;/p&gt;
&lt;p&gt;一个简单的单词计数示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;/*指定时间间隔为 5s*/&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;val sparkConf &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; SparkConf&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setAppName&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;NetworkWordCount&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;).&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setMaster&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;local[2]&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;val ssc &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; StreamingContext&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;sparkConf&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Seconds&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;5&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;/*创建文本输入流,并进行词频统计*/&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;val lines &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; ssc&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;socketTextStream&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hadoop001&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 9999&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;lines&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;flatMap&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;_&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;split&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)).&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;map&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;x &lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 1&lt;span style=&#34;color:#81a1c1&#34;&gt;)).&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;reduceByKey&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;_ &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; _&lt;span style=&#34;color:#81a1c1&#34;&gt;).&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;/*启动服务*/&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;ssc&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;start&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;/*等待服务结束*/&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;ssc&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;awaitTermination&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一个在 Shopee DataStudio 上执行 PySpark 用户自定义函数（UDF）任务的示例：&lt;/p&gt;
&lt;p&gt;首先编辑 py 文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# pyspark_udf_demo.py&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;pyspark.sql&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; SparkSession
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;add_udf&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#eceff4&#34;&gt;):&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; x &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; __name__ &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    spark &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; SparkSession&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;builder&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;appName&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;add_udf&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;enableHiveSupport&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;getOrCreate&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    sc &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; spark&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;sparkContext
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    sc&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;setLogLevel&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;WARN&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# register udf&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    spark&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;udf&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;register&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;test_add_udf&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; add_udf&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;int&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# use udf in sql&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    spark&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;sql&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;select test_add_udf(6)&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;show&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    spark&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;stop&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着创建 workflow，在 Resources 上传 &lt;code&gt;pyspark_udf_demo.py&lt;/code&gt; 文件，然后创建任务，指定 py 文件和相关版本即可。&lt;/p&gt;
&lt;h3 id=&#34;调优原则&#34;&gt;调优原则&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://tech.meituan.com/2016/04/29/spark-tuning-basic.html&#34;&gt;Spark 性能优化指南——基础篇&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://tech.meituan.com/2016/05/12/spark-tuning-pro.html&#34;&gt;Spark 性能优化指南——高级篇&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;flink&#34;&gt;Flink&lt;/h2&gt;
&lt;h3 id=&#34;基本概念-2&#34;&gt;基本概念&lt;/h3&gt;
&lt;p&gt;Flink 是一个分布式的流处理框架，它能够对有界和无界的数据流进行高效的处理。&lt;/p&gt;
&lt;p&gt;Flink 的核心是流处理，当然它也能支持批处理，Flink 将批处理看成是流处理的一种特殊情况，即数据流是有明确界限的，这和 Spark Streaming 的思想是刚好相反。&lt;/p&gt;
&lt;p&gt;Flink 核心架构如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1724122760394.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;Flink 核心组件工作流程如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1724142539037.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;实践测试&#34;&gt;实践测试&lt;/h3&gt;
&lt;p&gt;Flink 快速测试使用：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# INSTALL&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;wget https://dlcdn.apache.org/flink/flink-1.20.0/flink-1.20.0-bin-scala_2.12.tgz
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;tar -zxvf flink-1.20.0-bin-scala_2.12.tgz
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; flink-1.20.0
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# TEST&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;./bin/start-cluster.sh
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;./bin/flink run examples/streaming/WordCount.jar
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;tail tail log/flink-*-taskexecutor-*.out
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;./bin/stop-cluster.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;官方提供的两个 Flink 应用示例，可以很好地上手 Flink：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://nightlies.apache.org/flink/flink-docs-master/zh/docs/try-flink/datastream/&#34;&gt;基于 DataStream API 实现欺诈检测&lt;/a&gt;：快速上手 State + Timer 流式处理；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://nightlies.apache.org/flink/flink-docs-master/zh/docs/try-flink/table_api/&#34;&gt;基于 Table API 实现实时报表&lt;/a&gt;: 快速上手 Window 流式处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flink 的一个重要特性就是其状态管理，Flink 为什么要参与状态管理？在 Flink 不参与管理状态的情况下，你的应用也可以使用状态，但 Flink 为其管理状态提供了一些引人注目的特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本地性: Flink 状态是存储在使用它的机器本地的，并且可以以内存访问速度来获取&lt;/li&gt;
&lt;li&gt;持久性: Flink 状态是容错的，例如，它可以自动按一定的时间间隔产生 checkpoint，并且在任务失败后进行恢复&lt;/li&gt;
&lt;li&gt;纵向可扩展性: Flink 状态可以存储在集成的 RocksDB 实例中，这种方式下可以通过增加本地磁盘来扩展空间&lt;/li&gt;
&lt;li&gt;横向可扩展性: Flink 状态可以随着集群的扩缩容重新分布&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flink 的三个时间语义：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Event Time：是事件创建的时间。它通常由事件中的时间戳描述，例如采集的日志数据中，每一条日志都会记录自己的生成时间，Flink 通过时间戳分配器访问事件时间戳。&lt;/li&gt;
&lt;li&gt;Ingestion Time：是数据进入 Flink 的时间。&lt;/li&gt;
&lt;li&gt;Processing Time：是每一个执行基于时间操作的算子的本地系统时间，与机器相关，默认的时间属性就是 Processing Time。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flink 在窗口的场景处理上很重要，窗口是基于 Timer 实现的。Flink 窗口操作将无界数据流分解成有界数据流聚合分析。Flink 内置窗口分配器如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1724205350622.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;一些常见的对应使用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;滚动时间窗口：每分钟页面浏览量 - &lt;code&gt;TumblingEventTimeWindows.of(Time.minutes(1))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;滑动时间窗口：每 10 秒钟计算前 1 分钟的页面浏览量 - &lt;code&gt;SlidingEventTimeWindows.of(Time.minutes(1), Time.seconds(10))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;会话窗口：每个会话的网页浏览量，其中会话之间的间隔至少为 30 分钟 - &lt;code&gt;EventTimeSessionWindows.withGap(Time.minutes(30))&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;窗口操作的聚合类处理带来了新的问题，比如乱序/延迟。其解决方案就是 Watermark / allowLateNess / sideOutPut 这一组合拳。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Watermark 定义了什么时候不再等待更早的数据，用于处理乱序事件；&lt;/li&gt;
&lt;li&gt;allowLateNess 是将窗口关闭时间再延迟一段时间，用于容忍迟到事件；&lt;/li&gt;
&lt;li&gt;sideOutPut 是最后兜底操作，当指定窗口已经彻底关闭后，就会把所有过期延迟数据放到侧输出流，让用户决定如何处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;举个例子来理解上面这几个概念。假设我们需要通过 Flink 从 Kafka 消费数据，计算每五分钟的数据。&lt;/p&gt;
&lt;p&gt;首先列出我们知道的事情。我们知道当前实际时间所处的窗口 &lt;code&gt;[window_start, window_end]&lt;/code&gt;，每条从 Kafka 来的数据都包含一个事件时间 event_time，我们可以设置 watermark 为 90s，从而每条数据对应的 watermark 时间就是 event_time - 90s，注意这个时间会确保 &amp;gt;= window_start 且左边界只会正增长。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当前窗口第一条数据出现，设事件时间为 last_event_time，计算得到当前窗口下一条数据的 event_time 范围 &lt;code&gt;[last_event_time - 90s, window_end]&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;然后下一条数据到来，设事件时间为 event_time：
&lt;ul&gt;
&lt;li&gt;如果 &lt;code&gt;last_event_time - 90s &amp;lt;= event_time &amp;lt;= window_end&lt;/code&gt;，则落入窗口，然后根据 watermark 计算新的 event_time 范围，重复 2；&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;event_time &amp;gt; window_end&lt;/code&gt;，则开启新窗口，完成旧窗口 window 聚合计算。如果 event_time - 90s &amp;lt;= window_end，则表明 watermark 未到，窗口保持开启，否则窗口延迟 allowLateNess 秒后关闭（不再聚合更多延迟数据）。重复 1，2；&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;event_time &amp;lt; last_event_time - 90s&lt;/code&gt;，则事件发生延迟，如果旧窗口还在则落入窗口并触发旧窗口 window 聚合计算，否则放到侧输出流，重复 2。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可见，watermark 大大减少了聚合计算带来的开销，allowLateNess 在出现大量数据延迟的情况下则更有用。&lt;/p&gt;
&lt;p&gt;最后记录一个 Task，计算每小时所有出租车司机中的最高总小费获得值，下面给出任务描述和关键代码：&lt;/p&gt;
&lt;p&gt;The task of the exercise is to first calculate the total tips collected by each driver, hour by hour, and then from that stream, find the highest tip total in each hour.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; JobExecutionResult &lt;span style=&#34;color:#88c0d0&#34;&gt;execute&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throws&lt;/span&gt; Exception &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// set up streaming execution environment
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    StreamExecutionEnvironment env &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; StreamExecutionEnvironment&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getExecutionEnvironment&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// start the data generator and arrange for watermarking
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    DataStream&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;TaxiFare&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; fares &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;            env&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;addSource&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;source&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;                    &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;assignTimestampsAndWatermarks&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;                            &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// taxi fares are in order
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;                            WatermarkStrategy&lt;span style=&#34;color:#81a1c1&#34;&gt;.&amp;lt;&lt;/span&gt;TaxiFare&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;forMonotonousTimestamps&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;                                    &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;withTimestampAssigner&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;                                            &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;fare&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; t&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;-&amp;gt;&lt;/span&gt; fare&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getEventTimeMillis&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()));&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// compute tips per hour for each driver
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    DataStream&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Tuple3&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Long&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Long&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Float&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; hourlyTips &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;            fares&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;keyBy&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;((&lt;/span&gt;TaxiFare fare&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;-&amp;gt;&lt;/span&gt; fare&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;driverId&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;                    &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;window&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;TumblingEventTimeWindows&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;of&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Time&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;hours&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;)))&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;                    &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;process&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; AddTips&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// find the driver with the highest sum of tips for each hour
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    DataStream&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Tuple3&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Long&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Long&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Float&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; hourlyMax &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;            hourlyTips&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;windowAll&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;TumblingEventTimeWindows&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;of&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Time&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;hours&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;))).&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;maxBy&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;2&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;    hourlyMax&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;addSink&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;sink&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; env&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;execute&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Hourly Tips&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意这里假定数据是有序的，所以采用了 &lt;code&gt;WatermarkStrategy.&amp;lt;TaxiFare&amp;gt;forMonotonousTimestamps()&lt;/code&gt;，它将最大乱序程度设置为 0 毫秒，表示不允许有任何乱序。如果假定数据会乱序到达，则可以直接修改窗口 watermark 策略来完成。&lt;/p&gt;
&lt;p&gt;最后可以了解一下处理函数（Process Functions）。ProcessFunction 将事件处理与 Timer，State 结合在一起，使其成为流处理应用的强大构建模块。使用 ProcessFunction 可以创建自定义的窗口操作。这里我们通过重写 KeyedProcessFunction 实现自定义窗口，使用 MapState + Timer 来处理数据，总体流程如下，具体参考&lt;a href=&#34;https://nightlies.apache.org/flink/flink-docs-master/zh/docs/learn-flink/event_driven/&#34;&gt;flink-事件驱动应用&lt;/a&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;设 MapState 的 key 为窗口的结束时间戳，值为该窗口的小费总和；&lt;/li&gt;
&lt;li&gt;当窗口的第一个时间戳到达时，计算窗口结束时间戳，设置 MapState，注册回调 timer（回调时间可以设为 Watermark 到达窗口结束时间戳的实际时间）；&lt;/li&gt;
&lt;li&gt;后续时间戳到达，如果大于 Watermark 则 update MapState，否则为延迟事件；&lt;/li&gt;
&lt;li&gt;一个小时过去，触发 Timer，计算结果，清除当前窗口的结束时间戳 kv；&lt;/li&gt;
&lt;li&gt;重复 2～4。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;更深入地了解 Flink：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.whitewood.me/2021/01/02/%E8%AF%A6%E8%A7%A3-Flink-%E5%AE%B9%E5%99%A8%E5%8C%96%E7%8E%AF%E5%A2%83%E4%B8%8B%E7%9A%84-OOM-Killed/&#34;&gt;详解 Flink 容器化环境下的 OOM Killed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;state&#34;&gt;State&lt;/h3&gt;
&lt;p&gt;State 泛指 Flink 中有状态函数和运算符在各个元素(element)/事件(event)的处理过程中存储的数据。状态数据可以修改和查询，可以自己维护，根据自己的业务场景，保存历史数据或者中间结果到 State 中。&lt;/p&gt;
&lt;p&gt;使用状态计算的例子：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当应用程序搜索某些事件模式时，状态将存储到目前为止遇到的事件序列。&lt;/li&gt;
&lt;li&gt;在每分钟/小时/天聚合事件时，状态保存待处理的聚合。&lt;/li&gt;
&lt;li&gt;当在数据点流上训练机器学习模型时，状态保持模型参数的当前版本。&lt;/li&gt;
&lt;li&gt;当需要管理历史数据时，状态允许有效访问过去发生的事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;无状态计算指的是数据进入 Flink 后经过算子时只需要对当前数据进行处理就能得到想要的结果；有状态计算就是需要和历史的一些状态或进行相关操作，才能计算出正确的结果。&lt;/p&gt;
&lt;h3 id=&#34;checkpoint-机制&#34;&gt;Checkpoint 机制&lt;/h3&gt;
&lt;p&gt;Flink 是&lt;strong&gt;有状态&lt;/strong&gt;的流计算处理引擎，每个算子 Operator 可能都需要记录自己的运行数据，并在接收到新流入的元素后不断更新自己的状态数据。当分布式系统引入状态计算后，为了保证计算结果的正确性（特别是对于流处理系统，不可能每次系统故障后都从头开始计算），就必然要求系统具有容错性。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Checkpoint&lt;/strong&gt; 机制是 Flink 容错性、可靠性的基石，可以保证 Flink 集群在某个算子因为某些原因(如异常退出)出现故障时，能够将整个应用流图的状态恢复到故障之前的某 一状态，保证应用流图状态的一致性。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Barrier&lt;/strong&gt; 是 Flink 分布式快照的核心概念之一，称之为屏障或者数据栅栏（可以理解为快照的分界线）。Barrier 是一种特殊的内部消息，在进行 Checkpoint 的时候 Flink 会在数据流源头处周期性地注入 Barrier，这些 Barrier 会作为数据流的一部分，一起流向下游节点并且不影响正常的数据流。Barrier 的作用是将无界数据流从时间上&lt;strong&gt;切分成多个窗口&lt;/strong&gt;，每个窗口对应一系列连续的快照中的一个，每个 Barrier 都带有一个快照 ID，一个 Barrier 生成之后，在这&lt;strong&gt;之前的数据&lt;/strong&gt;都进入此快照，在这之后的数据则进入下一个快照。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1731986285943.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;每个需要 checkpoint 的应用在启动时，Flink 的 JobManager 为其创建一个 Checkpoint Coordinator，Checkpoint Coordinator 全权负责本应用的快照制作。如上图，Barrier-n 跟随着数据流一起流动，当算子从输入流接收到 Barrier-n 后，就会停止接收数据并&lt;strong&gt;对当前自身的状态做一次快照&lt;/strong&gt;，快照完成后再将 Barrier-n 以广播的形式传给&lt;strong&gt;下游节点&lt;/strong&gt;。一旦作业的 Sink 算子接收到 Barrier-n 后，会向 JobMnager 发送一个消息，确认 Barrier-n 对应的快照完成。当作业中的所有 Sink 算子都确认后，意味一次全局快照也就完成。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1731987362341.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;当一个算子有多个上游节点时，会接收到多个 Barrier，这时候需要进行 Barrier Align 对齐操作。假设一个算子有两个输入流，当算子从一个上游数据流接收到一个 Barrier-n 后，它不会立即向下游广播，而是先暂停对该数据流的处理，将到达的数据先缓存在 Input Buffer 中（因为这些数据属于下一次快照而不是当前快照，缓存数据可以不阻塞该数据流），直到从另外一个数据流中接收到 Barrier-n，才会进行快照处理并将 Barrier-n 向下游发送。&lt;/p&gt;
&lt;p&gt;综上，Flink Checkpoint 机制的核心思想实质上是通过 Barrier 来标记触发快照的时间点和对应需要进行快照的数据集，将数据流处理和快照操作解耦开来，从而最大程度降低快照对系统性能的影响。&lt;/p&gt;
&lt;h3 id=&#34;一致性&#34;&gt;一致性&lt;/h3&gt;
&lt;p&gt;Flink 的一致性和 Checkpoint 机制有紧密的关系：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当不开启 Checkpoint 时，节点发生故障时可能会导致数据丢失，这就是 At-Most-Once&lt;/li&gt;
&lt;li&gt;当开启 Checkpoint 但不进行 Barrier 对齐时，对于有多个输入流的节点如果发生故障，会导致有一部分数据可能会被处理多次，这就是 At-Least-Once&lt;/li&gt;
&lt;li&gt;当开启 Checkpoint 并进行 Barrier 对齐时，可以保证每条数据在故障恢复时只会被重放一次，这就是 Exactly-Once&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;并行度&#34;&gt;并行度&lt;/h3&gt;
&lt;p&gt;一个 Flink 程序由多个任务 task 组成（转换/算子、数据源和数据接收器）。一个 task 包括多个并行执行的实例，且每一个实例都处理 task 输入数据的一个子集。一个 task 的并行实例数被称为该 task 的 并行度 (parallelism)。&lt;/p&gt;
&lt;p&gt;Flink 提供了多种方式来设置并行度：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全局并行度: 在执行环境中设置，影响所有算子的并行度。&lt;/li&gt;
&lt;li&gt;算子级别并行度: 为每个算子单独设置并行度。&lt;/li&gt;
&lt;li&gt;客户端级别并行度: 在提交作业时设置并行度。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;并行度和 Slot：&lt;/p&gt;
&lt;p&gt;Slot（槽）是一个非常重要的概念，它代表了 TaskManager 上的一份固定大小的资源，一个 TaskManager 可以有多个 slot。一个 slot 可以执行一个或多个子任务，一个slot上有多个子任务时，这些子任务会共享该slot的资源。如果一个算子的并行度大于 slot 的数量，那么多个子任务会竞争 slot 资源。&lt;/p&gt;
&lt;h3 id=&#34;反压机制&#34;&gt;反压机制&lt;/h3&gt;
&lt;p&gt;Flink 的反压策略主要分为以下几个步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;任务反压：当下游任务的处理速度较慢时，Flink 会检测到这种情况，并认为这是一个反压信号。此时，Flink 会将这个反压信号传递给上游任务的管理器。&lt;/li&gt;
&lt;li&gt;调整数据生成速度：当上游任务的管理器收到反压信号后，会根据反压信号的强度来调整数据生成速度。通常情况下，反压信号越强，上游任务生成的数据量就会减少，以减轻下游任务的负担。&lt;/li&gt;
&lt;li&gt;控制反压：Flink 还会通过一些控制机制来避免过度反压。例如，当上游任务的数据生成速度过慢时，Flink 会限制反压的强度，以避免数据积压过多。此外，Flink 还会设置一个反压阈值，当反压信号超过这个阈值时，Flink 会认为任务已经处于一个不稳定的状态，并会采取相应的措施，如调整任务并行度、暂停任务等。&lt;/li&gt;
&lt;li&gt;恢复数据生成速度：当下游任务的处理速度恢复到正常水平时，Flink 会检测到这个变化，并逐渐增加上游任务的数据生成速度，以恢复数据流。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;三种时间语义&#34;&gt;三种时间语义&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1732264704693.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;Event Time 指的是数据流中每个元素或者每个事件自带的时间属性，一般是事件发生的时间。由于事件从发生到进入 Flink 时间算子之间有很多环节，一个较早发生的事件因为延迟可能较晚到达，因此使用 Event Time 意味着事件到达有可能是乱序的，所以使用 Watermark 通常是有必要的。&lt;/p&gt;
&lt;p&gt;Ingestion Time 是事件到达 Flink Souce 的时间。从 Source 到下游各个算子中间可能有很多计算环节，任何一个算子的处理速度快慢可能影响到下游算子的 Processing Time。而 Ingestion Time 定义的是数据流最早进入 Flink 的时间，因此不会被算子处理速度影响。&lt;/p&gt;
&lt;h2 id=&#34;lsm&#34;&gt;LSM&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1733973943263.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;LSM tree, short for Log-Structured-Merge Tree, is a clever algorithm design that helps us store massive amounts of data without making us wait forever to write it. It stores data in memory first, which is lightning fast. But since we can’t keep everything in memory, the LSM Tree periodically flushes data to disk.&lt;/p&gt;
&lt;p&gt;But here’s where it gets even cooler! It organizes the data into layers of sorted structures, each with more and more compressed data. The top layer is the fastest to access but the least compressed. As the data piles up, it’s compressed and written into a new layer called an SSTable (Sorted String Table). We can decide how many layers we need and how much compression to apply, based on the type of data we’re dealing with. This trick helps us minimize disk I/O operations and make our data storage super efficient!&lt;/p&gt;
&lt;p&gt;WRITE:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The data is first written to the in-memory layer for speedy performance.&lt;/li&gt;
&lt;li&gt;Simultaneously, the changes are recorded in the Write-Ahead Log to ensure data integrity.&lt;/li&gt;
&lt;li&gt;Then, at regular intervals or when the in-memory layer reaches a certain threshold, the data is flushed to disk and organized into SSTables.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;READ:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check the data at in-memory layer&lt;/li&gt;
&lt;li&gt;Check the bloom filter that indicates whether the data might exist in a specific SSTable&lt;/li&gt;
&lt;li&gt;Search the specified SSTable at on-disk layer&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;kafka&#34;&gt;Kafka&lt;/h2&gt;
&lt;p&gt;Apache Kafka 是一个分布式的流处理平台。我所知的 Kafka 通常是作为一个消息队列的角色而存在的，在 Shopee 的大数据处理架构中，Kafka 作为 MySQL 和大数据处理框架之间的一个桥梁。
Kafka 订阅了 Binlog，产生一些列消息，让大数据处理框架进行消费。&lt;/p&gt;
&lt;p&gt;TODO：之后会记录一些 Kafka 的原理知识和相关代码实践。&lt;/p&gt;
&lt;h2 id=&#34;hive&#34;&gt;Hive&lt;/h2&gt;
&lt;p&gt;Hive 是一个构建在 Hadoop 之上的数据仓库，它可以将结构化的数据文件映射成表，并提供类 SQL 查询功能，用于查询的 SQL 语句会被转化为 MapReduce 作业，然后提交到 Hadoop 上运行。Hive 架构如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1724403135747.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;Hive 由内部表和外部表的概念，在导入数据到内部表，内部表数据的生命周期由 Hive 来进行管理，存在自己的数据仓库目录下。
而外部表只是在元数据中存储了数据的位置。&lt;/p&gt;
&lt;p&gt;Hive 中有分区和分桶的概念，每个表可以有一个或多个分区键，用于确定数据的存储方式。
分区键的每个唯一值定义了表的一个分区。每个分区中的数据又可以基于表的某一列的散列函数的值被划分为桶。&lt;/p&gt;
&lt;p&gt;接下来我着重记录了 HiveSQL 相关知识。&lt;/p&gt;
&lt;p&gt;HiveSQL 在排序这一块与传统 SQL 有较大差别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;order by 是全局排序，可能性能会比较差；&lt;/li&gt;
&lt;li&gt;sort by 进行分区内排序，往往配合 distribute by 来确定该分区都有那些数据；&lt;/li&gt;
&lt;li&gt;distribute by 确定了数据分发的规则，满足相同条件的数据被分发到一个reducer；&lt;/li&gt;
&lt;li&gt;cluster by 当 distribute by 和 sort by 字段相同时，可以使用 cluster by 代替 distribute by 和 sort by；&lt;/li&gt;
&lt;li&gt;sort by limit 相当于每个 reduce 的数据 limit 之后，进行 order by 然后再 limit。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HiveSQL 支持 WITH AS 临时中间表，当我们书写一些结构相对复杂的 SQL 语句时，可能某个子查询在多个层级多个地方存在重复使用的情况，这个时候我们可以使用 WITH AS 语句将其独立出来，极大提高SQL可读性，简化 SQL。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- with table_name as(子查询语句) 其他sql
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WITH&lt;/span&gt; t1 &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;AS&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; abc
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	&lt;span style=&#34;color:#eceff4&#34;&gt;),&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	t2 &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;AS&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; efg
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;	&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; t1&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; t2&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 如果定义了 with 子句，但其后没有跟 select 查询，则会报错（没有使用没关系，其后必须有 select），因此不允许单独使用。
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;HiveSQL 支持窗口计算。在 Hive 中，窗口函数允许你在结果集的行上进行计算，这些计算不会影响你查询的结果集的行数。&lt;/p&gt;
&lt;p&gt;Hive 提供的窗口和分析函数可以分为聚合函数类窗口函数，分组排序类窗口函数，偏移量计算类窗口函数。语法如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 分析函数 
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;over&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;partition &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;by&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;列名&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;order&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;by&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;列名&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;rows&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;between&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;开始位置&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;结束位置&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 聚合函数类
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;count&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;sum&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;max&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;min&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;avg&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 分组排序类
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;row_number&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 按照排序的顺序输出窗口中的数据的行号信息
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;rank&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 按照指定列进行排名，如果值相同，则排名并列，下一个排名会出现跳跃，即排名是不连续的
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;dense_rank&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 相比 rank() 不会跳跃
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;percent_rank&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 按百分比进行排名
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;cume_dist&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 如果按升序排列，则统计：小于等于当前值的行数所占当前分区窗口总行数的比例。如果是降序排列，则统计：大于等于当前值的行数所占当前分区窗口总行数的比例
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;ntile&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 用于将按指定列分组的数据按照顺序切分成 N 片，返回当前切片值
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 求偏移量类
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;lead&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 用于统计窗口内往下第 n 行值
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;lag&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 用于统计窗口内往上第 n 行值
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;first_value&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 取分组内排序后，截止到当前行，第一个值
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;last_value&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 取分组内排序后，截止到当前行，最后一个值
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;over()&lt;/code&gt; 括号内为空时，是直接进行聚合计算。&lt;/li&gt;
&lt;li&gt;其中 &lt;code&gt;partition by&lt;/code&gt; 列名 是按指定列进行分组，进而进行聚合计算。&lt;/li&gt;
&lt;li&gt;最后的 &lt;code&gt;order by&lt;/code&gt; 列名 是按照指定列进行排序，进而进行聚合计算。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体用例参考&lt;a href=&#34;https://www.cnblogs.com/lubians/p/18119840&#34;&gt;这篇文章&lt;/a&gt;，特别详细，比如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 按照星座分组，统计出 pv 由高到低的排名。
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;select&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;id&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; client&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; gender&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;row_number&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;partition &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;by&lt;/span&gt; constellation &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;order&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;by&lt;/span&gt; pv &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;desc&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;as&lt;/span&gt; rank_id
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;from&lt;/span&gt; temp&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;user_info &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;where&lt;/span&gt; id &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 统计小于等于当前年龄的人数占总人数的比例。
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;select&lt;/span&gt; id&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; client&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; age&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;cume_dist&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; over&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;order&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;by&lt;/span&gt; age &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;desc&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;as&lt;/span&gt; rank_id
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;from&lt;/span&gt; temp&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;user_info &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;where&lt;/span&gt; id &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;order&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;by&lt;/span&gt; age&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;hbase&#34;&gt;HBase&lt;/h2&gt;
&lt;p&gt;HBase 是一个面向列式存储的分布式数据库，其设计思想来源于 Google 的 BigTable 论文。HBase 底层存储基于 HDFS 实现，集群的管理基于 ZooKeeper 实现。&lt;/p&gt;
&lt;p&gt;HBase 良好的分布式架构设计为海量数据的快速存储、随机访问提供了可能，基于数据副本机制和分区机制可以轻松实现在线扩容、缩容和数据容灾，是大数据领域中 Key-Value 数据结构存储最常用的数据库方案。&lt;/p&gt;
&lt;p&gt;HBase 的数据模型：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1731469549466.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;在 HBase 表中，一条数据拥有一个全局唯一的键(RowKey)和任意数量的列(Column)，一列或多列组成一个列族(Column Family)，同一个列族中列的数据在物理上都存储在同一个 HFile 中，这样基于列存储的数据结构有利于数据缓存和查询。&lt;/p&gt;
&lt;p&gt;HBase 中的表是疏松地存储的，因此用户可以动态地为数据定义各种不同的列。HBase 中的数据按主键排序，同时，HBase 会将表按主键划分为多个 Region 存储在不同 Region Server 上，以完成数据的分布式存储和读取。&lt;/p&gt;
&lt;p&gt;HBase 根据列成来存储数据，一个列族对应物理存储上的一个 HFile，列族包含多列列族在创建表的时候被指定。&lt;/p&gt;
&lt;p&gt;通过几条操作语句了解 HBase 数据模型：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# hbase shell&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# create &amp;#39;表名称&amp;#39;, &amp;#39;列族名称1&amp;#39;, &amp;#39;列族名称2&amp;#39;, &amp;#39;列族名称N&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;create &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;users&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;sex&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;info&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# put &amp;#39;表名称&amp;#39;,&amp;#39;行名称&amp;#39;,&amp;#39;列族名称(：列名称)&amp;#39;, &amp;#39;列值&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;put &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;users&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;jack&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;sex&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;male&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;put &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;users&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;jack&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;info:age&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;20&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;paimon&#34;&gt;Paimon&lt;/h2&gt;
&lt;p&gt;为什么要有 Paimon？在最近开发 Shopee 订单关键指标的过程中，通过当前整个大数据计算框架，我大致明白了，具体记录如下。&lt;/p&gt;
&lt;p&gt;首先，目前基于 Hadoop 的大数据计算体系中，如果单纯的基于 hdfs 进行 mp 计算，比如 hive，则只能实现 insert 或 insert overwrite，只能去计算 T+1 级别的数据，在计算 Shopee 订单关键指标时，就常常被用于计算一天内的订单量、成交额，这个是可以确保准确且稳定的。&lt;/p&gt;
&lt;p&gt;还是在 Hadoop 体系内，我们希望去计算更实时的数据，比如小时、分钟级别的，可能会去采用 hudi，因为 hudi 支持 upsert。hudi upsert 支持 mor 和 cow 两种模式，而一般采用的 cow 模式 cpu 占用率较高，根据 Shopee 实际情况，hudi 常常顶不住超大数据+复杂跨国链路的压力，加上带宽相关的限制，其他团队常常反馈数据延迟过高，通过 hudi 计算小时级别的数据常常不可靠，分钟级别的就更不必说了。目前，团队将向 paimon 迁移，后文继续说明。&lt;/p&gt;
&lt;p&gt;如果跳出 Hadoop 体系，那就是使用 flink 去计算实时数据，官方说是支持 ms 级别，但在超大数据复杂链路的情况下，一般是 s 级别，在计算 Shopee 订单关键指标时，我们采用 flink 来计算分钟级别的数据。只是在有些情况下，flink 可能不够稳定，需要加 dqc，通过离线数据去对账更新实时的数据。&lt;/p&gt;
&lt;p&gt;为更好地计算小时级别的数据，可以说是 T+0 数据(而一般 3-5 小时到 1 天级别的数据称为 T+1 数据)，也就是更低延迟、更低成本地去计算更细粒度时间级别的数据，目前 Paimon 是一种可能的解决方案。&lt;/p&gt;
&lt;p&gt;Apache Paimon 是一个湖格式，结合 Flink 及 Spark 构建流批处理的实时湖仓一体架构。Paimon 创新的结合湖格式与 LSM 技术，给数据湖带来了实时流更新以及完整的流处理能力。通常的实现方式是采用 Flink 实时计算相关数据写入 Paimon，这样利用了 Flink 的低延迟特性，也实现了对 hdfs 的 upsert 操作。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1724398725217.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;Paimon 是当今大数据前沿技术，这里有具体用法入门：&lt;a href=&#34;https://help.aliyun.com/zh/flink/use-cases/paimon-quick-start-basic-features?spm=a2c4g.11186623.0.0.36b2719eQZn9b4&#34;&gt;Paimon 快速开始：基本功能&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;后续会在项目中对 Paimon 进行具体实践，到时将技术设计同步到此处。&lt;/p&gt;
&lt;h2 id=&#34;hudi&#34;&gt;Hudi&lt;/h2&gt;
&lt;p&gt;Hudi（Hadoop Upserts Deletes and Incrementals）是一个用于跟踪大规模数据集的变化的数据管理库。&lt;/p&gt;
&lt;p&gt;Hudi 通过提供增量数据存储和查询能力，支持数据的插入、更新和删除操作。Hudi 还提供了时间旅行功能，可以让用户查询数据在不同时间点的快照。&lt;/p&gt;
&lt;p&gt;Hudi 适用于数据湖、实时分析和流处理场景。&lt;/p&gt;
&lt;p&gt;和 Hive 的区别：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1725244654807.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;clickhouse&#34;&gt;ClickHouse&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2 id=&#34;mpp&#34;&gt;MPP&lt;/h2&gt;
&lt;p&gt;MPP（Massively Parallel Processing）架构数据库是一种分布式数据库架构，它将数据分布到多个节点上，并利用这些节点的计算资源并行处理数据。MPP 数据库通常用于处理大规模数据集，能够提供更高的性能和扩展性。MPP 常见的应用场景包括数据分析、实时报表、数据仓库等。&lt;/p&gt;
&lt;p&gt;MPP 架构数据库通常由多个节点组成，每个节点都具有独立的计算资源和存储空间。数据被分区存储在不同的节点上，每个节点负责处理自己所存储的数据。当进行查询时，MPP 数据库可以并行处理多个节点上的数据，从而提高查询性能。&lt;/p&gt;
&lt;p&gt;MPP 应该与 Hadoop 进行比较，mpp 相当于找一群和自己能力差不多的任一起做事，每个人做的事情是一致的。而 Hadoop 就是找一群能力差一些的人，但只需要他们每个人只做一部分工作。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-of-knowledge-and-practices-related-to-big-data/image/1724402565211.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;starrocks&#34;&gt;StarRocks&lt;/h2&gt;
&lt;p&gt;StarRocks 采用 MPP (Massively Parallel Processing) 分布式执行框架。&lt;/p&gt;
&lt;p&gt;在 MPP 执行框架中，一条查询请求会被拆分成多个物理计算单元，在多机并行执行。每个执行节点拥有独享的资源（CPU、内存）。MPP 执行框架能够使得单个查询请求可以充分利用所有执行节点的资源，所以单个查询的性能可以随着集群的水平扩展而不断提升。&lt;/p&gt;
&lt;h2 id=&#34;bitmap&#34;&gt;BitMap&lt;/h2&gt;
&lt;p&gt;Bit 即比特，是目前计算机系统里数据的最小单位。BitMap 可以理解为通过一个 bit 数组来存储特定数据的一种数据结构，由于 bit 是数据的最小单位，所以这种数据结构往往是非常节省存储空间。&lt;/p&gt;
&lt;p&gt;比如一个公司有 8 个员工，现在需要记录公司的考勤记录，可以构造一个 8bit 的数组，将这 8 个员工跟员工号分别映射到这 8 个位置，如果当天正常考勤了，则将对应的这个位置置为 1，否则置为 0，这样可以每天采用恒定的 1 个byte即可保存当天的考勤记录，大量节省了存储空间。&lt;/p&gt;
&lt;p&gt;除了节省存储空间，BitMap 结构的另一个更重要的特点，就是很方便通过位的运算（AND,OR,XOR,NOT），高效的对多个 BitMap 数据进行处理。比如上边的考勤的例子里，如果想知道那个员工最近两天都没来，只要将昨天的 BitMap 和今天的 BitMap 做一个按位的 OR 计算，然后检查那些位置是 0，就可以得到最近两天都没来的员工的数据了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.woshipm.com/it/4070505.html&#34;&gt;BitMap 技术的原理和应用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.alibabacloud.com/help/zh/hologres/use-cases/roaring-bitmaps?spm=a2c63.p38356.0.nextDoc.42c167b8GfDbco#section-utb-kpk-ygj&#34;&gt;画像分析 - RoaringBitmap 优化方案&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;blogs&#34;&gt;Blogs&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.whitewood.me&#34;&gt;时间与精神的小屋&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://help.aliyun.com/zh/emr&#34;&gt;阿里 E-MapReduce&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Shopee 技术团队(微信公众号)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://nightlies.apache.org/flink/flink-docs-master/zh/&#34;&gt;Apache Flink 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/heibaiying/BigData-Notes?tab=readme-ov-file&#34;&gt;heibaiying/BigData-Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://spark.apache.org/docs/latest/index.html&#34;&gt;Apache Spark 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apachecn/spark-doc-zh/blob/master/SUMMARY.md&#34;&gt;Spark 第三方中文文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kafka.apache.org/documentation/&#34;&gt;Kafka 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apachecn/kafka-doc-zh/blob/master/mkdocs.yml&#34;&gt;Kafka 第三方中文文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://cloud.google.com/learn/what-is-hadoop?hl=zh-CN&#34;&gt;Google Cloud - Hadoop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cnblogs.com/rossiXYZ/p/12286407.html&#34;&gt;[白话解析] Flink 的 Watermark 机制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/apache/flink-training&#34;&gt;apache/flink-training&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://tech.meituan.com/2021/08/26/data-warehouse-in-meituan-waimai.html&#34;&gt;美团外卖实时数仓建设实践&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://help.aliyun.com/zh/emr/emr-on-ecs/user-guide/paimon/?spm=a2c4g.11186623.0.0.4e802463M9Hr3Y&#34;&gt;阿里开源大数据平台 - Paimon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://paimon.apache.org/docs/master/concepts/overview/&#34;&gt;Apache Paimon 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://juejin.cn/post/7260389317176361016&#34;&gt;当流计算邂逅数据湖：Paimon 的前生今世&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gairuo.com/p/hive-sql-tutorial&#34;&gt;Hive SQL 教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.ikeguang.com/article/1643&#34;&gt;Hive 中的四种排序详解，再也不会混淆用法了。&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://juejin.cn/post/7125800654589100063&#34;&gt;Flink Checkpoint 机制详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://juejin.cn/post/6844904038727680008&#34;&gt;Flink 基础教程：时间语义、Event Time 和 Watermark 机制原理与实践&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/@dwivedi.ankit21/lsm-trees-the-go-to-data-structure-for-databases-search-engines-and-more-c3a48fa469d2&#34;&gt;LSM Trees: the Go-To Data Structure for Databases, Search Engines, and More&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
    
      
    
      
      <item>
        <title>SpringBoot Starter 开发指南</title>
        <link>https://zhihang.org/posts/methods-for-developing-and-using-starters-in-different-editions-of-springboot/</link>
        <pubDate>Sun, 25 Feb 2024 21:24:58 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>methods-for-developing-and-using-starters-in-different-editions-of-springboot</guid>
        <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;SpringBoot 不同版本开发和使用 Starter 有区别，这里记录下开发的一些前置知识、实现步骤和一些遇到的问题。&lt;/p&gt;
&lt;h2 id=&#34;springboot-不同版本自动装配的原理及细微区别&#34;&gt;SpringBoot 不同版本自动装配的原理及细微区别&lt;/h2&gt;
&lt;p&gt;开发 Starter 很重要的一个目的就是自动装配，而不同版本的 SpringBoot 在装配细节上有着区别。&lt;/p&gt;
&lt;p&gt;SpringBoot 通过 &lt;code&gt;@EnableAutoConfiguration&lt;/code&gt; 开启自动装配，通过 &lt;code&gt;SpringFactoriesLoader&lt;/code&gt; 或 &lt;code&gt;ImportCandidates&lt;/code&gt; 加载 META-INF 下配置文件（不同版本有区别）中的自动配置类实现自动装配，自动配置类其实就是通过 &lt;code&gt;@Conditional&lt;/code&gt; 按需加载的配置类，想要其生效必须引入 &lt;code&gt;spring-boot-starter-xxx&lt;/code&gt; 包（官方 starter）或者 &lt;code&gt;xxx-spring-boot-starter&lt;/code&gt;（第三方 starter） 实现起步依赖。&lt;/p&gt;
&lt;p&gt;不同版本具体自动装配的方式有所区别，可通过阅读源码中 &lt;code&gt;org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getCandidateConfigurations&lt;/code&gt; 找到区别：&lt;/p&gt;
&lt;p&gt;2.6 最后一个版本 2.6.15 通过 &lt;code&gt;SpringFactoriesLoader&lt;/code&gt; 加载 &lt;code&gt;META-INF/spring.factories&lt;/code&gt; 完成自动装配：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 2.6.15
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;protected&lt;/span&gt; List&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getCandidateConfigurations&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;AnnotationMetadata metadata&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; AnnotationAttributes attributes&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    List&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; configurations &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; SpringFactoriesLoader&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;loadFactoryNames&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getSpringFactoriesLoaderFactoryClass&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(),&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getBeanClassLoader&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    Assert&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;notEmpty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;configurations&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; configurations&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从 2.7.0 开始，额外通过 &lt;code&gt;ImportCandidates&lt;/code&gt; 加载 &lt;code&gt;META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports&lt;/code&gt; 找到添加了 &lt;code&gt;@AutoConfiguration&lt;/code&gt; 注解的类完成装配，这时还是保证了向下兼容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 2.7.0
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;protected&lt;/span&gt; List&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getCandidateConfigurations&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;AnnotationMetadata metadata&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; AnnotationAttributes attributes&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    List&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; configurations &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; ArrayList&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;SpringFactoriesLoader&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;loadFactoryNames&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getSpringFactoriesLoaderFactoryClass&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(),&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getBeanClassLoader&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()));&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    ImportCandidates&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;load&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;AutoConfiguration&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getBeanClassLoader&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()).&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;forEach&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;configurations&lt;span style=&#34;color:#81a1c1&#34;&gt;::&lt;/span&gt;add&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    Assert&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;notEmpty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;configurations&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; configurations&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从 3.0.0 大版本开始，不在使用 &lt;code&gt;SpringFactoriesLoader&lt;/code&gt;，需要特别注意：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 3.0.0
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;protected&lt;/span&gt; List&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getCandidateConfigurations&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;AnnotationMetadata metadata&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; AnnotationAttributes attributes&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    List&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; configurations &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; ImportCandidates&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;load&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;AutoConfiguration&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getBeanClassLoader&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()).&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getCandidates&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    Assert&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;notEmpty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;configurations&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;No auto configuration classes found in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; configurations&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以下用 A 指代 &lt;code&gt;META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports&lt;/code&gt;，B 指代 &lt;code&gt;spring.factories&lt;/code&gt;，总结版本间的一些区别如下，开发和使用 Starter 时需要特别注意：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;3.0.0 及以上版本自动装配类通过 A 配置，而 2.6.15 及以下版本通过 B 完成，2.7.0 以上到 3.0.0 之前 AB 均可；&lt;/li&gt;
&lt;li&gt;A 配置文件为每行一个 class 的格式，B 为 &lt;code&gt;org.springframework.boot.autoconfigure.EnableAutoConfiguration=class1, class2, ...&lt;/code&gt; 的格式&lt;/li&gt;
&lt;li&gt;3.0.0 及以上版本自动装配类需要添加 &lt;code&gt;@AutoConfiguration&lt;/code&gt; 注解，而 2.6.15 及以下版本对应是添加 &lt;code&gt;@Configuration&lt;/code&gt;，2.7.0 以上到 3.0.0 则根据使用情况而定即可&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;至于为什么将自动配置类文件进行更改？可以从 Github 上的这个 issue 找到答案：&lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/29872&#34;&gt;Move away from spring.factories for auto-configurations&lt;/a&gt;，阅读后可以总结一下，就是为了避免在配置文件 &lt;code&gt;spring.factories&lt;/code&gt; 中手动添加类，通过 &lt;code&gt;@AutoConfiguration&lt;/code&gt; 注解自动完成配置，而具体实现是要让编译器扫描添加了 &lt;code&gt;@AutoConfiguration&lt;/code&gt; 的类并自动生成 &lt;code&gt;META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports&lt;/code&gt; 文件，但是这个功能还未实现，至少在 2024.2 最新版本 3.2.2 还未实现，可通过这个 &lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/31228&#34;&gt;issue&lt;/a&gt; 追踪进展。&lt;/p&gt;
&lt;h2 id=&#34;不同版本-starter-使用上需要注意的地方&#34;&gt;不同版本 Starter 使用上需要注意的地方&lt;/h2&gt;
&lt;p&gt;了解前文对于原理的解释后，就可以总结出一些开发 starter 时需要注意的地方了。&lt;/p&gt;
&lt;p&gt;如果项目使用了 SpringBoot 3.X，但是调用了一个第三方的通过 2.X 开发的 Starter，且是通过 &lt;code&gt;spring.factories&lt;/code&gt; 加载类，那么将无法完成自动装配，需要手动配置相关 bean 完成，比如使用 rocketmq-spring-boot-starter-2.2.3 将无法自动装配 &lt;code&gt;RocketMQTemplate&lt;/code&gt;，通过如下代码解决即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Configuration&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;RocketMQConfig&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Value&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;${rocketmq.producer.group}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; String producerGroup&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Value&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;${rocketmq.name-server}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; String namesrvAddr&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Bean&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;name &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;rocketMQTemplate&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; RocketMQTemplate &lt;span style=&#34;color:#88c0d0&#34;&gt;rocketMQTemplate&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        RocketMQTemplate template &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; RocketMQTemplate&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        DefaultMQProducer producer &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; DefaultMQProducer&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        producer&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setProducerGroup&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;producerGroup&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        producer&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setNamesrvAddr&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;namesrvAddr&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        template&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setProducer&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;producer&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; template&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过 &lt;code&gt;@Bean&lt;/code&gt; 和 &lt;code&gt;@Configuration&lt;/code&gt; 完成 &lt;code&gt;RocketMQTemplate&lt;/code&gt; 的注入。&lt;/p&gt;
&lt;h2 id=&#34;开发一个适应性更好的-starter&#34;&gt;开发一个适应性更好的 Starter&lt;/h2&gt;
&lt;p&gt;为了让所有版本都能自动完成自动装配，我们可以同时适应两种自动装配方法。注意 &lt;code&gt;@AutoConfiguration&lt;/code&gt; 也包含了 &lt;code&gt;@Configuration&lt;/code&gt; 注解，所以可以很简单的完成适应，只是需要多准备一份配置文件。&lt;/p&gt;
&lt;p&gt;下面使用 3.2.2 版本的 SpringBoot 开发一个模拟式的邮件服务 Starter：&lt;/p&gt;
&lt;h3 id=&#34;新建项目-email-spring-boot&#34;&gt;新建项目 email-spring-boot&lt;/h3&gt;
&lt;p&gt;编辑 &lt;code&gt;pom.xml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;project&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;xmlns=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://maven.apache.org/POM/4.0.0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;xmlns:xsi=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;         &lt;span style=&#34;color:#8fbcbb&#34;&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;xdu.zh&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;email-spring-boot&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;pom&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;modules&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;module&amp;gt;&lt;/span&gt;email-spring-boot-autoconfigure&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/module&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;module&amp;gt;&lt;/span&gt;email-spring-boot-starter&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/module&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/modules&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;新建子模块-email-spring-boot-autoconfigure&#34;&gt;新建子模块 email-spring-boot-autoconfigure&lt;/h3&gt;
&lt;p&gt;编辑 &lt;code&gt;pom.xml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;project&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;xmlns=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://maven.apache.org/POM/4.0.0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;xmlns:xsi=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;         &lt;span style=&#34;color:#8fbcbb&#34;&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;parent&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;xdu.zh&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;email-spring-boot&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;email-spring-boot-autoconfigure&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;jar&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-dependencies&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.2.2&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependencyManagement&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- Spring Boot自动配置依赖 --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-autoconfigure&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- 元数据配置处理器 --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-configuration-processor&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;optional&amp;gt;&lt;/span&gt;true&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/optional&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;38&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过 &lt;code&gt;EmailProperties&lt;/code&gt; 定义一些自动配置项，指定配置前缀为 &lt;code&gt;email.service&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@ConfigurationProperties&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;email.service&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;EmailProperties&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;boolean&lt;/span&gt; enable &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; String host&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; Integer port&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; String name&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; String password&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// getter and setter...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;具体邮件服务实现：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;EmailService&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;final&lt;/span&gt; EmailProperties emailProperties&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;EmailService&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;EmailProperties emailProperties&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;emailProperties&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; emailProperties&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;send&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String content&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;开始发送邮件:&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;format&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;基本信息: host: %s, port: %s&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; emailProperties&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getHost&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(),&lt;/span&gt; emailProperties&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getPort&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()));&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;发送内容: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; content&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;发送成功!&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;实现自动配置，当存在 &lt;code&gt;EmailService.class&lt;/code&gt; 且 &lt;code&gt;email.service&lt;/code&gt; 为 &lt;code&gt;true&lt;/code&gt; 且容器中不存在 &lt;code&gt;EmailService&lt;/code&gt; 这个 bean 时自动装配 &lt;code&gt;EmailService&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;/**
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt; * @author zh
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt; * @date 2024/2/24
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt; */&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@AutoConfiguration&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@ConditionalOnClass&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;EmailService&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@EnableConfigurationProperties&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; EmailProperties&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;EmailAutoConfiguration&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Bean&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@ConditionalOnMissingBean&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@ConditionalOnProperty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;prefix &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;email.service&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;enable&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; havingValue &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; EmailService &lt;span style=&#34;color:#88c0d0&#34;&gt;mailService&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;EmailProperties mailProperties&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; EmailService&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;mailProperties&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑 &lt;code&gt;META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;xdu.zh.EmailAutoConfiguration
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编辑 &lt;code&gt;META-INF/spring.factories&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;org.springframework.boot.autoconfigure.EnableAutoConfiguration&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;xdu.zh.EmailAutoConfiguration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;新建子模块-email-spring-boot-starter&#34;&gt;新建子模块 email-spring-boot-starter&lt;/h3&gt;
&lt;p&gt;编辑 &lt;code&gt;pom.xml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;project&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;xmlns=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://maven.apache.org/POM/4.0.0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;xmlns:xsi=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;         &lt;span style=&#34;color:#8fbcbb&#34;&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;parent&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;xdu.zh&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;email-spring-boot&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;email-spring-boot-starter&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;jar&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;xdu.zh&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;email-spring-boot-autoconfigure&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该模块只完成封装，包含 &lt;code&gt;email-spring-boot-autoconfigure&lt;/code&gt; 模块，以及其它一些可能的依赖项（可选），调用 starter 时只需引入此依赖。&lt;/p&gt;
&lt;h3 id=&#34;进行多版本功能测试&#34;&gt;进行多版本功能测试&lt;/h3&gt;
&lt;p&gt;为进行更实际的测试，在此之前将 &lt;code&gt;email-spring-boot&lt;/code&gt; 进行发布，在 IDEA 内 maven 命令行面板通过 &lt;code&gt;mvn install&lt;/code&gt; 命令安装到本地 maven 仓库。&lt;/p&gt;
&lt;p&gt;接着新建测试项目，编辑 &lt;code&gt;pom.xml&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;project&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;xmlns=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://maven.apache.org/POM/4.0.0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;xmlns:xsi=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;         &lt;span style=&#34;color:#8fbcbb&#34;&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;xdu.test&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;test&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;jar&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;parent&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!--        &amp;lt;version&amp;gt;3.0.0&amp;lt;/version&amp;gt;--&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!--        &amp;lt;version&amp;gt;2.7.0&amp;lt;/version&amp;gt;--&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.6.15&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;relativePath/&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/parent&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;xdu.zh&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;email-spring-boot-starter&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.1&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进行一些必要配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# resources/application.properties&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;email.service.enable&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;true&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;email.service.host&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;mail.qq.com&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;email.service.port&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;965&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;email.service.name&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;admin&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;email.service.password&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;admin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;新建 Spring 应用，注入 &lt;code&gt;EmailService&lt;/code&gt;，执行 &lt;code&gt;send&lt;/code&gt; 方法进行功能测试：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@SpringBootApplication&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;EmailStarterTestApplication&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; CommandLineRunner &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Autowired&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; EmailService emailService&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        SpringApplication&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;EmailStarterTestApplication&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;...&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throws&lt;/span&gt; Exception &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        emailService&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;send&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试结果：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;...
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;开始发送邮件:
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;基本信息: host: mail.qq.com, port: 965
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;发送内容: test
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;发送成功!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再分别将 SpringBoot 版本改为 2.7.0、3.0.0，测试均通过。&lt;/p&gt;
&lt;h2 id=&#34;参考来源&#34;&gt;参考来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/31228&#34;&gt;spring-boot/issues/31228&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/spring-projects/spring-boot/issues/29872&#34;&gt;spring-boot/issues/29872&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.spring.io/spring-boot/docs/3.2.2/reference/html/features.html#features.developing-auto-configuration&#34;&gt;spring-boot/docs/3.2.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://felord.cn/springboot2.7.html&#34;&gt;Spring Boot 2.7.0 发布&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cnblogs.com/zt007/p/17118514.html&#34;&gt;springboot 自动配置原理&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>搭建私人代理服务简易教程</title>
        <link>https://zhihang.org/posts/a-simple-tutorial-on-building-private-proxy-services/</link>
        <pubDate>Mon, 12 Feb 2024 21:52:12 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>a-simple-tutorial-on-building-private-proxy-services</guid>
        <description>&lt;h2 id=&#34;toc&#34;&gt;TOC&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#toc&#34;&gt;TOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%80%E8%B4%AD%E4%B9%B0%E5%9B%BD%E5%A4%96%E5%8F%AF%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%99%A8&#34;&gt;一、购买国外可用服务器&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BA%8C%E9%85%8D%E7%BD%AE-ssh-%E9%9A%A7%E9%81%93%E4%BB%A3%E7%90%86&#34;&gt;二、配置 SSH 隧道代理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%89%E9%85%8D%E7%BD%AE%E5%8A%A0%E5%AF%86%E5%8D%8F%E8%AE%AE%E4%BB%A3%E7%90%86&#34;&gt;三、配置加密协议代理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9B%9B%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BB%A3%E7%90%86%E9%85%8D%E7%BD%AE&#34;&gt;四、客户端代理配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BA%94%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%A2%AB%E5%B0%81%E7%9A%84%E5%8F%AF%E8%83%BD%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95&#34;&gt;五、服务器被封的可能解决方法&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#1%E6%9B%B4%E6%8D%A2-ip-%E6%88%96%E7%AB%AF%E5%8F%A3&#34;&gt;1、更换 IP 或端口&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#2%E9%80%9A%E8%BF%87-cdn-%E4%B8%AD%E8%BD%AC%E6%B5%81%E9%87%8F&#34;&gt;2、通过 CDN 中转流量&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%AD%E6%B5%8B%E8%AF%95%E7%BD%91%E9%80%9F&#34;&gt;六、测试网速&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%83%E8%A7%A3%E9%94%81%E6%9B%B4%E5%A4%9A%E5%9C%B0%E5%8C%BA&#34;&gt;七、解锁更多地区&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;一购买国外可用服务器&#34;&gt;一、购买国外可用服务器&lt;/h2&gt;
&lt;p&gt;从 ISP 服务商购买 &lt;a href=&#34;https://hostalk.net/deals.html&#34;&gt;VPS&lt;/a&gt;，下单前先测试服务器附带的公网 IP 是否被封(本地不要挂代理)：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;ping $ip
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 或者使用 traceroute，更加详细:（mac: traceroute $ip）&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# tracert $ip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;另外也推荐使用 &lt;code&gt;https://ping.pe&lt;/code&gt; 测试，可进行多地区测试，更为全面。访问 &lt;code&gt;https://ping.pe/$ip&lt;/code&gt; 以测试 IP，访问 &lt;code&gt;https://tcp.ping.pe/$ip:$port&lt;/code&gt; 以测试具体端口。&lt;/p&gt;
&lt;p&gt;完成购买后，即可开始搭建代理服务，下面记录了两种代理方式，SSH 隧道道理和加密协议代理。&lt;/p&gt;
&lt;h2 id=&#34;二配置-ssh-隧道代理&#34;&gt;二、配置 SSH 隧道代理&lt;/h2&gt;
&lt;p&gt;通过 ssh 动态转发的能力，可以在本地建立一个 socks 协议的代理，它可通过 ssh 隧道转发请求到代理服务器。这应该是较古老而简便的代理方式，只需在本地进行操作，便捷但稳定性一般。通过以下一条简单的命令即可建立代理：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;ssh -D &lt;span style=&#34;color:#b48ead&#34;&gt;1080&lt;/span&gt; -qCN $user@$ip
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# -D：本机SOCKS 服务端口&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# -q : quiet 模式，没有输出&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# -C : 数据压缩，可以节约一些带宽&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# -N : 不运行远程命令，只做端口转发&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为了让代理服务在后台长久运行，可通过 autossh 完成，通过 brew, apt 等源都可安装 autossh。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# brew install autossh&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;autossh -f -M &lt;span style=&#34;color:#b48ead&#34;&gt;1088&lt;/span&gt; -D &lt;span style=&#34;color:#b48ead&#34;&gt;1080&lt;/span&gt; -qCN $user@$ip
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# -f 后台运行&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# -M 监控服务端口&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完成后即可进行测试，如下是一些简单的用法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 使用代理登录其他服务器&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;ssh -o ProxyCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;/usr/bin/nc -X 5 -x 127.0.0.1:1080 %h %p&amp;#39;&lt;/span&gt; $user1@$ip1 -v
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 使用代理访问 web&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;export&lt;/span&gt; ALL_PROXY&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;socks5h://127.0.0.1:1080
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;curl https://google.com -v
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意这里 ALL_PROXY 变量使用了 socks5h，本机实测通过 socks5 无法顺利请求 google。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;socks5 通过本地 dns 解析目标主机域名&lt;/li&gt;
&lt;li&gt;socks5h 通过代理服务器 dns 解析目标主机域名&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外可以通过一些软件实现全局代理或者规则分流，比如 QuantumultX, V2rayN 等支持 socks 协议的客户端。以下是 QuantumultX 配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;server_local&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;socks5&lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;127.0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.1&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1080&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; fast-open&lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; udp-relay&lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; tag&lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;socks5-ssh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;三配置加密协议代理&#34;&gt;三、配置加密协议代理&lt;/h2&gt;
&lt;p&gt;现在用的多的协议应该是 Vmess、Shadowsocks、Trojan 和 Vless，个人建议使用 Vmess 即可，不推荐 Shadowsocks。VMess 协议是由 V2Ray 开发者原创并使用于 V2Ray 的加密传输协议。V2Ray 是一个代理软件，支持多种协议，它存在于客户端和服务端中，每个端均存在一个入口点和出口点，用于流量转发。安装代理服务，首先需要安装服务端，客户端进行简单对接即可。如下是一个基本的数据包流向：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;{本地请求目标网站} &amp;lt;--(socks)--&amp;gt; {V2Ray 客户端 inbound &amp;lt;-&amp;gt; V2Ray 客户端 outbound} &amp;lt;--(VMess)--&amp;gt;  {V2Ray 服务器 inbound &amp;lt;-&amp;gt; V2Ray 服务器 outbound} &amp;lt;--(Freedom)--&amp;gt; {目标网站}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下文以 Vmess 为例进行安装，将直接使用 &lt;a href=&#34;https://github.com/233boy/v2ray&#34;&gt;V2Ray 脚本&lt;/a&gt; 安装服务端 V2Ray 并进行自动化配置，该脚本还支持其它多种协议且易于装卸更新，如需深入了解原理或者手动安装，可阅读 &lt;a href=&#34;https://guide.v2fly.org/&#34;&gt;V2Ray 新白话文指南&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;首先登上服务器，然后运行如下命令进行安装：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;bash &amp;lt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;wget -qO- -o- https://git.io/v2ray.sh&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完成后即可通过 &lt;code&gt;v2ray&lt;/code&gt; 命令交互式的添加各种协议的代理。默认安装了 Vmess 协议代理，控制台将打印出配置信息。具体配置和可执行文件位于 &lt;code&gt;/etc/v2ray&lt;/code&gt; 目录下。如不放心，可参考 &lt;a href=&#34;https://guide.v2fly.org/basics/vmess.html&#34;&gt;Vmess 配置指南&lt;/a&gt; 进行操作。&lt;/p&gt;
&lt;p&gt;配置信息中最重要的就是用户 id，是一串用于认证流量的 uuid，据此和其它一些配置信息可以开始配置客户端 V2Ray。不过更方便的方式是使用配置信息中脚本为我们生成的 base64 加密 url，该 url 通过解析可以取得用户 id，协议信息，地址信息等服务器代理信息。将该 url 导入本地支持解析加密 url 的 V2Ray 客户端即可一键完成配置。&lt;/p&gt;
&lt;p&gt;完成到这里就差不多了，但是有域名的话推荐外加 TLS，比如配置 &lt;code&gt;Vmess + WebSocket + TLS&lt;/code&gt; 代理：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;购买一个域名，并添加(子)域名解析到服务器 ip&lt;/li&gt;
&lt;li&gt;服务器运行 &lt;code&gt;v2ray add ws $domain&lt;/code&gt;, 将会自动通过 Caddy 配置证书且安装代理服务&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;该脚本使用了 Caddy 作为服务管理工具（类似于 Nginx）。如果服务器本身使用了 Nginx，可以通过 &lt;code&gt;v2ray no-auto-tls&lt;/code&gt; 手动配置 Nginx 而不是通过 Caddy，运行后控制台将打印代理路径和端口，用于配置 Nginx 反向代理。如下是一个参考配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;server {&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#8fbcbb&#34;&gt;listen 443 ssl http2;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#8fbcbb&#34;&gt;listen [::]:443 ssl http2;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#8fbcbb&#34;&gt;server_name $domain;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#8fbcbb&#34;&gt;ssl_certificate /etc/letsencrypt/live/$domain/fullchain.pem;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#8fbcbb&#34;&gt;ssl_certificate_key /etc/letsencrypt/live/$domain/privkey.pem;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#8fbcbb&#34;&gt;ssl_protocols TLSv1.2 TLSv1.3;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#8fbcbb&#34;&gt;ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#8fbcbb&#34;&gt;location /$path {&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        &lt;span style=&#34;color:#8fbcbb&#34;&gt;if ($http_upgrade !&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;websocket&amp;#34;) {
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;            return 404;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;        }
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;        proxy_pass http://127.0.0.1:$port;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;        proxy_redirect off;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;        proxy_http_version 1.1;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;        proxy_set_header Upgrade $http_upgrade;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;        proxy_set_header Connection &amp;#34;upgrade&amp;#34;;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;        proxy_set_header Host $host;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;        proxy_set_header X-Real-IP $remote_addr;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;        proxy_read_timeout 5d;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    }&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将 &lt;code&gt;$domain&lt;/code&gt;, &lt;code&gt;$path&lt;/code&gt;, &lt;code&gt;$port&lt;/code&gt; 分别替换为域名、代理路径、代理端口即可。&lt;/p&gt;
&lt;h2 id=&#34;四客户端代理配置&#34;&gt;四、客户端代理配置&lt;/h2&gt;
&lt;p&gt;完成代理服务的搭建后，即可在客户端中配置代理服务器。&lt;/p&gt;
&lt;p&gt;对于 V2Ray 客户端选择，只要支持对应加密协议即可，比如 Windows 上的 V2rayN，MacOS 上的 QuantumultX，它们本质上都是内置了 V2Ray 的图形化界面软件，支持一键导入且可以方便完成其它配置（&lt;a href=&#34;https://itlanyan.com/v2ray-clients-download&#34;&gt;一些推荐的客户端&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;如果选择手动配置 V2Ray，则需要手动编辑配置文件，比较麻烦但可以进行更多定制化操作。在 Windows 和 macOS 中，配置文件通常是 V2Ray 同目录下的 config.json 文件，而在 Linux 中，配置文件通常位于 &lt;code&gt;/usr/local/etc/v2ray/config.json&lt;/code&gt; 文件，这里给出我的配置（更多信息具体可参考 &lt;a href=&#34;https://guide.v2fly.org/basics/vmess.html&#34;&gt;Vmess 配置指南&lt;/a&gt;）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// /usr/local/etc/v2ray/config.json                                
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;loglevel&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;info&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;access&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;inbounds&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;settings&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;udp&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;auth&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;noauth&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;socks&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;listen&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;7891&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;settings&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;timeout&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;360&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;7890&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;listen&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;],&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;outbounds&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;streamSettings&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;wsSettings&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;          &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;headers&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;zhihang.org&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;          &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;          &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;path&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/{proxy_uuid}&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;tlsSettings&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;          &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;serverName&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;zhihang.org&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;38&lt;/span&gt;          &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;allowInsecure&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;39&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;40&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;security&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;tls&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;41&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;network&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ws&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;42&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;43&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;mux&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;44&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;concurrency&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;45&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;enabled&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;46&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;47&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;settings&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;48&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;vnext&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;49&lt;/span&gt;          &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;50&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;users&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;51&lt;/span&gt;              &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;52&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{proxy_uuid}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;53&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;level&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;54&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;alterId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;55&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;security&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;auto&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;56&lt;/span&gt;              &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;57&lt;/span&gt;            &lt;span style=&#34;color:#eceff4&#34;&gt;],&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;58&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;address&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;zhihang.org&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;59&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;port&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;443&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;60&lt;/span&gt;          &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;61&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;62&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;63&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;tag&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;proxy&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;64&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;vmess&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;65&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;66&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;67&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;freedom&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;68&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;tag&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;direct&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;69&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;settings&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;70&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;userLevel&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;71&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;domainStrategy&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;UseIP&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;72&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;73&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;74&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;75&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;settings&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;76&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;response&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;77&lt;/span&gt;          &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;78&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;79&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;80&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;protocol&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;blackhole&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;81&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;tag&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;block&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;82&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;83&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;],&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;84&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;dns&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;85&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;routing&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;86&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;rules&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;87&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;88&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;field&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;89&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;ip&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;90&lt;/span&gt;          &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;geoip:private&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;91&lt;/span&gt;          &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;geoip:cn&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;92&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;],&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;93&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;outboundTag&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;direct&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;94&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;95&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;96&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;97&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;transport&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;98&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将 &lt;code&gt;{proxy_uuid}&lt;/code&gt; 替换为自己代理认证的 uuid，代理服务将跑在 http(7890) 和 socks(7891) 端口。&lt;/p&gt;
&lt;p&gt;最后附上 Linux 上的 V2ray 客户端安装和启动方法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 如果服务器能直连 Github:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# bash &amp;lt;(curl -L https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 如果服务器不能直连 Github 则在其它能连的机器手动下载后上传安装&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# https://github.com/v2fly/fhs-install-v2ray&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;wget https://github.com/v2fly/v2ray-core/releases/download/v5.29.3/v2ray-linux-64.zip
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;mkdir -p /usr/local/etc/v2ray
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;unzip v2ray-linux-64.zip -d /usr/local/etc/v2ray
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;export PATH=&lt;/span&gt;$PATH&lt;span style=&#34;color:#a3be8c&#34;&gt;:/usr/local/etc/v2ray&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; ~/.zprofile &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;source&lt;/span&gt; ~/.zprofile
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# v2ray run&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;nohup v2ray run &amp;gt;/dev/null 2&amp;gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;amp;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;五服务器被封的可能解决方法&#34;&gt;五、服务器被封的可能解决方法&lt;/h2&gt;
&lt;h3 id=&#34;1更换-ip-或端口&#34;&gt;1、更换 IP 或端口&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;ip 被封：需要前往 vps 服务商更换服务器 ip 并重新生成配置&lt;/li&gt;
&lt;li&gt;端口被封：通过修改配置更换端口即可&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如何判断 ip 还是端口被封了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;ping $ip&lt;/code&gt; or &lt;code&gt;tracert $ip&lt;/code&gt; or &lt;code&gt;https://ping.pe/$ip&lt;/code&gt; -&amp;gt; 不通 -&amp;gt; ip 被封&lt;/li&gt;
&lt;li&gt;&lt;code&gt;telnet $ip $port&lt;/code&gt; or &lt;code&gt;https://tcp.ping.pe/$ip:$port&lt;/code&gt; -&amp;gt; 不通 -&amp;gt; 端口被封&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;2通过-cdn-中转流量&#34;&gt;2、通过 CDN 中转流量&lt;/h3&gt;
&lt;p&gt;该方法适用于本身已经外加 WebSocket 的代理服务，如果不支持需要先进行安装，另外本方法还需要有一个域名指向服务器 ip。&lt;/p&gt;
&lt;p&gt;WebSocket 是一种新的通讯协议，支持在单个 TCP 连接上进行双向数据传输。如果代理服务不含 WebSocket 则无法配合 CDN 使用，同时 CDN 本身也需要支持 WebSocket(CloudFlare CDN 支持，建议使用)。&lt;/p&gt;
&lt;p&gt;CDN 一般情况下将任意选择靠近你的可用节点来中转你的流量到达被封服务器，使用它来中转流量通常可行，但可能导致速度下降。通过 cloudflare 可以很简单地完成配置：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将原域名服务商的 dns 服务器地址改为 cloudflare 提供的地址(如原服务商为 cloudflare 则忽略此步)&lt;/li&gt;
&lt;li&gt;在 SSL/TLS 处将加密模式选为&amp;quot;完全&amp;quot;&lt;/li&gt;
&lt;li&gt;在 cloudflare 添加(子)域名解析到被封 ip，代理状态选为已代理，即走让请求 cdn&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;六测试网速&#34;&gt;六、测试网速&lt;/h2&gt;
&lt;p&gt;Op1. 服务器测试：&lt;/p&gt;
&lt;p&gt;在服务器执行以下多地网速测试脚本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;curl -Lso- https://raw.githubusercontent.com/wn789/Superspeed/master/superbench.sh &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Op2. 本地挂全局代理测试：&lt;/p&gt;
&lt;p&gt;访问 &lt;a href=&#34;https://www.speedtest.net/&#34;&gt;speedtest&lt;/a&gt;，点击 GO 开始测试。&lt;/p&gt;
&lt;h2 id=&#34;七解锁更多地区&#34;&gt;七、解锁更多地区&lt;/h2&gt;
&lt;p&gt;上述代理可以满足我 99% 的需求，但只限于一个地区。如果要解锁更多地区，通常我们可以购买按量付费的机场节点来实现。不过如果为了省钱，也可以通过一些国外的云服务商实现，比如 BrightData。可以利用 BrightData 强大的 ISP Proxies 来构建 HTTP 代理，效果不错，以下是大致的步骤：&lt;/p&gt;
&lt;p&gt;首先开一个 BrightData 的 ISP Proxies，在配置中选择按 ip 付费，选择需要的 region，有几个 region 就至少配几个 ip。复制得到的 host、username 和 password，然后即可配置 http 代理，以 quantumultx 为例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;[server_local]
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;http=brd.superproxy.io:22225, username=$username, password=$password, fast-open=false, udp-relay=false, tag=HTTP-JP
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样就完成了，是不是很简单？注意这里有个坑，因为 BrightData 的 ISP Proxies 不能代理 Google(可以用 BrightData 的 SERP 来弥补)，而代理软件使用 Google 作为延迟测试，所以导致我以为配置有问题，其实直接更改延迟测试的 url 即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;[general]
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;server_check_url =http://www.apple.com/library/test/success.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再以 Python Requests 请求为例，使用 HTTP 代理只需提供代理地址即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;requests&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;url&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;xxx&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; proxies&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://$username:$password@brd.superproxy.io:22225&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;https&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://$username:$password@brd.superproxy.io:22225&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;区别之前的代理搭建方式，这样优点是不用买服务器，更方便和灵活，但缺点是可能不够稳定。不过，和之前的代理方式结合起来用，在稳定的基础上，实现了更灵活的代理，解锁了更多网站和功能，也更便于开发者集成到自己的应用中，两者结合，真的实现了我理想中的个人代理服务！&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;参考文章：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://guide.v2fly.org/&#34;&gt;V2Ray 新白话文指南&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/haoel/haoel.github.io&#34;&gt;科学上网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/233boy/v2ray/wiki/%E4%BD%BF%E7%94%A8Cloudflare%E4%B8%AD%E8%BD%ACV2Ray%E6%B5%81%E9%87%8F&#34;&gt;使用 Cloudflare 中转流量&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>消息队列重要知识整理</title>
        <link>https://zhihang.org/posts/important-knowledge-organization-of-message-queue/</link>
        <pubDate>Mon, 12 Feb 2024 01:49:02 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>important-knowledge-organization-of-message-queue</guid>
        <description>&lt;h2 id=&#34;toc&#34;&gt;TOC&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#toc&#34;&gt;TOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BD%BF%E7%94%A8%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%E7%9A%84%E7%9B%AE%E7%9A%84&#34;&gt;使用消息队列的目的&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%E7%9A%84%E9%AB%98%E5%8F%AF%E7%94%A8%E6%80%A7&#34;&gt;消息队列的高可用性&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#rabbitmq---%E9%95%9C%E5%83%8F%E9%9B%86%E7%BE%A4%E6%A8%A1%E5%BC%8F&#34;&gt;RabbitMQ - 镜像集群模式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#kafka---%E4%B8%BB%E4%BB%8E%E9%9B%86%E7%BE%A4%E6%A8%A1%E5%BC%8F&#34;&gt;Kafka - 主从集群模式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rocketmq---%E4%B8%BB%E4%BB%8E%E9%9B%86%E7%BE%A4%E6%A8%A1%E5%BC%8F&#34;&gt;RocketMQ - 主从集群模式&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B6%88%E8%B4%B9%E5%A6%82%E4%BD%95%E5%81%9A%E5%88%B0%E5%B9%82%E7%AD%89%E6%80%A7&#34;&gt;消费如何做到幂等性&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B6%88%E6%81%AF%E7%9A%84%E5%8F%AF%E9%9D%A0%E6%80%A7%E4%BC%A0%E8%BE%93&#34;&gt;消息的可靠性传输&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%BC%80%E5%90%AF%E7%A1%AE%E8%AE%A4%E6%A8%A1%E5%BC%8F&#34;&gt;开启确认模式&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E7%9A%84%E9%A1%BA%E5%BA%8F%E6%80%A7&#34;&gt;消息消费的顺序性&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B6%88%E6%81%AF%E7%A7%AF%E5%8E%8B%E9%97%AE%E9%A2%98%E7%9A%84%E5%A4%84%E7%90%86&#34;&gt;消息积压问题的处理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rocketmq-%E6%B6%88%E8%B4%B9%E7%8A%B6%E6%80%81&#34;&gt;RocketMQ 消费状态&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#kafka-%E6%B6%88%E8%B4%B9%E7%AD%96%E7%95%A5&#34;&gt;Kafka 消费策略&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reference&#34;&gt;Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;使用消息队列的目的&#34;&gt;使用消息队列的目的&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;解耦：降低模块之间耦合度，提高业务灵活度。&lt;/li&gt;
&lt;li&gt;异步：异步地执行一系列互不影响的操作，降低执行所需时间。&lt;/li&gt;
&lt;li&gt;削峰：防止高并发场景下大量数据操作直接访问数据库，导致系统不可用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;消息队列的高可用性&#34;&gt;消息队列的高可用性&lt;/h2&gt;
&lt;p&gt;保证高可用需要分消息队列选型来确定，相关重要文章如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://doocs.github.io/advanced-java/#/docs/high-concurrency/how-to-ensure-high-availability-of-message-queues&#34;&gt;如何保证消息队列的高可用？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://rocketmq.apache.org/zh/docs/deploymentOperations/01deploy&#34;&gt;RocketMQ 部署方式&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;rabbitmq---镜像集群模式&#34;&gt;RabbitMQ - 镜像集群模式&lt;/h3&gt;
&lt;p&gt;跟普通集群模式不一样的是，在镜像集群模式下，你创建的 queue，无论是元数据还是 queue 里的消息都会存在于多个实例上，就是说，每个 RabbitMQ 节点都有这个 queue 的一个完整镜像，包含 queue 的全部数据的意思。然后每次你写消息到 queue 的时候，都会自动把消息同步到多个实例的 queue 上。&lt;/p&gt;
&lt;h3 id=&#34;kafka---主从集群模式&#34;&gt;Kafka - 主从集群模式&lt;/h3&gt;
&lt;p&gt;Kafka 由多个 broker 组成，每个 broker 是一个节点。创建一个 topic，这个 topic 根据 key(也可以是随机) 可划分为多个 partition，每个 broker 都存有所有的 partition。对于每个 key 对应的多个 partition，其中一个 broker 下的 partition 会被选为 leader，其他 partition 作为 follower。&lt;/p&gt;
&lt;p&gt;任何一个 partition 都可用于读，写则只作用于 leader。在正常情况下，任何一个 broker 都可以得到利用，因为每个主题的某个 key 对应的 leader partition 可能存在于任一 broker 中。而由于每个 broker 都存了所有 partition 数据，当出现故障则进行选举，调整 leader-follower 关系即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/important-knowledge-organization-of-message-queue/image/1733826165650.png&#34; loading=&#34;lazy&#34; alt=&#34;arch-kafka&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;rocketmq---主从集群模式&#34;&gt;RocketMQ - 主从集群模式&lt;/h3&gt;
&lt;p&gt;Master（主节点）可以进行读和写操作，Slave（从节点）只可以读，不进行写操作。RocketMQ 提供两种数据同步模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;异步模式：每个 Master 配置一个 Slave，有多组 Master-Slave，HA 采用异步复制方式，主备有短暂消息延迟（毫秒级）。&lt;/li&gt;
&lt;li&gt;同步模式：每个 Master 配置一个 Slave，有多组 Master-Slave，HA 采用同步双写方式，即只有主备都写成功，才向应用返回成功。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/important-knowledge-organization-of-message-queue/image/1733826183561.png&#34; loading=&#34;lazy&#34; alt=&#34;arch-rocketmq&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;消费如何做到幂等性&#34;&gt;消费如何做到幂等性&lt;/h2&gt;
&lt;p&gt;从源头角度解决，就要确保不重复消费某条消息，从结果角度解决，就要确保重复消费后对实际业务没有任何影响。&lt;/p&gt;
&lt;p&gt;针对这两个角度，有两种解决方案：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;状态判断法：消费者消费数据后把消费数据记录在 redis 中，比如设定一个可唯一确定该条消息的全局 ID，下次消费时先到 redis 中查看是否存在该消息，存在则表示消息已经消费过，直接丢弃消息。&lt;/li&gt;
&lt;li&gt;业务判断法：通常数据消费后都需要插入到数据库中，使用数据库的唯一性约束防止重复消费。每次消费直接尝试插入数据，如果提示唯一性字段重复，则直接丢失消息。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;消息的可靠性传输&#34;&gt;消息的可靠性传输&lt;/h2&gt;
&lt;h3 id=&#34;开启确认模式&#34;&gt;开启确认模式&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/important-knowledge-organization-of-message-queue/image/1721207582151.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;消息传输过程中，在生产者、消息队列存储端、消费者端三个点都可能发生丢失。且对于不同的消息队列，需要进行不同的考虑。具体可以参考文章：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://doocs.github.io/advanced-java/#/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages&#34;&gt;如何保证消息的可靠性传输？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dunwu.github.io/bigdata-tutorial/kafka/Kafka%E5%8F%AF%E9%9D%A0%E4%BC%A0%E8%BE%93.html#%E6%B6%88%E6%81%AF%E4%B8%8D%E4%B8%A2%E5%A4%B1&#34;&gt;Kafka 可靠传输&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kafka 通过如下手段确保消息不丢失：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数据持久化&lt;/strong&gt;：日志写入磁盘（&lt;code&gt;log.dirs&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多副本存储&lt;/strong&gt;：ISR 机制（同步副本）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生产者 &lt;code&gt;acks=all&lt;/code&gt;&lt;/strong&gt; 确保消息持久化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消费者手动提交 Offset&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总结地讲，我们可以从消息可能丢失的三个地方入手，一般而言对于生产者和消费者端，都要开启确认模式，以 ACK 的方式来确认消息是否被成功生产或消费，注意是要进行手动的 ACK 而不是自动 ACK。对于消息队列存储端，需要关注磁盘，要开启消息的持久化，同时可以采用同步刷盘的方式确保消息被顺利存入。&lt;/p&gt;
&lt;h2 id=&#34;消息消费的顺序性&#34;&gt;消息消费的顺序性&lt;/h2&gt;
&lt;p&gt;参考文章：&lt;a href=&#34;https://xie.infoq.cn/article/c84491a814f99c7b9965732b1&#34;&gt;如何保证消息的顺序性？&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;总结如下，对于 RabbitMQ 和 RocketMQ，将同一事务的消息顺序存入同一队列，且该队列绑定给一个消费者进行消费即可。对于 Kafka，由于一个 topic 下同一个 partition 中的消息是有序的，将同一事务的消息顺序存入一个 partition，由一个消费者进行消费即可。&lt;/p&gt;
&lt;p&gt;最后对于消费者端可能存在的多线程消费方式，只需要一个事务中的消息被一个线程处理即可，可以在线程处理前增加个内存队列，每个线程只负责处理其中一个内存队列的消息，同一个事务中的消息发送到同一个内存队列中即可。&lt;/p&gt;
&lt;h2 id=&#34;消息积压问题的处理&#34;&gt;消息积压问题的处理&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;水平扩展消费者：消费者数量增多，则可以并行提升消息消费的速度，从而避免消息积压的问题。&lt;/li&gt;
&lt;li&gt;优化消费者处理速度：提升消费者的消费速度也可以避免消息积压的问题，它的解决方案有：
&lt;ul&gt;
&lt;li&gt;优化消费者处理消息的逻辑，减少不必要的计算和 I/O 操作。&lt;/li&gt;
&lt;li&gt;对于可以并行处理的任务，使用多线程或异步处理来提高吞吐量。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;限流生产者和使用背压机制：
&lt;ul&gt;
&lt;li&gt;在生产者端实施限流策略，确保消息产生的速度不会超过系统的处理能力。&lt;/li&gt;
&lt;li&gt;使用背压机制，即当消息队列达到某个阈值时，通知生产者降低发送速率或暂停发送。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;使用死信队列：在消费者处理消息出现失败或超时的情况下，加入消息重试机制或将异常消息放入死信队列，避免异常消息一直占用队列资源。&lt;/li&gt;
&lt;li&gt;监控和告警：设置合理的告警阈值，当消息积压达到一定程度时及时发出告警，以便快速响应和处理。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;rocketmq-消费状态&#34;&gt;RocketMQ 消费状态&lt;/h2&gt;
&lt;p&gt;PushConsumer 有如下五种消费状态：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ready：已就绪状态。消息在 Apache RocketMQ 服务端已就绪，可以被消费者消费。&lt;/li&gt;
&lt;li&gt;Inflight：处理中状态。消息被消费者客户端获取，处于消费中还未返回消费结果的状态。&lt;/li&gt;
&lt;li&gt;WaitingRetry：待重试状态，PushConsumer 独有的状态。当消费者消息处理失败或消费超时，会触发消费重试逻辑判断。如果当前重试次数未达到最大次数，则该消息变为待重试状态，经过重试间隔后，消息将重新变为已就绪状态可被重新消费。多次重试之间，可通过重试间隔进行延长，防止无效高频的失败。&lt;/li&gt;
&lt;li&gt;Commit：提交状态。消费成功的状态，消费者返回成功响应即可结束消息的状态机。&lt;/li&gt;
&lt;li&gt;DLQ：死信状态。消费逻辑的最终兜底机制，若消息一直处理失败并不断进行重试，直到超过最大重试次数还未成功，此时消息不会再重试，会被投递至死信队列。可以通过消费死信队列的消息进行业务恢复。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;和 PushConsumer 消费重试策略不同的是，SimpleConsumer 消费者的重试间隔是预分配的，每次获取消息时，消费者会在调用 API 时设置一个不可见时间参数 InvisibleDuration，即消息的最大处理时长。若消息消费失败则触发重试，不需要设置下一次重试的时间间隔，直接复用不可见时间参数的取值。&lt;/p&gt;
&lt;h2 id=&#34;kafka-消费策略&#34;&gt;Kafka 消费策略&lt;/h2&gt;
&lt;p&gt;latest 和 earliest 区别&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;earliest 当各分区下有已提交的 offset 时，从提交的 offset 开始消费；无提交的 offset 时，从头开始消费&lt;/li&gt;
&lt;li&gt;latest 当各分区下有已提交的 offset 时，从提交的 offset 开始消费；无提交的 offset 时，消费新产生的该分区下的数据&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://doocs.github.io/advanced-java/#/docs/high-concurrency/mq-interview&#34;&gt;消息队列面试场景&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://xie.infoq.cn/article/c84491a814f99c7b9965732b1&#34;&gt;如何保证消息的顺序性？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dunwu.github.io/bigdata-tutorial/kafka/Kafka%E5%8F%AF%E9%9D%A0%E4%BC%A0%E8%BE%93.html#%E6%B6%88%E6%81%AF%E4%B8%8D%E4%B8%A2%E5%A4%B1&#34;&gt;Kafka 可靠传输&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://rocketmq.apache.org/zh/docs/deploymentOperations/01deploy&#34;&gt;RocketMQ 部署方式&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>RSSHub 开发者食用指南</title>
        <link>https://zhihang.org/posts/quickly-develop-an-rsshub-router/</link>
        <pubDate>Thu, 21 Dec 2023 10:47:06 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>quickly-develop-an-rsshub-router</guid>
        <description>&lt;p&gt;注：由于 RSSHub 已经对整个项目进行了重构，本篇文档所介绍的开发流程不再适用于最新版本的 RSSHub。重构后的 RSSHub 完全使用 TS 进行开发，步骤更加清晰简洁，且官方提供的开发文档很详细，具体可参考&lt;a href=&#34;https://docs.rsshub.app/zh/joinus/new-rss/start-code&#34;&gt;官方开发文档&lt;/a&gt;。如果你还使用着未重构的老版本 RSSHub，则可以考虑参考本文。—— 2024.4.22 更新&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;最近写了几个 &lt;a href=&#34;https://github.com/DIYgod/RSSHub&#34;&gt;RSSHub&lt;/a&gt; 的路由，由于官方的开发步骤较为杂乱，这里提供一个简易的开发步骤，最后还记录了手动配置部署的过程。&lt;/p&gt;
&lt;p&gt;下面以开发 &lt;a href=&#34;https://tophub.today/&#34;&gt;今日热榜&lt;/a&gt; 的榜单路由为例进行介绍。&lt;/p&gt;
&lt;h2 id=&#34;下载安装-rsshub&#34;&gt;下载安装 RSSHub&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git clone git@github.com:DIYgod/RSSHub.git &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; RSSHub
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;pnpm i &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# npm install -g pnpm&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;pnpm run dev &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# localhost:1200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本文中基本都是用 pnpm 进行操作（pnpm 是新一代包管理器，它解决了 npm 幻影依赖和分身问题并较好地解决了依赖包复用问题，实现了依赖包高效快速的安装），其他操作方式详见官方文档。打开浏览器访问 &lt;code&gt;localhost:1200&lt;/code&gt; 即可看到 RSSHub index 页面。&lt;/p&gt;
&lt;p&gt;接着在 &lt;code&gt;lib/v2&lt;/code&gt; 下开始开发路由，一个文件夹对应一个域，这里创建文件夹 &amp;ldquo;tophub&amp;rdquo; 即可。&lt;/p&gt;
&lt;h2 id=&#34;定义路由规则&#34;&gt;定义路由规则&lt;/h2&gt;
&lt;p&gt;首先要分析网站结构，今日热榜一个榜单对应一个唯一的 id，那么可以将这个 id 作为匹配对象：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// router.js
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;module&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;exports &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;router&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    router&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;/list/:id&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; require&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;./list&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;));&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里生成了一个路由规则，用户可通过 &lt;code&gt;/tophub/list/xxxxx&lt;/code&gt; 这样的路由来生成 rss，通过同一目录下的 &lt;code&gt;list.js&lt;/code&gt; 完成具体抓取和生成逻辑。&lt;/p&gt;
&lt;h2 id=&#34;定义抓取和生成逻辑&#34;&gt;定义抓取和生成逻辑&lt;/h2&gt;
&lt;p&gt;首先引用下依赖包如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// list.js
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; got &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; require&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;@/utils/got&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; cheerio &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; require&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;cheerio&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; config &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; require&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;@/config&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;value&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; path &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; require&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt; art &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; require&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;@/utils/render&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;got&lt;/code&gt;：用于发起 http 请求&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cheerio&lt;/code&gt;：一个为服务器 jQuery 实现，可方便地解析页面&lt;/li&gt;
&lt;li&gt;&lt;code&gt;config&lt;/code&gt;：用于读取配置文件，经过分析发现爬取需使用 cookie，所以需要用户手动配置 cookie&lt;/li&gt;
&lt;li&gt;&lt;code&gt;path&lt;/code&gt;：路径生成工具&lt;/li&gt;
&lt;li&gt;&lt;code&gt;art&lt;/code&gt;：一个模板引擎（art-template），由于生成榜单需要定制 html 界面，所以需要使用它（仓库维护者的要求）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面是具体逻辑：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// list.js
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;module&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;exports &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;ctx&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; id &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; ctx&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;params&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;id&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; link &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;`https://tophub.today/n/&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;id&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;`&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; response &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;await&lt;/span&gt; got&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;link&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        headers&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;            Referer&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;https://tophub.today&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;            Cookie&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; config&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;tophub&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;cookie&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;});&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; $ &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; cheerio&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;load&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;response&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;data&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 解析榜单标题
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; title &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; $&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;div.Xc-ec-L.b-L&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;text&lt;span style=&#34;color:#eceff4&#34;&gt;().&lt;/span&gt;trim&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 解析榜单元素
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; items &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; $&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;div.Zd-p-Sc &amp;gt; div:nth-child(1) tr&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;toArray&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;map&lt;span style=&#34;color:#eceff4&#34;&gt;((&lt;/span&gt;e&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;({&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;            title&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; $&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;find&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;td.al a&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;text&lt;span style=&#34;color:#eceff4&#34;&gt;().&lt;/span&gt;trim&lt;span style=&#34;color:#eceff4&#34;&gt;(),&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;            link&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; $&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;find&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;td.al a&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;attr&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;href&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;),&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;            heatRate&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; $&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;find&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;td:nth-child(3)&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;text&lt;span style=&#34;color:#eceff4&#34;&gt;().&lt;/span&gt;trim&lt;span style=&#34;color:#eceff4&#34;&gt;(),&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;}));&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 将所有条目标题合一用于生成 GUID
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; combinedTitles &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; items&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;map&lt;span style=&#34;color:#eceff4&#34;&gt;((&lt;/span&gt;item&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&amp;gt;&lt;/span&gt; item&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;title&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;join&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 渲染榜单
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; renderRank &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; art&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;path&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;join&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;__dirname&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;templates/rank.art&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;),&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt; items &lt;span style=&#34;color:#eceff4&#34;&gt;});&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;    ctx&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;state&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;data &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;        title&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;        link&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;        item&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;            &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;                title&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;                link&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;                description&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; renderRank&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;                guid&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; combinedTitles&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;            &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;],&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;38&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;39&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里通过 jquery 语法读取元素: &lt;code&gt;$(&#39;div.Xc-ec-L.b-L&#39;)&lt;/code&gt;，具体可以参考 &lt;a href=&#34;https://cheerio.js.org/docs/intro&#34;&gt;cheerio 官方文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;由于当榜单中任一个条目顺序或内容发生变化都可认为是更新了，同时 &lt;code&gt;guid&lt;/code&gt; 可以唯一标识一个 rss 条目，所以将所有条目标题合一用于生成 &lt;code&gt;guid&lt;/code&gt; 即可，下面是关于 guid 的介绍：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;guid: A string that uniquely identifies the item.&lt;/p&gt;
&lt;p&gt;引自：&lt;a href=&#34;https://www.rssboard.org/rss-specification&#34;&gt;rss 标准&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最后，&lt;code&gt;ctx.state.data&lt;/code&gt; 生成了一个 rss，&lt;code&gt;title&lt;/code&gt; 用于标识 rss 标题，&lt;code&gt;link&lt;/code&gt; 为原网址（tophub.today），&lt;code&gt;item&lt;/code&gt; 为一个数组，保存了最新的条目，具体可参考 &lt;a href=&#34;https://www.rssboard.org/rss-specification&#34;&gt;rss 标准&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;编写渲染模版&#34;&gt;编写渲染模版&lt;/h2&gt;
&lt;p&gt;编辑 &lt;code&gt;template/rank.art&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;table&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;thead&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;tr&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;th&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;排名&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;th&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;th&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;标题&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;th&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;th&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;热度&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;th&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;tr&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;thead&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;tbody&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    {{each items}}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;tr&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;td&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;{{ $index + 1 }}&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;td&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;td&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;          &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{{ $value.link }}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;            {{ $value.title }}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;          &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;a&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;td&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;td&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;{{ $value.heatRate }}&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;td&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;tr&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;    {{/each}}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;tbody&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;table&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里用 &lt;code&gt;each&lt;/code&gt; 操作遍历传入的 &lt;code&gt;items&lt;/code&gt;，&lt;code&gt;$index&lt;/code&gt; 为下标，&lt;code&gt;$value&lt;/code&gt; 为对应值，具体语法可以参考&lt;a href=&#34;https://aui.github.io/art-template/&#34;&gt;官方文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;另外注意传入 &lt;code&gt;items&lt;/code&gt; 的方式：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;art&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;path&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;join&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;__dirname&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;templates/rank.art&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;),&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt; items &lt;span style=&#34;color:#eceff4&#34;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;传入的是一个 object，需要用 {} 扩住 &lt;code&gt;items&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id=&#34;定义路由维护者&#34;&gt;定义路由维护者&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// maintainer.js
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;module&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;exports &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;/list/:id&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;akynazh&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;],&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;/list/:id&lt;/code&gt; 这个路由对应 &lt;code&gt;github.com/akynazh&lt;/code&gt; 这个开发者。&lt;/p&gt;
&lt;p&gt;注意同一路由可有多个维护者，feat 和 fix 提交都可以加入该路由的维护者名单。&lt;/p&gt;
&lt;h2 id=&#34;编写路由文档&#34;&gt;编写路由文档&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;website/docs/routes&lt;/code&gt; 下编写路由对应的文档，方便用户使用，首先确定路由类型，这里可以认为是新媒体，所以编辑 &lt;code&gt;new-media.mdx&lt;/code&gt; 即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-md&#34; data-lang=&#34;md&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#88c0d0;font-weight:bold&#34;&gt;## 今日热榜 {#jin-ri-re-bang}
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#88c0d0;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;:::warning
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;由于需要登录后的 Cookie 值才能获取原始链接，所以需要自建，需要在环境变量中配置 &lt;span style=&#34;color:#a3be8c&#34;&gt;`TOPHUB_COOKIE`&lt;/span&gt;，详情见部署页面的配置模块。
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;:::
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#88c0d0;font-weight:bold&#34;&gt;### 榜单列表 {#jin-ri-re-bang-bang-dan-lie-biao}
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#88c0d0;font-weight:bold&#34;&gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Route&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;author&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;akynazh&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;example&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/tophub/list/Om4ejxvxEN&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;path&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/tophub/list/:id&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;paramsDesc&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;{[&amp;#39;榜单id，可在&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;URL&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;中找到&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;&amp;#39;]}&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;{#jin-ri-re-bang}&lt;/code&gt; 定义了中文名对应的拼写名，用于快速定位。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:::warning:::&lt;/code&gt; 定义了一个重要注意事项模块，其他模块可参考官方文档。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Route&lt;/code&gt; 标签定义了一条路由。&lt;/p&gt;
&lt;h2 id=&#34;支持-radar-插件&#34;&gt;支持 Radar 插件&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;module&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;exports &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;tophub.today&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;        _name&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;今日热榜&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;            &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;                title&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;榜单列表&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;                docs&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;https://docs.rsshub.app/routes/new-media#jin-ri-re-bang-bang-dan-lie-biao&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;                source&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;/n/:id&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;],&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;                target&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;/tophub/list/:id&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;            &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;],&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;docs&lt;/code&gt; 为文档地址。&lt;code&gt;source&lt;/code&gt; 为原路由，&lt;code&gt;target&lt;/code&gt; 为目标路由，通过 &lt;code&gt;:id&lt;/code&gt; 映射了 &lt;code&gt;id&lt;/code&gt; 值，另外 target 还支持更复杂的操作（比如正则），具体可参考官方文档。&lt;/p&gt;
&lt;h2 id=&#34;配置环境变量&#34;&gt;配置环境变量&lt;/h2&gt;
&lt;p&gt;前面我们通过 &lt;code&gt;config.tophub.cookie&lt;/code&gt; 读取 cookie，对应为全大写+下划线分隔生成的 KEY，在 RSSHub 根目录下编辑 &lt;code&gt;.env&lt;/code&gt; 即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;TOPHUB_COOKIE&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;测试&#34;&gt;测试&lt;/h2&gt;
&lt;p&gt;接着，即可在本地进行调试了，通过 curl 或者浏览器访问对应路由，注意观察逻辑是否正确和渲染效果即可。&lt;/p&gt;
&lt;p&gt;另外最好也把文档进行测试：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; website
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;pnpm i
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;pnpm run start:zh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;部署&#34;&gt;部署&lt;/h2&gt;
&lt;p&gt;测试确保没问题后可以向 RSSHub 提交合并请求，需要格外注意格式，比如新增路由为 &lt;code&gt;feat(route): xxx&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果嫌官方处理合并请求太慢，建议自己部署使用（另外需要配置变量的基本都得自己部署）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git clone git@github.com:DIYgod/RSSHub.git &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; RSSHub
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;pnpm i &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# npm install -g pnpm&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;pm2 start lib/index.js --name rsshub &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# npm install pm2 -g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里是用 &lt;code&gt;pm2&lt;/code&gt; 让 RSSHub 运行在后台，可通过 &lt;code&gt;pnpm start&lt;/code&gt; 之类的操作运行在前台。&lt;/p&gt;
&lt;p&gt;之后每次更新，拉取完代码后重启即可 &lt;code&gt;pm2 restart rsshub&lt;/code&gt;，但如果有新的依赖，需要先运行 &lt;code&gt;pnpm i&lt;/code&gt; 以更新依赖。&lt;/p&gt;
&lt;h2 id=&#34;可能出现的问题&#34;&gt;可能出现的问题&lt;/h2&gt;
&lt;p&gt;这里记录下遇到的问题，持续更新。&lt;/p&gt;
&lt;h3 id=&#34;commit-失败&#34;&gt;commit 失败&lt;/h3&gt;
&lt;p&gt;报错提示说缺少某个依赖(pinyin-pro)，是文档相关的。&lt;/p&gt;
&lt;p&gt;如果修改了文档，那么需要到 website 下运行 &lt;code&gt;pnpm i&lt;/code&gt; 安装相关依赖，以便于 commit 检查。&lt;/p&gt;
&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.rsshub.app/zh/joinus/quick-start&#34;&gt;RSSHub 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.rssboard.org/rss-specification&#34;&gt;rssboard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>InfluxDb 重要知识整理</title>
        <link>https://zhihang.org/posts/important-concepts-and-operation-records-of-influxdb/</link>
        <pubDate>Mon, 04 Dec 2023 11:40:20 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>important-concepts-and-operation-records-of-influxdb</guid>
        <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;InfluxDB 是一个用于存储和分析时间序列数据的开源数据库，对与时间相关联的数据进行分析、处理和存储时有较大的优势，比如针对某一个智能设备连续不断收集的数据，可以将其进行合理地存储和整理，从时间角度对数据进行分析以得到相关的统计数据，通过内置的 CQ 与 RP 操作，可以对大量的数据进行采样和保留。&lt;/p&gt;
&lt;p&gt;本文介绍的 InfluxDb 版本为 v2。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%89%8D%E8%A8%80&#34;&gt;前言&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%89%E8%A3%85%E4%B8%8E%E5%90%AF%E5%8A%A8&#34;&gt;安装与启动&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%87%8D%E8%A6%81%E6%A6%82%E5%BF%B5&#34;&gt;重要概念&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E7%BB%84%E7%BB%87%E5%BD%A2%E5%BC%8F&#34;&gt;数据组织形式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%87%8D%E8%A6%81%E5%AE%9A%E4%B9%89&#34;&gt;重要定义&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AD%98%E5%82%A8%E5%BC%95%E6%93%8E&#34;&gt;存储引擎&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E6%93%8D%E4%BD%9C&#34;&gt;数据操作&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%9B%E5%BB%BA%E6%95%B0%E6%8D%AE%E5%BA%93&#34;&gt;创建数据库&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E5%86%99%E5%85%A5&#34;&gt;数据写入&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E6%9F%A5%E8%AF%A2&#34;&gt;数据查询&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%AC%AC%E4%B8%89%E6%96%B9%E6%8E%A5%E5%8F%A3%E4%BD%BF%E7%94%A8&#34;&gt;第三方接口使用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8F%82%E8%80%83%E6%96%87%E6%A1%A3&#34;&gt;参考文档&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;安装与启动&#34;&gt;安装与启动&lt;/h2&gt;
&lt;p&gt;这里暂时只记录了 MacOS 的操作步骤。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# install influxdb and its cli tool&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;brew install influxdb influxdb-cli
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# start influxdb | listen 8086&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;influxd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动成功后，访问 &lt;code&gt;localhost:8086&lt;/code&gt; 根据提示完成用户初始化，并得到一个认证 token 用于 API 调用。influxdb 默认将数据保存在 &lt;code&gt;~/.influxdbv2&lt;/code&gt; 目录下面。&lt;/p&gt;
&lt;h2 id=&#34;重要概念&#34;&gt;重要概念&lt;/h2&gt;
&lt;h3 id=&#34;数据组织形式&#34;&gt;数据组织形式&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;bucket: 存储时序数据的地方，一个 bucket 可以包含多个 measurement，相当于 database&lt;/li&gt;
&lt;li&gt;measurement: 用于描述时序数据，包含 timestamp, tags 和 fields，相当于 table&lt;/li&gt;
&lt;li&gt;timestamp: 记录时序数据的时间&lt;/li&gt;
&lt;li&gt;tag: 键值对，用于标识一个时序数据的特点&lt;/li&gt;
&lt;li&gt;field: 键值对，用于记录时序数据的具体值&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;第一次接触 bucket 的概念，可能会有所疑惑，下面是官方的解释：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A bucket is a named location where data is stored that has a retention policy. It&amp;rsquo;s similar to an InfluxDB v1. x “database,” but is a combination of both a database and a retention policy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也就是说它类似于 v1 版本中的 &amp;ldquo;database&amp;rdquo;，但是多了一个数据保存策略。&lt;/p&gt;
&lt;p&gt;时序数据通常是海量的，对其进行合适的数据清理和保存是十分重要的，每个数据库对应着一个数据保存策略以适应于实际场景的使用。&lt;/p&gt;
&lt;p&gt;在一个 bucket 中，插入每条数据需要遵循以下格式（行协议）：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/important-concepts-and-operation-records-of-influxdb/image/1706000856893.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;重要定义&#34;&gt;重要定义&lt;/h3&gt;
&lt;p&gt;Point 和 Series 是官方列出的两个重要定义。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Point: Single data record identified by its measurement, tag keys, tag values, field key, and timestamp.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Point 其实就相当于数据库表中的一条记录。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Series: A group of points with the same measurement, tag keys, and tag values.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Series 可以理解为同一 measurement 中具有相同 tag 的数据组成的数据集。&lt;/p&gt;
&lt;h3 id=&#34;存储引擎&#34;&gt;存储引擎&lt;/h3&gt;
&lt;p&gt;TSM 采用了类似于 LSM 的存储思路，LSM 是许多 NOSQL 采用的存储引擎，大致的过程如下图(来源网络)：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/important-concepts-and-operation-records-of-influxdb/image/1701784062047.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;LSM 树核心思想的核心就是放弃部分读能力，换取写入的最大化能力。&lt;/p&gt;
&lt;p&gt;LSM 假定不需要每次有数据更新就必须同时将数据写入到磁盘中，而可以先将最新的数据驻留在内存中，等到积累到足够多之后再使用归并排序的方式将内存内的数据合并追加到磁盘队尾(因为所有待排序的树都是有序的，可以通过合并排序的方式快速合并到一起)。&lt;/p&gt;
&lt;p&gt;这也就是 LSM 在某些情况比 B+ 树更合适的原因，如果你的场景一直需要大量的写入，而不需要很多读取和修改操作，推荐使用 LSM，比如时序数据的存储，一般不会进行任何修改操作而会有海量的写入操作。&lt;/p&gt;
&lt;p&gt;TSM 存储流程大同小异，如下所述：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Batches of points are sent to InfluxDB, compressed, and written to a WAL for immediate durability. Points are also written to an in-memory cache and become immediately queryable. The in-memory cache is periodically written to disk in the form of TSM files. As TSM files accumulate, the storage engine combines and compacts accumulated them into higher level TSM files.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;批量的 points 将会被写或更新到 cache 中并将操作写入 wal 中以确保在宕机之类的情况发生时数据的可恢复性。cache 中的数据按 series key 有序地被组织好，且会周期性地写入到磁盘中，以 TSM 文件的格式存储着。&lt;/p&gt;
&lt;p&gt;对于 TSM 文件，TSM 全称 Time-Structured Merge Tree，即时间结构化归并树，从名字可以大概推知其组织数据的形式，下面是官方解释：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To efficiently compact and store data, the storage engine groups field values by series key, and then orders those field values by time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;根据 series key 分组数据，并且将他们根据时间排序好。&lt;/p&gt;
&lt;p&gt;其中 series key 由 measurement, tag key &amp;amp; value, field key 进行定义。&lt;/p&gt;
&lt;p&gt;那么 TSM 如何一步步地合并与分组数据的呢？它大致是基于分级压缩的策略来进行的，当多个一级数据达到一定大小后会合并压缩为二级数据，直到达到四级数据，然后将会为这些数据分出一个新的 TSM 文件，所有具有相同 series key 的数据将为位于同一 TSM 文件中，这样确保了索引数据的效率，因为数据是连续的。&lt;/p&gt;
&lt;h2 id=&#34;数据操作&#34;&gt;数据操作&lt;/h2&gt;
&lt;h3 id=&#34;创建数据库&#34;&gt;创建数据库&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;influx bucket create &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--org&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$org&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--token&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$token&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--name&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$bucket&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--retention &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3d&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--shard-group-duration &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;1h&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该语句创建了一个 bucket，其中数据保留 3 天，分片时间跨度为 1 小时。&lt;/p&gt;
&lt;p&gt;分片是时间序列数据的横向分区，每个分片包含其指定时间范围内的时间序列数据子集。在这个例子中，由于数据最多保留 3 天，分片时间跨度为 1 小时，那么将产生 3 * 24 个分片。&lt;/p&gt;
&lt;p&gt;分片持续期的选择影响查询性能、数据压缩和存储效率，需要仔细考虑后进行使用。&lt;/p&gt;
&lt;h3 id=&#34;数据写入&#34;&gt;数据写入&lt;/h3&gt;
&lt;p&gt;influxdb 在插入数据时自动创建 measurement，插入数据的格式需要符合行协议。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;influx write &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--org&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$org&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--token&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$token&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--bucket $bucket &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--precision s &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;health_data_t1,cardId=&amp;#39;20181214062&amp;#39;,type=1 heartrate=80,bloodOxygen=97,microcirculation=80 1706002825
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;health_data_t1,cardId=&amp;#39;20181215062&amp;#39;,type=1 heartrate=81,bloodOxygen=87,microcirculation=81 1706002825
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;health_data_t1,cardId=&amp;#39;20181214072&amp;#39;,type=1 heartrate=82,bloodOxygen=98,microcirculation=80 1706002825
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;health_data_t1,cardId=&amp;#39;20181214052&amp;#39;,type=1 heartrate=80,bloodOxygen=97,microcirculation=84 1706002825
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;health_data_t1,cardId=&amp;#39;20181212062&amp;#39;,type=1 heartrate=86,bloodOxygen=99,microcirculation=80 1706002825
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;health_data_t1,cardId=&amp;#39;20181214162&amp;#39;,type=1 heartrate=80,bloodOxygen=97,microcirculation=82 1706002825
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以上操作将创建一个名为 health_data_t1 的 measurement，有 cardId，type 这两个 tag，有 heartrate，bloodOxygen，microcirculation 这三个 field，最后跟着的是时间戳，通过 &lt;code&gt;--precision&lt;/code&gt; 指定其单位为 s（如果不是纳秒级都需要自己指定单位）。&lt;/p&gt;
&lt;h3 id=&#34;数据查询&#34;&gt;数据查询&lt;/h3&gt;
&lt;p&gt;influx 支持通过 flux 和 influxql(sql) 进行查询，flux 更为灵活而强大，下面只介绍 flux。&lt;/p&gt;
&lt;p&gt;如下是一个查询示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;influx query &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--org&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$org&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--token&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$token&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;from(bucket: &amp;#34;equipments&amp;#34;)
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    |&amp;gt; range(start: 2024-01-23T16:00:00Z, stop: 2024-01-23T19:00:01Z)
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    |&amp;gt; filter(fn: (r) =&amp;gt; r._measurement == &amp;#34;health_data_t1&amp;#34;)
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    |&amp;gt; filter(fn: (r) =&amp;gt; r._field == &amp;#34;heartrate&amp;#34;)
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要注意数据中时间的时区以 UTC 作为标准，如果需要使用当地时间，比如中国，则修改时间范围为如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;range&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;start: 2024-01-23T16:00:00+08:00, stop: 2024-01-23T19:00:01+08:00&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更多用法记录：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 映射操作&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;|&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;map&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;fn&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;r&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;({&lt;/span&gt;r &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;with&lt;/span&gt; _value&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; r&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;_value &lt;span style=&#34;color:#81a1c1&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;100.0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}))&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 求平均值&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;|&amp;gt;&lt;/span&gt; mean&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 定时任务&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;option task &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;name&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;downsample_5m_precision&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; every&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;h&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; offset&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;m&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;from&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;bucket&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;equipments&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;|&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;range&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;start&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;task&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;every&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;|&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;filter&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;fn&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;r&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; r&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;_measurement &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;mem&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;and&lt;/span&gt; r&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;host &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;myHost&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;|&amp;gt;&lt;/span&gt; aggregateWindow&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;every&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;m&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; fn&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; mean&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;|&amp;gt;&lt;/span&gt; to&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;bucket&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;equipments-downsample&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中，定时任务每一小时执行一次，时间偏移为 0，时间窗口设为五分钟，对五分钟内的数据取平均值得到新的数据，然后存入新的 bucket 中，一般新的 bucket 会采用时间更长的保存策略。&lt;/p&gt;
&lt;h2 id=&#34;第三方接口使用&#34;&gt;第三方接口使用&lt;/h2&gt;
&lt;p&gt;这里记录下 Java 的接入方式。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.influxdb&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;influxdb-client-java&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;6.6.0&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;官方提供了三种写入方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use InfluxDB Line Protocol to write data（行协议的方式）&lt;/li&gt;
&lt;li&gt;Use a Data Point to write data（Point 方式）&lt;/li&gt;
&lt;li&gt;Use POJO and corresponding class to write data（POJO 映射方式）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这里采用第二种作为示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;String url &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://localhost:8086&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;String token &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;your_token&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;String bucket &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;String org &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;xdu&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;try&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;InfluxDBClient client &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; InfluxDBClientFactory&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;create&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;url&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        token&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;toCharArray&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(),&lt;/span&gt; org&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; bucket&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    Point p &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; Point&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;measurement&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;cpu&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;addTag&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;host&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;serverB&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;addTag&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;region&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;cn&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;addField&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;2318&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;addField&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;value1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;8238&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;addField&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;value2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;s1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;time&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Instant&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;now&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(),&lt;/span&gt; WritePrecision&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;NS&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    client&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getWriteApiBlocking&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;writePoint&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;p&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Exception e&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getMessage&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查询操作可以直接通过 flux 脚本完成。找出过去 12h 内 measurement 为 &amp;ldquo;cpu&amp;rdquo;，host 为 &amp;ldquo;serverB&amp;rdquo;，且展现 field 为 &amp;ldquo;value1&amp;rdquo;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;String query &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;from(bucket:\&amp;#34;test\&amp;#34;)\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;  |&amp;gt; range(start: -12h)\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;  |&amp;gt; filter(fn: (r) =&amp;gt;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;    r._measurement == \&amp;#34;cpu\&amp;#34; and\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;    r._field == \&amp;#34;value1\&amp;#34; and\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;    r.host == \&amp;#34;serverB\&amp;#34;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;  )&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着调用该脚本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;List&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;FluxTable&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; tables &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; client&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getQueryApi&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;query&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;query&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; org&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;FluxTable table &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; tables&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;FluxRecord record &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; table&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getRecords&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;())&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;record&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getValues&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;参考文档&#34;&gt;参考文档&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.influxdata.com/influxdb/v2&#34;&gt;InfluxDb 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jasper-zhang1.gitbooks.io/influxdb&#34;&gt;InfluxDb 第三方中文文档&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>QuantumultX 重要使用记录</title>
        <link>https://zhihang.org/posts/quantum-streaming-rewriting-fast-configuration/</link>
        <pubDate>Sat, 11 Nov 2023 23:51:44 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>quantum-streaming-rewriting-fast-configuration</guid>
        <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;本文记录了通过 QuantumultX 配置代理，书写分流规则，抓包分析并重写规则，启用定时任务等简易操作流程，另外还记录了其他一些相关操作。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%89%8D%E8%A8%80&#34;&gt;前言&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%85%8D%E7%BD%AE%E4%BB%A3%E7%90%86&#34;&gt;配置代理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B9%A6%E5%86%99%E5%88%86%E6%B5%81%E8%A7%84%E5%88%99&#34;&gt;书写分流规则&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%8A%93%E5%8C%85%E5%88%86%E6%9E%90%E5%B9%B6%E9%87%8D%E5%86%99%E8%A7%84%E5%88%99&#34;&gt;抓包分析并重写规则&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%AE%BE%E7%BD%AE%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1&#34;&gt;设置定时任务&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%85%8D%E7%BD%AE-geoip-%E6%95%B0%E6%8D%AE%E5%BA%93%E6%BA%90&#34;&gt;配置 GeoIP 数据库源&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#ios-%E4%B8%8E-macos-%E9%85%8D%E7%BD%AE%E5%8F%8C%E5%90%91%E5%90%8C%E6%AD%A5&#34;&gt;IOS 与 MacOS 配置双向同步&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;配置代理&#34;&gt;配置代理&lt;/h2&gt;
&lt;p&gt;可以导入自己搭建的节点，也可以通过引用导入 QuantumultX 格式的订阅链接，步骤比较简单略过，记录一个点，如果相关机场不支持 QuantumultX 格式的订阅，可以通过解析器完成转换，在配置中引用转换脚本即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;general&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;resource_parser_url&lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;https&lt;span style=&#34;color:#bf616a&#34;&gt;://&lt;/span&gt;raw&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;githubusercontent&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;com&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;KOP-XIAO&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;QuantumultX&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;master&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;Scripts&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;resource-parser&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;resource-parser.js&lt;/code&gt; 是 github 上的一个资源解析转换脚本，主要功能是将其它格式的订阅解析成 QuantumultX 格式的订阅，以及可以对引用的重写/分流规则进行转换和筛选。&lt;/p&gt;
&lt;h2 id=&#34;书写分流规则&#34;&gt;书写分流规则&lt;/h2&gt;
&lt;p&gt;分流规则可以简单理解，就是对某一类地址进行分流，通过一定的分流策略来处理这些地址的相关请求，这里以一个例子引入：&lt;/p&gt;
&lt;p&gt;我需要在访问 &lt;code&gt;*.dmm.co.jp&lt;/code&gt; 这类日本网址时使用日本节点，那么可以首先创建一个分流策略，名为 Japan，类型可以选择 avaiable(可用性) 或者 static(静态指定)，也可以视情况选择如负载均衡之类的其他策略，匹配的节点标签可以根据自己的日本节点名称来填写，比如“日本”。&lt;/p&gt;
&lt;p&gt;接着可以书写分流规则，host 需要填写一个正则式，这里就填 &lt;code&gt;*.dmm.co.jp&lt;/code&gt;，类型即是 &lt;code&gt;HOST-WILDCARD&lt;/code&gt;(通配符类型)，策略即指定为 Japan。&lt;/p&gt;
&lt;p&gt;以上操作同样都可通过直接编辑配置文件完成：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;filter_local&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;host-wildcard&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;dmm&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;co&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;jp&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; Japan
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;policy&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;available&lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;Japan&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; server-tag-regex&lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;日本&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; img-url&lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;🇯🇵&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;抓包分析并重写规则&#34;&gt;抓包分析并重写规则&lt;/h2&gt;
&lt;p&gt;由于很多请求是 https 的，为了抓包和重写 https 请求，需要安装并信任证书。&lt;/p&gt;
&lt;p&gt;首先在设置界面开启重写和 MitM(中间人攻击)，然后点击生成、配置证书。&lt;/p&gt;
&lt;p&gt;接着，对于 IOS，需要在设置界面信任证书。对于 MacOS，点击生成证书会在 Safari 完成生成，然后双击证书在 Keychain Access 应用进行信任操作，如提示不可安装，则手动从 finder 将证书拖到 Keychain Access 的 login 列表中。&lt;/p&gt;
&lt;p&gt;完成以上步骤后，即可开启 Http 抓取功能进行抓包和重写规则了，注意对于每个 https 请求，需要在 mitm 处添加对应的域名才能进行抓包和重写，而 http 请求则不用。&lt;/p&gt;
&lt;p&gt;下面以屏蔽知乎的开屏广告为例子来进行一次规则重写。&lt;/p&gt;
&lt;p&gt;开启抓包，如果是通过 http 加载的广告则很方便，直接开始抓包，但一些广告的加载可能是通过 https 加载，所以可以先通过 Activity 观察一下一些可能的 https 广告网址，然后在 mitm 处配置域名。&lt;/p&gt;
&lt;p&gt;打开知乎加载开屏广告，抓包发现加载开屏广告图片的请求为:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;http://images.pinduoduo.com/marketing_api/2023-11-09/ce00e978-7d7f-11ee-81f3-0a580a4a3166.png?filtered=pread&amp;amp;filtered=pread
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是一个 http 请求，我们就可以通过一个正则式来 reject 这类请求，添加重写规则，类型可以指定为 reject，匹配的 url 为以下正则式：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;^https?:&lt;span style=&#34;color:#ebcb8b&#34;&gt;\/\/&lt;/span&gt;images&lt;span style=&#34;color:#ebcb8b&#34;&gt;\.&lt;/span&gt;pinduoduo&lt;span style=&#34;color:#ebcb8b&#34;&gt;\.&lt;/span&gt;com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;考虑到同网址可能有 https 相关的广告，可以在 mitm 处再添加 &lt;code&gt;images.pinduoduo.com&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;接着重新打开知乎，发现开屏广告已经不出现了。注意这只是一个简陋的例子，很多广告是通过 https 加载的，广告地址可能动态变化且繁多，需要更多更复杂的匹配，建议直接引用社区维护的规则：&lt;a href=&#34;https://github.com/blackmatrix7/ios_rule_script/tree/master/rewrite/QuantumultX/AdvertisingLite&#34;&gt;AdvertisingLite&lt;/a&gt;，但是不保证一直可用，关键还需自己抓包分析。&lt;/p&gt;
&lt;p&gt;同样以上操作对应到配置文件如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;rewrite_local&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;^&lt;/span&gt;https&lt;span style=&#34;color:#bf616a&#34;&gt;?:\/\/&lt;/span&gt;images&lt;span style=&#34;color:#bf616a&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;pinduoduo&lt;span style=&#34;color:#bf616a&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;com url reject
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;mitm&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;hostname &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; images&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;pinduoduo&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;设置定时任务&#34;&gt;设置定时任务&lt;/h2&gt;
&lt;p&gt;QuantumultX 支持以 crontab 格式设置定时任务，任务脚本为 js 脚本，可以实现定时签到等操作，具体可以自行抓包分析并书写自动化脚本。&lt;/p&gt;
&lt;p&gt;下面以书写一个简单的定时汇率播报脚本为例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// currency.js
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; from_cur &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;USD&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; to_cur &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;CNY&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; amount &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; token &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;your_exchangerate-api_token&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; url &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;`https://v6.exchangerate-api.com/v6/&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;token&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;/pair/&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;from_cur&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;to_cur&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;amount&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;`&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; method &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; headers &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{};&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; data &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{};&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;const&lt;/span&gt; myRequest &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    url&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; url&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    method&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; method&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    headers&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; headers&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    body&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; JSON&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;stringify&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;data&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;$task&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;fetch&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;myRequest&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;then&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;response &lt;span style=&#34;color:#eceff4&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; m &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; JSON&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;parse&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;response&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;body&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;conversion_result&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;    $notify&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;今日汇率 -- 美元兑人民币&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;`&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;m&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;`&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 中间那个是副标题
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    $done&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt; reason &lt;span style=&#34;color:#eceff4&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;    $notify&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;今日汇率 -- 美元兑人民币&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; reason&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;error&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// Error!
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    $done&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中注意这几个 QuantumultX 提供的 API:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;$task.fetch&lt;/code&gt; 可以触发定时任务发送 http 请求&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$notify&lt;/code&gt; 可以方便地调用系统通知&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$done&lt;/code&gt; 标志一个任务的完成&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;接着把脚本放到 &lt;code&gt;Quantumult X/Scripts/&lt;/code&gt; 这个文件夹下，然后编写配置，在早上 10 点定时播报汇率情况：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;task_local&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;*&lt;/span&gt; currency&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;js&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; tag&lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;今日汇率&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; enabled&lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;另外，QuantumultX 还支持引用社区的脚本，但是感觉不太安全，建议阅读完代码确认没问题再引用。&lt;/p&gt;
&lt;h2 id=&#34;配置-geoip-数据库源&#34;&gt;配置 GeoIP 数据库源&lt;/h2&gt;
&lt;p&gt;目前市面上绝大多数的代理工具都依赖于 GeoIP2 数据库判断地址所属地，QuantumultX 也不例外。GeoIP2 数据库是来自于 MaxMind 的 GeoLite2 免费数据库，据官方说法，这个数据库目前存在一下几个问题：获取不便，数据量大，准确度低。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/Hackl0us/GeoIP2-CN&#34;&gt;GeoIP2-CN&lt;/a&gt; 是一个小巧精悍、准确、实用 GeoIP2 数据库，而支持 QuantumultX，在设置页的 GeoLite2 项设置来源为如下链接，即可引用 GeoIP2-CN：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;https://github.com/Hackl0us/GeoIP2-CN/raw/release/Country.mmdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;ios-与-macos-配置双向同步&#34;&gt;IOS 与 MacOS 配置双向同步&lt;/h2&gt;
&lt;p&gt;首先在每个端的设置-资源开启 icloud，然后在一个端的关联配置下点击 icloud 新增 profile，然后其他端都 link profile，之后即可实现双向同步，默认有更新延迟，可以点击立即更新强制更新。&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Git 重要用法整理</title>
        <link>https://zhihang.org/posts/git-important-operations-and-knowledge-summary/</link>
        <pubDate>Fri, 15 Sep 2023 19:42:58 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>git-important-operations-and-knowledge-summary</guid>
        <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;这里记录一些重要的 Git 操作和知识, 随着学习和工作中遇到的 git 相关问题而持续更新。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%89%8D%E8%A8%80&#34;&gt;前言&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%9D%E5%A7%8B%E5%8C%96%E9%85%8D%E7%BD%AE&#34;&gt;初始化配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%9D%E5%A7%8B%E5%8C%96%E4%BB%93%E5%BA%93&#34;&gt;初始化仓库&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#head-%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86&#34;&gt;HEAD 相关知识&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BB%A3%E7%A0%81%E7%9A%84%E6%8F%90%E4%BA%A4%E4%B8%8E%E4%BF%AE%E6%94%B9&#34;&gt;代码的提交与修改&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BF%AE%E6%94%B9%E4%B8%8A%E6%AC%A1%E6%8F%90%E4%BA%A4&#34;&gt;修改上次提交&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BF%AE%E6%94%B9%E5%A4%9A%E6%AC%A1%E6%8F%90%E4%BA%A4&#34;&gt;修改多次提交&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8F%96%E6%B6%88%E6%88%96%E5%88%A0%E9%99%A4%E6%8F%90%E4%BA%A4&#34;&gt;取消或删除提交&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8F%96%E6%B6%88%E6%88%96%E7%A7%BB%E5%8A%A8%E6%9C%AA%E6%8F%90%E4%BA%A4%E7%9A%84%E6%9B%B4%E6%94%B9&#34;&gt;取消或移动未提交的更改&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%90%88%E5%B9%B6%E6%9F%90%E5%87%A0%E4%B8%AA%E6%8F%90%E4%BA%A4&#34;&gt;合并某几个提交&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%9B%86%E6%88%90%E6%9F%90%E5%87%A0%E4%B8%AA%E6%8F%90%E4%BA%A4&#34;&gt;集成某几个提交&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%90%88%E5%B9%B6%E4%B8%8A%E6%B8%B8%E5%88%86%E6%94%AF&#34;&gt;合并上游分支&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%A1%E6%9F%A5%E5%90%8C%E4%BA%8B%E6%8F%90%E4%BA%A4&#34;&gt;审查同事提交&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BB%A3%E7%A0%81%E6%81%A2%E5%A4%8D%E6%8A%A2%E6%95%91&#34;&gt;代码恢复抢救&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%81%A2%E5%A4%8D%E4%B8%A2%E5%BC%83%E7%9A%84-stash-%E6%95%B0%E6%8D%AE&#34;&gt;恢复丢弃的 stash 数据&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%9F%A5%E7%9C%8B%E6%88%96%E6%81%A2%E5%A4%8D%E8%A2%AB%E8%A6%86%E7%9B%96%E6%8E%89%E7%9A%84%E6%8F%90%E4%BA%A4%E5%8E%86%E5%8F%B2&#34;&gt;查看或恢复被覆盖掉的提交历史&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%BC%80%E6%BA%90%E4%BB%93%E5%BA%93%E5%89%8D%E6%B8%85%E9%99%A4%E5%8E%86%E5%8F%B2%E6%8F%90%E4%BA%A4&#34;&gt;开源仓库前清除历史提交&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AD%90%E6%A8%A1%E5%9D%97%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C&#34;&gt;子模块相关操作&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AD%90%E6%A8%A1%E5%9D%97%E5%88%9D%E5%A7%8B%E5%8C%96%E5%8F%8A%E6%9B%B4%E6%96%B0%E6%96%B9%E6%B3%95&#34;&gt;子模块初始化及更新方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%8C%E5%85%A8%E7%A7%BB%E9%99%A4%E5%AD%90%E6%A8%A1%E5%9D%97%E7%9A%84%E6%96%B9%E6%B3%95&#34;&gt;完全移除子模块的方法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%9E%84%E5%BB%BA%E8%87%AA%E5%B7%B1%E7%9A%84-git-%E5%AD%98%E5%82%A8%E5%BA%93&#34;&gt;构建自己的 Git 存储库&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#license-%E9%85%8D%E7%BD%AE&#34;&gt;License 配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#commit-%E8%A7%84%E8%8C%83&#34;&gt;Commit 规范&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%A0%BC%E5%BC%8F-format&#34;&gt;格式 Format&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%BB%E9%A2%98-subject&#34;&gt;主题 Subject&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%B1%BB%E5%9E%8B-type&#34;&gt;类型 Type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BD%9C%E7%94%A8%E5%9F%9F-scope&#34;&gt;作用域 Scope&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%BB%E4%BD%93-body&#34;&gt;主体 Body&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%84%9A%E6%B3%A8-footer&#34;&gt;脚注 Footer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9B%9E%E9%80%80-revert&#34;&gt;回退 Revert&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#git-alias&#34;&gt;Git Alias&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%BB%BA%E8%AE%AE%E7%94%A8%E6%B3%95&#34;&gt;建议用法&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BD%BF%E7%94%A8-rebase-%E6%9D%A5%E9%9B%86%E6%88%90%E5%85%B6%E4%BB%96%E5%88%86%E6%94%AF%E4%BF%AE%E6%94%B9&#34;&gt;使用 rebase 来集成其他分支修改&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BD%BF%E7%94%A8-fast-forward-%E6%9D%A5%E9%9B%86%E6%88%90%E5%85%B6%E4%BB%96%E5%88%86%E6%94%AF%E4%BF%AE%E6%94%B9&#34;&gt;使用 fast-forward 来集成其他分支修改&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reference&#34;&gt;Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;初始化配置&#34;&gt;初始化配置&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 配置用户&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;git config --global user.name &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;akynazh&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;git config --global user.email &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;akynazh@gmail.com&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 禁用换行符自动转换&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;git config --global core.autocrlf &lt;span style=&#34;color:#81a1c1&#34;&gt;false&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 配置 http 代理&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;git config --global http.proxy &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://127.0.0.1:7890&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;git config --global https.proxy &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://127.0.0.1:7890&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 设置 commit 编辑工具为 vim&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;git config --global core.editor &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;vim&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 配置 SSH 代理&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 编辑 ~/.ssh/config 如下:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;#########################################################&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;Host github.com
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;    User git
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;    Port &lt;span style=&#34;color:#b48ead&#34;&gt;22&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;    Hostname github.com
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;    IdentityFile ~/.ssh/id_rsa
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# Winodws&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# ProxyCommand connect -S 127.0.0.1:7890 -a none %h %p&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# Mac&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;    ProxyCommand nc -X &lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt; -x 127.0.0.1:7890 %h %p
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;Host ssh.github.com
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;    User git
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;    Port &lt;span style=&#34;color:#b48ead&#34;&gt;443&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;    Hostname ssh.github.com
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;    IdentityFile ~/.ssh/id_rsa
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# Winodws&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# ProxyCommand connect -S 127.0.0.1:7890 -a none %h %p&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# Mac&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;    ProxyCommand nc -X &lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt; -x 127.0.0.1:7890 %h %p
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;38&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# connect 命令是在 Windows 中位于 git 安装目录下的一个操作命令, 位置大致在：C:\Program Files\Git\mingw64\bin\connect.exe&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;39&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# nc 为 netcat 可通过 brew, apt 安装&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;40&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;#########################################################&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;41&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;42&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 如果使用 HTTP 进行 Git 拉取或推送，需要使用 ACCESS_TOKEN&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;43&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# Username for &amp;#39;https://github.com&amp;#39;: akynazh&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;44&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# Password for &amp;#39;https://akynazh@github.com&amp;#39;: (输入 ACCESS_TOKEN)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;45&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 为了避免重复输入，对 TOKEN 进行持久化：&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;46&lt;/span&gt;git config --global credential.helper store
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;初始化仓库&#34;&gt;初始化仓库&lt;/h2&gt;
&lt;p&gt;首先从代码托管网站建立一个仓库，获取仓库地址 url (如果是 ssh 类型的 url, 需要上传本机公钥)，然后进入项目所在文件夹，运行以下代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;url&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;your_repo_url&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git init &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 初始化仓库，生成.git文件&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;git add . &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 将项目文件的修改信息添加到 .git 内的一个暂存区（index）&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;git commit -m “init” &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 将暂存区的修改信息提交到分支&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;git remote add origin $url &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 添加远程仓库&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;git push origin master &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 将本地分支推送到远程仓库&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里执行完 &lt;code&gt;git commit -m &amp;quot;init&amp;quot;&lt;/code&gt; 后，我们查看一下本地分支信息：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&amp;gt; git branch
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;* master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可见 git 自动为我们本地创建了一个 master 分支。&lt;/p&gt;
&lt;p&gt;执行完 &lt;code&gt;git push origin master&lt;/code&gt; 后，我们查看一下本地分支与远程分支的映射关系：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&amp;gt; git branch -a
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;* master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;  remotes/origin/master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&amp;gt; git branch -vv
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;* master 3a31f4c init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可见并没有产生映射。所以如果直接使用 &lt;code&gt;git push&lt;/code&gt; 提交代码会报错，因为 git 不知道你要提交到哪个远程分支。为了方便提交, 我们可以建立映射关系:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git branch -u origin/dev_r 将当前分支与远程分支 dev_r 建立映射关系
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果建立了映射关系，那么以后在当前分支 &lt;code&gt;git push&lt;/code&gt; 时默认 push 到与当前分支建立关系的那个远程分支。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实际操作如下：&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&amp;gt; git branch -u origin/master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;Branch &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;master&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;set&lt;/span&gt; up to track remote branch &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;master&amp;#39;&lt;/span&gt; from &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;origin&amp;#39;&lt;/span&gt;.
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&amp;gt; git branch -vv
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;* master 3a31f4c &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;origin/master&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; init &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 可看见产生了映射关系：master &amp;lt;&amp;gt; origin/master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;head-相关知识&#34;&gt;HEAD 相关知识&lt;/h2&gt;
&lt;p&gt;HEAD 代表当前分支的最新提交名称，它可以由一些修饰符进行修饰进而产生不同的含义。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关于 HEAD~{n}&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;~&lt;/code&gt; 是用来在当前提交路径上回溯的修饰符。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HEAD~{n}&lt;/code&gt; 表示当前所在的提交路径上的前 n 个提交（n &amp;gt;= 0）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HEAD = HEAD~0&lt;/code&gt; （即当前最新的一次commit）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HEAD~ = HEAD~1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HEAD~~ = HEAD~2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;关于 HEAD^{n}&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;^&lt;/code&gt; 是用来切换父级提交路径的修饰符。&lt;/p&gt;
&lt;p&gt;当我们始终在一个分支比如 dev 开发/提交代码时，每个 commit 都只会有一个父级提交，就是上一次提交。此时 &lt;code&gt;HEAD~1&lt;/code&gt; 等价于 &lt;code&gt;HEAD^&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;当并行多个分支开发，feat1, feat2, feat3，完成后 merge feat1 feat2 feat3 回 dev 分支后，此次的 merge commit 就会有多个父级提交。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HEAD^ = HEAD^1&lt;/code&gt; 第一个父级提交&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HEAD^2~1&lt;/code&gt; 第二个父级提交的上一次提交&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;代码的提交与修改&#34;&gt;代码的提交与修改&lt;/h2&gt;
&lt;h3 id=&#34;修改上次提交&#34;&gt;修改上次提交&lt;/h3&gt;
&lt;p&gt;这里以对提交的信息和作者进行修改为例，注意邮箱两侧由 &amp;lt;&amp;gt; 包括住&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git commit --amend --message&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;modify&amp;#34;&lt;/span&gt; --author&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;your_name &amp;lt;your_email&amp;gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git push -f
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;修改多次提交&#34;&gt;修改多次提交&lt;/h3&gt;
&lt;p&gt;首先列出近 n 次提交：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 列出最近3次提交&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git rebase -i HEAD~3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注: 进行 &lt;code&gt;git rebase&lt;/code&gt; 之前，先将本地修改提交完毕。&lt;/p&gt;
&lt;p&gt;得到大致如下内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;pick 8ae7972 update
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;pick 1a22dfd update
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;pick 00433e4 update
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;# Rebase 368e5c8..00433e4 onto 368e5c8 (3 commands)
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;#
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;# Commands:
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;# p, pick &amp;lt;commit&amp;gt; = use commit
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;# r, reword &amp;lt;commit&amp;gt; = use commit, but edit the commit message
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;# e, edit &amp;lt;commit&amp;gt; = use commit, but stop for amending
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;# s, squash &amp;lt;commit&amp;gt; = use commit, but meld into previous commit
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;# f, fixup [-C | -c] &amp;lt;commit&amp;gt; = like &amp;#34;squash&amp;#34; but keep only the previous
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;......
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可见确实列出了前面 3 次的修改记录。&lt;/p&gt;
&lt;p&gt;将需要修改的 commit-id 前面对应 “pick” 改为 “edit”，即可在后续操作中对该分支进行修改。&lt;/p&gt;
&lt;p&gt;之后，x 次修改就进行 x 次下面两条命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git commit --amend --message&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;modify&amp;#34;&lt;/span&gt; --author&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;your_name &amp;lt;your_email&amp;gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git rebase --continue
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;经过 x 次以上命令，不出什么问题的话，将会有大致如下的提示出现：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;Successfully rebased and updated refs/heads/master.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在，强制推送即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git push -f
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;取消或删除提交&#34;&gt;取消或删除提交&lt;/h3&gt;
&lt;p&gt;当你在某一次提交中不小心忘记了把一些敏感信息进行 ignore，那么你很可能需要删除那一次提交。&lt;/p&gt;
&lt;p&gt;可以使用 &lt;code&gt;git reset&lt;/code&gt; 删除提交，记录将被真正删除，是将 HEAD 指向某个 commit-id， 该操作需要谨慎使用。比如, 删除上一次提交，也就是把 &lt;code&gt;HEAD&lt;/code&gt; 指向 &lt;code&gt;HEAD^&lt;/code&gt;, 追加 &lt;code&gt;--hard&lt;/code&gt; 使得工作区和暂存区里面的文件也回到以前的状态，下面是 reset 三种操作选项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ndash;soft: 重置 HEAD 到指定的提交，但保持工作目录和暂存区的更改。&lt;/li&gt;
&lt;li&gt;&amp;ndash;mixed（默认）：重置 HEAD 到指定的提交，并重置暂存区，但保持工作目录的更改。&lt;/li&gt;
&lt;li&gt;&amp;ndash;hard：重置 HEAD 到指定的提交，并重置暂存区和工作目录的所有更改。这意味着所有未提交的更改将丢失。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果使用 &lt;code&gt;git revert&lt;/code&gt; 则只是取消修改，提交记录还在，并且多生成了一次 &amp;ldquo;revert&amp;rdquo; 提交记录，而对 &amp;ldquo;revert&amp;rdquo; 提交进行 &amp;ldquo;revert&amp;rdquo; 则会恢复对应修改，并生成一次 &amp;ldquo;reapply&amp;rdquo; 提交记录。注意 revert 对于敏感信息的处理是无效的。&lt;/p&gt;
&lt;p&gt;在进行 revert 之前需要提交或贮藏(stash)本地修改，而 reset 可以无视当前工作区状态。下面是一些具体操作：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;git revert &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;倒数第一个提交&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;倒数第二个提交&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# e.g. git revert HEAD HEAD~1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 取消上次提交&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;git revert HEAD
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 接上，恢复上次提交&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;git revert HEAD
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 取消上次提交(删除提交记录, 保留工作区修改)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;git reset HEAD^
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 取消上次提交(删除提交记录, 保留工作区和暂存区修改)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;git reset --soft HEAD^
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 删除本地所有最新提交, 直接使用远程分支覆盖本地分支&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;git reset --hard origin/master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 删除上一次提交&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;git reset --hard HEAD^
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 删除某次提交&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;git reset --hard commit_id
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;取消或移动未提交的更改&#34;&gt;取消或移动未提交的更改&lt;/h3&gt;
&lt;p&gt;将本地未提交的更改合并到另一个分支:&lt;/p&gt;
&lt;p&gt;通过 stash 操作存储我们在当前分支上所做的更改, 然后我们可以切换到正确的分支并将它们应用到它上面:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git stash
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git checkout &amp;lt;right-branch&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;git stash pop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;取消本地未提交的更改:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git stash
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# git stash show&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;git stash drop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;合并某几个提交&#34;&gt;合并某几个提交&lt;/h3&gt;
&lt;p&gt;有些公司要求每个 PR 对应一个 Commit，这时就需要将多个 Commit 合并到一个 Commit 中，可以使用 &lt;code&gt;git rebase&lt;/code&gt; 命令完成，具体操作如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git rebase -i HEAD~2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这条命令会打开你默认的文本编辑器，列出最近的两个 commit，类似这样：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;pick abc1234 第一个 commit 信息
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;pick def5678 第二个 commit 信息
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;# 命令：
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;# p, pick = 使用这个 commit
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;# r, reword = 使用这个 commit，但修改提交信息
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;# s, squash = 使用这个 commit，但合并到前一个 commit 中
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;# f, fixup = 类似 squash，但丢弃提交信息
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;修改第二个 commit 的操作为 &lt;code&gt;squash&lt;/code&gt; 或 &lt;code&gt;s&lt;/code&gt; 即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;pick abc1234 第一个 commit 信息
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;s def5678 第二个 commit 信息
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;保存并关闭编辑器。接着 Git 会再次打开编辑器，让你编辑合并后的新 commit 信息。你可以保留、修改或删除部分内容。&lt;/p&gt;
&lt;p&gt;保存后，两个 commit 就成功合并为一个了。最后强制提交即可。&lt;/p&gt;
&lt;h3 id=&#34;集成某几个提交&#34;&gt;集成某几个提交&lt;/h3&gt;
&lt;p&gt;如果需要另一个分支的所有代码变动，那么就采用 merge。而如果只需要部分代码变动（某几个提交），这时可以采用 cherry-pick（意为挑选最有利的一个）。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 将提交 A 和提交 B 集成到当前分支&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git cherry-pick &amp;lt;HashA&amp;gt; &amp;lt;HashB&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 如果有冲突则解决后继续执行 --continue, 如果回到操作前的样子则 --abort, 如果不想则 --quit&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;git cherry-pick --continue
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;合并上游分支&#34;&gt;合并上游分支&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# git remote add upstream https://github.com/whoever/whatever.git&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git fetch upstream
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;git checkout master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;git merge upstream/master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;git push origin master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;审查同事提交&#34;&gt;审查同事提交&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git remote add zhihang https://gitlab.com/zhihang/smps.git
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git fetch zhihang
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;git checkout zhihang/release-26.05.01.tesla
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样很方便，但如果是要修改或者在 IDE 内比对分支，则需要使用 switch：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git remote add zhihang https://gitlab.com/zhihang/smps.git
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git fetch zhihang
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;git switch -c test/release-26.05.01.tesla zhihang/release-26.05.01.tesla
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;代码恢复抢救&#34;&gt;代码恢复抢救&lt;/h2&gt;
&lt;p&gt;有时候脑子瓦特了做出一些离谱的操作, 导致辛苦写的代码白白消失不见, 这时候就需要抢救了&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;恢复丢弃的-stash-数据&#34;&gt;恢复丢弃的 stash 数据&lt;/h3&gt;
&lt;p&gt;这是一次真实经历过的事件, 有个 stash 的记录忘记 pop 了, 后来操作失误直接 drop 了, 发现之后直接头脑一片空白! 记录下抢救措施！&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git fsck --lost-found
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;会看到一条条记录类似:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;dangling commit 6cb2480fa3a59c140b58a07ac734838a2d958d44
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;dangling commit e9b4c85c437aacf628e724903df21648538963d4
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;dangling blob 983515c6f78d232f1c8878e98598218c142aa9b9
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;dangling commit 4ab67a050c5a8288da28154f79ea89106918ea36
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;dangling commit c2363d6a03dad8f2bc986f8d21ab0fa38c74477b
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;dangling blob 4338d18c5224397a03b40548b7e0f1ea9ca3ffff
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;复制 dangling commit 的 id (其他的 dangling blob 不用关心), 通过 show 操作查看具体的修改：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git show 6cb2480fa3a59c140b58a07ac734838a2d958d44
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中日期是 stash 的日期, 摘要会记录你是在哪一条 commit 上进行 stash 操作。&lt;/p&gt;
&lt;p&gt;再找到想要的记录后执行 merge 即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git merge 6cb2480fa3a59c140b58a07ac734838a2d958d44
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;查看或恢复被覆盖掉的提交历史&#34;&gt;查看或恢复被覆盖掉的提交历史&lt;/h3&gt;
&lt;p&gt;之前我使用 &lt;code&gt;git commit --amend&lt;/code&gt; 修改以前的提交，这样使得 &lt;code&gt;git log&lt;/code&gt; 见不到上次提交的信息, 但事实上 git 并没有真的删除上次提交，而是重新创建了一批新的提交，并将当前分支顶端指向了新提交。&lt;/p&gt;
&lt;p&gt;可以使用 &lt;code&gt;git reflog&lt;/code&gt; 找到并且重新指向原来的提交来恢复它们，注意 reflog 保存的提交是有期限的，需要及时进行操作。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git reflog
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 可以查看到 amend 前的一条提交 99d2720 如下&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;3805bba &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;HEAD -&amp;gt; master, origin/master, origin/HEAD&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; HEAD@&lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;0&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;: commit &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;amend&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;: update
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;99d2720 HEAD@&lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;: commit: update
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;拿到 commit id 99d2720 之后就好办了, 使用 &lt;code&gt;git reset --hard 99d2720&lt;/code&gt; 即可恢复。&lt;/p&gt;
&lt;h3 id=&#34;开源仓库前清除历史提交&#34;&gt;开源仓库前清除历史提交&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git checkout --orphan x
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git add -A
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;git commit -am &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;oss&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;git branch -D master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;git branch -m master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;git push -f origin master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;子模块相关操作&#34;&gt;子模块相关操作&lt;/h2&gt;
&lt;h3 id=&#34;子模块初始化及更新方法&#34;&gt;子模块初始化及更新方法&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# add &amp;gt;&amp;gt; .gitmodules&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;git submodule add https://github.com/chaconinc/DbConnector
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# clone&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;git clone --recurse-submodules https://github.com/chaconinc/MainProject
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# or&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;git clone https://github.com/chaconinc/MainProject &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git submodule update --init --recursive
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# renew&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; your/submodule/path &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git checkout master &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git pull &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; your/proj/root &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit -am &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;update submodule&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git push
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# checkout master on all submodules in a single line (submodules are pinned to a specific sha)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;git submodule foreach --recursive git checkout master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# publish&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; your/submodule/path &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit -am &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;update&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git push &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; your/proj/root &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit -am &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;update submodule&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git push
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;完全移除子模块的方法&#34;&gt;完全移除子模块的方法&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;手动删除子模块目录；&lt;/li&gt;
&lt;li&gt;手动删除 &lt;code&gt;.git/modules&lt;/code&gt; 下子模块暂存区目录；&lt;/li&gt;
&lt;li&gt;更新 &lt;code&gt;.gitmodules&lt;/code&gt; 文件，移除子模块信息块；&lt;/li&gt;
&lt;li&gt;更新 &lt;code&gt;.git/config&lt;/code&gt; 文件，移除子模块信息块；&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;构建自己的-git-存储库&#34;&gt;构建自己的 Git 存储库&lt;/h2&gt;
&lt;p&gt;这里介绍最简单便捷的方法，需要有自己的一台服务器，假设用户是 root，然后先通过配置密钥实现免密登陆服务器，接着进行下面操作即可。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# to remote server: s1(alias)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;ssh root@your_server_ip &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# ssh s1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# init git &lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;mkdir /git &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; /git
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;git init --bare site.git
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# remote: clone repo&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;git clone /git/site.git
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# local: clone repo&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;git clone ssh://root@your_server_ip/git/site.git &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# git clone s1:/git/site.git&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样就基本可以了，如果是已经使用了 github 之类的托管网站的仓库，添加 remote 即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# remote: add remote&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git remote add &lt;span style=&#34;color:#81a1c1&#34;&gt;local&lt;/span&gt; /git/site.git
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# local: add remote&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;git remote add server_git ssh://root@your_server_ip/git/site.git &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# git remote add server_git s1:/git/site.git&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;license-配置&#34;&gt;License 配置&lt;/h2&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/git-important-operations-and-knowledge-summary/image/1735195042266.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;这里讲的比较宽泛，而实际上也不建议去记忆这些，在用到时去找到适合自己项目的 License 即可。如果是使用别人的代码，则再具体去了解对应 License 的条款即可，在 github 中点击 License，也可以很清楚的看到 Permissions、Limitations 以及 Conditions，比如常见的 GPLv3:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Permissions&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Commercial use&lt;/strong&gt;: 允许用于商业目的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Modification&lt;/strong&gt;: 允许修改源代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distribution&lt;/strong&gt;: 允许分发原始或修改后的代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Patent use&lt;/strong&gt;: 提供专利使用权。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private use&lt;/strong&gt;: 允许私下使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limitations&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Liability&lt;/strong&gt;: 不提供责任担保。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Warranty&lt;/strong&gt;: 不提供任何保证。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conditions&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;License and copyright notice&lt;/strong&gt;: 必须保留版权声明和许可证信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State changes&lt;/strong&gt;: 必须声明对源代码所做的更改。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disclose source&lt;/strong&gt;: 分发时必须提供完整的源代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Same license&lt;/strong&gt;: 衍生作品必须在相同的许可证下发布。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;commit-规范&#34;&gt;Commit 规范&lt;/h2&gt;
&lt;p&gt;良好的，遵循一定规则的提交信息不仅有助于编码历史的回顾，也有助于 &lt;strong&gt;CHANGELOG&lt;/strong&gt; 等文件的生成。&lt;/p&gt;
&lt;h3 id=&#34;格式-format&#34;&gt;格式 Format&lt;/h3&gt;
&lt;p&gt;每次提交，Commit message 都包括三个部分：&lt;strong&gt;Header&lt;/strong&gt;，&lt;strong&gt;Body&lt;/strong&gt; 和 &lt;strong&gt;Footer&lt;/strong&gt;。其中，&lt;strong&gt;Header&lt;/strong&gt; 是必需的，&lt;strong&gt;Body&lt;/strong&gt; 和 &lt;strong&gt;Footer&lt;/strong&gt; 可以省略。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&amp;lt;type&amp;gt;(&amp;lt;scope&amp;gt;): &amp;lt;subject&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&amp;lt;空行&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&amp;lt;body&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&amp;lt;空行&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&amp;lt;footer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不管是哪一个部分，任何一行都不得超过 72 个字符（或 100 个字符）。Header 部分只有一行，包括三个字段：&lt;code&gt;type&lt;/code&gt;（必需）、&lt;code&gt;scope&lt;/code&gt;（可选）和 &lt;code&gt;subject&lt;/code&gt;（必需）。Footer 部分如果提交存在一个与之关联的 Issue 则要关联。&lt;/p&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;fix(release): need to depend on latest rxjs and zone.js
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;The version in our package.json gets copied to the one we publish, 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;and users need the latest of these.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;主题-subject&#34;&gt;主题 Subject&lt;/h3&gt;
&lt;p&gt;subject 是本次 commit 目的的简短描述，一般不要超过 50 个字符：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;使用祈使句和现在时&lt;/strong&gt;：例如使用 &amp;ldquo;change&amp;rdquo; 而不是 &amp;ldquo;changed&amp;rdquo; 或 &amp;ldquo;changes&amp;rdquo;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;规范大小写和相应书写规则。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无需加句号符标识结尾。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;类型-type&#34;&gt;类型 Type&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Commit Type&lt;/th&gt;
&lt;th&gt;Title&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;feat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Features&lt;/td&gt;
&lt;td&gt;A new feature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fix&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Bug Fixes&lt;/td&gt;
&lt;td&gt;A bug Fix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Documentation&lt;/td&gt;
&lt;td&gt;Documentation only changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;style&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Styles&lt;/td&gt;
&lt;td&gt;Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;refactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Code Refactoring&lt;/td&gt;
&lt;td&gt;A code change that neither fixes a bug nor adds a feature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;perf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Performance Improvements&lt;/td&gt;
&lt;td&gt;A code change that improves performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;Adding missing tests or correcting existing tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Builds&lt;/td&gt;
&lt;td&gt;Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ci&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Continuous Integrations&lt;/td&gt;
&lt;td&gt;Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Chores&lt;/td&gt;
&lt;td&gt;Other changes that don&amp;rsquo;t modify src or test files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;revert&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reverts&lt;/td&gt;
&lt;td&gt;Reverts a previous commit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;作用域-scope&#34;&gt;作用域 Scope&lt;/h3&gt;
&lt;p&gt;scope 用于说明 commit 影响的范围，比如数据层、控制层、视图层等等，视项目不同而不同，同样属于枚举类型。&lt;/p&gt;
&lt;p&gt;常见的有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;$cmpt&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$container&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$view&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$api&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;主体-body&#34;&gt;主体 Body&lt;/h3&gt;
&lt;p&gt;Body是对本地提交的一个详细描述，需要注意的是，描述每行字符不应超过 72 个字符，这利于各种环境下良好的阅读体验。&lt;/p&gt;
&lt;h3 id=&#34;脚注-footer&#34;&gt;脚注 Footer&lt;/h3&gt;
&lt;p&gt;Footer 部分只用于两种情况：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Breaking Changes: 如果当前代码与上一个版本不兼容，则 Footer 部分以 BREAKING CHANGE 开头，后面是对变动的描述、以及变动理由和迁移方法。&lt;/li&gt;
&lt;li&gt;Closes Issue: 如果当前 commit 针对某个 issue，那么可以在 Footer 部分关闭或关联这个 issue，或多个 issue:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;Closes #234
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;Closes #123, #245, #992
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;Ref #234
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;回退-revert&#34;&gt;回退 Revert&lt;/h3&gt;
&lt;p&gt;还有一种特殊情况，如果当前 commit 用于撤销以前的 commit，格式规定如下&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;header 以  &lt;code&gt;revert:&lt;/code&gt;  开头，后面跟着被撤销 commit 的 header&lt;/li&gt;
&lt;li&gt;body 以  &lt;code&gt;This reverts commit &amp;lt;hash&amp;gt;&lt;/code&gt;  的格式，其中的 &lt;code&gt;hash&lt;/code&gt; 是被撤销 commit 的 SHA 标识符。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;revert: feat(pencil): add &amp;#39;graphiteWidth&amp;#39; option
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;This reverts commit 667ecc1654a317a13331b17617d973392f415f
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果当前 commit 与被撤销的 commit，在同一个发布（release）里面，那么它们都不会出现在 Change log 里面。如果两者在不同的发布，那么当前 commit，会出现在 Change log 的 &lt;code&gt;Reverts&lt;/code&gt; 小标题下面。&lt;/p&gt;
&lt;h2 id=&#34;git-alias&#34;&gt;Git Alias&lt;/h2&gt;
&lt;p&gt;Git 别名（alias）允许你为常用的 Git 命令创建简短的、易于记忆的替代名称。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 单命令别名&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;git config --global alias.co checkout
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# git co main&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 多命令别名&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;git config --global alias.commitall &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;!git add -A &amp;amp;&amp;amp; git commit -am&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# git commitall &amp;#34;Initial commit&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 运行外部脚本&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;git config --global alias.deploy &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;!sh ~/scripts/deploy.sh&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# git deploy&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;#查看别名配置&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;git config --global --get-regexp &lt;span style=&#34;color:#81a1c1&#34;&gt;alias&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 删除别名&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;git config --global --unset alias.co
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以直接编辑 Git 配置文件来添加别名。全局配置文件通常位于 &lt;code&gt;~/.gitconfig&lt;/code&gt;，本地配置文件通常位于仓库根目录下的 &lt;code&gt;.git/config&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;[alias]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#8fbcbb&#34;&gt;co&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;checkout
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    ci = commit
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    br = branch
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    st = status
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    commitall = !git add -A &amp;amp;&amp;amp; git commit -am
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    bra = !git branch -a
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    pf = !git push -f
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    tags = !git tag
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;    stashes = !git stash list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;建议用法&#34;&gt;建议用法&lt;/h2&gt;
&lt;h3 id=&#34;使用-rebase-来集成其他分支修改&#34;&gt;使用 rebase 来集成其他分支修改&lt;/h3&gt;
&lt;p&gt;rebase 通常用于重写提交历史。下面的使用场景在大多数 Git 工作流中是十分常见的：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;我们从 master 分支拉取了一条 feature 分支在本地进行功能开发&lt;/li&gt;
&lt;li&gt;远程的 master 分支在之后又合并了一些新的提交&lt;/li&gt;
&lt;li&gt;我们想在 feature 分支集成 master 的最新更改&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;基本操作流程如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [feature]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;git checkout feature
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# feature 集成 master 修改&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;git rebase master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 手动解决冲突&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# ...&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;git rebase --continue
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;git push origin feature -f
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 或者通过 git pull 完成:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;git pull origin feature --rebase
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# git config pull.rebase true # 也可以进行默认配置&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 手动解决冲突&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;git push origin feature
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;---------------------------------
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [master]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;git checkout master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;git merge origin feature
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;git push origin master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样, 提交的历史将是很干净的, 即使在 master 进行了 merge 但是提交历史仍然不会出现 &amp;ldquo;merge &amp;hellip;&amp;rdquo; 之类的提交, 因为 merge 的目标分支 feature 经过了 rebase, 现在合并后 feature 上的提交就如同在 master 上进行提交一般，效果如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/git-important-operations-and-knowledge-summary/image/1732179807944.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;使用-fast-forward-来集成其他分支修改&#34;&gt;使用 fast-forward 来集成其他分支修改&lt;/h3&gt;
&lt;p&gt;如果当前分支没有新提交，则可以通过 fast-forward 集成其他基于当前分支开发最新提交的其他分支带来的变更，可以少一条 merge 信息，也让提交历史更为干净。不过其实这是执行 &lt;code&gt;git merge&lt;/code&gt; 时的默认策略。&lt;/p&gt;
&lt;p&gt;而如果当前分支有新提交，则执行 &lt;code&gt;git merge&lt;/code&gt; 时，如果有冲突，则需要手动处理冲突，如果没有冲突，则会生成一条 merge 信息，而且也无法进行 fast-forward 操作。&lt;/p&gt;
&lt;p&gt;所以其实大部份情况下还是得通过 rebase 来完成提交历史的简洁化。&lt;/p&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit?usp=sharing&#34;&gt;AngularJS Git Commit Message Conventions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Docker 重要使用记录</title>
        <link>https://zhihang.org/posts/docker-important-software-installation-and-usage-records/</link>
        <pubDate>Wed, 14 Jun 2023 23:03:41 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>docker-important-software-installation-and-usage-records</guid>
        <description>&lt;h2 id=&#34;toc&#34;&gt;TOC&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#toc&#34;&gt;TOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#install&#34;&gt;Install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mirror&#34;&gt;Mirror&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#proxy&#34;&gt;Proxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#manual-pull-image&#34;&gt;Manual Pull Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#webdav&#34;&gt;Webdav&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#alist&#34;&gt;Alist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#it-tools&#34;&gt;IT-Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#kafka-zookeeper&#34;&gt;Kafka-Zookeeper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#freshrss&#34;&gt;FreshRSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mysql&#34;&gt;MySQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#postgresql&#34;&gt;PostgreSQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rsshub&#34;&gt;RSSHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#redis&#34;&gt;Redis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#fakashop&#34;&gt;FakaShop&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;install&#34;&gt;Install&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# op1. apt&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;apt update &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt install docker.io -y &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt install docker-compose -y
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# op2. yum&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# yum install -y yum-utils device-mapper-persistent-data lvm2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;yum install docker-ce
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;curl -L &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;$(&lt;/span&gt;uname -s&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;$(&lt;/span&gt;uname -m&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; -o /usr/local/bin/docker-compose
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;chmod +x /usr/local/bin/docker-compose
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# op3. script&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;curl -fsSL https://get.docker.com -o get-docker.sh
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;sudo sh get-docker.sh
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;curl -SL https://github.com/docker/compose/releases/download/v2.32.4/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;chmod +x /usr/local/bin/docker-compose
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# op4. 阿里云服务器版&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 参考 https://help.aliyun.com/zh/ecs/use-cases/install-and-use-docker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;systemctl start docker &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; systemctl &lt;span style=&#34;color:#81a1c1&#34;&gt;enable&lt;/span&gt; docker
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;mirror&#34;&gt;Mirror&lt;/h2&gt;
&lt;p&gt;EDIT: &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;registry-mirrors&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;          &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;https://docker.mirrors.ustc.edu.cn&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;          &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://hub-mirror.c.163.com&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;          &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;https://registry.docker-cn.com&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;proxy&#34;&gt;Proxy&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;sudo mkdir -p /etc/systemd/system/docker.service.d
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;Service&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;Environment&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;HTTP_PROXY=http://127.0.0.1:7890&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;Environment&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;HTTPS_PROXY=http://127.0.0.1:7890&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;sudo systemctl daemon-reload
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;sudo systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;manual-pull-image&#34;&gt;Manual Pull Image&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# local desktop&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;docker save node:20 &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; gzip -c -9 &amp;gt; node20.tar.gz
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# remote server&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;docker load &amp;lt; node20.tar.gz 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;webdav&#34;&gt;Webdav&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;webdav&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; bytemark/webdav
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; unless-stopped
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;8099:80&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;AUTH_TYPE&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; Basic
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;USERNAME&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; ${WEBDAV_USERNAME}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;PASSWORD&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; ${WEBDAV_PASSWORD}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;      - ./data/:/var/lib/dav
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;alist&#34;&gt;Alist&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;alist&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;xhofe/alist:latest&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; alist
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;            - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;./data:/opt/alist/data&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;            - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;${ALIST_PORT}:5244&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;            - PUID=0
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;            - PGID=0
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;            - UMASK=022
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; always
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;it-tools&#34;&gt;IT-Tools&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;docker run -d --name it-tools --restart unless-stopped -p &lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;IT_TOOLS_PORT&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;:80 corentinth/it-tools:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;kafka-zookeeper&#34;&gt;Kafka-Zookeeper&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;zoo1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; zookeeper:3.4.9
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;hostname&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; zoo1
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;${ZOOKEEPER_PORT}:2181&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;ZOO_MY_ID&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;ZOO_PORT&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2181&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;ZOO_SERVERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; server.1=zoo1:2888:3888
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;      - ./zk-single-kafka-single/zoo1/data:/data
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;      - ./zk-single-kafka-single/zoo1/datalog:/datalog
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;kafka1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; confluentinc/cp-kafka:5.3.1
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;hostname&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; kafka1
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;${KAFKA_PORT}:9092&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_ADVERTISED_LISTENERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; LISTENER_DOCKER_INTERNAL://kafka1:19092,LISTENER_DOCKER_EXTERNAL://${DOCKER_HOST_IP:-127.0.0.1}:9092
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_LISTENER_SECURITY_PROTOCOL_MAP&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; LISTENER_DOCKER_INTERNAL:PLAINTEXT,LISTENER_DOCKER_EXTERNAL:PLAINTEXT
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_INTER_BROKER_LISTENER_NAME&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; LISTENER_DOCKER_INTERNAL
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_ZOOKEEPER_CONNECT&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;zoo1:2181&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_BROKER_ID&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_LOG4J_LOGGERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;kafka.controller=INFO,kafka.producer.async.DefaultEventHandler=INFO,state.change.logger=INFO&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;      - ./zk-single-kafka-single/kafka1/data:/var/lib/kafka/data
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;      - zoo1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;kafka1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; bitnami/kafka:3.5.2
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; kafka1
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; always
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;      - &lt;span style=&#34;color:#b48ead&#34;&gt;19092&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;9092&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;      - &lt;span style=&#34;color:#b48ead&#34;&gt;19093&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;9093&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;privileged&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;networks&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;      - kafka-net
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;      &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;#是否使用KRaft模式&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_ENABLE_KRAFT&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;yes&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_PROCESS_ROLES&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; broker,controller
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_CONTROLLER_LISTENER_NAMES&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; CONTROLLER
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_LISTENERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; PLAINTEXT://:9092,CONTROLLER://:9093
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_KRAFT_CLUSTER_ID&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; VaW86rUCTMmoxIcDiER_lA
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_CONTROLLER_QUORUM_VOTERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;@kafka1:9093,2@kafka2:9093,3@kafka3:9093
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;ALLOW_PLAINTEXT_LISTENER&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;yes&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_HEAP_OPTS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; -Xmx512M -Xms256M
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;      &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;#broker单独配置&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_NODE_ID&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_ADVERTISED_LISTENERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; PLAINTEXT://172.20.103.104:19092
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;kafka2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; bitnami/kafka:3.5.2
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; kafka2
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; always
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;      - &lt;span style=&#34;color:#b48ead&#34;&gt;29092&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;9092&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;      - &lt;span style=&#34;color:#b48ead&#34;&gt;29093&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;9093&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;privileged&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;networks&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;38&lt;/span&gt;      - kafka-net
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;39&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;40&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_ENABLE_KRAFT&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;yes&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;41&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_PROCESS_ROLES&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; broker,controller
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;42&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_CONTROLLER_LISTENER_NAMES&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; CONTROLLER
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;43&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_LISTENERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; PLAINTEXT://:9092,CONTROLLER://:9093
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;44&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;45&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_KRAFT_CLUSTER_ID&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; VaW86rUCTMmoxIcDiER_lA
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;46&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_CONTROLLER_QUORUM_VOTERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;@kafka1:9093,2@kafka2:9093,3@kafka3:9093
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;47&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;ALLOW_PLAINTEXT_LISTENER&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;yes&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;48&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_HEAP_OPTS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; -Xmx512M -Xms256M
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;49&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;50&lt;/span&gt;      &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;#broker单独配置&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;51&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_NODE_ID&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;52&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_ADVERTISED_LISTENERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; PLAINTEXT://172.20.103.104:29092
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;53&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;54&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;kafka3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;55&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; bitnami/kafka:3.5.2
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;56&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; kafka3
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;57&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; always
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;58&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;59&lt;/span&gt;      - &lt;span style=&#34;color:#b48ead&#34;&gt;39092&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;9092&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;60&lt;/span&gt;      - &lt;span style=&#34;color:#b48ead&#34;&gt;39093&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;9093&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;61&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;privileged&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;62&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;networks&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;63&lt;/span&gt;      - kafka-net
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;64&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;65&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_ENABLE_KRAFT&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;yes&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;66&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_PROCESS_ROLES&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; broker,controller
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;67&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_CONTROLLER_LISTENER_NAMES&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; CONTROLLER
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;68&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_LISTENERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; PLAINTEXT://:9092,CONTROLLER://:9093
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;69&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;70&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_KRAFT_CLUSTER_ID&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; VaW86rUCTMmoxIcDiER_lA
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;71&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_CONTROLLER_QUORUM_VOTERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;@kafka1:9093,2@kafka2:9093,3@kafka3:9093
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;72&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;ALLOW_PLAINTEXT_LISTENER&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;yes&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;73&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_HEAP_OPTS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; -Xmx512M -Xms256M
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;74&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;75&lt;/span&gt;      &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;#broker单独配置&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;76&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_NODE_ID&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;77&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;KAFKA_CFG_ADVERTISED_LISTENERS&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; PLAINTEXT://172.20.103.104:39092
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;78&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;79&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;networks&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;80&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;kafka-net&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;81&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;driver&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; bridge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;freshrss&#34;&gt;FreshRSS&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;freshrss&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; freshrss/freshrss:latest
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; freshrss
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; unless-stopped
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;logging&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;options&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;max-size&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; 10m
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;      - ./data:/var/www/FreshRSS/data
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;      - ./extensions:/var/www/FreshRSS/extensions
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;${FRESHRSS_PORT}:80&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;TZ&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Asia/Shanghai&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;CRON_MIN&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3,33&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;mysql&#34;&gt;MySQL&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;mysql&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; mysql:8
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; mysql
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; unless-stopped
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;      - ${DB_PORT}:3306
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;      - MYSQL_DATABASE=${DB_DATABASE}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;      - MYSQL_USER=${DB_USERNAME}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;      - MYSQL_PASSWORD=${DB_PASSWORD}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;      - ./data:/var/lib/mysql
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;      - ./conf:/etc/mysql/conf.d
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;postgresql&#34;&gt;PostgreSQL&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;postgres&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; postgres:15
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;      - ${PORT}:5432
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;      - ./data:/var/lib/postgresql/data
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;      - POSTGRES_USER=${POSTGRES_USER}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;      - POSTGRES_DB=${POSTGRES_DB}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;rsshub&#34;&gt;RSSHub&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;wget https://raw.githubusercontent.com/DIYgod/RSSHub/master/docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;redis&#34;&gt;Redis&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;redis&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; redis:alpine
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; redis
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;${REDIS_PORT}:6379&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; always
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;redis-server --requirepass ${REDIS_PASSWORD}&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# command: &amp;#34;redis-server&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;      - ./data:/data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;fakashop&#34;&gt;FakaShop&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;faka&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; ghcr.io/apocalypsor/dujiaoka:latest
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; faka
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;      - INSTALL=${INSTALL}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;      - ./.env:/dujiaoka/.env
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;      - ./uploads:/dujiaoka/public/uploads
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;      - ./storage:/dujiaoka/storage
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;      - ${PORT}:80
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; always
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;      - db
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;      - redis
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;db&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; mariadb:focal
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; faka-data
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; always
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;environment&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;      - MYSQL_DATABASE=${DB_DATABASE}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;      - MYSQL_USER=${DB_USERNAME}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;      - MYSQL_PASSWORD=${DB_PASSWORD}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;      - ./data:/var/lib/mysql
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;redis&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; redis:alpine
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; faka-redis
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;${REDIS_PORT}:6379&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; always
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;redis-server --requirepass ${REDIS_PASSWORD}&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;      - ./redis:/data
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# .env&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;INSTALL&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;false # first time -&amp;gt; true&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;PORT&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;80&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;APP_NAME&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;APP_NAME&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;APP_ENV&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;local&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;APP_KEY&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;APP_KEY&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;APP_DEBUG&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;false&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;APP_URL&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;APP_URL&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;ADMIN_HTTPS&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;false&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;ADMIN_ROUTE_PREFIX&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;/admin&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;DB_CONNECTION&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;mysql&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;DB_HOST&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;db&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;DB_PORT&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;3306&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;DB_ROOT_PASSWORD&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;DB_ROOT_PASSWORD&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;DB_DATABASE&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;dujiaoka&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;DB_USERNAME&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;dujiaoka&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;DB_PASSWORD&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;DB_PASSWORD&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;REDIS_HOST&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;redis&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;REDIS_PASSWORD&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;REDIS_PASSWORD&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;REDIS_PORT&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;6379&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;CACHE_DRIVER&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;redis&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;QUEUE_CONNECTION&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;redis&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;LOG_CHANNEL&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;stack&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;BROADCAST_DRIVER&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;log&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;SESSION_DRIVER&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;file&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;SESSION_LIFETIME&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;120&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# zh_CN zh_TW en&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;DUJIAO_ADMIN_LANGUAGE&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;zh_CN&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      </item>
      
    
      
      <item>
        <title>技术问题追踪与处理记录</title>
        <link>https://zhihang.org/posts/summary-record-of-daily-development-bugs/</link>
        <pubDate>Wed, 10 May 2023 18:13:33 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>summary-record-of-daily-development-bugs</guid>
        <description>&lt;h2 id=&#34;toc&#34;&gt;TOC&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#toc&#34;&gt;TOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#header-field-too-long&#34;&gt;Header Field Too Long&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#tomcat-dbcp-jmx-%E9%97%AE%E9%A2%98&#34;&gt;Tomcat DBCP JMX 问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#tomcat-%E8%BF%90%E8%A1%8C%E9%A1%B9%E7%9B%AE%E5%87%BA%E7%8E%B0-mysql-%E8%BF%9E%E6%8E%A5%E5%99%A8%E9%97%AE%E9%A2%98&#34;&gt;Tomcat 运行项目出现 Mysql 连接器问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#wsl-gradle-jvm-%E9%97%AE%E9%A2%98&#34;&gt;WSL Gradle JVM 问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%B7%A8%E5%9F%9F%E9%97%AE%E9%A2%98&#34;&gt;跨域问题&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#springboot-%E8%B7%A8%E5%9F%9F%E9%85%8D%E7%BD%AE&#34;&gt;SpringBoot 跨域配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#options-%E8%AF%B7%E6%B1%82%E8%B7%A8%E5%9F%9F%E9%97%AE%E9%A2%98&#34;&gt;Options 请求跨域问题&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#fastjson-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%AF%B9%E8%B1%A1%E4%BF%AE%E9%A5%B0%E7%AC%A6%E9%97%AE%E9%A2%98&#34;&gt;fastjson 反序列化对象修饰符问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%9C%AC%E5%9C%B0%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%B5%8B%E8%AF%95%E5%A4%A9%E5%9D%91-%E6%B5%8B%E8%AF%95%E6%96%B9%E6%B3%95%E5%BC%80%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%B2%A1%E8%B7%91%E5%AE%8C&#34;&gt;本地多线程测试天坑: 测试方法开的线程没跑完&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#idea-maven-reload--out-of-memory-error&#34;&gt;IDEA maven reload : out of memory error&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sqlite-jdbc-no-native-library-is-found&#34;&gt;sqlite-jdbc No native library is found&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hibernate--sqlite-%E9%97%AE%E9%A2%98&#34;&gt;hibernate + sqlite 问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#jar-%E5%8C%85%E9%A1%B9%E7%9B%AE%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E9%97%AE%E9%A2%98&#34;&gt;JAR 包项目文件上传问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%B1%BB%E6%96%87%E4%BB%B6%E5%85%B7%E6%9C%89%E9%94%99%E8%AF%AF%E7%9A%84%E7%89%88%E6%9C%AC-550-%E5%BA%94%E4%B8%BA-520&#34;&gt;类文件具有错误的版本 55.0, 应为 52.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-server-selected-protocol-version-tls10-is-not-accepted-by-client-preferences-tls13-tls12&#34;&gt;The server selected protocol version TLS10 is not accepted by client preferences [TLS13, TLS12]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rocketmq-it-may-be-caused-by-one-of-the-following-reasons-the-brokers-disk-is-full&#34;&gt;RocketMQ: It may be caused by one of the following reasons: the broker&amp;rsquo;s disk is full&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#springboot-3x-%E4%BD%BF%E7%94%A8-springboot-2x-%E7%9A%84-starter-%E6%97%A0%E6%B3%95%E5%AE%8C%E6%88%90%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D&#34;&gt;SpringBoot 3.X 使用 SpringBoot 2.X 的 Starter 无法完成自动装配&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#listremove-%E6%AD%A3%E7%A1%AE%E7%9A%84%E4%BD%BF%E7%94%A8%E9%87%8D%E8%BD%BD&#34;&gt;list.remove() 正确的使用重载&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%90%8E%E7%AB%AF%E8%BF%94%E5%9B%9E%E7%9A%84-json-%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F%E5%87%BA%E9%94%99&#34;&gt;后端返回的 json 数据格式出错&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#idea-%E4%B8%AD%E5%9C%A8-maven-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E9%85%8D%E7%BD%AE-jvm-%E5%90%AF%E5%8A%A8%E5%8F%82%E6%95%B0&#34;&gt;IDEA 中在 maven 配置文件中配置 JVM 启动参数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#bigdecimal-%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9A%84%E7%BB%93%E6%9E%9C%E5%8F%AF%E8%83%BD%E4%B8%8D%E5%8F%AF%E9%A2%84%E6%B5%8B&#34;&gt;BigDecimal 构造函数的结果可能不可预测&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96-boolean-%E5%AD%97%E6%AE%B5%E5%A4%B1%E8%B4%A5%E7%9A%84%E9%97%AE%E9%A2%98&#34;&gt;反序列化 boolean 字段失败的问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#maven-%E7%9A%84-http-%E9%97%AE%E9%A2%98&#34;&gt;maven 的 http 问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#failed-to-determine-a-suitable-driver-class&#34;&gt;Failed to determine a suitable driver class&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%9A%90%E8%97%8F%E7%9A%84%E4%BE%9D%E8%B5%96%E7%89%88%E6%9C%AC%E5%86%B2%E7%AA%81%E9%97%AE%E9%A2%98&#34;&gt;隐藏的依赖版本冲突问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#bufferedwriter-%E6%97%A0%E6%B3%95%E6%AD%A3%E7%A1%AE%E5%86%99%E5%87%BA%E9%97%AE%E9%A2%98&#34;&gt;BufferedWriter 无法正确写出问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#pnpm-build-error-rollup&#34;&gt;pnpm build error: Rollup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#spark-cannot-safely-cast&#34;&gt;Spark: Cannot safely cast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#node-error-message-error0308010cdigital-envelope-routinesunsupported&#34;&gt;Node: Error message &amp;ldquo;error:0308010C:digital envelope routines::unsupported&amp;rdquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-watch-%E6%97%A0%E6%B3%95%E6%9B%B4%E6%96%B0%E4%B8%80%E7%9B%B4%E6%98%BE%E7%A4%BA%E5%B7%B2%E6%9A%82%E5%81%9C&#34;&gt;Apple Watch 无法更新，一直显示已暂停&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-map-icloud-%E5%85%B3%E9%97%AD%E5%90%8C%E6%AD%A5%E5%90%8E%E6%8C%87%E5%8D%97%E4%B8%A2%E5%A4%B1&#34;&gt;Apple Map icloud 关闭同步后指南丢失&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#go-build-stuck&#34;&gt;go build stuck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#iterm2-scp-%E4%B8%8B%E8%BD%BD%E6%AF%8F%E6%AC%A1%E9%83%BD%E8%A6%81%E8%AF%A2%E9%97%AE-key&#34;&gt;iterm2 scp 下载每次都要询问 key&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#latex-%E4%B8%AD%E6%96%87%E7%BC%96%E7%A0%81%E9%97%AE%E9%A2%98&#34;&gt;latex 中文编码问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#certbot-renew-%E6%8A%A5%E9%94%99-urlib3-%E4%BE%9D%E8%B5%96%E9%97%AE%E9%A2%98&#34;&gt;certbot renew 报错 urlib3 依赖问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mybatis-%E5%88%A4%E6%96%AD%E5%92%8C%E8%AF%AD%E6%B3%95%E9%94%99%E8%AF%AF&#34;&gt;mybatis 判断和语法错误&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#curl-%E8%AF%B7%E6%B1%82%E8%B7%AF%E5%BE%84%E6%AD%A3%E7%A1%AE%E4%BD%86%E6%8A%A5-404-%E6%88%96%E5%8F%82%E6%95%B0%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%BC%82%E5%B8%B8&#34;&gt;curl 请求路径正确但报 404 或参数反序列化异常&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sqlserver-tlsv1-was-negotiated-please-update-server-and-client-to-use-tlsv12-at-minimum&#34;&gt;sqlserver TLSv1 was negotiated. Please update server and client to use TLSv1.2 at minimum.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#unittest-test-discovery-error-for-workspace&#34;&gt;Unittest test discovery error for workspace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#gitignore-%E5%A4%B1%E6%95%88&#34;&gt;Gitignore 失效&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#nginx-error-pid&#34;&gt;Nginx Error PID&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#nginx-%E7%9B%B8%E5%AF%B9%E5%9C%B0%E5%9D%80%E8%B5%84%E6%BA%90%E5%BC%95%E7%94%A8%E4%B8%8D%E8%B5%B0%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86&#34;&gt;Nginx 相对地址资源引用不走反向代理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#nginx-%E6%97%A0%E6%B3%95%E5%8A%A0%E8%BD%BD-css&#34;&gt;Nginx 无法加载 css&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#dujiaoka-%E9%87%8D%E5%90%AF%E5%90%8E%E5%89%8D%E5%8F%B0%E9%9C%80%E8%A6%81%E9%87%8D%E6%96%B0%E5%AE%89%E8%A3%85&#34;&gt;dujiaoka 重启后前台需要重新安装&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#manpath-cant-set-the-locale-make-sure-lc_-and-lang-are-correct&#34;&gt;manpath: can&amp;rsquo;t set the locale; make sure $LC_* and $LANG are correct&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rsshub-commit-%E4%B8%8D%E9%80%9A%E8%BF%87&#34;&gt;RSSHub commit 不通过&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#influxdb-%E5%BC%95%E5%8F%B7%E9%97%AE%E9%A2%98&#34;&gt;InfluxDb 引号问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#docker-compose-%E5%AE%B9%E5%99%A8%E5%86%85%E6%97%A0%E6%B3%95%E8%BF%9E%E6%8E%A5%E6%9C%8D%E5%8A%A1%E7%9A%84%E9%97%AE%E9%A2%98&#34;&gt;docker-compose 容器内无法连接服务的问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#xx-%E4%B8%8D%E5%85%81%E8%AE%B8%E5%8F%91%E9%80%81%E6%8C%89%E9%94%AE&#34;&gt;XX 不允许发送按键&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#gitignore-%E5%8F%8D%E9%80%89%E7%9A%84%E6%AD%A3%E7%A1%AE%E7%94%A8%E6%B3%95&#34;&gt;.gitignore 反选的正确用法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#brew-%E5%AE%89%E8%A3%85%E6%8A%A5%E9%94%99-curl-56-failure-when-receiving-data-from-the-peer&#34;&gt;brew 安装报错 curl: (56) Failure when receiving data from the peer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#oh-my-zsh-agnoster-%E4%B8%BB%E9%A2%98%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98&#34;&gt;oh-my-zsh agnoster 主题乱码问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#docker-compose-volume-%E6%8C%87%E5%AE%9A%E5%AF%B9%E8%B1%A1%E4%B8%BA%E6%96%87%E4%BB%B6%E6%97%B6%E4%BA%A7%E7%94%9F%E7%9A%84%E9%97%AE%E9%A2%98&#34;&gt;docker-compose volume 指定对象为文件时产生的问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sqlite3-%E6%89%A7%E8%A1%8C-sql-%E5%87%BA%E9%94%99&#34;&gt;Sqlite3 执行 sql 出错&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#iterm2-%E6%97%A0%E6%B3%95%E4%BD%BF%E7%94%A8-scp&#34;&gt;iterm2 无法使用 scp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#python-%E7%89%88%E6%9C%AC%E5%86%B2%E7%AA%81%E9%97%AE%E9%A2%98&#34;&gt;Python 版本冲突问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#python-requests_cache-%E5%9C%A8%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%8E%AF%E5%A2%83%E4%B8%8B%E5%8F%91%E7%94%9F%E9%94%99%E8%AF%AF-database-is-locked&#34;&gt;Python requests_cache 在多线程环境下发生错误 &amp;ldquo;database is locked&amp;rdquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#errno-24-too-many-open-files&#34;&gt;[Errno 24] Too many open files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#django-%E6%89%8B%E5%8A%A8%E5%88%A0%E9%99%A4-migrations-%E7%9B%AE%E5%BD%95%E5%90%8E-migrate-%E6%97%A0%E6%95%88&#34;&gt;Django 手动删除 migrations 目录后 migrate 无效&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mac-m1-python379-modulenotfounderror-no-module-named-_ctypes&#34;&gt;mac m1 python3.7.9 ModuleNotFoundError: No module named &amp;lsquo;_ctypes&amp;rsquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#windows-%E4%B8%8B%E5%AE%89%E8%A3%85-lxml-%E6%8A%A5%E9%94%99&#34;&gt;Windows 下安装 lxml 报错&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#unicodedecodeerror-utf-8-codec-cant-decode-byte-0xff-in-position-0-invalid-start-byte&#34;&gt;UnicodeDecodeError: &amp;lsquo;utf-8&amp;rsquo; codec can&amp;rsquo;t decode byte 0xff in position 0: invalid start byte&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8C%85%E5%86%B2%E7%AA%81&#34;&gt;包冲突&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sslerrorsslcertverificationerror&#34;&gt;SSLError(SSLCertVerificationError)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#pipenv-%E6%97%A0%E6%B3%95%E6%AD%A3%E5%B8%B8-install&#34;&gt;pipenv 无法正常 install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#python-requests-%E5%BA%93-headers-%E5%AD%97%E6%AE%B5%E7%BC%96%E7%A0%81%E9%94%99%E8%AF%AF&#34;&gt;Python requests 库 headers 字段编码错误&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#python--crontab-%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F&#34;&gt;python + crontab 环境变量&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#python-%E5%85%B3%E4%BA%8E%E7%88%AC%E8%99%AB%E6%89%80%E8%AE%BE%E7%BD%AE%E7%9A%84-headers-%E4%B8%AD%E7%9A%84-useragent&#34;&gt;Python 关于爬虫所设置的 Headers 中的 UserAgent&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;header-field-too-long&#34;&gt;Header Field Too Long&lt;/h2&gt;
&lt;p&gt;Bad Request - Header Field Too Long
HTTP Error 400. A request header field is too long.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;F12 清除 cookie&lt;/p&gt;
&lt;h2 id=&#34;tomcat-dbcp-jmx-问题&#34;&gt;Tomcat DBCP JMX 问题&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;Tomcat 9.x DBCP basicdatasource methods returning java.time.* cannot be mapped to JMX OpenType.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&#34;https://stackoverflow.com/questions/70803376/tomcat-9-x-dbcp-basicdatasource-methods-returning-java-time-cannot-be-mapped-t&#34;&gt;https://stackoverflow.com/questions/70803376/tomcat-9-x-dbcp-basicdatasource-methods-returning-java-time-cannot-be-mapped-t&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We also struggled with this issue. Stumbled upon another question that was similar and someone mentioned a PR that lead us down the path of looking at commits in the tomcat project and the changelogs. If you look at the changelog for Tomcat 9.x you can find that for a dev/nightly release (at the time of this writing) of 9.0.59:&lt;/p&gt;
&lt;p&gt;Revert the cherry-pick of JavaDoc fix from DBCP applied in 9.0.57 that broke the DataSourceMXBean by using a type that isn&amp;rsquo;t supported by MXBeans. (markt)&lt;/p&gt;
&lt;p&gt;If you are still struggling with this you could either try the latest dev/nightly build (not yet published in maven central) or use version 9.0.56, which is what we used, and it should resolve this issue.&lt;/p&gt;
&lt;h2 id=&#34;tomcat-运行项目出现-mysql-连接器问题&#34;&gt;Tomcat 运行项目出现 Mysql 连接器问题&lt;/h2&gt;
&lt;p&gt;java.sql.SQLException: Cannot load JDBC driver class &amp;lsquo;com.mysql.cj.jdbc.Driver&amp;rsquo;
Caused by: java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver&lt;/p&gt;
&lt;p&gt;这意味着 Tomcat 在运行时无法加载 MySQL 的 JDBC 驱动类 com.mysql.cj.jdbc.Driver，通常是因为 MySQL JDBC 驱动（即 mysql-connector-java）没有正确部署到应用或 Tomcat 环境中。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;下载 mysql-connector-java-8.0.33.jar 或更高版本&lt;/li&gt;
&lt;li&gt;复制到 /usr/share/tomcat9-56/lib/&lt;/li&gt;
&lt;li&gt;检查 context.xml 中的 driverClassName 是否为 com.mysql.cj.jdbc.Driver&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;wsl-gradle-jvm-问题&#34;&gt;WSL Gradle JVM 问题&lt;/h2&gt;
&lt;p&gt;使用 Windows-IDEA 打开项目，执行 Main 函数时无法找到 JVM，执行 Spring Application，Test 等都没问题。&lt;/p&gt;
&lt;p&gt;使用 Windows-IDEA-WSL 打开项目，执行 Main 函数时成功。&lt;/p&gt;
&lt;p&gt;大概率就是 Gradle 插件的问题，如果需要执行 Main 函数，就到别的地方执行，或者使用 Windows-IDEA-WSL 打开项目吧。&lt;/p&gt;
&lt;h2 id=&#34;跨域问题&#34;&gt;跨域问题&lt;/h2&gt;
&lt;h3 id=&#34;springboot-跨域配置&#34;&gt;SpringBoot 跨域配置&lt;/h3&gt;
&lt;p&gt;这是一段跨域配置的代码，有一些问题需要注意。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Configuration&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;CorsConfig&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; WebMvcConfigurer &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;addCorsMappings&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;CorsRegistry registry&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        registry&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;addMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/**&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;allowedOriginPatterns&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://127.0.0.1:*&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;https://127.0.0.1:*&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://localhost:*&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;https://localhost:*&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;allowedMethods&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;HEAD&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;PUT&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;DELETE&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;OPTIONS&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;allowCredentials&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;allowedHeaders&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;maxAge&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;3600&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一，&lt;code&gt;127.0.0.1&lt;/code&gt; 和 &lt;code&gt;localhost&lt;/code&gt; 需要同时指定！通过测试，如果只指定其中一个，无法进行另一个的请求。&lt;/p&gt;
&lt;p&gt;第二，当项目里使用的 springboot 的版本是 2.1.2.RELEASE 时，使用 &lt;code&gt;allowedOrigins(&amp;quot;*&amp;quot;)&lt;/code&gt; 没有问题，但是当版本改为 2.4.4 后会提示报错。&lt;/p&gt;
&lt;p&gt;当 allowCredentials 为 true 时，allowedOrigins 不能包含特殊值 &amp;ldquo;*&amp;quot;，因为它不能在 &amp;ldquo;Access-Control-Allow-Origin&amp;rdquo; 响应头中设置。&lt;/p&gt;
&lt;p&gt;要允许一组起源的凭证，明确地列出它们，或者考虑使用 allowedOriginPatterns 代替。&lt;/p&gt;
&lt;h3 id=&#34;options-请求跨域问题&#34;&gt;Options 请求跨域问题&lt;/h3&gt;
&lt;p&gt;在浏览器内请求跨域时，浏览器会先进行一次 preflight request（预检请求），以确认目标域是否允许跨域，如果允许，再进行实际操作中的请求。&lt;/p&gt;
&lt;p&gt;在接口请求中我们总会自定义请求头做 token，但是浏览器预检请求中的 OPTIONS 只会携带自定义的 token 字段但不会带相应的值，导致跨域以及报错。&lt;/p&gt;
&lt;p&gt;所以要处理跨域以及在 SpringSecurity 的认证过滤器链中需要过滤掉 OPTIONS。&lt;/p&gt;
&lt;p&gt;如果使用的是 Interceptor，则可以在定义的拦截器中将 OPTIONS 方法的请求放行即可。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Component&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;EnterInterceptor&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; HandlerInterceptor &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;preHandle&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;HttpServletRequest request&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; HttpServletResponse response&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Object handler&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throws&lt;/span&gt; Exception &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;request&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getMethod&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;equals&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;OPTIONS&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;AuthUtil&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;checkToken&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;request&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;            response&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;sendRedirect&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/api/error/401/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; URLEncoder&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;encode&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;token 验证失败&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;));&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;除此之外，为节省资源，可以通过配置缓存时间以防止浏览器频繁进行预检请求。&lt;/p&gt;
&lt;p&gt;在 CORS 中，当浏览器发送跨域请求时，服务器可以返回一个 &lt;code&gt;Access-Control-Max-Age&lt;/code&gt; 响应头，它指定了在这个响应被缓存多久。这意味着，在接下来的一段时间内，浏览器不需要向服务器再发送预检请求，而可以直接发送实际请求。&lt;/p&gt;
&lt;p&gt;还是如下这段跨域配置代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;addCorsMappings&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;CorsRegistry registry&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    registry&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;addMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/**&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;allowedOriginPatterns&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://127.0.0.1:*&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;https://127.0.0.1:*&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://localhost:*&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;https://localhost:*&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;allowedMethods&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;HEAD&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;PUT&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;DELETE&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;OPTIONS&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;allowCredentials&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;allowedHeaders&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;maxAge&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;3600&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上面的代码片段中，&lt;code&gt;maxAge(3600)&lt;/code&gt; 指定了响应在缓存中的最长时间为 3600 秒（1 小时），在这段时间内，浏览器将不再发送预检请求，从而提高了跨域请求的性能和效率。然而，需要注意的是，设置 maxAge 过长可能会导致安全风险，因为在这段时间内，任何网站都可以使用这个响应进行访问。因此，应该根据实际需求设置一个适当的值。&lt;/p&gt;
&lt;h2 id=&#34;fastjson-反序列化对象修饰符问题&#34;&gt;fastjson 反序列化对象修饰符问题&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;Caused by: java.lang.IllegalAccessException: class com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer cannot access a member of class com.jzh.test.json.SubmitTime with modifiers &amp;#34;public&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;fastjson 通过有参构造函数反序列化可能会出现此问题，原因是 SubmitTime 这个类没有被 public 修饰，而其构造函数使用 public 修饰，所以导致反序列化失败。而如果通过无参构造加 setter 进行反序列化则无此问题。&lt;/p&gt;
&lt;h2 id=&#34;本地多线程测试天坑-测试方法开的线程没跑完&#34;&gt;本地多线程测试天坑: 测试方法开的线程没跑完&lt;/h2&gt;
&lt;p&gt;如果测试方法中包含异步操作，那么直接运行测试方法，异步方法未执行完成时，主线程已经退出，导致异步方法无法正常执行完！！&lt;/p&gt;
&lt;p&gt;解决方法是在 @Test 测试方法中打个断点，不要让 @Test 的方法直接完成退出！&lt;/p&gt;
&lt;h2 id=&#34;idea-maven-reload--out-of-memory-error&#34;&gt;IDEA maven reload : out of memory error&lt;/h2&gt;
&lt;p&gt;Maven | Importing | VM options for importer: -Xmx6144m&lt;/p&gt;
&lt;h2 id=&#34;sqlite-jdbc-no-native-library-is-found&#34;&gt;sqlite-jdbc No native library is found&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;Caused by: java.lang.Exception: No native library is found for os.name=Mac and os.arch=aarch64. path=/org/sqlite/native/Mac/aarch64
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you are using Apple M1 chip&lt;/p&gt;
&lt;p&gt;One of the release notes they have mentioned by jetpack (Version 2.4.0-alpha03 )&lt;/p&gt;
&lt;p&gt;Fixed an issue with Room’s SQLite native library to support Apple’s M1 chips.
Change Version to 2.4.0-alpha03 or above&lt;/p&gt;
&lt;p&gt;For those who are facing this problem, you can simply add this line before the room-compiler as a workaround now:&lt;/p&gt;
&lt;p&gt;kapt &amp;ldquo;org.xerial:sqlite-jdbc:3.34.0&amp;rdquo;&lt;/p&gt;
&lt;h2 id=&#34;hibernate--sqlite-问题&#34;&gt;hibernate + sqlite 问题&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;Description:
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;An attempt was made to call a method that does not exist. The attempt was made from the following location:
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    org.sqlite.hibernate.dialect.SQLiteDialect.&amp;lt;init&amp;gt;(SQLiteDialect.java:57)
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;The following method did not exist:
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &amp;#39;void org.sqlite.hibernate.dialect.SQLiteDialect.registerColumnType(int, java.lang.String)&amp;#39;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;The calling method&amp;#39;s class, org.sqlite.hibernate.dialect.SQLiteDialect, was loaded from the following location:
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    jar:file:/Users/zh/.m2/repository/com/github/gwenn/sqlite-dialect/0.1.2/sqlite-dialect-0.1.2.jar!/org/sqlite/hibernate/dialect/SQLiteDialect.class
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;The called method&amp;#39;s class, org.sqlite.hibernate.dialect.SQLiteDialect, is available from the following locations:
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    jar:file:/Users/zh/.m2/repository/com/github/gwenn/sqlite-dialect/0.1.2/sqlite-dialect-0.1.2.jar!/org/sqlite/hibernate/dialect/SQLiteDialect.class
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;The called method&amp;#39;s class hierarchy was loaded from the following locations:
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;    org.sqlite.hibernate.dialect.SQLiteDialect: file:/Users/zh/.m2/repository/com/github/gwenn/sqlite-dialect/0.1.2/sqlite-dialect-0.1.2.jar
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;    org.hibernate.dialect.Dialect: file:/Users/zh/.m2/repository/org/hibernate/orm/hibernate-core/6.4.1.Final/hibernate-core-6.4.1.Final.jar
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;Action:
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;Correct the classpath of your application so that it contains a single, compatible version of org.sqlite.hibernate.dialect.SQLiteDialect
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;fix:&lt;/p&gt;
&lt;p&gt;From Hibernate 6, SQLite dialect is supported. We have to import in our pom.xml:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.hibernate.orm&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;hibernate-community-dialects&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Copy And in our application properties:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!--jpa--&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-data-jpa&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- sqlite --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.xerial&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;sqlite-jdbc&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.34.0&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!--        &amp;lt;dependency&amp;gt;--&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!--            &amp;lt;groupId&amp;gt;com.github.gwenn&amp;lt;/groupId&amp;gt;--&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!--            &amp;lt;artifactId&amp;gt;sqlite-dialect&amp;lt;/artifactId&amp;gt;--&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!--            &amp;lt;version&amp;gt;0.1.4&amp;lt;/version&amp;gt;--&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!--        &amp;lt;/dependency&amp;gt;--&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.hibernate.orm&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;hibernate-community-dialects&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;具体就是要删去 sqlite-dialect 并引入 hibernate-community-dialects，然后添加 jpa 配置。&lt;/p&gt;
&lt;h2 id=&#34;jar-包项目文件上传问题&#34;&gt;JAR 包项目文件上传问题&lt;/h2&gt;
&lt;p&gt;获取类路径：&lt;/p&gt;
&lt;p&gt;如果单纯运行一个 java 项目：&lt;code&gt;${project}/target/classes&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;如果是运行 jar 包，且是在 Linux 系统上：&lt;code&gt;${jar包名}!/BOOT-INF/classes!&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;所以如果是 jar 包启动并上传文件，则无法正确放到类路径下，需指定新的上传路径。&lt;/p&gt;
&lt;p&gt;可以在 jar 包同一路径下新建并编辑 application.yaml 文件如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;spring:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    resources&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;locations&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt; classpath&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;/&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt; file&lt;span style=&#34;color:#81a1c1&#34;&gt;:/&lt;/span&gt;app&lt;span style=&#34;color:#81a1c1&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在文件上传是指定上传路径即可。&lt;/p&gt;
&lt;h2 id=&#34;类文件具有错误的版本-550-应为-520&#34;&gt;类文件具有错误的版本 55.0, 应为 52.0&lt;/h2&gt;
&lt;p&gt;上面报错中的 55.0 是 JDK11 使用的类文件格式 (class file format) 的版本号，提示的意思是当面项目使用的类文件格式版本比某个依赖包使用的类文件格式版本低。&lt;/p&gt;
&lt;p&gt;实际就是指当前项目使用的 JDK 版本比某个依赖包使用的 JDK 版本低。&lt;/p&gt;
&lt;p&gt;Mockito 5.8 使用了 JDK 11，而项目使用 JDK 8，那么会报错。&lt;/p&gt;
&lt;h2 id=&#34;the-server-selected-protocol-version-tls10-is-not-accepted-by-client-preferences-tls13-tls12&#34;&gt;The server selected protocol version TLS10 is not accepted by client preferences [TLS13, TLS12]&lt;/h2&gt;
&lt;p&gt;Remove &amp;ldquo;TLSv1, TLSv1.1&amp;rdquo; from &amp;ldquo;jdk.tls.disabledAlgorithms&amp;rdquo; property in file ${soapui_home}/jre/conf/securityjava.security.&lt;/p&gt;
&lt;h2 id=&#34;rocketmq-it-may-be-caused-by-one-of-the-following-reasons-the-brokers-disk-is-full&#34;&gt;RocketMQ: It may be caused by one of the following reasons: the broker&amp;rsquo;s disk is full&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; conf/2m-2s-sync
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;vim broker-a.properties
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;diskMaxUsedSpaceRatio&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;99&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;springboot-3x-使用-springboot-2x-的-starter-无法完成自动装配&#34;&gt;SpringBoot 3.X 使用 SpringBoot 2.X 的 Starter 无法完成自动装配&lt;/h2&gt;
&lt;p&gt;SpringBoot 3.X 自动装配类通过 &lt;code&gt;META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports&lt;/code&gt; 配置，而 2.X 通过 &lt;code&gt;META-INF/spring.factories&lt;/code&gt; 完成，所以无法完成自动装配。解决方式是自己通过 &lt;code&gt;@Bean&lt;/code&gt; 和 &lt;code&gt;@Configuration&lt;/code&gt; 装配 Bean。&lt;/p&gt;
&lt;h2 id=&#34;listremove-正确的使用重载&#34;&gt;list.remove() 正确的使用重载&lt;/h2&gt;
&lt;p&gt;调用 &lt;code&gt;set.remove(i)&lt;/code&gt; 选择重载 &lt;code&gt;remove(E)&lt;/code&gt; 方法，其中 E 是 set (Integer) 的元素类型，将 基本类型 i 由 int 自动装箱为 Integer 中。这是你所期望的行为，因此程序最终会从集合中删除指定大小的值。&lt;/p&gt;
&lt;p&gt;调用 &lt;code&gt;list.remove(i)&lt;/code&gt; 的调用选择重载 &lt;code&gt;remove(int i)&lt;/code&gt; 方法，它将删除列表中指定位置的元素。若要删除指定大小的元素，对于 &lt;code&gt;List&amp;lt;E&amp;gt;&lt;/code&gt; 接口对方法有的两个重载: remove(E) 和 remove(int)，需要强制转换的参数为类型，迫使其选择正确的重载。&lt;/p&gt;
&lt;h2 id=&#34;后端返回的-json-数据格式出错&#34;&gt;后端返回的 json 数据格式出错&lt;/h2&gt;
&lt;p&gt;首先注意，json 采用驼峰命名法。&lt;/p&gt;
&lt;p&gt;一般对于前后端分离的项目，后端都是返回 json 格式数据，比如使用 &lt;code&gt;@RestController&lt;/code&gt; 进行自动的转换。&lt;/p&gt;
&lt;p&gt;对于一个采用驼峰命名法命名的变量，比如 userId，转换后返回前端的 json 属性名是 userId，没有问题。&lt;/p&gt;
&lt;p&gt;但是当变量名为 uId时，转换后则变为 uid，这就产生了问题。我还测试了其它一些变量，如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;userId&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;obj&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;userId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;uId&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;obj&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;uid&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;Id&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;obj&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;uuId&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ok&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;obj&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;uuId&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可见当为 uId 和 Id 时，都会出现问题。&lt;/p&gt;
&lt;p&gt;一般可以考虑在后端变量命名时，不让第二个字符大写，或者采用 &lt;code&gt;@JsonProperty(&amp;quot;uId&amp;quot;)&lt;/code&gt; 进行解决。&lt;/p&gt;
&lt;h2 id=&#34;idea-中在-maven-配置文件中配置-jvm-启动参数&#34;&gt;IDEA 中在 maven 配置文件中配置 JVM 启动参数&lt;/h2&gt;
&lt;p&gt;有些是 &lt;code&gt;.maven/maven.config&lt;/code&gt;，有些是 &lt;code&gt;.mvn/jvm.config&lt;/code&gt;，必须在设置 &amp;gt; maven 中查看。&lt;/p&gt;
&lt;h2 id=&#34;bigdecimal-构造函数的结果可能不可预测&#34;&gt;BigDecimal 构造函数的结果可能不可预测&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;BigDecimal amount1 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; BigDecimal&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;0&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;02&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;BigDecimal amount2 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; BigDecimal&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;0&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;03&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;amount2&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;subtract&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;amount1&lt;span style=&#34;color:#81a1c1&#34;&gt;));&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 0.0099999999999999984734433411404097569175064563751220703125
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/summary-record-of-daily-development-bugs/image/1691484382578.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;正确方法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;BigDecimal amount1 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; BigDecimal&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;valueOf&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;0&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;02&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;BigDecimal amount2 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; BigDecimal&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;valueOf&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;0&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;03&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;反序列化-boolean-字段失败的问题&#34;&gt;反序列化 boolean 字段失败的问题&lt;/h2&gt;
&lt;p&gt;直接以一个例子说明这个问题：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;FastJsonTest&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Test&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;test1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;        Vote vote &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Vote&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        vote&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setTitle&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        vote&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setIsOverdue&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        vote&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setDeleted&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        vote&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setImportant&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        String voteJson &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; JSON&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;toJSONString&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;vote&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;voteJson&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// {&amp;#34;deleted&amp;#34;:false,&amp;#34;important&amp;#34;:true,&amp;#34;isOverdue&amp;#34;:true,&amp;#34;title&amp;#34;:&amp;#34;test&amp;#34;}
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ok
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;        Vote voteFromJson &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; JSON&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;parseObject&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;voteJson&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Vote&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;voteFromJson&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// {&amp;#34;deleted&amp;#34;:false,&amp;#34;isImportant&amp;#34;:true,&amp;#34;isOverdue&amp;#34;:true,&amp;#34;title&amp;#34;:&amp;#34;test&amp;#34;}
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;        String anotherVoteJson &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{\&amp;#34;deleted\&amp;#34;:false,\&amp;#34;isImportant\&amp;#34;:true,\&amp;#34;isOverdue\&amp;#34;:true,\&amp;#34;title\&amp;#34;:\&amp;#34;test\&amp;#34;}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;        Vote anotherVote &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; JSON&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;parseObject&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;anotherVoteJson&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Vote&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;anotherVote&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 反序列化失败：
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// Vote(isOverdue=true, deleted=false, isImportant=false, title=test)
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Data&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Vote&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ok
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; Boolean isOverdue&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ok
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; Boolean deleted&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// fail
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;boolean&lt;/span&gt; isImportant&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; String title&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 fastjson 反序列化时，由于 Vote 对象存在空参构造, 所以将根据 set 方法反序列化，如果字段是 Boolean 类型，那么反序列化成功，如果是 boolean 类型，且字段命名以 &lt;code&gt;is&lt;/code&gt; 开头，那么反序列化失败。&lt;/p&gt;
&lt;p&gt;所以，建议布尔类型都不要加 &lt;code&gt;is&lt;/code&gt; 作为前缀，否则部分框架解析可能会有问题。(来自阿里巴巴 Java 开发手册)&lt;/p&gt;
&lt;h2 id=&#34;maven-的-http-问题&#34;&gt;maven 的 http 问题&lt;/h2&gt;
&lt;p&gt;Maven 升级到 3.8.1 之后，执行 &lt;code&gt;mvn clean package&lt;/code&gt; 命令后会报错如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;maven 在 3.8.1 的默认配置文件中增加了一组标签，如果仓库镜像是 http 而不是 https 就会被拦截禁止访问&lt;/p&gt;
&lt;p&gt;新增节点：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&amp;lt;mirror&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &amp;lt;id&amp;gt;maven-default-http-blocker&amp;lt;/id&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &amp;lt;mirrorOf&amp;gt;dummy&amp;lt;/mirrorOf&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &amp;lt;name&amp;gt;Dummy mirror to override default blocking mirror that blocks http&amp;lt;/name&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    &amp;lt;url&amp;gt;http://0.0.0.0/&amp;lt;/url&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&amp;lt;/mirror&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或回退版本&lt;/p&gt;
&lt;h2 id=&#34;failed-to-determine-a-suitable-driver-class&#34;&gt;Failed to determine a suitable driver class&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;2023&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;05&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;31T16&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;52&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;18&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;233&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;08&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;00  WARN 28432 &lt;span style=&#34;color:#81a1c1&#34;&gt;---&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;           main&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; ConfigServletWebServerApplicationContext &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; Exception encountered during context initialization &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt; cancelling refresh attempt&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; org&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;springframework&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;beans&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;factory&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;BeanCreationException&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; Error creating bean with name &lt;span style=&#34;color:#bf616a&#34;&gt;&amp;#39;&lt;/span&gt;dataSource&lt;span style=&#34;color:#bf616a&#34;&gt;&amp;#39;&lt;/span&gt; defined in &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;path&lt;/span&gt; resource &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;org&lt;span style=&#34;color:#81a1c1&#34;&gt;/&lt;/span&gt;springframework&lt;span style=&#34;color:#81a1c1&#34;&gt;/&lt;/span&gt;boot&lt;span style=&#34;color:#81a1c1&#34;&gt;/&lt;/span&gt;autoconfigure&lt;span style=&#34;color:#81a1c1&#34;&gt;/&lt;/span&gt;jdbc&lt;span style=&#34;color:#81a1c1&#34;&gt;/&lt;/span&gt;DataSourceConfiguration$Hikari&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;]:&lt;/span&gt; Failed to instantiate &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;com&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;zaxxer&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;hikari&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;HikariDataSource&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;]:&lt;/span&gt; Factory method &lt;span style=&#34;color:#bf616a&#34;&gt;&amp;#39;&lt;/span&gt;dataSource&lt;span style=&#34;color:#bf616a&#34;&gt;&amp;#39;&lt;/span&gt; threw exception with message&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; Failed to determine a suitable driver &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;2023&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;05&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;31T16&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;52&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;18&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;235&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;08&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;00  INFO 28432 &lt;span style=&#34;color:#81a1c1&#34;&gt;---&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;           main&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; o&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;apache&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;catalina&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;core&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;StandardService&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; Stopping service &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;Tomcat&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;2023&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;05&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;31T16&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;52&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;18&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;250&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;08&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;00  INFO 28432 &lt;span style=&#34;color:#81a1c1&#34;&gt;---&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;           main&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;b&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;a&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;l&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;ConditionEvaluationReportLogger&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;......&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;Failed to configure a DataSource&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;&amp;#39;&lt;/span&gt;url&lt;span style=&#34;color:#bf616a&#34;&gt;&amp;#39;&lt;/span&gt; attribute is not specified and no embedded datasource could be configured&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;Reason:&lt;/span&gt; Failed to determine a suitable driver &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;Action&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;Consider the following&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;  If you want an embedded &lt;span style=&#34;color:#88c0d0&#34;&gt;database&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;H2&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; HSQL or Derby&lt;span style=&#34;color:#81a1c1&#34;&gt;),&lt;/span&gt; please put it on the classpath&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;  If you have database settings to be loaded from a particular profile you may need to activate &lt;span style=&#34;color:#88c0d0&#34;&gt;it&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;no profiles are currently active&lt;span style=&#34;color:#81a1c1&#34;&gt;).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关键在于：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;Error creating bean with name &amp;#39;dataSource&amp;#39; defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method &amp;#39;dataSource&amp;#39; threw exception with message: Failed to determine a suitable driver class
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以发现是 springboot 自动配置的锅，找不到一个合适的 driver 进行数据源的连接。&lt;/p&gt;
&lt;p&gt;解决方法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@SpringBootApplication&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;exclude &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;DataSourceAutoConfiguration&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;隐藏的依赖版本冲突问题&#34;&gt;隐藏的依赖版本冲突问题&lt;/h2&gt;
&lt;p&gt;当我从 SpringBoot 2.7 迁移到 SpringBoot 3.0 时，发现项目启动报错，原来的项目能正常启动，证明可能是依赖错误的问题了。&lt;/p&gt;
&lt;p&gt;而 pom.xml 中有着很多依赖，由于是和 SpringBoot 有关，所以估计是一些第三方的 starter 有问题，最终发现是 MybatisPlus 的 3.4.3.4 版本不能正常在 SpringBoot 3.0 中使用，升级到 3.5.3.1 就没这个问题了。&lt;/p&gt;
&lt;h2 id=&#34;bufferedwriter-无法正确写出问题&#34;&gt;BufferedWriter 无法正确写出问题&lt;/h2&gt;
&lt;p&gt;这是一段客户端代码，向服务器端发送消息，然后接收服务器端的回复：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;try&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;        BufferedReader in &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; BufferedReader&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; InputStreamReader&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;socket&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getInputStream&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()));&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;        BufferedWriter out &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; BufferedWriter&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; OutputStreamWriter&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;socket&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getOutputStream&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()))&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    String message&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;while&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;((&lt;/span&gt;message &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; stdIn&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;readLine&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;())&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        out&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;write&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;message&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        out&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;flush&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Receive from server: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; in&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;readLine&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Exception e&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getMessage&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是服务端代码的一部分，接收客户端消息，并向客户端回复：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;try&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;        BufferedReader in &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; BufferedReader&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; InputStreamReader&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;socket&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getInputStream&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()));&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;        BufferedWriter out &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; BufferedWriter&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; OutputStreamWriter&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;socket&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getOutputStream&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()))&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    String message&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;while&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;((&lt;/span&gt;message &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; in&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;readLine&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;())&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Thread&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;currentThread&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getName&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;: receive from port &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; socket&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getPort&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; message&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        out&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;write&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;message&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        out&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;flush&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Exception e&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getMessage&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里两端都使用了 &lt;code&gt;BufferedReader&lt;/code&gt; 和 &lt;code&gt;BufferedWriter&lt;/code&gt; 作为消息的传输工具。&lt;/p&gt;
&lt;p&gt;经过测试发现，消息传输是失败的。&lt;/p&gt;
&lt;p&gt;问题出现在 &lt;code&gt;out.write(message);&lt;/code&gt; 和 &lt;code&gt;message = in.readLine()&lt;/code&gt; 这两个地方，因为 &lt;code&gt;in.readLine()&lt;/code&gt; 读取的是一行数据，即数据必须要存在换行符，如果不存在的话将无法读完，一直处于阻塞状态。&lt;/p&gt;
&lt;p&gt;所以，解决方法就是将写出的数据通过 &lt;code&gt;newLine&lt;/code&gt; 操作加上换行符：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;out&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;write&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;message&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 如果使用BufferedWriter，则需要添加换行符
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;out&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;newLine&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;另一种更好的方法是使用 &lt;code&gt;PrintWriter&lt;/code&gt;，使用它的写出操作 &lt;code&gt;println&lt;/code&gt; 进行消息的输出。&lt;/p&gt;
&lt;h2 id=&#34;pnpm-build-error-rollup&#34;&gt;pnpm build error: Rollup&lt;/h2&gt;
&lt;p&gt;构建失败的原因是 Rollup 在处理代码时遇到了一个错误：Cannot read properties of null (reading &amp;lsquo;render&amp;rsquo;)。这种错误通常与代码中的某些语法或依赖问题有关。&lt;/p&gt;
&lt;p&gt;某些第三方库可能与 Rollup 不兼容，尤其是使用了动态导入或复杂语法的库。检查 node_modules 中是否有库的版本更新或损坏。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 清理缓存&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;pnpm store prune
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 删除 node_modules 和 lock 文件&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;rm -rf node_modules pnpm-lock.yaml
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 重新安装依赖&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;pnpm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;spark-cannot-safely-cast&#34;&gt;Spark: Cannot safely cast&lt;/h2&gt;
&lt;p&gt;Spark-sql 执行 sql 语句报：Cannot safely cast xxx string to int.&lt;/p&gt;
&lt;p&gt;原因是 spark-sql 执行 sql 有三中模式：ANSI, LEGACY, STRICT。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ANSI 模式是标准 sql，不允许不合理的类型转换，与 PostgreSQL 相同；&lt;/li&gt;
&lt;li&gt;LEGACY 模式允许类型强制转换，只要它是有效的 Cast，这也是 Spark 2.x 中的唯一行为，它与 Hive 兼容；&lt;/li&gt;
&lt;li&gt;STRICT 模式下 Spark 不允许任何可能的精度损失或数据截断。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;解决方法是添加如下配置即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;spark.sql.storeAssignmentPolicy=LEGACY
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;node-error-message-error0308010cdigital-envelope-routinesunsupported&#34;&gt;Node: Error message &amp;ldquo;error:0308010C:digital envelope routines::unsupported&amp;rdquo;&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;export&lt;/span&gt; NODE_OPTIONS&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;--openssl-legacy-provider
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;apple-watch-无法更新一直显示已暂停&#34;&gt;Apple Watch 无法更新，一直显示已暂停&lt;/h2&gt;
&lt;p&gt;在 Apple Watch 中的储存空间下删除之前的更新文件即可。&lt;/p&gt;
&lt;h2 id=&#34;apple-map-icloud-关闭同步后指南丢失&#34;&gt;Apple Map icloud 关闭同步后指南丢失&lt;/h2&gt;
&lt;p&gt;卸载重装 Apple Map 即可&lt;/p&gt;
&lt;h2 id=&#34;go-build-stuck&#34;&gt;go build stuck&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;go build -v -o bepusdt ./main
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;github.com/goccy/go-json/internal/encoder/vm
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# stuck here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Try cleaning the build cache to ensure that no corrupted files are causing the problem.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;go clean -cache -modcache -i -r
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;iterm2-scp-下载每次都要询问-key&#34;&gt;iterm2 scp 下载每次都要询问 key&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;ssh-add -K ~/.ssh/id_rsa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;latex-中文编码问题&#34;&gt;latex 中文编码问题&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;\usepackage{CJKutf8}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;\begin{document}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;\begin{CJK}{UTF8}{gbsn}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;...
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;\end{CJK}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;\end{document}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;certbot-renew-报错-urlib3-依赖问题&#34;&gt;certbot renew 报错 urlib3 依赖问题&lt;/h2&gt;
&lt;p&gt;try:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;pip install --upgrade --force-reinstall &amp;#39;requests==2.6.0&amp;#39; urllib3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve had the same problem &lt;a href=&#34;https://niuhp.com/other/https-certbot.html&#34;&gt;https://niuhp.com/other/https-certbot.html&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;mybatis-判断和语法错误&#34;&gt;mybatis 判断和语法错误&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&amp;lt;if test=&amp;#34;employeeIds != null and employeeIds.size &amp;gt; 0&amp;#34;&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    AND A.EmployeeId in
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &amp;lt;foreach collection=&amp;#34;employeeIds&amp;#34; index=&amp;#34;index&amp;#34; item=&amp;#34;item&amp;#34; open=&amp;#34;(&amp;#34; separator=&amp;#34;,&amp;#34; close=&amp;#34;)&amp;#34;&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;        #{item}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    &amp;lt;/foreach&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&amp;lt;/if&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;ORDER BY A.FeedId DESC
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;and employeeIds.size &amp;gt; 0&lt;/code&gt; 不可少否则报错：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;org.springframework.jdbc.BadSqlGrammarException
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;curl-请求路径正确但报-404-或参数反序列化异常&#34;&gt;curl 请求路径正确但报 404 或参数反序列化异常&lt;/h2&gt;
&lt;p&gt;去掉 content-length 限制 &lt;code&gt;-H &#39;Content-Length: 19&#39;&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;sqlserver-tlsv1-was-negotiated-please-update-server-and-client-to-use-tlsv12-at-minimum&#34;&gt;sqlserver TLSv1 was negotiated. Please update server and client to use TLSv1.2 at minimum.&lt;/h2&gt;
&lt;p&gt;由于公司的 sqlserver 只支持 tls1 所以需要安装旧版本 driver 并配置 VM option：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&amp;#34;-Djdk.tls.disabledAlgorithms=SSLv3, TLSv1.1, RC4, DES, MD5withRSA, DH keySize &amp;lt; 1024, EC keySize &amp;lt; 224, 3DES_EDE_CBC, anon, NULL&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;driver 使用 8 及以下版本即可。&lt;/p&gt;
&lt;h2 id=&#34;unittest-test-discovery-error-for-workspace&#34;&gt;Unittest test discovery error for workspace&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;2024-02-05 15:27:34.532 [error]     from typing_extensions import Literal, NotRequired, TypedDict
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;  File &amp;#34;/Users/zh/.vscode/extensions/ms-python.python-2024.0.0/pythonFiles/lib/python/typing_extensions.py&amp;#34;, line 916
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    def TypedDict(typename, fields=_marker, /, *, total=True, **kwargs):
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;                                            ^
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;SyntaxError: invalid syntax
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;2024-02-05 15:27:34.544 [error] Subprocess exited unsuccessfully with exit code 1 and signal null on workspace /Users/zh/Codes/jvav. Creating and sending error discovery payload 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;2024-02-05 15:27:34.544 [error] Unittest test discovery error for workspace:  /Users/zh/Codes/jvav 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Fixed by &lt;a href=&#34;https://github.com/microsoft/vscode-python/issues/21757&#34;&gt;#21757&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thank you for your issue report. We are looking into this now! In the meantime, you are likely on the new testing rewrite and this is why you saw a change in behavior. You can opt out of the rewrite as I get this fix in by setting this in your user settings: &amp;ldquo;python.experiments.optOutFrom&amp;rdquo;: [&amp;ldquo;pythonTestAdapter&amp;rdquo;],. If this doesn&amp;rsquo;t work let me know as this will mean it is a different issue. Thank you and I will send updates in this thread as I get a fix in.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// settings.json
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;python.experiments.optOutFrom&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;pythonTestAdapter&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;gitignore-失效&#34;&gt;Gitignore 失效&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git rm -rf --cached .
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git add .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;nginx-error-pid&#34;&gt;Nginx Error PID&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;nginx: [error] invalid PID number &amp;#34;&amp;#34; in &amp;#34;/run/nginx.pid&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;pkill nginx
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;nginx
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;nginx -s reload
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;nginx-相对地址资源引用不走反向代理&#34;&gt;Nginx 相对地址资源引用不走反向代理&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;location /pay/usdt/ {
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;  sub_filter &amp;#39;src=&amp;#34;/img/&amp;#39;  &amp;#39;src=&amp;#34;/pay/usdt/img/&amp;#39;;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;  sub_filter &amp;#39;src=&amp;#34;/js/&amp;#39; &amp;#39;src=&amp;#34;/pay/usdt/js/&amp;#39; ;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;  sub_filter &amp;#39;src=&amp;#34;/css/&amp;#39; &amp;#39;src=&amp;#34;/pay/usdt/css/&amp;#39; ;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;  sub_filter_once off;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;  proxy_pass http://127.0.0.1:8080/;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;nginx-无法加载-css&#34;&gt;Nginx 无法加载 css&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;http {
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    include /etc/nginx/mime.types;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;dujiaoka-重启后前台需要重新安装&#34;&gt;dujiaoka 重启后前台需要重新安装&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# enter dujiaoka container&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ok&amp;#34;&lt;/span&gt; &amp;gt; /dujiaoka/install.lock
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;manpath-cant-set-the-locale-make-sure-lc_-and-lang-are-correct&#34;&gt;manpath: can&amp;rsquo;t set the locale; make sure $LC_* and $LANG are correct&lt;/h2&gt;
&lt;p&gt;Add these lines to /etc/environment:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;LANG&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;en_US.utf-8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;LC_ALL&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;en_US.utf-8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;rsshub-commit-不通过&#34;&gt;RSSHub commit 不通过&lt;/h2&gt;
&lt;p&gt;报错提示说缺少某个依赖(pinyin-pro)，是文档相关的。&lt;/p&gt;
&lt;p&gt;如果修改了文档，那么需要到 website 下运行 &lt;code&gt;pnpm i&lt;/code&gt; 安装相关依赖，以便于 commit 检查。&lt;/p&gt;
&lt;h2 id=&#34;influxdb-引号问题&#34;&gt;InfluxDb 引号问题&lt;/h2&gt;
&lt;p&gt;插入数据时，tag 不带引号，field 字符串类型带双引号&lt;/p&gt;
&lt;p&gt;查询数据时，字符串类型带单引号&lt;/p&gt;
&lt;h2 id=&#34;docker-compose-容器内无法连接服务的问题&#34;&gt;docker-compose 容器内无法连接服务的问题&lt;/h2&gt;
&lt;p&gt;这是一个 docker-compose 配置文件:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; redis
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; bash -c &amp;#34;mkdir -p ${PATH_REDIS} &amp;amp;&amp;amp; touch ${PATH_REDIS}/redis.conf &amp;amp;&amp;amp; redis-server ${PATH_REDIS}/redis.conf&amp;#34;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;6379:6379&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;      - ${HOST_PATH_ROOT}/redis:${PATH_REDIS}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;      - ${HOST_PATH_ROOT}/redis/data:/data
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;web&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;build&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; .
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;      - ${HOST_PATH_ROOT}:${PATH_ROOT}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;      - cache
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# network_mode: &amp;#34;host&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我组织了两个容器服务，redis 和 web，在 web 中需要连接到 redis，如果指定的 redis 地址为 127.0.0.1 则无法连接到，报错如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;ERROR: 无法连接到 redis 服务: 127.0.0.1:6379 : Error 111 connecting to 127.0.0.1:6379. Connection refused.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是因为通过 docker-compose 组织的容器，主机名被设置为 cache 和 web，将 127.0.0.1 改为 cache 即可。&lt;/p&gt;
&lt;h2 id=&#34;xx-不允许发送按键&#34;&gt;XX 不允许发送按键&lt;/h2&gt;
&lt;p&gt;执行发送按键的 applescript 时可能会失败：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;execution error: “System Events”遇到一个错误：“osascript”不允许发送按键。 &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;1002&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在隐私与安全性 -&amp;gt; 辅助功能 -&amp;gt; + -&amp;gt; 添加 /usr/bin/osascript 即可&lt;/p&gt;
&lt;h2 id=&#34;gitignore-反选的正确用法&#34;&gt;.gitignore 反选的正确用法&lt;/h2&gt;
&lt;p&gt;排除 /.xxx 下除了 jvm.cfg 的所有文件:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;/.xxx/*
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;!/.xxx/jvm.cfg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果 /.xxx/* 写为 /.xxx/ 或 /.xxx 都将失效，因为这样忽略的是 ./xxx 这个文件夹，而不是整个文件夹下的文件，导致反选无效。&lt;/p&gt;
&lt;h2 id=&#34;brew-安装报错-curl-56-failure-when-receiving-data-from-the-peer&#34;&gt;brew 安装报错 curl: (56) Failure when receiving data from the peer&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;git config --global http.sslVerify &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;git config --global https.sslVerify &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;false&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;oh-my-zsh-agnoster-主题乱码问题&#34;&gt;oh-my-zsh agnoster 主题乱码问题&lt;/h2&gt;
&lt;p&gt;从这个链接下载字体文件： &lt;a href=&#34;https://github.com/lxbrtsch/Menlo-for-Powerline&#34;&gt;https://github.com/lxbrtsch/Menlo-for-Powerline&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;mv &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Menlo for Powerline.ttf&amp;#34;&lt;/span&gt; ~/Library/Fonts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;VSCode -&amp;gt; Terminal Font Family 设置字体为 Menlo for Powerline&lt;/p&gt;
&lt;p&gt;Terminal -&amp;gt; 设置 -&amp;gt; 字体 -&amp;gt; 更改&lt;/p&gt;
&lt;h2 id=&#34;docker-compose-volume-指定对象为文件时产生的问题&#34;&gt;docker-compose volume 指定对象为文件时产生的问题&lt;/h2&gt;
&lt;p&gt;如果指定为文件（命名为 a），且事先没有创建该文件，那么当启动后，docker 将会自动创建一个名为 a 的目录。&lt;/p&gt;
&lt;p&gt;这样就读取不到该文件了。&lt;/p&gt;
&lt;p&gt;所以，如果指定的对象为文件，建议先创建。&lt;/p&gt;
&lt;h2 id=&#34;sqlite3-执行-sql-出错&#34;&gt;Sqlite3 执行 sql 出错&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;sqlite&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;select&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;from&lt;/span&gt; t_record &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;comment&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;Parse error&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;no&lt;/span&gt; such &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;column&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;select&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;from&lt;/span&gt; t_record &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;where&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;comment&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;                            error here &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;---^
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应该将双引号改为单引号。&lt;/p&gt;
&lt;p&gt;根据 SQL 标准，通常在标识符（例如表名或列名）周围使用双引号，而在字符串字面量周围使用单引号。&lt;/p&gt;
&lt;p&gt;在 3.41 版本往后 cli 默认禁用了双引号表示字符串，使用单引号就不报错了：https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted&lt;/p&gt;
&lt;h2 id=&#34;iterm2-无法使用-scp&#34;&gt;iterm2 无法使用 scp&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# server side&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;vim .zprofile
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;export&lt;/span&gt; iterm2_hostname&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;your_server_global_ip
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# then relogin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;python-版本冲突问题&#34;&gt;Python 版本冲突问题&lt;/h2&gt;
&lt;p&gt;certbot 依赖系统 python3 的 requests 包，但它和某个项目依赖的 requests 包版本不一样，如果项目不使用 venv，将会导致 certbot 不可用。&lt;/p&gt;
&lt;p&gt;建议在资源允许的情况下所有项目都使用 venv 来隔离 python 环境。&lt;/p&gt;
&lt;h2 id=&#34;python-requests_cache-在多线程环境下发生错误-database-is-locked&#34;&gt;Python requests_cache 在多线程环境下发生错误 &amp;ldquo;database is locked&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;代码包含了使用了 requests_cache 的引用包，而引用包中存在的 &lt;code&gt;requests_cache.install_cache&lt;/code&gt; 将影响所有范围的 requests，代码中有着多线程操作，其中某个线程长时间占用 sqlite，锁长时间无法释放，从而导致其它线程无法访问数据库（sqlite3 本身是线程安全的）、CPU 占用率飙升。引用包建议单独使用 &lt;code&gt;requests_cache.CachedSession&lt;/code&gt; 完成操作。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;FYI, a better option for using requests-cache is using CachedSession directly, instead of patching with install_cache(). It makes it more explicit what you are and aren&amp;rsquo;t caching, and doesn&amp;rsquo;t affect downstream requests calls. It&amp;rsquo;s mostly thread-safe, except for cache_disabled(), as you noted; instead, when you want to make a non-cached request, you can just use a regular requests.Session.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;errno-24-too-many-open-files&#34;&gt;[Errno 24] Too many open files&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;ulimit&lt;/span&gt; -n &lt;span style=&#34;color:#b48ead&#34;&gt;50000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;django-手动删除-migrations-目录后-migrate-无效&#34;&gt;Django 手动删除 migrations 目录后 migrate 无效&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;python3 manage.py migrate --fake &amp;lt;app-name&amp;gt; zero
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;python3 manage.py makemigrations &amp;lt;app-name&amp;gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;python3 manage.py migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;mac-m1-python379-modulenotfounderror-no-module-named-_ctypes&#34;&gt;mac m1 python3.7.9 ModuleNotFoundError: No module named &amp;lsquo;_ctypes&amp;rsquo;&lt;/h2&gt;
&lt;p&gt;Use python3.7.12 instead.&lt;/p&gt;
&lt;h2 id=&#34;windows-下安装-lxml-报错&#34;&gt;Windows 下安装 lxml 报错&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;Error while installing lxml through pip: Microsoft Visual C++ 14.0 is required
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;pip install wheel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Download lxml from &lt;a href=&#34;http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml&#34;&gt;http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml&lt;/a&gt;, if your python version is 3.5, download lxml-3.6.4-cp35-cp35m-win32.whl (补充一句: 经测试 3.12 版本的安装无法 3.11 版本的)&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pip install lxml-3.6.4-cp35-cp35m-win32.whl&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;unicodedecodeerror-utf-8-codec-cant-decode-byte-0xff-in-position-0-invalid-start-byte&#34;&gt;UnicodeDecodeError: &amp;lsquo;utf-8&amp;rsquo; codec can&amp;rsquo;t decode byte 0xff in position 0: invalid start byte&lt;/h2&gt;
&lt;p&gt;byte 0xff in position 0 could also mean the file is encoded in UTF-16, then you can do with
open(path, encoding=&amp;lsquo;utf-16&amp;rsquo;) as f: instead&lt;/p&gt;
&lt;h2 id=&#34;包冲突&#34;&gt;包冲突&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;ModuleNotFoundError: No module named &amp;#39;utils.util_bus&amp;#39;; &amp;#39;utils&amp;#39; is not a package
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;项目下的 utils 文件夹 &amp;lt;-&amp;gt; pip 某个依赖包中的 utils.py 文件名 &amp;ldquo;utils&amp;rdquo; 冲突！&lt;/p&gt;
&lt;p&gt;默认先扫描当前目录下包，但是识别不到 utils 包，因为 utils 文件夹下缺失了 &lt;code&gt;__init__.py&lt;/code&gt; 文件！&lt;/p&gt;
&lt;h2 id=&#34;sslerrorsslcertverificationerror&#34;&gt;SSLError(SSLCertVerificationError)&lt;/h2&gt;
&lt;p&gt;使用 requests 库时出现 bug:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;(Caused by SSLError(SSLCertVerificationError(1, &amp;#39;[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)&amp;#39;)))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;解决方法：&lt;a href=&#34;https://stackoverflow.com/questions/10667960/python-requests-throwing-sslerror&#34;&gt;python-requests-throwing-sslerror&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;From requests documentation on SSL verification:&lt;/p&gt;
&lt;p&gt;Requests can verify SSL certificates for HTTPS requests, just like a web browser. To check a host’s SSL certificate, you can use the verify argument:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;requests&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;https://kennethreitz.com&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; verify&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;True&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;pipenv-无法正常-install&#34;&gt;pipenv 无法正常 install&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;PS C:\Users\akyna\Codes\test\test_py&amp;gt; pipenv install
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;Usage: pipenv install [OPTIONS] [PACKAGES]...
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;ERROR:: --system is intended to be used for pre-existing Pipfile installation, not installation of specific packages. Aborting.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;解决方法：&lt;/p&gt;
&lt;p&gt;因为pipenv检测到之前在该目录下创建过了环境，需要先删除之前的环境才可以：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;PS C:\Users\akyna\Codes\test\test_py&amp;gt; pipenv --rm
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;Removing virtualenv (C:\Users\akyna\.virtualenvs\test_py-_qApXuy4)...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;python-requests-库-headers-字段编码错误&#34;&gt;Python requests 库 headers 字段编码错误&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;UnicodeEncodeError: &amp;#39;latin-1&amp;#39; codec can&amp;#39;t encode characters in position 30-34: ordinal not in range(256)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;解决方法：&lt;/p&gt;
&lt;p&gt;加上.encode(&amp;lsquo;utf-8&amp;rsquo;)：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;User-Agent&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;Host&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; HOST&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;Connection&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;close&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;X-Requested-With&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;XMLHttpRequest&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;    &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;Referer&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; url&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;encode&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;),&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;## fix bug&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;python--crontab-环境变量&#34;&gt;python + crontab 环境变量&lt;/h2&gt;
&lt;p&gt;crontab运行python时，如果python中使用了环境变量，将无法正常获取。&lt;/p&gt;
&lt;p&gt;解决方法：&lt;/p&gt;
&lt;p&gt;在crontab中配置好 python 中用到的环境变量：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;## backup
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;0 1 * * * env code=/root/Codes /bin/bash /root/Codes/scripts/unix/bbak
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;## tg send
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;0 8 * * * env code=/root/Codes /bin/python3 ~/Codes/scripts/py/submit_tg_send.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;python-关于爬虫所设置的-headers-中的-useragent&#34;&gt;Python 关于爬虫所设置的 Headers 中的 UserAgent&lt;/h2&gt;
&lt;p&gt;这是一个很难以发现的点，但不能说是bug吧。&lt;/p&gt;
&lt;p&gt;Headers 中的 UserAgent 可以配置不同的设备端，如果设置了类似于 Android 这样的手机端，那从 &lt;code&gt;requests.get()&lt;/code&gt; 返回得到的页面是手机端的界面！如果这个网站手机端的界面和电脑端的界面不是一样的，那么这个问题是很值得注意的。&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Clannad, 一曲治愈而忧伤的诗</title>
        <link>https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/</link>
        <pubDate>Thu, 27 Apr 2023 16:11:45 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>clannad-a-poem-of-healing-and-sadness</guid>
        <description>&lt;p&gt;Clannad 是京都动画根据 Key 社同名游戏改编的电视动画作品，总体上，Clannad 给人的感觉还是温馨，治愈的，搞笑欢乐的情节也不少，但同时带有淡淡的忧伤。它富有情感的剧情和优雅的音乐，让它成为一曲动人的诗。&lt;/p&gt;
&lt;p&gt;我想记录一下 Clannad 中让我印象深刻的一些故事，音乐，人物等，写写我的感受。&lt;/p&gt;
&lt;h2 id=&#34;忧伤温柔的轻音乐&#34;&gt;忧伤，温柔的轻音乐&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;《東風-piano-》by 折户伸治&lt;/li&gt;
&lt;li&gt;《町, 時の流れ人》(小镇时光的流逝人) by 折户伸治&lt;/li&gt;
&lt;li&gt;《潮鳴り》(潮鸣) by 折户伸治&lt;/li&gt;
&lt;li&gt;《白詰草》(白诘草) by 折户伸治&lt;/li&gt;
&lt;li&gt;《日々の遑》(日常生活) by 折户伸治&lt;/li&gt;
&lt;li&gt;《空に光る》(天空中闪烁着光) by 戸越まごめ&lt;/li&gt;
&lt;li&gt;《渚～坂の下の別れ》(渚~坡下的离别) by 麻枝准&lt;/li&gt;
&lt;li&gt;《汐》by 戸越まごめ&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Clannad 可谓是动画 BGM 的教科书，完美诠释了音乐在故事构建中的重要性。&lt;/p&gt;
&lt;p&gt;每当《潮鳴り》响起，感情就会不由自主地被带动。就如《未闻花名》中《secret base》一曲一样。&lt;/p&gt;
&lt;p&gt;Clannad 中很多音乐都带有一种淡淡的忧伤感，就比如《渚～坂の下の別れ》，但其实也都是温柔而治愈的。&lt;/p&gt;
&lt;p&gt;《白詰草》给人就是一种温柔的感觉，每当听到这一曲，就会觉得很舒服，优雅婉转的笛声，久久难忘。&lt;/p&gt;
&lt;h2 id=&#34;即使如此你还会喜欢上这里吗&#34;&gt;即使如此，你还会喜欢上这里吗&lt;/h2&gt;
&lt;p&gt;无法忘记渚在那条樱花坡道上说了的这么一段话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你喜欢这所学校吗&lt;/p&gt;
&lt;p&gt;我非常非常喜欢&lt;/p&gt;
&lt;p&gt;但所有的这一切，都在不断变化着&lt;/p&gt;
&lt;p&gt;无论是多么愉快的事，还是多么开心的事，一切&lt;/p&gt;
&lt;p&gt;都在不断改变着&lt;/p&gt;
&lt;p&gt;即使如此，你还会喜欢上这里吗&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1683123391495.png&#34; loading=&#34;lazy&#34; alt=&#34;1683123391495&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;时间带走了许多东西，我们曾经一起度过的岁月一去不返。那片老树林已经不见了，取而代之的是一座高楼。学校的旧教室将要翻新，旧时安静的街道现在已经车水马龙，忙忙碌碌。&lt;/p&gt;
&lt;p&gt;我们人的一生总在经历着变化，永无止境的变化，然而尽管如此，你还会喜欢上那些变化后的事物吗？&lt;/p&gt;
&lt;p&gt;我接受着变化，但是我无法忘记从前，无法忘记那些旧事物的模样。记忆是一种美好的东西，但又是一种残忍的东西。人的一生是漫长的，但又是稍纵即逝的。珍惜当下吧，因为很快当下这一切又将成为回忆！&lt;/p&gt;
&lt;h2 id=&#34;伊吹风子的故事&#34;&gt;伊吹风子的故事&lt;/h2&gt;
&lt;p&gt;风子是一个相当可爱的角色，她作为一个思念体而存在着。&lt;/p&gt;
&lt;p&gt;她的姐姐伊吹公子每天都会去医院看望她，尽管医生说风子可能已经不会再醒过来。伊吹公子有着婚约，但是一直不愿意无法放下妹妹，让自己去幸福，她内心怀着坚定的信念，相信妹妹风子有一天会醒过来。但风子希望姐姐放下自己，去追寻自己的幸福，她不希望姐姐因为自己而无法获得属于自己的幸福。&lt;/p&gt;
&lt;p&gt;寄托着风子愿望的亲情，让风子化作思念体，来到学校，整天在旧校舍空教室里默默雕刻，并把雕刻得像星型的木雕分送给人，当做姐姐公子婚礼上的请帖。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1682600851624.png&#34; loading=&#34;lazy&#34; alt=&#34;1682600851624&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;最后，风子终于完成了自己的愿望。姐姐似乎感受到了风子的心意，勇敢地放下负担，去追求自己的幸福。在婚礼的最后，风子将最后一个海星送给了姐姐，说完”一直，一直要幸福哦“，便化作一阵风，伴随着《Ana》这一首动人的歌曲，永远地消失在了空中：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The place changes and goes&lt;/p&gt;
&lt;p&gt;Like a wind like clouds&lt;/p&gt;
&lt;p&gt;Like the traces of the heart&lt;/p&gt;
&lt;p&gt;No halt at the places&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;风子是我最喜欢的角色之一，特别喜欢她俏皮可爱而又天然呆的样子 ヾ(≧▽≦*)o 风子赛高！&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1682600660125.png&#34; loading=&#34;lazy&#34; alt=&#34;1682600660125&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;你的梦想就是我们的梦想&#34;&gt;你的梦想就是我们的梦想&lt;/h2&gt;
&lt;p&gt;当渚意外翻到爸妈的青春回忆录，内心几乎快要奔溃。她终于知道了爸妈一直对自己隐瞒的事。&lt;/p&gt;
&lt;p&gt;渚小的时候，有一次生病了。他们在安顿好了渚之后，由于都有着不能请假的理由，无法继续陪伴生病的渚，各自离开去处理自己的事情。而当他们回来后，看到的是因等待，寻找爸妈不得，害怕孤单，心力交瘁后晕倒在雪地中的女儿。&lt;/p&gt;
&lt;p&gt;他们因为自己的失职而后悔不已，发誓要将自己的后半生的时间花在陪伴家人，照顾女儿上面。于是，他们放弃了自己的梦想，开了自己的面包店。而面包店的生活是十分幸福快乐的，他们并未感到后悔。&lt;/p&gt;
&lt;p&gt;渚知道了爸爸曾经在高中时代也是演剧部的一员，上演了高水平的戏剧，成为一名优秀的演员是他的梦想。而自己现在也将要踏上舞台，去实现自己的梦想。她自责地认为是因为自己的原因让爸爸不能再去追求梦想，并对站上舞台产生了恐惧，丧失了自信。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1682601005145.png&#34; loading=&#34;lazy&#34; alt=&#34;1682601005145&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;当渚在舞台上抑制不住自己的感情而落泪，没有勇气和自信继续自己的戏剧时，爸爸古田秋生冲后面从了进来，大声地喊：“渚！你是笨蛋吗？孩子的梦想就是父母的梦想，由你去实现就行！我们梦想着你能实现自己的梦想，我们并没有放弃自己的梦想！只是把自己的梦想寄托在了你的梦想身上！所谓父母就是这样的，所谓家族就是这样的！所以，从那天开始就一直&amp;hellip;&amp;hellip;一直过着烤面包的生活，一直&amp;hellip;&amp;hellip;我们一直都在渴望着这一刻！如果你在这里气馁了，我们会很失落的！”&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;最后，渚终于顺利完成了戏剧，大家的努力没有白费，渚也不再感到自责。&lt;/p&gt;
&lt;p&gt;亲情是如此的伟大。看到这里，多少能理解一些为人父母的感觉。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1682601016147.png&#34; loading=&#34;lazy&#34; alt=&#34;1682601016147&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;无法再次抬起发力的右臂&#34;&gt;无法再次抬起发力的右臂&lt;/h2&gt;
&lt;p&gt;冈崎的母亲因为事故过世，父亲绝望地失去了生活的希望，整日酗酒赌博，对儿子毫不关心。&lt;/p&gt;
&lt;p&gt;冈崎在一次和父亲大打出手中，右臂受重伤，导致自己无法再次抬起右臂发力，进而让自己无法再碰篮球。&lt;/p&gt;
&lt;p&gt;这让他在以体育生的身份进入的高中迷失了自我。&lt;/p&gt;
&lt;p&gt;所幸，他遇到了和他一样迷失自我的春原，遇到了渚，还有其它一些朋友。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1682602976657.png&#34; loading=&#34;lazy&#34; alt=&#34;1682602976657&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;在一起为演剧部的建立而进行的篮球赛中，冈崎拼尽全力，终究投进了球。&lt;/p&gt;
&lt;p&gt;尽管知道自己做不到，但还是去尝试，万一发生奇迹了呢？&lt;/p&gt;
&lt;p&gt;在重建演剧部的过程中，冈崎邂逅了各式各样的人，为他们做出了自己力所能及的事，也渐渐接收过去遇到的种种挫折，认真地对待起了自己。到最后步入社会，拿到自己的第一份工作，右臂刚好会对这份工作造成影响。但他不是简单地逃避，也没有自怨自艾，而是努力克服自己的弱点，顺利完成了工作。&lt;/p&gt;
&lt;p&gt;人生，要往前看，要善待他人，更要善待自己。&lt;/p&gt;
&lt;h2 id=&#34;不要忘记那些不应被忘记的事&#34;&gt;不要忘记，那些不应被忘记的事&lt;/h2&gt;
&lt;p&gt;冈崎在遇到奶奶，和她进行了一次长谈之后，渐渐回忆起了儿时的回忆，是关于他父亲的回忆，是一段他不该忘记的回忆。&lt;/p&gt;
&lt;p&gt;他的父亲早年也丧失了自己的妻子，绝望的经历让他痛苦万分。尽管他仍无法摆脱绝望的心情，但是仍旧尽心尽力养育儿子，用少的可怜的积蓄给儿子买零食和玩具，供儿子上学。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1683124831044.png&#34; loading=&#34;lazy&#34; alt=&#34;1683124831044&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;儿时的记忆，往往会是我们一生中非常重要，但是又非常易于忘记的记忆。我们的父母在那段时间里，需要费很大的精力来养育我们，他们青春年华的色彩很可能就在那几年慢慢地褪去&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;很多事情我们可能都只能等到自己为人父母时，才能慢慢地体会吧。&lt;/p&gt;
&lt;p&gt;在那片美丽的花田，夕阳覆盖了父女两人，冈崎终于知道放下过去的伤痛，去珍惜和保护汐。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1683124897654.png&#34; loading=&#34;lazy&#34; alt=&#34;1683124897654&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;看不到终点的时间&#34;&gt;看不到终点的时间&lt;/h2&gt;
&lt;p&gt;在 Clannad 中不乏有非常令人绝望的剧情。在失去自己生命中最重要，最不可或缺的东西之后，冈崎陷入了绝望。在这段时间里，看不到希望，看不到生命的意义，这痛苦的每分每秒似乎将永远持续下去，没有终点。生与死的间隔，是永远，是彻底的天各一方。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1683125741213.png&#34; loading=&#34;lazy&#34; alt=&#34;1683125741213&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;我们人生中，无可避免的要经历生死离别。这是没有办法的事，我们只有真正珍惜过了，才能尽量地避免更多的悲伤和后悔。怎么说呢，人是一种有感情的生物，正是因为我们拥有感情，我们的生命才更加地有意义。所以，如果知道有一天自己在经历那些时刻时会感到悲伤，那就努力去珍视他们吧。&lt;/p&gt;
&lt;h2 id=&#34;一生的朋友&#34;&gt;一生的朋友&lt;/h2&gt;
&lt;p&gt;昔日的好友重聚，人生中，能有几个能联系一辈子的朋友，真的很幸运。尽管各自有了自己新的，不一样的生活，但在重要的日子时，还是会抽时间聚在一起聊天，聊过去，聊现在。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1683127505777.png&#34; loading=&#34;lazy&#34; alt=&#34;1683127505777&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;在 Clannad 中，展现了很多人生的真实场景：离别，变化，重聚，我们一生都在面对着这样的事情。&lt;/p&gt;
&lt;p&gt;每次返回家乡，我下意识地就会观察一下家乡的建筑，街道，哪家的店不见了呀，哪条街道又翻新了呀，会观察家里的家具的变化，会观察亲人的变化。我们无法阻止那些变化，但我们可以让不变的东西永远存在——感情。&lt;/p&gt;
&lt;p&gt;很可惜的是，我没有从高中到现在，都能一直保持联系的朋友。在高中，初中，甚至更久以前，和我要好的那些朋友们，你们都还好吗？&lt;/p&gt;
&lt;h2 id=&#34;其它一些值得记录的事情&#34;&gt;其它一些值得记录的事情&lt;/h2&gt;
&lt;p&gt;远漂重洋的行李箱，装着的不是论文手稿，而是女儿想要的小熊。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1682601364703.png&#34; loading=&#34;lazy&#34; alt=&#34;1682601364703&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;因为受到父亲牵连的冈崎，在近乎奔溃的时候，渚给了他安慰，终于让他平静下来。或许，也只有渚才可以做到了吧。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1682601527964.png&#34; loading=&#34;lazy&#34; alt=&#34;1682601527964&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;冈崎或许正是在这时意识到了自己人生中不能没有渚，所以顺势地求婚了：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1682602506962.png&#34; loading=&#34;lazy&#34; alt=&#34;1682602506962&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;因为身体原因，无法和大家一起毕业的渚，终于在第五年顺利毕业了。可惜在毕业典礼当天，又因为身体原因无法参加。冈崎准备为渚准备一次毕业典礼。昔日的好友，虽然已经各自步向自己新的生活，但还是接受了邀请，来为自己的旧朋友送上祝福。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1682601750902.png&#34; loading=&#34;lazy&#34; alt=&#34;1682601750902&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;冈崎和怀孕后的渚坐在海边，一起为肚子里的孩子取名，取名为汐。冈崎希望渚和他一起许愿，来年，和汐一起，再来这里看海。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1682601921769.png&#34; loading=&#34;lazy&#34; alt=&#34;1682601921769&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;被芽衣妹妹教坏的渚同学：（其实就是想让平时总是不太自信的渚能表现得自信一点，结果闹笑话了，不过目的是达到了，和冈崎关系更进一步！）&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1683126598728.png&#34; loading=&#34;lazy&#34; alt=&#34;1683126598728&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;在 After Story 中，可爱的风子醒过来了！仍旧是那个熟悉的味道，那个可爱俏皮的风子！&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1683125678035.png&#34; loading=&#34;lazy&#34; alt=&#34;1683125678035&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;在最后的最后，我们看到了我们想看到的一幕，一家三口散步的场景。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/clannad-a-poem-of-healing-and-sadness/image/1683126489626.png&#34; loading=&#34;lazy&#34; alt=&#34;1683126489626&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;个人觉得总体来说，Clannad 真的值得一看吧，不管是音乐，剧情，还是对于人生的一些启示，都很不错。但由于它本身是游戏改编，所以有一些 IF 线剧集，个人不是很喜欢。另外前期有一定的后宫色彩，不是很好（但总体上是纯爱）。另外，个人也不是很能接受最后做梦的剧情，稍有点狗血（虽然也是为了推进剧情服务）。不管怎么说，瑕不掩瑜，Clannad 绝对称得上日漫中的经典之作，在亲情这类番剧中会是难以超越的作品。&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Hugo 实现搜索功能</title>
        <link>https://zhihang.org/posts/hugo-realizes-search-function/</link>
        <pubDate>Fri, 07 Apr 2023 21:48:58 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>hugo-realizes-search-function</guid>
        <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;这里记录了两种实现方式，一种通过 Fuse 进行，一种通过 Algolia 进行。通过 fuse 实现是纯静态的方式，更为简单便捷，且很稳定，而通过 algolia 实现需要依赖于 algolia 服务，搜索功能更强大但可能不够稳定（特别是墙内用户）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%89%8D%E8%A8%80&#34;&gt;前言&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#fuse&#34;&gt;Fuse&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%94%9F%E6%88%90%E6%90%9C%E7%B4%A2%E6%95%B0%E6%8D%AE&#34;&gt;生成搜索数据&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%8B%E8%BD%BD%E5%BC%95%E7%94%A8-fuse&#34;&gt;下载引用 fuse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%B0%83%E7%94%A8-fuse-%E5%AE%9E%E7%8E%B0%E6%90%9C%E7%B4%A2%E5%8A%9F%E8%83%BD&#34;&gt;调用 fuse 实现搜索功能&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%9B%E5%BB%BA%E6%90%9C%E7%B4%A2%E5%9D%97&#34;&gt;创建搜索块&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%9B%E5%BB%BA%E6%90%9C%E7%B4%A2%E5%9B%BE%E6%A0%87&#34;&gt;创建搜索图标&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#algolia&#34;&gt;Algolia&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B3%A8%E5%86%8C%E8%B4%A6%E5%8F%B7%E5%B9%B6%E5%88%9B%E5%BB%BA-index&#34;&gt;注册账号并创建 Index&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%90%9C%E7%B4%A2%E6%95%B0%E6%8D%AE%E7%94%9F%E6%88%90%E5%8F%8A%E4%B8%8A%E4%BC%A0&#34;&gt;搜索数据生成及上传&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%85%8D%E7%BD%AE-algolia-%E8%BE%93%E5%87%BA%E6%96%87%E4%BB%B6&#34;&gt;配置 algolia 输出文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%94%9F%E6%88%90-algoliajson&#34;&gt;生成 algolia.json&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9C%A8-githubaction-%E6%96%B0%E5%BB%BA%E5%B7%A5%E4%BD%9C%E6%B5%81&#34;&gt;在 GithubAction 新建工作流&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%B3%E4%BA%8E%E6%90%9C%E7%B4%A2%E7%B1%BB%E5%9E%8B%E5%8F%8A%E4%BC%98%E5%85%88%E7%BA%A7%E7%9A%84%E8%AE%BE%E7%BD%AE&#34;&gt;关于搜索类型及优先级的设置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9A%E5%88%B6%E6%90%9C%E7%B4%A2%E6%A1%86&#34;&gt;定制搜索框&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;fuse&#34;&gt;Fuse&lt;/h2&gt;
&lt;h3 id=&#34;生成搜索数据&#34;&gt;生成搜索数据&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;layouts/_default/&lt;/code&gt; 下新建 &lt;code&gt;index.json&lt;/code&gt; 文件，编辑如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Scratch&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Add &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt; slice &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Site&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;RegularPages &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;{{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Scratch&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Add &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;dict &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Title &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;tags&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Params&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;tags &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;categories&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Params&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;categories &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;contents&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Plain &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;permalink&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Permalink&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt; end &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Scratch&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;Get &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; jsonify &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在配置文件(这里以 config.yaml 为例)中进行输出文件的配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;outputs&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;home&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;HTML, JSON, RSS]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意，HTML, JSON, RSS 分别生成 index.html, index.json, index.xml。&lt;/p&gt;
&lt;p&gt;这样，运行 hugo 生成命令即可生成搜索数据文件 index.json。&lt;/p&gt;
&lt;h3 id=&#34;下载引用-fuse&#34;&gt;下载引用 fuse&lt;/h3&gt;
&lt;p&gt;About fuse: Lightweight fuzzy-search, in JavaScript.&lt;/p&gt;
&lt;p&gt;可以从 &lt;a href=&#34;https://github.com/krisk/Fuse&#34;&gt;github&lt;/a&gt; 下载到 fuse。&lt;/p&gt;
&lt;p&gt;将 fuse 脚本（fuse.min.js）放置到根路径下（比如 static/js）。&lt;/p&gt;
&lt;h3 id=&#34;调用-fuse-实现搜索功能&#34;&gt;调用 fuse 实现搜索功能&lt;/h3&gt;
&lt;p&gt;该脚本参考了 &lt;a href=&#34;https://gist.github.com/cmod/5410eae147e4318164258742dd053993&#34;&gt;github&lt;/a&gt; 上的代码，然后在一些地方进行了小改动。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;  1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; fuse&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// holds our search engine
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;  2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; fuseIndex&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;  3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; searchVisible &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;  4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; firstRun &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// allow us to delay loading json data unless search activated
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;  5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; list &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchResults&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// targets the &amp;lt;ul&amp;gt;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;  6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; first &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; list&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;firstChild&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// first child of search list
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;  7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; last &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; list&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;lastChild&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// last child of search list
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;  8&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; maininput &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchInput&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// input box for search
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;  9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; resultsAvailable &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// Did we get any search results?
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ==========================================
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// The main keyboard event listener running the show
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;//
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;addEventListener&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;keydown&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;event&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 15&lt;/span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// CMD-/ to show / hide Search
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 16&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;event&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;altKey &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; event&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;which &lt;span style=&#34;color:#81a1c1&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;191&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 17&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// Load json search index if first time invoking search
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 18&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// Means we don&amp;#39;t load json unless searches are going to happen; keep user payload small unless needed
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 19&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    doSearch&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;event&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 20&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 21&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 22&lt;/span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// Allow ESC (27) to close search box
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 23&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;event&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;keyCode &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;27&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 24&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;searchVisible&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 25&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;fastSearch&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;style&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;visibility &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 26&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;activeElement&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;blur&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 27&lt;/span&gt;      searchVisible &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 28&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 29&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 30&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 31&lt;/span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// DOWN (40) arrow
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 32&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;event&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;keyCode &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;40&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 33&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;searchVisible &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; resultsAvailable&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 34&lt;/span&gt;      console&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;log&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;down&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 35&lt;/span&gt;      event&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;preventDefault&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// stop window from scrolling
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 36&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;activeElement &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; maininput&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 37&lt;/span&gt;        first&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;focus&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 38&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// if the currently focused element is the main input --&amp;gt; focus the first &amp;lt;li&amp;gt;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 39&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;activeElement &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; last&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 40&lt;/span&gt;        last&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;focus&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 41&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// if we&amp;#39;re at the bottom, stay there
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 42&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 43&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;activeElement&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;parentElement&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;nextSibling&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;firstElementChild&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;focus&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 44&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// otherwise select the next search result
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 45&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 46&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 47&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 48&lt;/span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// UP (38) arrow
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 49&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;event&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;keyCode &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;38&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 50&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;searchVisible &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; resultsAvailable&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 51&lt;/span&gt;      event&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;preventDefault&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// stop window from scrolling
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 52&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;activeElement &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; maininput&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 53&lt;/span&gt;        maininput&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;focus&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 54&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// If we&amp;#39;re in the input box, do nothing
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 55&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;activeElement &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; first&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 56&lt;/span&gt;        maininput&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;focus&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 57&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// If we&amp;#39;re at the first item, go to input box
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 58&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 59&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;activeElement&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;parentElement&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;previousSibling&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;firstElementChild&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;focus&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 60&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// Otherwise, select the search result above the current active one
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 61&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 62&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 63&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;});&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 64&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 65&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ==========================================
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 66&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// execute search as each character is typed
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 67&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;//
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 68&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchInput&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;onkeyup &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 69&lt;/span&gt;  executeSearch&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;value&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 70&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 71&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 72&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;querySelector&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;html&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;onclick &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 73&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;target&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;id &lt;span style=&#34;color:#81a1c1&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchInput&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 74&lt;/span&gt;    hideSearch&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 75&lt;/span&gt;    $&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;#menu&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;css&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;visibility&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;visible&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 76&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 77&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 78&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 79&lt;/span&gt;searchBtn &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchBtn&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 80&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;searchBtn&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 81&lt;/span&gt;  searchBtn&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;onclick &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 82&lt;/span&gt;    $&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;#menu&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;css&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;visibility&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 83&lt;/span&gt;    doSearch&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 84&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 85&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 86&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 87&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; doSearch&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;e&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 88&lt;/span&gt;  e&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;stopPropagation&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 89&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;firstRun&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 90&lt;/span&gt;    loadSearch&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// loads our json data and builds fuse.js search index
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 91&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    firstRun &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// let&amp;#39;s never do this again
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 92&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 93&lt;/span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// Toggle visibility of search box
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 94&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;!&lt;/span&gt;searchVisible&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 95&lt;/span&gt;    showSearch&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// search visible
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 96&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 97&lt;/span&gt;    hideSearch&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 98&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 99&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;100&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;101&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; hideSearch&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;102&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchInput&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;103&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;fastSearch&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;style&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;visibility &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// hide search box
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;104&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchResults&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;innerHTML &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// remmove results
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;105&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;activeElement&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;blur&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// remove focus from search box
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;106&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  searchVisible &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;107&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;108&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;109&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; showSearch&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;110&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;fastSearch&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;style&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;visibility &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;visible&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// show search box
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;111&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchInput&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;focus&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// put focus in input box so you can just start typing
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;112&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  searchVisible &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;113&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;114&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;115&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ==========================================
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;116&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// fetch some json without jquery
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;117&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;//
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;118&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; fetchJSONFile&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;path&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; callback&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;119&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; httpRequest &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; XMLHttpRequest&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;120&lt;/span&gt;  httpRequest&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;onreadystatechange &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;121&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;httpRequest&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;readyState &lt;span style=&#34;color:#81a1c1&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;122&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;httpRequest&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;status &lt;span style=&#34;color:#81a1c1&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;123&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; data &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; JSON&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;parse&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;httpRequest&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;responseText&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;124&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;callback&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; callback&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;data&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;125&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;126&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;127&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;128&lt;/span&gt;  httpRequest&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;open&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; path&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;129&lt;/span&gt;  httpRequest&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;send&lt;span style=&#34;color:#eceff4&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;130&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;131&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;132&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ==========================================
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;133&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// load our search index, only executed once
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;134&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// on first call of search box (CMD-/)
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;135&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;//
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;136&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; loadSearch&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;137&lt;/span&gt;  console&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;log&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;loadSearch()&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;138&lt;/span&gt;  fetchJSONFile&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/index.json&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;data&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;139&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; options &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;140&lt;/span&gt;      &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// fuse.js options; check fuse.js website for details
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;141&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;      shouldSort&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;142&lt;/span&gt;      location&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;143&lt;/span&gt;      distance&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;100&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;144&lt;/span&gt;      threshold&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0.4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;145&lt;/span&gt;      minMatchCharLength&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;146&lt;/span&gt;      keys&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;permalink&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;contents&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;],&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;147&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;148&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// Create the Fuse index
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;149&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    fuseIndex &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; Fuse&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;createIndex&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;options&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;keys&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; data&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;150&lt;/span&gt;    fuse &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Fuse&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;data&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; options&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; fuseIndex&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// build the index from the json file
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;151&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;});&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;152&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;153&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;154&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ==========================================
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;155&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// using the index we loaded on CMD-/, run
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;156&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// a search query (for &amp;#34;term&amp;#34;) every time a letter is typed
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;157&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// in the search box
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;158&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;//
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;159&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; executeSearch&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;term&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;160&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; results &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; fuse&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;search&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;term&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// the actual query being run using fuse.js
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;161&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; searchitems &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// our results bucket
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;162&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;163&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;results&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;length &lt;span style=&#34;color:#81a1c1&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;164&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// no results based on what was typed into the input box
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;165&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    resultsAvailable &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;166&lt;/span&gt;    searchitems &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;167&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;168&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// build our html
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;169&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// console.log(results)
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;170&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    permalinks &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[];&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;171&lt;/span&gt;    numLimit &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;172&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; item &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;in&lt;/span&gt; results&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;173&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;item &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; numLimit&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;174&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;break&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;175&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;176&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;permalinks&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;includes&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;results&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;item&lt;span style=&#34;color:#eceff4&#34;&gt;].&lt;/span&gt;item&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;permalink&lt;span style=&#34;color:#eceff4&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;177&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;continue&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;178&lt;/span&gt;      &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;179&lt;/span&gt;      &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;//   console.log(&amp;#39;item: %d, title: %s&amp;#39;, item, results[item].item.title)
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;180&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;      searchitems &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;181&lt;/span&gt;        searchitems &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;182&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;#34;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;183&lt;/span&gt;        results&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;item&lt;span style=&#34;color:#eceff4&#34;&gt;].&lt;/span&gt;item&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;permalink &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;184&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;&amp;#34; tabindex=&amp;#34;0&amp;#34;&amp;gt;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;185&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;lt;span&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;186&lt;/span&gt;        results&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;item&lt;span style=&#34;color:#eceff4&#34;&gt;].&lt;/span&gt;item&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;title &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;187&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;188&lt;/span&gt;      permalinks&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;push&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;results&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;item&lt;span style=&#34;color:#eceff4&#34;&gt;].&lt;/span&gt;item&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;permalink&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;189&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;190&lt;/span&gt;    resultsAvailable &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;191&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;192&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;193&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchResults&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;innerHTML &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; searchitems&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;194&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;results&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;length &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;195&lt;/span&gt;    first &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; list&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;firstChild&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;firstElementChild&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// first result container — used for checking against keyboard up/down location
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;196&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    last &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; list&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;lastChild&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;firstElementChild&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// last result container — used for checking against keyboard up/down location
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;197&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;198&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将该脚本放置到根路径下（比如 static/js）。&lt;/p&gt;
&lt;p&gt;接着，在需要用到搜索功能的界面中同时引用 fuse 脚本和该脚本。&lt;/p&gt;
&lt;h3 id=&#34;创建搜索块&#34;&gt;创建搜索块&lt;/h3&gt;
&lt;p&gt;在 partials 下创建 search.html，编写内容如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;fastSearch&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchInput&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;tabindex&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;ul&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchResults&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;ul&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在需要调用搜索功能的地方放置 &lt;code&gt;{{ partial &amp;quot;search.html&amp;quot; . }}&lt;/code&gt; 即可（同一界面需要引用了以上两个脚本）。&lt;/p&gt;
&lt;p&gt;参考 css：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;fastSearch&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;visibility&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;hidden&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;font-size&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;z-index&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;99999&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;searchInput&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;color&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;color&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;search-text&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;background-color&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;color&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;search-bg&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;position&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;fixed&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;display&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;inline&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;top&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;30&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;right&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;height&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;30&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;width&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;300&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;padding&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;outline&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;none&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;searchResults&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;visibility&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;inherit&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;display&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;inline&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;position&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;fixed&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;top&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;64&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;right&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;width&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;340&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;  &lt;span style=&#34;color:#bf616a&#34;&gt;li&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;padding&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;list-style&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;none&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;background-color&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;color&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;search-bg&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;border-bottom&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;dotted&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;color&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;search-border&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;media&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;max-width&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;683px&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;searchInput&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;top&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;38&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;left&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;39&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;right&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;auto&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;40&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;41&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;42&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;searchResults&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;43&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;top&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;50&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;44&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;left&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;-25&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;px&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;45&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;right&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;auto&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;46&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;47&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;创建搜索图标&#34;&gt;创建搜索图标&lt;/h3&gt;
&lt;p&gt;上面的搜索块通过参考 css 作用，在未被触发的情况下是隐藏的。&lt;/p&gt;
&lt;p&gt;通过点击搜索图标可以弹出搜索块，可以通过 font-awesome 快速实现：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;icon&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;#&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;searchBtn&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;fas fa-search&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;a&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在需要用到的地方放置该代码块即可（同个界面还需要包含搜索块和之前的两个脚本）。&lt;/p&gt;
&lt;h2 id=&#34;algolia&#34;&gt;Algolia&lt;/h2&gt;
&lt;h3 id=&#34;注册账号并创建-index&#34;&gt;注册账号并创建 Index&lt;/h3&gt;
&lt;p&gt;官网链接：&lt;a href=&#34;https://www.algolia.com&#34;&gt;Algolia&lt;/a&gt;，注册完成后保存好 ApiID 和 ApiKey。&lt;/p&gt;
&lt;p&gt;接着，创建一个 Index，保存好 Index 的名称。&lt;/p&gt;
&lt;h3 id=&#34;搜索数据生成及上传&#34;&gt;搜索数据生成及上传&lt;/h3&gt;
&lt;p&gt;这里可以通过 github action 方便地实现，另外也通过 hugo-algolia 插件的方式进行，但是个人认为不够方便，这里不介绍了。&lt;/p&gt;
&lt;h4 id=&#34;配置-algolia-输出文件&#34;&gt;配置 algolia 输出文件&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;outputs&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;home&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    - HTML
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    - RSS
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    - Algolia
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;outputFormats&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Algolia&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;mediaType&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; application/json
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;baseName&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; algolia
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;isPlainText&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;生成-algoliajson&#34;&gt;生成 algolia.json&lt;/h4&gt;
&lt;p&gt;编辑 &lt;code&gt;{site}/themes/layouts/_default/list.algolia.json&lt;/code&gt; 如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{-&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;$index,&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;$entry&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;.Site.RegularPages&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{-&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;$index&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;objectID&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{{ .File.TranslationBaseName }}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;.Permalink&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;jsonify&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;.Title&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;jsonify&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;.PublishDate&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;jsonify&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;tags&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;.Params.tags&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;jsonify&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;categories&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{.Params.categories&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;jsonify&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;summary&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;.Summary&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;jsonify&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;.Plain&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;jsonify&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{-&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里可以自行查阅文档定制化查询数据。&lt;/p&gt;
&lt;p&gt;接着，通过 hugo 相关命令即可在 public 下生成 algolia.json 文件，这样就得到了搜索数据。&lt;/p&gt;
&lt;h4 id=&#34;在-githubaction-新建工作流&#34;&gt;在 GithubAction 新建工作流&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; Algolia Upload Records
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;on&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;push] &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 推送时执行&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;jobs&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;algolia&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;runs-on&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; ubuntu-latest
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;steps&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    - &lt;span style=&#34;color:#81a1c1&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; Checkout
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 获取代码 Checkout&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;uses&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; actions/checkout@v2
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    - &lt;span style=&#34;color:#81a1c1&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; Upload Records
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 使用 Action&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;uses&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; iChochy/Algolia-Upload-Records@main
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 设置环境变量&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;env&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;APPLICATION_ID&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; ${{secrets.ALGOLIA_APPID}} &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# appID&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;ADMIN_API_KEY&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; ${{secrets.ALGOLIA_KEY}} &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# key&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;INDEX_NAME&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; ${{secrets.ALGOLIA_INDEX}} &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# index&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;FILE_PATH&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; algolia.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意添加好对应环境变量。&lt;/p&gt;
&lt;p&gt;之后，每次 push 都会自动将 algolia.json 推送到 algolia 数据库啦。&lt;/p&gt;
&lt;h3 id=&#34;关于搜索类型及优先级的设置&#34;&gt;关于搜索类型及优先级的设置&lt;/h3&gt;
&lt;p&gt;前往 algolia 的 indices 进行搜索类型的设置，可以选择按 tag，category，content 等内容进行搜索，并指定优先级。&lt;/p&gt;
&lt;p&gt;这里也就是 algolia 更加强大的一个点了。&lt;/p&gt;
&lt;h3 id=&#34;定制搜索框&#34;&gt;定制搜索框&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;{site}/themes/{theme}/layouts/partials&lt;/code&gt; 下创建 search.html：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;modalSearch&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;modal fade&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;role&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;dialog&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;modal-dialog&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;modal-content&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;            &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;modal-body&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;                &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;aa-input-container&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;aa-input-container&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;                    &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;search&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;aa-search-input&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;aa-input-search&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;placeholder&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;write here...&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;search&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;autocomplete&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;off&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;                &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;            &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;div&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{{ &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;https:&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;//&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;res&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;cloudinary&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;jimmysong&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;raw&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;upload&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;rootsongjc-hugo&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;algoliasearch&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;min&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;js&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;absURL&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;}}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;script&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{{ &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;https:&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;//&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;res&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;cloudinary&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;jimmysong&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;raw&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;upload&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;rootsongjc-hugo&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;autocomplete&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;min&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;js&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;absURL&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;}}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;script&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;script&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; client &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; algoliasearch&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{appID}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{key}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; index &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; client&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;initIndex&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;{indexName}&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;autocomplete&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;#aa-search-input&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt; hint&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;    source&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; autocomplete&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;sources&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;hits&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;index&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;hitsPerPage&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}),&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;    displayKey&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;    templates&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;        suggestion&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;suggestion&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; des_url &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; suggestion&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;uri&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; reg &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;/[《》（）]/g&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 转化一些中文字符，可以自己指定需要的
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;            des_url &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; des_url&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;toLowerCase&lt;span style=&#34;color:#eceff4&#34;&gt;().&lt;/span&gt;replace&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;reg&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 转为小写
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;&amp;lt;span&amp;gt;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;&amp;lt;a href=&amp;#34;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; des_url &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;&amp;#34;&amp;#34;&amp;gt;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;            suggestion&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;_highlightResult&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;title&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;value &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;});&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;script&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中注意代码片段：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; client &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; algoliasearch&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{appID}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{key}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; index &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; client&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;initIndex&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;{indexName}&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;自己填入自己的 appID，key，index 名称即可。&lt;/p&gt;
&lt;p&gt;最后在自己需要的地方放置搜索框即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;!&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;--&lt;/span&gt;搜索文章&lt;span style=&#34;color:#81a1c1&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{{&lt;/span&gt; partial &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;search.html&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      </item>
      
    
      
      <item>
        <title>软件设计模式</title>
        <link>https://zhihang.org/posts/design-pattern-knowledge-collation/</link>
        <pubDate>Fri, 31 Mar 2023 23:35:52 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>design-pattern-knowledge-collation</guid>
        <description>&lt;h2 id=&#34;toc&#34;&gt;TOC&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#toc&#34;&gt;TOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F&#34;&gt;观察者模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%90%86%E8%A7%A3&#34;&gt;理解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0&#34;&gt;实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A3%85%E9%A5%B0%E8%80%85%E6%A8%A1%E5%BC%8F&#34;&gt;装饰者模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%90%86%E8%A7%A3-1&#34;&gt;理解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0-1&#34;&gt;实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F&#34;&gt;工厂模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%90%86%E8%A7%A3-2&#34;&gt;理解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F%E5%AE%9E%E7%8E%B0&#34;&gt;工厂方法模式实现&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F%E5%AE%9E%E7%8E%B0&#34;&gt;抽象工厂模式实现&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%A6%82%E4%BD%95%E5%86%B3%E5%AE%9A%E4%BD%BF%E7%94%A8%E5%93%AA%E4%B8%AA%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F&#34;&gt;如何决定使用哪个工厂模式&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F&#34;&gt;策略模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%A3%E9%87%8A&#34;&gt;解释&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0-2&#34;&gt;实现&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%92%8C%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F%E7%9A%84%E5%8C%BA%E5%88%AB&#34;&gt;和工厂模式的区别&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F&#34;&gt;单例模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%90%86%E8%A7%A3-3&#34;&gt;理解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%87%92%E6%B1%89%E5%BC%8F&#34;&gt;懒汉式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%87%92%E6%B1%89%E5%BC%8F%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8&#34;&gt;懒汉式（线程安全）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%87%92%E6%B1%89%E5%BC%8F%E5%8F%8C%E9%87%8D%E6%A3%80%E6%9F%A5%E9%94%81&#34;&gt;懒汉式（双重检查锁）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%A5%BF%E6%B1%89%E5%BC%8F&#34;&gt;饿汉式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%A5%BF%E6%B1%89%E5%BC%8F%E9%9D%99%E6%80%81%E5%86%85%E9%83%A8%E7%B1%BB&#34;&gt;饿汉式（静态内部类）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%A5%BF%E6%B1%89%E5%BC%8F%E6%9E%9A%E4%B8%BE&#34;&gt;饿汉式（枚举）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%A0%B4%E5%9D%8F%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%E7%9A%84%E6%96%B9%E6%B3%95%E5%8F%8A%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95&#34;&gt;破坏单例模式的方法及解决办法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F&#34;&gt;命令模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%90%86%E8%A7%A3-4&#34;&gt;理解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0-3&#34;&gt;实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F&#34;&gt;适配器模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%A3%E9%87%8A-1&#34;&gt;解释&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0-4&#34;&gt;实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%A4%96%E8%A7%82%E6%A8%A1%E5%BC%8F&#34;&gt;外观模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%A3%E9%87%8A-2&#34;&gt;解释&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0-5&#34;&gt;实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%A8%A1%E6%9D%BF%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F&#34;&gt;模板方法模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%A3%E9%87%8A-3&#34;&gt;解释&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0-6&#34;&gt;实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F&#34;&gt;迭代器模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%A3%E9%87%8A-4&#34;&gt;解释&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0-7&#34;&gt;实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BB%84%E5%90%88%E6%A8%A1%E5%BC%8F&#34;&gt;组合模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%A3%E9%87%8A-5&#34;&gt;解释&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0-8&#34;&gt;实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F&#34;&gt;状态模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%A3%E9%87%8A-6&#34;&gt;解释&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0-9&#34;&gt;实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F&#34;&gt;代理模式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%A3%E9%87%8A-7&#34;&gt;解释&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0%E9%9D%99%E6%80%81%E4%BB%A3%E7%90%86&#34;&gt;实现静态代理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86&#34;&gt;实现动态代理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#cglib-%E4%BB%A3%E7%90%86&#34;&gt;Cglib 代理&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BB%93%E5%90%88%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F%E5%AE%9E%E7%8E%B0%E5%8A%A8%E6%80%81-bean&#34;&gt;结合策略模式实现动态 Bean&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8F%82%E8%80%83&#34;&gt;参考&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;观察者模式&#34;&gt;观察者模式&lt;/h2&gt;
&lt;h3 id=&#34;理解&#34;&gt;理解&lt;/h3&gt;
&lt;p&gt;对于观察者模式，既然有观察者，那么就首先有被观察者。&lt;/p&gt;
&lt;p&gt;观察者可以通过订阅，监听等方式实现“观察”，被观察者需要通过通知，发消息之类的方式通知观察者接收信息。&lt;/p&gt;
&lt;p&gt;假设有一个气象观测站，天气数据对象作为被观察者，各个气象观测站作为观察者订阅天气数据，而天气数据记录各个订阅了自己的观测站，以便于通知。&lt;/p&gt;
&lt;p&gt;再比如 rss 订阅工具，它作为观察者，而各个用户订阅的 rss 地址作为被观察者，rss 订阅工具定时抓取 rss 内容，并将有更新的内容发送给用户。&lt;/p&gt;
&lt;h3 id=&#34;实现&#34;&gt;实现&lt;/h3&gt;
&lt;p&gt;下面以气象站为例进行模拟实现。&lt;/p&gt;
&lt;p&gt;首先定义两个接口：&lt;/p&gt;
&lt;p&gt;被观察者：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Subject&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;registerObserver&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Observer o&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;removeObserver&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Observer o&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;notifyObservers&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;观察者：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Observer&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;update&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; temp&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; humidity&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; pressure&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着，定义对象，实现接口：&lt;/p&gt;
&lt;p&gt;天气数据对象：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;WeatherData&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; Subject &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; List&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Observer&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; observers&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; temperature&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; humidity&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; pressure&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;WeatherData&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;		observers &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; ArrayList&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Observer&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;registerObserver&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Observer o&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;		observers&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;o&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;removeObserver&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Observer o&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;		observers&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;remove&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;o&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;notifyObservers&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Observer observer &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; observers&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;			observer&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;update&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;temperature&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;humidity&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;pressure&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;measurementsChanged&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;		notifyObservers&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;setMeasurements&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; temperature&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; humidity&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; pressure&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;temperature&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; temperature&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;humidity&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; humidity&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;pressure&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; pressure&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;		measurementsChanged&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getTemperature&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; temperature&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;38&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;39&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;40&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getHumidity&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;41&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; humidity&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;42&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;43&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;44&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getPressure&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;45&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; pressure&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;46&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;47&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;48&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;气象观测站对象：&lt;/p&gt;
&lt;p&gt;省略了 StatisticsDisplay 和 ForecastDisplay。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;CurrentConditionsDisplay&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; Observer &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; temperature&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; humidity&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; WeatherData weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;CurrentConditionsDisplay&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;WeatherData weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;weatherData&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;		weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;registerObserver&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;update&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; temperature&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; humidity&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;float&lt;/span&gt; pressure&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;temperature&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; temperature&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;humidity&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; humidity&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;		display&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;display&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后，编写测试代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;WeatherStation&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;		WeatherData weatherData &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; WeatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;		CurrentConditionsDisplay currentDisplay &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;			&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; CurrentConditionsDisplay&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;		StatisticsDisplay statisticsDisplay &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; StatisticsDisplay&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		ForecastDisplay forecastDisplay &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; ForecastDisplay&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;		weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setMeasurements&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;80&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;65&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;30&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;4f&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;		weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setMeasurements&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;82&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;70&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;29&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;2f&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setMeasurements&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;78&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;90&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;29&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;2f&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;		
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;		weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;removeObserver&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;forecastDisplay&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;		weatherData&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setMeasurements&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;62&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;90&lt;span style=&#34;color:#bf616a&#34;&gt;，&lt;/span&gt;28&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;1f&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;装饰者模式&#34;&gt;装饰者模式&lt;/h2&gt;
&lt;h3 id=&#34;理解-1&#34;&gt;理解&lt;/h3&gt;
&lt;p&gt;装饰，如其名，就是对一个对象进行加工，包装，修饰。&lt;/p&gt;
&lt;p&gt;假设一杯“普通的咖啡，价格 10”，我们可以选择添加自己喜欢的配料。&lt;/p&gt;
&lt;p&gt;首先我们添加牛奶，那么就变成了一杯“含牛奶配料的咖啡，价格 2 +（价格 12）”；&lt;/p&gt;
&lt;p&gt;我想再加点巧克力，那么再往上包装变成“含巧克力的含牛奶配料的咖啡，价格 3 +【价格 2+（价格 12）】”。&lt;/p&gt;
&lt;p&gt;这么一层层封装上去就是装饰模式。&lt;/p&gt;
&lt;p&gt;我们要在每一个配料中定义一个可包装的对象，在包装后返回这个对象。具体代码如下文。&lt;/p&gt;
&lt;h3 id=&#34;实现-1&#34;&gt;实现&lt;/h3&gt;
&lt;p&gt;以饮料店作为例子编写代码。&lt;/p&gt;
&lt;p&gt;首先定义一些抽象类：&lt;/p&gt;
&lt;p&gt;饮料抽象类：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Beverage&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	String description &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Unknown Beverage&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;getDescription&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; description&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;double&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;cost&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配料抽象类：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意这里配料也继承了饮料类，这样Beverage在通过包装之后还是返回一个Beverage，具体见测试代码。&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;CondimentDecorator&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;extends&lt;/span&gt; Beverage &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	Beverage beverage&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;getDescription&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着，定义一些实际的饮料和配料：&lt;/p&gt;
&lt;p&gt;牛奶配料：（其他配料省略）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Milk&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;extends&lt;/span&gt; CondimentDecorator &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Milk&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Beverage beverage&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;beverage&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; beverage&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;getDescription&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; beverage&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getDescription&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;，Milk&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;double&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;cost&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; beverage&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;cost&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;浓缩咖啡类：（其他饮料略）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Espresso&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;extends&lt;/span&gt; Beverage &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Espresso&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;		description &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Espresso&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;double&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;cost&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; 1&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;99&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后，编写测试代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;StarbuzzCoffee&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String args&lt;span style=&#34;color:#81a1c1&#34;&gt;[])&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;		Beverage beverage &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Espresso&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;beverage&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getDescription&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;				&lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34; $&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; beverage&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;cost&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;		Beverage beverage2 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; DarkRoast&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		beverage2 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Mocha&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;beverage2&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		beverage2 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Mocha&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;beverage2&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;		beverage2 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Whip&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;beverage2&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;beverage2&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getDescription&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;				&lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34; $&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; beverage2&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;cost&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;		Beverage beverage3 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; HouseBlend&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;		beverage3 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Soy&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;beverage3&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;		beverage3 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Mocha&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;beverage3&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;		beverage3 &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Whip&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;beverage3&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;beverage3&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getDescription&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;				&lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34; $&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; beverage3&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;cost&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;工厂模式&#34;&gt;工厂模式&lt;/h2&gt;
&lt;h3 id=&#34;理解-2&#34;&gt;理解&lt;/h3&gt;
&lt;p&gt;工厂模式，包括工厂方法模式和抽象工厂模式。&lt;/p&gt;
&lt;p&gt;对于工厂方法模式，工厂是一个抽象类，提供了一些默认实现方法和一些抽象方法，具体工厂继承于它，实现对应抽象方法。&lt;/p&gt;
&lt;p&gt;假设有多家比萨店，他们提供不同口味的比萨，而都有相同的订购比萨的方法，那么可以定义一个抽象类，提供订购比萨的具体方法和创建比萨的抽象方法。&lt;/p&gt;
&lt;p&gt;对于抽象工厂模式，工厂是一个接口，提供了一些具体工厂会用到的方法，同时还需要定义这些方法可能用到的接口。具体工厂需要首先实现抽象工厂定义的方法可能用到的接口，然后实现抽象工厂的所有方法。&lt;/p&gt;
&lt;p&gt;假设有多家生产比萨配料的工厂，他们都有自己的独特的配料（实现所有配料接口），那么可以定义一个抽象工厂（一个接口），提供所有配料创建方法，具体工厂各自实现所有创建方法即可。&lt;/p&gt;
&lt;p&gt;总之，他们的具体区别如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;工厂方法模式使用继承，把对象的创建委托给子类，子类实现工厂方法来创建对象。&lt;/li&gt;
&lt;li&gt;抽象工厂模式使用对象组合，对象的创建被实现在工厂接口所暴露出来的方法中。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;工厂方法模式实现&#34;&gt;工厂方法模式实现&lt;/h3&gt;
&lt;p&gt;下面通过披萨店的例子来进行模拟。&lt;/p&gt;
&lt;p&gt;从抽象开始，定义一个比萨店抽象类：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PizzaStore&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; Pizza &lt;span style=&#34;color:#88c0d0&#34;&gt;createPizza&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String item&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Pizza &lt;span style=&#34;color:#88c0d0&#34;&gt;orderPizza&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String type&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;		Pizza pizza &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; createPizza&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;type&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;--- Making a &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; pizza&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getName&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34; ---&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;		pizza&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;prepare&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		pizza&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;bake&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		pizza&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;cut&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;		pizza&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;box&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; pizza&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;定义一些具体的比萨店，比如一个芝加哥的比萨店：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;ChicagoPizzaStore&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;extends&lt;/span&gt; PizzaStore &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	Pizza &lt;span style=&#34;color:#88c0d0&#34;&gt;createPizza&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String item&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;        	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;item&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;equals&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;cheese&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;            		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; ChicagoStyleCheesePizza&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;item&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;equals&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;veggie&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        	    	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; ChicagoStyleVeggiePizza&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;item&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;equals&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;clam&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        	    	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; ChicagoStyleClamPizza&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;item&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;equals&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;pepperoni&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;            		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; ChicagoStylePepperoniPizza&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关于其它比萨店和比萨的实现省略了。&lt;/p&gt;
&lt;p&gt;最后进行代码的测试：&lt;/p&gt;
&lt;p&gt;根据自然的思路：首先应有比萨店，顾客选择比萨店，选择具体口味的比萨，完成订单。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;PizzaStore nyStore &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; NYPizzaStore&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;PizzaStore chicagoStore &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; ChicagoPizzaStore&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;Pizza pizza &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; nyStore&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;orderPizza&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;cheese&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Ethan ordered a &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; pizza&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getName&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;pizza &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; chicagoStore&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;orderPizza&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;cheese&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Joel ordered a &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; pizza&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getName&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;pizza &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; nyStore&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;orderPizza&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;clam&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Ethan ordered a &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; pizza&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getName&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;抽象工厂模式实现&#34;&gt;抽象工厂模式实现&lt;/h3&gt;
&lt;p&gt;还是从抽象开始，定义一个配料工厂接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PizzaIngredientFactory&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Dough &lt;span style=&#34;color:#88c0d0&#34;&gt;createDough&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Sauce &lt;span style=&#34;color:#88c0d0&#34;&gt;createSauce&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Cheese &lt;span style=&#34;color:#88c0d0&#34;&gt;createCheese&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Veggies&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;createVeggies&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Pepperoni &lt;span style=&#34;color:#88c0d0&#34;&gt;createPepperoni&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Clams &lt;span style=&#34;color:#88c0d0&#34;&gt;createClam&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着提供各种配料接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Cheese&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;toString&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其它的省略了。&lt;/p&gt;
&lt;p&gt;然后实现配料接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;MozzarellaCheese&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; Cheese &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;toString&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Shredded Mozzarella&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其它的省略了。&lt;/p&gt;
&lt;p&gt;接着再实现配料工厂接口，也就是定义具体的配料工厂，提供自己实现的配料。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;ChicagoPizzaIngredientFactory&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; PizzaIngredientFactory &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Dough &lt;span style=&#34;color:#88c0d0&#34;&gt;createDough&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; ThickCrustDough&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Sauce &lt;span style=&#34;color:#88c0d0&#34;&gt;createSauce&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; PlumTomatoSauce&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其它配料工厂省略了。&lt;/p&gt;
&lt;p&gt;接着，再从抽象开始。抽象的比萨应该含有所有工厂可能用到的配料，同时应该提供一个准备配料的抽象方法，在具体的比萨中实现这个方法，指定需要的配料，不要的则为null。抽象的比萨店如工厂方法模式一样。这里代码省略了。测试代码亦如工厂方法模式一样，这里省略了。&lt;/p&gt;
&lt;h3 id=&#34;如何决定使用哪个工厂模式&#34;&gt;如何决定使用哪个工厂模式&lt;/h3&gt;
&lt;p&gt;工厂方法模式和抽象工厂模式都是创建对象的设计模式，但它们的使用场景略有不同。&lt;/p&gt;
&lt;p&gt;当需求只需要单个对象的实例时，可以使用工厂方法模式。在这种模式下，一个工厂类负责实例化唯一的具体产品类。&lt;/p&gt;
&lt;p&gt;而当需要创建多个相关的对象（产品族）时，可以使用抽象工厂模式。在这种模式下，一个抽象工厂类定义了一组方法，每个方法都用于实例化一个相关的具体产品类。使用抽象工厂模式的好处是，它能够确保创建的产品族是相互兼容的，因为所有产品都是由同一个工厂创建的。&lt;/p&gt;
&lt;p&gt;在实践中，需要仔细考虑需求，以确定是否需要使用工厂方法模式或抽象工厂模式。&lt;/p&gt;
&lt;p&gt;当需要创建一个简单图形的绘画程序时，可以使用工厂方法模式。&lt;/p&gt;
&lt;p&gt;例如，一个工厂类可以根据用户选择创建圆形、矩形或三角形的实例。这些形状对象可以继承自一个通用的 Shape 类，该类定义了绘制图形所需的公共接口。&lt;/p&gt;
&lt;p&gt;当需要创建一个跨不同操作系统的 UI 组件时，可以使用抽象工厂模式。&lt;/p&gt;
&lt;p&gt;例如，一个抽象工厂类（一个应用程序）可以定义一组方法，每个方法都用于实例化一个操作系统特定的 UI 组件，如窗口、按钮和文本框。不同操作系统的具体工厂类（应用程序在某个操作系统上的表现）可以实现这些方法以创建适用于特定操作系统的 UI 组件（实现各个组件对应的接口并在实现工厂方法时使用对应的组件）。在这种情况下，每个具体工厂类实现的产品族都包含不同操作系统的 UI 组件，但它们共同满足了通用的接口。&lt;/p&gt;
&lt;h2 id=&#34;策略模式&#34;&gt;策略模式&lt;/h2&gt;
&lt;h3 id=&#34;解释&#34;&gt;解释&lt;/h3&gt;
&lt;p&gt;策略模式定义了算法族，分别封装起来，让它们之间可以互相替换，此模式让算法的变化独立于使用算法的客户。&lt;/p&gt;
&lt;p&gt;比如对于鸭子而言，不同鸭子的叫声方式可能不一样也可能一样，我们可以定义一个叫声行为接口，然后通过创建不同的叫声行为实现这个接口，在实例化鸭子时设定叫声行为即可。&lt;/p&gt;
&lt;p&gt;这样相比于直接继承抽象鸭子后重写叫声行为方法，好处是减少了重复代码，而坏处是增加了类的数量。&lt;/p&gt;
&lt;h3 id=&#34;实现-2&#34;&gt;实现&lt;/h3&gt;
&lt;p&gt;首先定义一个叫声接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;QuackBehavior&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;quack&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其它接口省略。&lt;/p&gt;
&lt;p&gt;实现叫声接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;MuteQuack&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; QuackBehavior &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;quack&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;lt;&amp;lt; Silence &amp;gt;&amp;gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其它实现省略。&lt;/p&gt;
&lt;p&gt;创建抽象鸭子：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Duck&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	FlyBehavior flyBehavior&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	QuackBehavior quackBehavior&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Duck&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;setFlyBehavior&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;FlyBehavior fb&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		flyBehavior &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; fb&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;setQuackBehavior&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;QuackBehavior qb&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		quackBehavior &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; qb&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;display&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;performFly&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;		flyBehavior&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;fly&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;performQuack&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;		quackBehavior&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;quack&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;swim&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;All ducks float, even decoys!&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后，即可创建具体鸭子，继承于抽象鸭子，实例化时指定具体行为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;MallardDuck&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;extends&lt;/span&gt; Duck &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;MallardDuck&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;		quackBehavior &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Quack&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;		flyBehavior &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; FlyWithWings&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;display&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;I&amp;#39;m a real Mallard duck&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同样可以轻松地创建其它鸭子。&lt;/p&gt;
&lt;h3 id=&#34;和工厂模式的区别&#34;&gt;和工厂模式的区别&lt;/h3&gt;
&lt;p&gt;工厂模式是创建型模式，适应对象的变化；策略模式是行为性模式，适应行为的变化。&lt;/p&gt;
&lt;p&gt;形象点的例子：&lt;/p&gt;
&lt;p&gt;工厂模式：&lt;/p&gt;
&lt;p&gt;有一天你决定去吃培根披萨，首先得选择店铺，A 店和 B 店都有培根披萨；你点了 A 店的培根披萨，过了二十分钟，你的披萨就来了就可以吃到了。但这个披萨是怎么做的，到底面粉放了多少，培根放了多少，佐料放了多少，有多少道工序，你是不需要管的，你需要的是一个美味培根披萨。&lt;/p&gt;
&lt;p&gt;策略模式：&lt;/p&gt;
&lt;p&gt;在披萨店，你要一个培根披萨，老板说有标准的 pizza，也可以自己去做。原料有培根、面粉、佐料。工序有 1、2、3 工序，你自己去做吧。然后你就需要自己去做，到底放多少培根，放多少面粉，放多少佐料，这都你自己来决定，工序 1、2、3，你是怎么实现的，都你自己决定。最后你得到了披萨。&lt;/p&gt;
&lt;h2 id=&#34;单例模式&#34;&gt;单例模式&lt;/h2&gt;
&lt;h3 id=&#34;理解-3&#34;&gt;理解&lt;/h3&gt;
&lt;p&gt;单例模式，容易知道需要某个对象是独一无二的，那么它首先应该是静态的，不能在程序动态运行期间被再次创建。&lt;/p&gt;
&lt;p&gt;当在多个线程中用到它时，在创建时需要考虑线程安全问题，可通过加锁等方式解决。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;单例模式的实现方式有多种，下面从最简单的方式开始实现，接着使用线程安全的方式实现，最后对多线程性能进行改善。&lt;/p&gt;
&lt;h3 id=&#34;懒汉式&#34;&gt;懒汉式&lt;/h3&gt;
&lt;p&gt;如其名，不是“急切”地进行对象的创建，而是在第一次主动获取对象时才加锁进行对象的初始化，实现对象的懒加载。&lt;/p&gt;
&lt;p&gt;定义一个私有实例化的对象，把单例对象作为一个私有的静态成员变量，通过静态方法 &lt;code&gt;Singleton.getInstance()&lt;/code&gt; 获取，若获取为 null 则创建对象。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Singleton&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; Singleton uniqueInstance&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Singleton&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; Singleton &lt;span style=&#34;color:#88c0d0&#34;&gt;getInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;uniqueInstance &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;			uniqueInstance &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Singleton&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; uniqueInstance&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;懒汉式线程安全&#34;&gt;懒汉式（线程安全）&lt;/h3&gt;
&lt;p&gt;上面的懒汉式是线程不安全的，只适用于单线程环境。在多线程环境下，同时初始化该对象时将导致重复初始化对象的问题。解决方法如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Singleton&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; Singleton uniqueInstance&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Singleton&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;synchronized&lt;/span&gt; Singleton &lt;span style=&#34;color:#88c0d0&#34;&gt;getInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;uniqueInstance &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;			uniqueInstance &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Singleton&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; uniqueInstance&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如上线程安全的代码，&lt;code&gt;getInstance()&lt;/code&gt; 在多次调用的情况下性能太低，需要进行改善。&lt;/p&gt;
&lt;h3 id=&#34;懒汉式双重检查锁&#34;&gt;懒汉式（双重检查锁）&lt;/h3&gt;
&lt;p&gt;这里需要通过双重检查并加锁的方式实现，在进入 &lt;code&gt;getInstance()&lt;/code&gt; 方法后检查对象是否为空，以及在获得锁之后，再次检查对象是否为空。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Singleton&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; Singleton uniqueInstance&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Singleton&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; Singleton &lt;span style=&#34;color:#88c0d0&#34;&gt;getInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;uniqueInstance &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;			&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;synchronized&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Singleton&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;				&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;uniqueInstance &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;					uniqueInstance &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Singleton&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;				&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;			&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; uniqueInstance&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;volatile 用于告诉编译器该变量可能会被其它线程或外部程序修改，一次每次访问该变量时都需要从内存重新读取其值，而不是使用缓存。这样可以确保当 uniqueInstance 被初始化时，多个线程正确处理 uniqueInstance 变量，保证并发的正确性。&lt;/p&gt;
&lt;p&gt;另外 volatile 还可以防止编译器对代码进行重排序优化。比如在多线程环境下，几个线程对某个对象进行读操作，其它几个进行写操作，在写操作中，如果在进行对象的初始化，并且构造函数中操作比较多时，为了提升效率，JVM 会在构造函数里面的属性未全部完成实例化时，就返回对象。这样可能导致其它进行读操作的线程读取到未初始化完全的对象，而加上 volatile 关键字就没有这个问题了。&lt;/p&gt;
&lt;p&gt;为什么之前的线程安全方式不需要添加 volatile 呢？因为之前的 synchronized 是作用在方法上的，也就是说在进入该方法之前不会访问到 uniqueInstance 变量，也就不会有缓存，不需要重新读取值。同时，也不会被重排序优化影响，因为读操作或写操作都是在进入方法内部之后进行的。&lt;/p&gt;
&lt;p&gt;而这里是进入 getInstance 方法后首先访问 uniqueInstance 变量，之后再尝试获取锁，所以编译器可能会对 uniqueInstance 进行优化，将其缓存到寄存器中，同时，写操作和读操作都是进入方法之后进行的，可能被重排序优化影响。&lt;/p&gt;
&lt;p&gt;双重检查锁模式是一种比较好的单例实现模式，能够保证在多线程的情况下线程安全也不会有性能问题。&lt;/p&gt;
&lt;h3 id=&#34;饿汉式&#34;&gt;饿汉式&lt;/h3&gt;
&lt;p&gt;如其名，就是“急切”地创建实例，也就是在 JVM 加载该类时马上创建实例，也可以保证线程安全。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Singleton&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;final&lt;/span&gt; Singleton uniqueInstance &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Singleton&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Singleton&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; Singleton &lt;span style=&#34;color:#88c0d0&#34;&gt;getInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; uniqueInstance&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该方式不能实现懒加载，造成空间浪费，如果一个类比较大，我们在初始化的时就加载了这个类，但是我们长时间没有使用这个类，这就导致了内存空间的浪费。当然如果类比较小可以考虑使用。&lt;/p&gt;
&lt;h3 id=&#34;饿汉式静态内部类&#34;&gt;饿汉式（静态内部类）&lt;/h3&gt;
&lt;p&gt;静态内部类单例模式也称单例持有者模式，实例由内部类创建，由于 JVM 在加载外部类的过程中，是&lt;strong&gt;不会加载静态内部类&lt;/strong&gt;的，只有内部类的属性/方法被调用时才会被加载，并初始化其静态属性。静态属性由static修饰，保证只被实例化一次，并且严格保证实例化顺序。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Singleton&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Singleton&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;InstanceHolder&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; Singleton instance &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Singleton&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; Singleton &lt;span style=&#34;color:#88c0d0&#34;&gt;getInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; InstanceHolder&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;instance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;静态内部类单例模式是一种优秀的单例模式，是开源项目中比较常用的一种单例模式。在没有加任何锁的情况下，保证了多线程下的安全，并且没有任何性能影响和空间的浪费。&lt;/p&gt;
&lt;h3 id=&#34;饿汉式枚举&#34;&gt;饿汉式（枚举）&lt;/h3&gt;
&lt;p&gt;为什么可以通过枚举实现单例？这是因为我们定义的一个枚举，只有在第一次被真正用到的时候，才会被虚拟机加载并初始化。基于这个特性，可以知道通过枚举实现的单例是天生线程安全的。&lt;/p&gt;
&lt;p&gt;枚举类实现单例模式是 effective java 作者极力推荐的单例实现模式，因为枚举类型是线程安全的，并且只会装载一次，设计者充分的利用了枚举的这个特性来实现单例模式，枚举的写法非常简单，而且枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Singleton&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Singleton&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;enum&lt;/span&gt; SingletonEnum &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        INSTANCE&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;final&lt;/span&gt; Singleton instance&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        SingletonEnum&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;            instance &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Singleton&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; Singleton &lt;span style=&#34;color:#88c0d0&#34;&gt;getInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; instance&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; Singleton &lt;span style=&#34;color:#88c0d0&#34;&gt;getInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; SingletonEnum&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;INSTANCE&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;破坏单例模式的方法及解决办法&#34;&gt;破坏单例模式的方法及解决办法&lt;/h3&gt;
&lt;p&gt;1、除枚举方式外，其他方法都会通过&lt;strong&gt;反射&lt;/strong&gt;的方式破坏单例，反射是通过调用&lt;strong&gt;构造方法&lt;/strong&gt;生成新的对象，所以如果我们想要阻止单例破坏，可以在构造方法中进行判断，若已有实例，则阻止生成新的实例，解决办法如下:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Singleton&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;instance &lt;span style=&#34;color:#81a1c1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;){&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; RuntimeException&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;实例已经存在，请通过 getInstance()方法获取&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;2、如果单例类实现了序列化接口 Serializable，就可以通过反序列化破坏单例，所以我们可以不实现序列化接口，如果非得实现序列化接口，可以重写反序列化方法 &lt;code&gt;readResolve()&lt;/code&gt;，反序列化时直接返回相关单例对象。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Object &lt;span style=&#34;color:#88c0d0&#34;&gt;readResolve&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throws&lt;/span&gt; ObjectStreamException &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; instance&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;命令模式&#34;&gt;命令模式&lt;/h2&gt;
&lt;h3 id=&#34;理解-4&#34;&gt;理解&lt;/h3&gt;
&lt;p&gt;命令模式将“请求”封装成对象，以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。&lt;/p&gt;
&lt;p&gt;比如对于遥控器而已，我们会将操作封装为一个按钮（命令）对象，通过按下按钮执行操作。&lt;/p&gt;
&lt;h3 id=&#34;实现-3&#34;&gt;实现&lt;/h3&gt;
&lt;p&gt;下面以遥控器作为例子进行代码模拟。&lt;/p&gt;
&lt;p&gt;首先从接口开始，定义一个命令接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Command&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;execute&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着，定义操作对象风扇：（其它对象省略了）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Light&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	String location &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Light&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String location&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; location&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;on&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;location &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34; light is on&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;off&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;location &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34; light is off&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后编写操作风扇的命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 开风扇，其它操作省略了
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;LightOnCommand&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; Command &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	Light light&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;LightOnCommand&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Light light&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;light&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; light&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;execute&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		light&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;on&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;还需要定义空命令，用于初始化遥控器命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;NoCommand&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; Command &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;execute&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后，定义遥控器，包含两个数组，分别用于开命令和关命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;RemoteControl&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	Command&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; onCommands&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	Command&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; offCommands&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;RemoteControl&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;		onCommands &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Command&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;7&lt;span style=&#34;color:#81a1c1&#34;&gt;];&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		offCommands &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Command&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;7&lt;span style=&#34;color:#81a1c1&#34;&gt;];&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		Command noCommand &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; NoCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt; i &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt; 7&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt; i&lt;span style=&#34;color:#81a1c1&#34;&gt;++)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;			onCommands&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;i&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; noCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;			offCommands&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;i&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; noCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;setCommand&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; slot&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Command onCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Command offCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;		onCommands&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;slot&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; onCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;		offCommands&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;slot&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; offCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;onButtonWasPushed&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; slot&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;		onCommands&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;slot&lt;span style=&#34;color:#81a1c1&#34;&gt;].&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;execute&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;offButtonWasPushed&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; slot&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;		offCommands&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;slot&lt;span style=&#34;color:#81a1c1&#34;&gt;].&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;execute&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;toString&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对代码进行简单测试：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 定义遥控
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;RemoteControl remoteControl &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; RemoteControl&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 定义一些遥控对象
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;Light livingRoomLight &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Light&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Living Room&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 定义作用在某个遥控对象上的一些命令
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;LightOnCommand livingRoomLightOn &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; LightOnCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;livingRoomLight&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;LightOffCommand livingRoomLightOff &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; LightOffCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;livingRoomLight&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;LightOnCommand kitchenLightOn &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; LightOnCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;kitchenLight&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;LightOffCommand kitchenLightOff &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; LightOffCommand&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;kitchenLight&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 配置遥控器命令
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;remoteControl&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setCommand&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;0&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; livingRoomLightOn&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; livingRoomLightOff&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 操作遥控
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;remoteControl&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;onButtonWasPushed&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;0&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;remoteControl&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;offButtonWasPushed&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;0&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;适配器模式&#34;&gt;适配器模式&lt;/h2&gt;
&lt;h3 id=&#34;解释-1&#34;&gt;解释&lt;/h3&gt;
&lt;p&gt;适配器模式将一个类的接口，转换成客户期望的另一个接口，适配器让原本接口不兼容的类可以合作无间。&lt;/p&gt;
&lt;h3 id=&#34;实现-4&#34;&gt;实现&lt;/h3&gt;
&lt;p&gt;鸭子和火鸡叫声不一样，通过编写适配器让火鸡适配鸭的方法。&lt;/p&gt;
&lt;p&gt;首先，从接口开始，定义鸭子和火鸡接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Duck&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;quack&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;fly&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Turkey&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;gobble&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;fly&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着编写适配器，让火鸡适配鸭子，也就是让火鸡适配器实现鸭子接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;TurkeyAdapter&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; Duck &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	Turkey turkey&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;TurkeyAdapter&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Turkey turkey&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;turkey&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; turkey&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;quack&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		turkey&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;gobble&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;fly&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; i&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;0&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt; i &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt; 5&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt; i&lt;span style=&#34;color:#81a1c1&#34;&gt;++)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;			turkey&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;fly&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着就可以编写一些具体类了：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 绿头鸭
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;MallardDuck&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; Duck &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 野火鸡：
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;WildTurkey&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; Turkey &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后对代码进行测试：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;DuckTestDrive&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;testDuck&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Duck duck&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;		duck&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;quack&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;		duck&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;fly&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		Duck duck &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; MallardDuck&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		Turkey turkey &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; WildTurkey&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		Duck turkeyAdapter &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; TurkeyAdapter&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;turkey&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;		turkey&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;gobble&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		turkey&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;fly&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;		testDuck&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;duck&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;		testDuck&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;turkeyAdapter&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;外观模式&#34;&gt;外观模式&lt;/h2&gt;
&lt;h3 id=&#34;解释-2&#34;&gt;解释&lt;/h3&gt;
&lt;p&gt;外观模式提供了一个统一的接口，用来访问子系统中的一群接口，外观定义了一个高层接口，让子系统更容易使用。&lt;/p&gt;
&lt;p&gt;最少知识原则：减少对象之间的交互，只和“密友”谈话，也就是减少一个类所交互的类的数量。&lt;/p&gt;
&lt;h3 id=&#34;实现-5&#34;&gt;实现&lt;/h3&gt;
&lt;p&gt;执行一些复杂操作需要一步步执行许多小操作，那么可以将复杂操作封装为一个高层类中的方法，将所有复杂操作需要用到的类作为高层类的成员，在复杂操作的方法中可以方便的调用各个类执行各自的功能。&lt;/p&gt;
&lt;p&gt;下面是一个家庭影院的例子：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;HomeTheaterFacade&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	Amplifier amp&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	Tuner tuner&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	StreamingPlayer player&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	CdPlayer cd&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	Projector projector&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;	TheaterLights lights&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;	Screen screen&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;	PopcornPopper popper&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;HomeTheaterFacade&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Amplifier amp&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;				 Tuner tuner&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;				 StreamingPlayer player&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;				 Projector projector&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;				 Screen screen&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;				 TheaterLights lights&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;				 PopcornPopper popper&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;					&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;watchMovie&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String movie&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Get ready to watch a movie...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;		popper&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;on&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;		popper&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;pop&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;		lights&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;dim&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;10&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;		screen&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;down&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;		projector&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;on&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;		projector&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;wideScreenMode&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;		amp&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;on&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;		amp&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setStreamingPlayer&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;player&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;		amp&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setSurroundSound&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;		amp&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setVolume&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;5&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;		player&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;on&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;		player&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;play&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;movie&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;38&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;endMovie&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;39&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Shutting movie theater down...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;40&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;41&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;42&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;43&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;listenToRadio&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;double&lt;/span&gt; frequency&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;44&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Tuning in the airwaves...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;45&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;46&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;47&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;48&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;endRadio&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;49&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Shutting down the tuner...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;50&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;51&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;52&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;各个功能器件的代码和测试代码省略了。&lt;/p&gt;
&lt;h2 id=&#34;模板方法模式&#34;&gt;模板方法模式&lt;/h2&gt;
&lt;h3 id=&#34;解释-3&#34;&gt;解释&lt;/h3&gt;
&lt;p&gt;模板方法模式在一个方法中定义一个算法的骨架，而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下，重新定义算法中的某些步骤。&lt;/p&gt;
&lt;p&gt;关于好莱坞原则：别调用我们，我们会调用你。&lt;/p&gt;
&lt;p&gt;其实就是防止“依赖腐败”，也就是要避免高层组件和低层组件相互依赖。一般由高层组件依赖低层组件。&lt;/p&gt;
&lt;h3 id=&#34;实现-6&#34;&gt;实现&lt;/h3&gt;
&lt;p&gt;泡茶和泡咖啡有着几乎相同的步骤，但在某些子步骤中有差别。通过模板方法可以很好地解决问题。&lt;/p&gt;
&lt;p&gt;可以定义一个泡饮料的模板方法，其中子步骤 &lt;code&gt;brew()&lt;/code&gt; 和 &lt;code&gt;addCondiments()&lt;/code&gt; 为抽象方法，由子类进行具体实现。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;CaffeineBeverage&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;prepareRecipe&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;		boilWater&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;		brew&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;		pourInCup&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		addCondiments&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;brew&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;addCondiments&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;boilWater&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Boiling water&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;pourInCup&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Pouring into cup&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其它代码就省略了。&lt;/p&gt;
&lt;h2 id=&#34;迭代器模式&#34;&gt;迭代器模式&lt;/h2&gt;
&lt;h3 id=&#34;解释-4&#34;&gt;解释&lt;/h3&gt;
&lt;p&gt;迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素，而又不暴露其内部的表示。&lt;/p&gt;
&lt;p&gt;通过一个 Iterator，可以方便地遍历各种类型，如 HashMap，LinkedList 等。特别对于 LinkedList，使用迭代器进行迭代比使用下标进行迭代会快很多，因为是它基于链表的结构。&lt;/p&gt;
&lt;h3 id=&#34;实现-7&#34;&gt;实现&lt;/h3&gt;
&lt;p&gt;下面通过菜单的例子进行说明。&lt;/p&gt;
&lt;p&gt;分别用简单数组 &lt;code&gt;String[]&lt;/code&gt; 和 &lt;code&gt;ArrayList&amp;lt;String&amp;gt;&lt;/code&gt; 类创建菜单内容。&lt;/p&gt;
&lt;p&gt;首先创建菜单接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Menu&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Iterator&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;createIterator&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个菜单都可以返回一个迭代器。&lt;/p&gt;
&lt;p&gt;接着创建 Diner 的菜单，用String[]创建内容，需要编写自己的迭代器。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;DinerMenu&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; Menu &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; MAX_ITEMS &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 6&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; numberOfItems &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	String&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; menuItems&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;DinerMenu&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		menuItems &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; String&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;MAX_ITEMS&lt;span style=&#34;color:#81a1c1&#34;&gt;];&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		addItem&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Vegetarian BLT&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;addItem&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String name&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;numberOfItems &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;=&lt;/span&gt; MAX_ITEMS&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;			System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;err&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Sorry, menu is full!  Can&amp;#39;t add item to menu&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;			menuItems&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;numberOfItems&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; name&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;			numberOfItems &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; numberOfItems &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getMenuItems&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; menuItems&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Iterator&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;createIterator&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; DinerMenuIterator&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;menuItems&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 后面需要进行实现
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;toString&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Diner Menu&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// other menu methods here
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着，创建菜单迭代器，需要实现 &lt;code&gt;Iterater&amp;lt;String&amp;gt;&lt;/code&gt; 接口，实现 &lt;code&gt;next()&lt;/code&gt;，&lt;code&gt;hasNext()&lt;/code&gt; 和 &lt;code&gt;remove()&lt;/code&gt; 方法。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;DinerMenuIterator&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; Iterator&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	String&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; list&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; position &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;DinerMenuIterator&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; list&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; list&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;next&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		String menuItem &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; list&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;position&lt;span style=&#34;color:#81a1c1&#34;&gt;];&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;		position &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; position &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; menuItem&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;hasNext&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;position &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;=&lt;/span&gt; list&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;||&lt;/span&gt; list&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;position&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;			&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;			&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;remove&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;position &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;=&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;			&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; IllegalStateException
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;				&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;You can&amp;#39;t remove an item until you&amp;#39;ve done at least one next()&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;list&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;position&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;			&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; position&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt; i &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;list&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;length&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt; i&lt;span style=&#34;color:#81a1c1&#34;&gt;++)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;				list&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;i&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; list&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;i&lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;];&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;			&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;			list&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;list&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;length&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以后，访问菜单就很方便了，只需要获得菜单的迭代器即可。&lt;/p&gt;
&lt;p&gt;其它代码省略了。&lt;/p&gt;
&lt;h2 id=&#34;组合模式&#34;&gt;组合模式&lt;/h2&gt;
&lt;h3 id=&#34;解释-5&#34;&gt;解释&lt;/h3&gt;
&lt;p&gt;允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。&lt;/p&gt;
&lt;p&gt;对于菜单内容而言，假如只有简单的菜品项，那么通过迭代器可以轻松地遍历，但是如果菜单内容中含有子菜单，那么就需要组合模式了。&lt;/p&gt;
&lt;h3 id=&#34;实现-8&#34;&gt;实现&lt;/h3&gt;
&lt;p&gt;下面就以菜单为例子展示组合模式，每个菜单既可能由菜单项，也可能有子菜单，所以可以把菜单项和子菜单这两者都理解为菜单组件，作为一个抽象的对象，具体操作时根据需要进行实现即可。&lt;/p&gt;
&lt;p&gt;首先创建菜单组件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;MenuComponent&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;   
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;MenuComponent menuComponent&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; UnsupportedOperationException&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;remove&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;MenuComponent menuComponent&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; UnsupportedOperationException&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; MenuComponent &lt;span style=&#34;color:#88c0d0&#34;&gt;getChild&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; i&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; UnsupportedOperationException&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;getName&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; UnsupportedOperationException&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;getDescription&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; UnsupportedOperationException&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;double&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getPrice&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; UnsupportedOperationException&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;isVegetarian&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; UnsupportedOperationException&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; UnsupportedOperationException&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着创建具体的菜单，继承菜单组件，实现父类方法中关于操作子菜单：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Menu&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;extends&lt;/span&gt; MenuComponent &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	ArrayList&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;MenuComponent&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; menuComponents &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; ArrayList&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;MenuComponent&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	String name&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	String description&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;Menu&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String name&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; String description&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; name&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;description&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; description&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;MenuComponent menuComponent&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;		menuComponents&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;menuComponent&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;remove&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;MenuComponent menuComponent&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;		menuComponents&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;remove&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;menuComponent&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; MenuComponent &lt;span style=&#34;color:#88c0d0&#34;&gt;getChild&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; i&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;MenuComponent&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;menuComponents&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;get&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;i&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;getName&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; name&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;getDescription&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; description&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// getPrice 和 isVegetarian 就不需要了，因为是菜单
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; getName&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; getDescription&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;---------------------&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;MenuComponent menuComponent &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; menuComponents&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;			menuComponent&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着创建菜单项，它也是一个菜单组件，但是它不需要重写部分关于子菜单的方法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;MenuItem&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;extends&lt;/span&gt; MenuComponent &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	String name&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	String description&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;boolean&lt;/span&gt; vegetarian&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;double&lt;/span&gt; price&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;MenuItem&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String name&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;	                String description&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;	                &lt;span style=&#34;color:#81a1c1&#34;&gt;boolean&lt;/span&gt; vegetarian&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	                &lt;span style=&#34;color:#81a1c1&#34;&gt;double&lt;/span&gt; price&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;//...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;getName&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; name&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;getDescription&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; description&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;double&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getPrice&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; price&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;isVegetarian&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; vegetarian&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;print&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后进行测试：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;MenuTestDrive&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String args&lt;span style=&#34;color:#81a1c1&#34;&gt;[])&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 主菜单
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;		MenuComponent allMenus &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Menu&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ALL MENUS&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;All menus combined&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 一些子菜单
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;		MenuComponent pancakeHouseMenu &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;			&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Menu&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;PANCAKE HOUSE MENU&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Breakfast&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 其它子菜单省略了
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 添加子菜单
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;		allMenus&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;pancakeHouseMenu&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;		allMenus&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;dinerMenu&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		allMenus&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;cafeMenu&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 在子菜单中添加菜单项
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;		pancakeHouseMenu&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; MenuItem&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;			&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;K&amp;amp;B&amp;#39;s Pancake Breakfast&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;			&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Pancakes with scrambled eggs and toast&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;			&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;			2&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;99&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;));&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 省略其它菜品项
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;		&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 子菜单添加子菜单
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;		dinerMenu&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;dessertMenu&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;状态模式&#34;&gt;状态模式&lt;/h2&gt;
&lt;h3 id=&#34;解释-6&#34;&gt;解释&lt;/h3&gt;
&lt;p&gt;状态模式允许对象在内部状态改变时改变它的行为，对象看起来好像修改了它的类。&lt;/p&gt;
&lt;p&gt;比如某个机器有各种复杂的状态，每个状态都着共同的参数，而这些参数值有区别。用户通过某些操作会改变机器的状态，机器转变状态后，以当前状态的方法给用户反馈。&lt;/p&gt;
&lt;h3 id=&#34;实现-9&#34;&gt;实现&lt;/h3&gt;
&lt;p&gt;以机器的例子说明。每次对机器进行操作，机器的状态都可能发生改变，但是下一个状态是什么需要由当前状态决定。所以每个具体的状态定义好了从当前状态经过当前操作会跳转到哪个状态。&lt;/p&gt;
&lt;p&gt;首先编写一个状态接口，其中包括该机器可能的所有状态：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;State&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;insertQuarter&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;ejectQuarter&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;turnCrank&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;dispense&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;refill&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着创建机器类：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;GumballMachine&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 各种机器状态，后续需要进行具体实现
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	State soldOutState&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	State noQuarterState&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;	State hasQuarterState&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	State soldState&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 当前状态
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	State state&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; count &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 初始化该机器的各个状态
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;GumballMachine&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; numberGumballs&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		soldOutState &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; SoldOutState&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 这些状态依赖于该机器
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;		noQuarterState &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; NoQuarterState&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;		hasQuarterState &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; HasQuarterState&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;		soldState &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; SoldState&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; numberGumballs&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt; 		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;numberGumballs &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;			state &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; noQuarterState&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;			state &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; soldOutState&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 定义一些操作，经过某个操作后，机器状态发生改变
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;turnCrank&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;		state&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;turnCrank&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;		state&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;dispense&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 其它操作省略了
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// constructor getter setter
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着，定义各种机器状态，以其中一个状态为例子：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;HasQuarterState&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; State &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;	GumballMachine gumballMachine&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 依赖某个具体的机器
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;HasQuarterState&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;GumballMachine gumballMachine&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;		&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;gumballMachine&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; gumballMachine&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 经过该操作，该机器从 HasQuarterState 转移到下一个状态
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;ejectQuarter&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;		System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Quarter returned&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;		gumballMachine&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setState&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;gumballMachine&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getNoQuarterState&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 转移到该机器的其它状态
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 重写的其它方法省略了
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试部分代码省略了。&lt;/p&gt;
&lt;h2 id=&#34;代理模式&#34;&gt;代理模式&lt;/h2&gt;
&lt;h3 id=&#34;解释-7&#34;&gt;解释&lt;/h3&gt;
&lt;p&gt;代理模式提供了对目标对象另外的访问方式，即通过代理对象访问目标对象。这样做的好处是可以在目标对象实现的基础上，增强额外的功能操作，即扩展目标对象的功能。&lt;/p&gt;
&lt;p&gt;这里使用到编程中的一个思想：不要随意去修改别人已经写好的代码或者方法，如果需改修改，可以通过代理的方式来扩展该方法。&lt;/p&gt;
&lt;h3 id=&#34;实现静态代理&#34;&gt;实现静态代理&lt;/h3&gt;
&lt;p&gt;静态代理在使用时，需要定义接口或者父类，被代理对象与代理对象一起实现相同的接口或者是继承相同父类。&lt;/p&gt;
&lt;p&gt;下面举个案例来解释。&lt;/p&gt;
&lt;p&gt;模拟保存动作，定义一个保存操作的接口 IUserDao，然后目标对象实现这个接口的方法 UserDao，此时如果使用静态代理方式，就需要在代理对象 UserDaoProxy 中也实现 IUserDao 接口，调用的时候通过调用代理对象的方法来调用目标对象。&lt;/p&gt;
&lt;p&gt;需要注意的是，代理对象与目标对象要实现相同的接口，然后通过调用相同的方法来调用目标对象的方法。&lt;/p&gt;
&lt;p&gt;首先定义接口 IUserDao：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;IUserDao&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;save&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着定义目标对象 UserDao：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;UserDao&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; IUserDao &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;save&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;saved.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后代理对象 UserDaoProxy：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;UserDaoProxy&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; IUserDao&lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 接收保存目标对象
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; IUserDao target&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;UserDaoProxy&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;IUserDao target&lt;span style=&#34;color:#81a1c1&#34;&gt;){&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;target&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;save&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;before...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 增强的方法
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;        target&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;save&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 执行目标对象的方法
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;after...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 增强的方法
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;静态代理在编译器就完成了，可以做到在不修改目标对象的功能前提下，对目标功能扩展。但因为代理对象需要与目标对象实现一样的接口，所以会有很多代理类。同时，一旦接口增加方法，目标对象与代理对象都要维护。&lt;/p&gt;
&lt;h3 id=&#34;实现动态代理&#34;&gt;实现动态代理&lt;/h3&gt;
&lt;p&gt;在动态代理中，代理对象不需要实现接口。代理对象的生成利用了 JDK 的 API，动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)。&lt;/p&gt;
&lt;p&gt;JDK 实现代理只需要使用 newProxyInstance 方法，该方法需要接收三个参数，完整的写法是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; Object &lt;span style=&#34;color:#88c0d0&#34;&gt;newProxyInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;ClassLoader loader&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Class&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;?&amp;gt;[]&lt;/span&gt; interfaces&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; InvocationHandler h&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;ClassLoader loader: 指定当前目标对象使用类加载器，获取加载器的方法是固定的&lt;/li&gt;
&lt;li&gt;Class&amp;lt;?&amp;gt;[] interfaces: 目标对象实现的接口的类型，使用泛型方式确认类型&lt;/li&gt;
&lt;li&gt;InvocationHandler h: 事件处理，执行目标对象的方法时，会触发事件处理器的方法，会把当前执行目标对象的方法作为参数传入&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接口类IUserDao.java以及接口实现类,目标对象UserDao是一样的,没有做修改.在这个基础上,增加一个代理工厂类(ProxyFactory.java),将代理类写在这个地方,然后在测试类(需要使用到代理的代码)中先建立目标对象和代理对象的联系,然后代用代理对象的中同名方法&lt;/p&gt;
&lt;p&gt;定义一个代理工厂类 ProxyFactory，用于方便地生成代理对象：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;ProxyFactory&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;//维护一个目标对象
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; Object target&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;ProxyFactory&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Object target&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;target&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;target&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;   &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;//给目标对象生成代理对象
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Object &lt;span style=&#34;color:#88c0d0&#34;&gt;getProxyInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; Proxy&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;newProxyInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;                target&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getClass&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getClassLoader&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(),&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;                target&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getClass&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getInterfaces&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(),&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; InvocationHandler&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;                    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;                    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Object &lt;span style=&#34;color:#88c0d0&#34;&gt;invoke&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Object proxy&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Method method&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Object&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throws&lt;/span&gt; Throwable &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;                        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;before...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;                        Object returnValue &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; method&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;invoke&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;target&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;                        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;after...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;                        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; returnValue&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;                    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代理对象不需要实现接口，但是目标对象一定要实现接口，否则不能用动态代理。&lt;/p&gt;
&lt;h3 id=&#34;cglib-代理&#34;&gt;Cglib 代理&lt;/h3&gt;
&lt;p&gt;上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象，但是有时候目标对象只是一个单独的对象，并没有实现任何的接口，这个时候就可以使用以目标对象子类的方式类实现代理，这种方法就叫做 Cglib 代理。&lt;/p&gt;
&lt;p&gt;Cglib 代理，也叫作&lt;strong&gt;子类代理&lt;/strong&gt;，它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。&lt;/p&gt;
&lt;p&gt;Cglib 是一个强大的高性能的代码生成包，它可以在运行期扩展类与实现接口，广泛的被许多 AOP 的框架使用，例如 Spring。Cglib 包的底层是通过使用一个小而快的字节码处理框架 ASM 来转换字节码并生成新的类。&lt;/p&gt;
&lt;p&gt;Cglib 子类代理实现方法:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;需要引入 cglib 的 jar 文件，但是 Spring 的核心包中已经包括了 Cglib 功能，所以直接引入 spring-core-3.2.5.jar 也可以；&lt;/li&gt;
&lt;li&gt;代理的类不能为 final；&lt;/li&gt;
&lt;li&gt;目标对象的方法如果为 final/static，那么就不会被拦截，即不会执行目标对象额外的业务方法；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;创建一个 Cglib 代理工厂 ProxyFactory：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;ProxyFactory&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; MethodInterceptor&lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 维护目标对象
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; Object target&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;ProxyFactory&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Object target&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;target&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; target&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 给目标对象创建一个代理对象
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Object &lt;span style=&#34;color:#88c0d0&#34;&gt;getProxyInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(){&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 1.工具类
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;        Enhancer en &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Enhancer&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 2.设置父类
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;        en&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setSuperclass&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;target&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getClass&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 3.设置回调函数
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;        en&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setCallback&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 4.创建子类(代理对象)
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; en&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;create&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Object &lt;span style=&#34;color:#88c0d0&#34;&gt;intercept&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Object obj&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Method method&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Object&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; MethodProxy proxy&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throws&lt;/span&gt; Throwable &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;before...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;        Object returnValue &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; method&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;invoke&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;target&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;        System&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;println&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;after...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; returnValue&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 Spring 的 AOP 编程中:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果加入容器的目标对象有实现接口，用 JDK 代理&lt;/li&gt;
&lt;li&gt;如果目标对象没有实现接口，用 Cglib 代理&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;结合策略模式实现动态-bean&#34;&gt;结合策略模式实现动态 Bean&lt;/h3&gt;
&lt;p&gt;假设在某个业务类中存在一个注入 bean 如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Autowired&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; TestService testService&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 TestService 是一个接口，假设我们有该接口有多种实现：TestServiceImpl1 和 TestServiceImpl2，在不同环境下按需调用接口对应的实现（比如可能需要能根据请求参数进行选择），这时如何实现呢？&lt;/p&gt;
&lt;p&gt;可以通过反射的机制并配合 Spring 注解实现，以下是具体的实现过程分析。&lt;/p&gt;
&lt;p&gt;首先我们可以设计一个 TestApiSwitcher:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Bean&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;name &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;testService&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Primary&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; TestService &lt;span style=&#34;color:#88c0d0&#34;&gt;getTestService&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; Reflection&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;newProxy&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;TestService&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; switcherInvocationHandler&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中，@Bean 是 Spring 中的注解之一，通常用于在配置类中声明一个方法，并将其&lt;strong&gt;返回值&lt;/strong&gt;作为一个 Bean 注册到 Spring 容器中。而 @Primary 注解配合于 @Bean 注解，用于指定一个 Bean 作为默认首选的候选项。&lt;/p&gt;
&lt;p&gt;当有多个同类型的 Bean 需要注入时，Spring 容器会根据类型匹配进行自动装配。但如果存在多个匹配的 Bean 时，会产生歧义性，导致无法确定要注入哪个 Bean。使用 @Primary 注解，可以将一个 Bean 标记为首选的候选项。当需要注入该类型的 Bean 时，如果代码中没有通过 @Resource 之类的注解进行指定, Spring 容器会优先选择被 @Primary 注解标记的 Bean 作为注入对象。&lt;/p&gt;
&lt;p&gt;观察方法内部，我们通过 guava 库的反射操作 &lt;code&gt;Reflection.newProxy&lt;/code&gt; 为 TestService 设置代理对象 switcherInvocationHandler，那么继续设计我们的 switcherInvocationHandler。&lt;/p&gt;
&lt;p&gt;首先，我们需要判断被调用的方法是否是 Object 类中的方法（即通用的方法，如equals()、hashCode()、toString()等）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果是通用方法，则直接在代理对象上调用该方法并返回结果。&lt;/li&gt;
&lt;li&gt;如果被调用的方法不是通用方法，则根据请求参数 args 进行路由，选择合适的实现类，进行对应方法的调用即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;大致实现思路如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;SwitcherInvocationHandler&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; InvocationHandler &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;final&lt;/span&gt; Set&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; METHODS_ON_OBJECT_CLASS &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Set&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; Arrays&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;stream&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Object&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getMethods&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()).&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;map&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Method&lt;span style=&#34;color:#81a1c1&#34;&gt;::&lt;/span&gt;getName&lt;span style=&#34;color:#81a1c1&#34;&gt;).&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;collect&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Collectors&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;toSet&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Object &lt;span style=&#34;color:#88c0d0&#34;&gt;invoke&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Object proxy&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Method method&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Object&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throws&lt;/span&gt; Throwable &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;METHODS_ON_OBJECT_CLASS&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;contains&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;method&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getName&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()))&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; method&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;invoke&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;try&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;                &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 根据 args 进行路由
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;getArgInfo&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; 1&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; method&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;invoke&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;TestServiceImpl1&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;getArgInfo&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; 2&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; method&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;invoke&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;TestServiceImpl2&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;getArgInfo&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; 3&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; method&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;invoke&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;TestServiceImpl1&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;catch&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;InvocationTargetException e&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;                &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; e&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getCause&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中， METHODS_ON_OBJECT_CLASS 是一个记录了 Object 类基本方法的集合。&lt;/p&gt;
&lt;p&gt;SwitcherInvocationHandler 为一个代理类，实现了 InvocationHandler 接口，通过 JDK 动态代理进行实现。在每个方法调用前将会先进行 invoke 方法的调用。&lt;/p&gt;
&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;《Head First 设计模式》&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>微服务重要知识整理</title>
        <link>https://zhihang.org/posts/organizing-knowledge-related-to-microservices/</link>
        <pubDate>Sun, 12 Mar 2023 01:49:47 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>organizing-knowledge-related-to-microservices</guid>
        <description>&lt;h2 id=&#34;preface&#34;&gt;Preface&lt;/h2&gt;
&lt;p&gt;本篇 Blog 对接触到的微服务相关知识做一个整理汇总，仅供查阅学习。如有错误，请批评指正；如发现有文段引用自别处但未在文末加来源，请联系我。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#preface&#34;&gt;Preface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%BE%AE%E6%9C%8D%E5%8A%A1&#34;&gt;微服务&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%80%9D%E6%83%B3&#34;&gt;基本思想&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%A0%B8%E5%BF%83%E7%89%B9%E7%82%B9&#34;&gt;核心特点&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%B3%E9%94%AE%E7%BB%84%E4%BB%B6&#34;&gt;关键组件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%9B%A0&#34;&gt;设计原因&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%87%8D%E8%A6%81%E6%A1%86%E6%9E%B6&#34;&gt;重要框架&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%8E%E5%8F%91%E7%8E%B0&#34;&gt;服务注册与发现&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#eureka&#34;&gt;Eureka&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#eureka-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84&#34;&gt;Eureka 微服务架构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#eureka-%E4%BE%9D%E8%B5%96&#34;&gt;Eureka 依赖&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#7001-%E5%92%8C-7002-%E7%AB%AF%E5%8F%A3%E5%85%B3%E9%94%AE%E9%85%8D%E7%BD%AE%E5%86%85%E5%AE%B9&#34;&gt;7001 和 7002 端口关键配置内容&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#8001-%E5%92%8C-8002-%E7%AB%AF%E5%8F%A3%E5%85%B3%E9%94%AE%E9%85%8D%E7%BD%AE%E5%86%85%E5%AE%B9&#34;&gt;8001 和 8002 端口关键配置内容&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#80-%E7%AB%AF%E5%8F%A3%E5%85%B3%E9%94%AE%E9%85%8D%E7%BD%AE%E5%86%85%E5%AE%B9&#34;&gt;80 端口关键配置内容&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%88%E6%9E%9C%E5%B1%95%E7%A4%BA&#34;&gt;效果展示&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#nacos&#34;&gt;Nacos&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%BB%E8%A6%81%E5%8A%9F%E8%83%BD&#34;&gt;主要功能&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%9E%B6%E6%9E%84&#34;&gt;基本架构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E8%B7%B5%E6%B5%8B%E8%AF%95&#34;&gt;实践测试&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%80%BB%E4%BD%93%E6%9E%B6%E6%9E%84&#34;&gt;总体架构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%9C%8D%E5%8A%A1%E8%AF%B4%E6%98%8E&#34;&gt;服务说明&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%90%AD%E5%BB%BA-nacos-%E7%8E%AF%E5%A2%83&#34;&gt;搭建 nacos 环境&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BF%A1%E6%81%AF&#34;&gt;配置数据库信息&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%BF%90%E8%A1%8C-docker&#34;&gt;运行 docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%90%AD%E5%BB%BA-nginx-%E7%8E%AF%E5%A2%83&#34;&gt;搭建 nginx 环境&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%9B%E5%BB%BA%E5%BE%AE%E6%9C%8D%E5%8A%A1&#34;&gt;创建微服务&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BC%96%E5%86%99%E6%9C%8D%E5%8A%A1&#34;&gt;编写服务&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%8C%E6%88%90%E6%B5%8B%E8%AF%95&#34;&gt;完成测试&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#api-%E7%BD%91%E5%85%B3&#34;&gt;API 网关&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BD%91%E5%85%B3%E7%9A%84%E4%BD%9C%E7%94%A8&#34;&gt;网关的作用&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#springcloud-gateway-%E5%AE%9E%E8%B7%B5&#34;&gt;SpringCloud Gateway 实践&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BE%9D%E8%B5%96%E5%BC%95%E5%85%A5&#34;&gt;依赖引入&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%96%87%E4%BB%B6%E9%85%8D%E7%BD%AE&#34;&gt;文件配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%BF%87%E6%BB%A4%E5%99%A8%E9%85%8D%E7%BD%AE&#34;&gt;过滤器配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B5%8B%E8%AF%95&#34;&gt;测试&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%86%E5%B8%83%E5%BC%8F%E9%85%8D%E7%BD%AE&#34;&gt;分布式配置&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5&#34;&gt;基本概念&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#spring-cloud-config&#34;&gt;Spring Cloud Config&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95&#34;&gt;操作方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BE%9D%E8%B5%96%E5%BC%95%E5%85%A5-1&#34;&gt;依赖引入&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E7%A1%80%E9%85%8D%E7%BD%AE&#34;&gt;基础配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BC%96%E5%86%99%E7%9B%B8%E5%85%B3%E6%8E%A5%E5%8F%A3&#34;&gt;编写相关接口&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B5%8B%E8%AF%95-1&#34;&gt;测试&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%9C%8D%E5%8A%A1%E9%80%9A%E4%BF%A1&#34;&gt;服务通信&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%87%87%E7%94%A8%E5%8D%8F%E8%AE%AE&#34;&gt;采用协议&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#grpc-%E5%8D%8F%E8%AE%AE%E4%BB%8B%E7%BB%8D&#34;&gt;gRPC 协议介绍&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#dubbo-%E5%8D%8F%E8%AE%AE%E4%BB%8B%E7%BB%8D&#34;&gt;Dubbo 协议介绍&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1&#34;&gt;负载均衡&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%80%9D%E6%83%B3-1&#34;&gt;基本思想&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%B3%E4%BA%8E%E9%9B%86%E4%B8%AD%E5%BC%8F-lb-%E5%92%8C%E8%BF%9B%E7%A8%8B%E5%86%85-lb&#34;&gt;关于集中式 LB 和进程内 LB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#dubbo&#34;&gt;Dubbo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#ribbon&#34;&gt;Ribbon&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%B7%E4%BD%93%E5%8A%9F%E8%83%BD&#34;&gt;具体功能&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%9E%B6%E6%9E%84-1&#34;&gt;基本架构&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E8%B7%B5%E6%B5%8B%E8%AF%95-1&#34;&gt;实践测试&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%87%AA%E5%B7%B1%E5%AE%9E%E7%8E%B0%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1&#34;&gt;自己实现负载均衡&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BC%96%E5%86%99-lb-%E6%8E%A5%E5%8F%A3%E5%8D%B3%E5%AE%9E%E7%8E%B0%E7%B1%BB&#34;&gt;编写 LB 接口即实现类&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BC%96%E5%86%99-controller&#34;&gt;编写 Controller&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%B9%E9%94%99%E6%9C%BA%E5%88%B6%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD&#34;&gt;容错机制：服务熔断&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%80%9D%E6%83%B3-2&#34;&gt;基本思想&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6&#34;&gt;实现机制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hystrix-%E5%AE%9E%E8%B7%B5&#34;&gt;Hystrix 实践&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BE%9D%E8%B5%96%E5%AF%BC%E5%85%A5&#34;&gt;依赖导入&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE&#34;&gt;基本配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%96%B9%E6%B3%95%E5%AE%9E%E7%8E%B0&#34;&gt;方法实现&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B5%8B%E8%AF%95-2&#34;&gt;测试&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%B9%E9%94%99%E6%9C%BA%E5%88%B6%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7&#34;&gt;容错机制：服务降级&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%80%9D%E6%83%B3-3&#34;&gt;基本思想&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0%E6%9C%BA%E5%88%B6-1&#34;&gt;实现机制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hystrix-%E5%AE%9E%E8%B7%B5-1&#34;&gt;Hystrix 实践&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BE%9D%E8%B5%96%E5%AF%BC%E5%85%A5-1&#34;&gt;依赖导入&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE-1&#34;&gt;基本配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%96%B9%E6%B3%95%E5%AE%9E%E7%8E%B0-1&#34;&gt;方法实现&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B5%8B%E8%AF%95-3&#34;&gt;测试&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%B9%E9%94%99%E6%9C%BA%E5%88%B6%E6%9C%8D%E5%8A%A1%E9%99%90%E6%B5%81&#34;&gt;容错机制：服务限流&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E7%8E%B0%E7%9B%AE%E6%A0%87&#34;&gt;实现目标&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%99%90%E6%B5%81%E7%AE%97%E6%B3%95&#34;&gt;限流算法&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%B9%E9%94%99%E6%9C%BA%E5%88%B6sentinel&#34;&gt;容错机制：Sentinel&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5-1&#34;&gt;基本概念&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%9E%B6%E6%9E%84%E8%AF%B4%E6%98%8E&#34;&gt;架构说明&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%E7%94%9F%E4%BA%A7%E8%80%85%E7%AB%AF&#34;&gt;代码实现（生产者端）&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE-2&#34;&gt;基本配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%96%B9%E6%B3%95%E5%AE%9E%E7%8E%B0-2&#34;&gt;方法实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%E6%B6%88%E8%B4%B9%E8%80%85%E7%AB%AF&#34;&gt;代码实现（消费者端）&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BE%9D%E8%B5%96%E5%AF%BC%E5%85%A5-2&#34;&gt;依赖导入&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE-3&#34;&gt;基本配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%96%B9%E6%B3%95%E5%AE%9E%E7%8E%B0-3&#34;&gt;方法实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B5%8B%E8%AF%95-4&#34;&gt;测试&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reference&#34;&gt;Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;微服务&#34;&gt;微服务&lt;/h2&gt;
&lt;h3 id=&#34;基本思想&#34;&gt;基本思想&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;微服务（Microservices）&lt;/strong&gt; 是一种软件架构风格，它将一个复杂的应用拆分成一组&lt;strong&gt;小型、独立运行的服务&lt;/strong&gt;。每个微服务都是围绕某个特定的业务功能构建的，并且能够通过轻量级的通信协议（如 HTTP 或消息队列）相互协作。&lt;/p&gt;
&lt;p&gt;这种架构以&lt;strong&gt;解耦、灵活性和扩展性&lt;/strong&gt;为核心目标，是对传统单体架构（Monolithic Architecture）的改进。&lt;/p&gt;
&lt;h3 id=&#34;核心特点&#34;&gt;核心特点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;单一职责&lt;/strong&gt;：每个微服务只专注于完成一个业务功能，例如用户管理、订单处理、支付服务等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;独立部署&lt;/strong&gt;：每个微服务可以单独构建、测试、部署和升级，而无需影响其他服务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术多样性&lt;/strong&gt;：不同微服务可以使用不同的编程语言、数据库或技术栈，根据具体需求选择最佳实现方式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;轻量级通信&lt;/strong&gt;：微服务通过轻量化的协议（如 HTTP REST API、gRPC 或消息队列）进行通信，避免复杂的交互。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自治性&lt;/strong&gt;：每个微服务独立运行，拥有自己的逻辑、数据存储和业务边界。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;去中心化管理&lt;/strong&gt;：微服务架构倾向于分布式治理，各服务独立开发、独立运维。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高扩展性&lt;/strong&gt;：可以根据流量或业务需求，对特定服务进行横向扩展，而不是整体扩展整个系统。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;关键组件&#34;&gt;关键组件&lt;/h3&gt;
&lt;p&gt;为了实现微服务架构，通常需要以下组件的支持：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务注册与发现：实现服务之间动态查找，例如通过 &lt;strong&gt;Eureka&lt;/strong&gt;、&lt;strong&gt;Consul&lt;/strong&gt; 或 &lt;strong&gt;Zookeeper&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;API 网关：统一入口，管理微服务之间的请求路由、安全认证和限流等功能，例如 &lt;strong&gt;Kong&lt;/strong&gt;、&lt;strong&gt;Spring Cloud Gateway&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;分布式配置：集中管理配置，支持动态更新，例如 &lt;strong&gt;Spring Cloud Config&lt;/strong&gt;、&lt;strong&gt;Consul KV Store&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;服务通信：HTTP、gRPC、MQ 等。&lt;/li&gt;
&lt;li&gt;负载均衡：在服务实例之间分发请求，例如使用 &lt;strong&gt;Ribbon&lt;/strong&gt; 或 &lt;strong&gt;Spring Cloud LoadBalancer&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;监控和日志：监控和追踪服务运行状态，例如 &lt;strong&gt;Prometheus&lt;/strong&gt;、&lt;strong&gt;Grafana&lt;/strong&gt; 或分布式追踪工具 &lt;strong&gt;Zipkin&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;容错机制：实现熔断、限流和自动重试功能，例如通过 &lt;strong&gt;Hystrix&lt;/strong&gt; 或 &lt;strong&gt;Resilience4j&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;设计原因&#34;&gt;设计原因&lt;/h3&gt;
&lt;p&gt;微服务架构解决了单体架构在开发、扩展和运维中的诸多痛点，特别适合现代复杂应用。它的核心价值在于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;灵活性&lt;/strong&gt;：独立部署与技术栈多样性。每个服务是独立模块，可以单独开发、测试和部署，而无需影响其他服务；不同的微服务可以根据需求选择最合适的技术栈或编程语言。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可扩展性&lt;/strong&gt;：按需扩展，优化资源利用。微服务允许针对不同服务进行独立扩展，而不是整体扩展整个系统；由于服务的独立性，可以在必要时为高负载服务分配更多资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;容错性&lt;/strong&gt;：故障隔离和快速恢复。一个服务的故障不会直接导致整个系统宕机；微服务部署简单，受影响的服务可以快速替换或恢复。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;重要框架&#34;&gt;重要框架&lt;/h3&gt;
&lt;p&gt;微服务框架 是一种为开发和管理微服务架构提供支持的工具集或技术栈。它们帮助开发者构建、部署和维护微服务，并简化了许多微服务架构中常见的挑战，如上文提到的大多微服务关键组件。&lt;/p&gt;
&lt;p&gt;现在主要存在两种微服务框架，SpringCloud 和 Dubbo，它们都是分布式系统中广泛使用的微服务框架。对比如下&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Dubbo&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Spring Cloud&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;语言支持&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;主要支持 Java（虽然有一些其他语言支持，但偏向 Java）&lt;/td&gt;
&lt;td&gt;支持多语言，尤其是与 REST 和 HTTP 接口交互&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;服务治理&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;内置完善的服务治理，如负载均衡、容错、动态路由等，也可以集成 Sentinel&lt;/td&gt;
&lt;td&gt;通过集成其他工具实现服务治理（如 Ribbon、Hystrix、Eureka 等）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;服务注册与发现&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;支持多种注册中心（如 Zookeeper、Nacos、Redis）&lt;/td&gt;
&lt;td&gt;提供内置支持，如 Eureka、Consul、Zookeeper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;通信协议&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;支持多种协议（Dubbo、HTTP、gRPC 等）&lt;/td&gt;
&lt;td&gt;主要基于 HTTP 和 REST&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;开发方式&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;通过 Java 接口定义远程调用接口，并通过框架自动实现&lt;/td&gt;
&lt;td&gt;使用 Spring Boot，通过注解和配置文件配置服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;扩展性&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;高度可定制，适合高性能服务间通信需求&lt;/td&gt;
&lt;td&gt;灵活但依赖更多外部组件（如 Hystrix、Ribbon）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Dubbo 大致框架：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/organizing-knowledge-related-to-microservices/image/1732084784650.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;SpringCloud 大致框架：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/organizing-knowledge-related-to-microservices/image/1732085695642.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;服务注册与发现&#34;&gt;服务注册与发现&lt;/h2&gt;
&lt;h3 id=&#34;eureka&#34;&gt;Eureka&lt;/h3&gt;
&lt;h4 id=&#34;eureka-微服务架构&#34;&gt;Eureka 微服务架构&lt;/h4&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/organizing-knowledge-related-to-microservices/image/eureka1.png&#34; loading=&#34;lazy&#34; alt=&#34;eureka1&#34;  /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务接口采用集群模式，8001 和 8002 端口都实现支付接口服务。&lt;/li&gt;
&lt;li&gt;用户接口在运行在 80 端口，调用 8001 和 8002 的服务。&lt;/li&gt;
&lt;li&gt;注册中心内部也采用集群模式，7001 和 7002 端口都实现注册服务。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;eureka-依赖&#34;&gt;Eureka 依赖&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- client端 --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-netflix-eureka-client&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- server端 --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-netflix-eureka-server&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;7001-和-7002-端口关键配置内容&#34;&gt;7001 和 7002 端口关键配置内容&lt;/h4&gt;
&lt;p&gt;在启动类开启注解 &lt;code&gt;@EnableEurekaServer&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@SpringBootApplication&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@EnableEurekaServer&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;EurekaMain7001&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;        SpringApplication&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;EurekaMain7001&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着进行基础配置如下：&lt;/p&gt;
&lt;p&gt;对于 7001 端口服务：（7002 端口类似）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;eureka&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;instance&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;hostname&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; eureka7001.com
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;client&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# false 表示不向注册中心注册自己&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;register-with-eureka&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# false 表示自己端就是注册中心，我的职责就是维护服务实例，并不需要去检索服务&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;fetch-registry&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;false&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;service-url&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;defaultZone&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; http://eureka7002.com:7002/eureka/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意 defaultZone 配置指向其他注册服务端口，需满足“相互注册”。&lt;/p&gt;
&lt;p&gt;另外，eureka7001.com 和 eureka7002.com 其实配置指向 localhost，这里只是为了模拟多台机器。&lt;/p&gt;
&lt;h4 id=&#34;8001-和-8002-端口关键配置内容&#34;&gt;8001 和 8002 端口关键配置内容&lt;/h4&gt;
&lt;p&gt;注：(2023-03-20 更新)&lt;/p&gt;
&lt;p&gt;Eureka version 4.0.0 onwards, which is being used in Spring Cloud 2022.0.0, you do not need to explicitly register using the annotation &lt;code&gt;@EnableEurekaClient&lt;/code&gt;, It automatically gets registered as client if &lt;code&gt;spring-cloud-starter-netflix-eureka-client&lt;/code&gt; is on the class path.&lt;/p&gt;
&lt;p&gt;By having spring-cloud-starter-netflix-eureka-client on the classpath, your application automatically registers with the Eureka Server. Configuration is required to locate the Eureka server.&lt;/p&gt;
&lt;p&gt;否则需要开启 &lt;code&gt;@EnableEurekaClient&lt;/code&gt; 注解:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@SpringBootApplication&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@EnableEurekaClient&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PaymentMain8001&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;        SpringApplication&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;PaymentMain8001&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着进行基础配置如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# eureka 配置部分&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;eureka&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;client&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;register-with-eureka&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 配置是否进行注册&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;fetch-registry&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 配置是否从eureka注册中心拉取注册信息&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;service-url&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 配置注册地址&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;defaultZone&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;instance&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;instance-id&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; payment8001
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;prefer-ip-address&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 鼠标到instance上会显示ip&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 配置服务名称&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;spring&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; cloud-payment-service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个服务名很重要，用于配置后面用户接口的服务地址。&lt;/p&gt;
&lt;h4 id=&#34;80-端口关键配置内容&#34;&gt;80 端口关键配置内容&lt;/h4&gt;
&lt;p&gt;开启 &lt;code&gt;@EnableEurekaClient&lt;/code&gt; 注解:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@SpringBootApplication&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@EnableEurekaClient&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;OrderMain80&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;        SpringApplication&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;OrderMain80&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置 RestTemplate，开启负载均衡:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Configuration&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;ApplicationContextConfig&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Bean&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@LoadBalanced&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 赋予负载均衡能力
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; RestTemplate &lt;span style=&#34;color:#88c0d0&#34;&gt;getRestTemplate&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; RestTemplate&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Controller 指定负载均衡访问服务地址:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@RestController&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Slf4j&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;OrderController&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;final&lt;/span&gt; String PAYMENT_URL &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://CLOUD-PAYMENT-SERVICE&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Resource&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; RestTemplate restTemplate&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@GetMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/consumer/payment/create&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; CommonResult&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Integer&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;create&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@RequestParam&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;serial&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; String serial&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        Payment payment &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; Payment&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;0L&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; serial&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        log&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;info&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;serial: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; serial&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; restTemplate&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;postForObject&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;PAYMENT_URL &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/payment/create&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; payment&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; CommonResult&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@GetMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/consumer/payment/get/{id}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt;  CommonResult&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Payment&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getPayment&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@PathVariable&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; Long id&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; restTemplate&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getForObject&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;PAYMENT_URL &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/payment/get/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; id&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; CommonResult&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Controller 必须是 GetMapping，然后通过 &lt;code&gt;restTemplate.getForObject()&lt;/code&gt;或 &lt;code&gt;restTemplate.postForObject()&lt;/code&gt;发送 get 或 post 请求。&lt;/li&gt;
&lt;li&gt;配置的服务地址前缀为 &lt;code&gt;http://&lt;/code&gt; 加上服务接口对应的 application-name 的全大写形式。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;效果展示&#34;&gt;效果展示&lt;/h4&gt;
&lt;p&gt;访问 http://localhost:7001 或者 &lt;a href=&#34;http://eureka7001.com:7001&#34;&gt;http://eureka7001.com:7001&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/organizing-knowledge-related-to-microservices/image/eureka2.png&#34; loading=&#34;lazy&#34; alt=&#34;eureka2&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;可见所有服务已经成功注册。&lt;/p&gt;
&lt;p&gt;访问 http://localhost/consumer/payment/get/3&lt;/p&gt;
&lt;p&gt;成功返回结果，服务端口动态变换：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;查询成功，访问端口：8001&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;serial&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ajefskldfa&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;查询成功，访问端口：8002&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;serial&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ajefskldfa&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;nacos&#34;&gt;Nacos&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Nacos&lt;/strong&gt; 是阿里巴巴开源的一款动态服务发现、配置管理和服务管理平台，主要用于微服务架构中。Nacos 的名字来源于 &lt;strong&gt;Dynamic Naming and Configuration Service&lt;/strong&gt;，它致力于帮助开发者实现服务的高可用性和动态管理。&lt;/p&gt;
&lt;h4 id=&#34;主要功能&#34;&gt;主要功能&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;服务注册与发现：微服务实例启动时会将自己的地址和元数据注册到 Nacos，注册后，Nacos 会维护服务实例的健康状态；其他服务可以通过 Nacos 查询可用的服务实例列表，支持 &lt;strong&gt;DNS&lt;/strong&gt; 和 &lt;strong&gt;HTTP REST&lt;/strong&gt; 两种服务发现机制。&lt;/li&gt;
&lt;li&gt;配置管理：应用的所有配置可以集中存储在 Nacos 中，简化配置管理，配置可以动态刷新，服务无需重启即可更新配置，支持多环境和多租户。&lt;/li&gt;
&lt;li&gt;动态服务配置：Nacos 可以根据流量动态调整服务的路由策略，结合服务网格实现流量分配与治理。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;基本架构&#34;&gt;基本架构&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;核心组件&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;服务端&lt;/strong&gt;：提供服务注册、发现、配置管理和健康检查等功能。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;客户端&lt;/strong&gt;：微服务通过 Nacos SDK 与服务端交互，实现注册、发现和配置读取。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;工作流程&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务实例启动时，向 Nacos 注册自己的元数据。&lt;/li&gt;
&lt;li&gt;其他服务通过 Nacos 获取服务列表，并根据路由策略调用目标服务。&lt;/li&gt;
&lt;li&gt;配置更新后，Nacos 将变更通知到相关的服务实例。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;实践测试&#34;&gt;实践测试&lt;/h4&gt;
&lt;h5 id=&#34;总体架构&#34;&gt;总体架构&lt;/h5&gt;
&lt;p&gt;在一台 CentOS 主机上部署，版本为 7.9，IP 为 192.168.1.127。&lt;/p&gt;
&lt;p&gt;通过 docker 创建三台 nacos 环境的机器，端口均运行在 8848，分别映射到主机的 8848，8858，8868 端口上，名称（hostname）分别为 nacos-server1，nacos-server2，nacos-server3。&lt;/p&gt;
&lt;p&gt;主机通过 nginx 监听 8080 端口，通过负载均衡将请求转发到三台 nacos 机器上。&lt;/p&gt;
&lt;p&gt;主机作为数据库源，使用 mysql 作为数据库，端口为 3306，三台机器都安装 mysql 环境，端口运行在 3306，映射到主机 3307 端口。&lt;/p&gt;
&lt;h5 id=&#34;服务说明&#34;&gt;服务说明&lt;/h5&gt;
&lt;p&gt;创建一个简单的服务，注册到上述 nacos 环境中，通过在 bootstrap.yaml 中读取 nacos 配置来验证环境是否配置成功。&lt;/p&gt;
&lt;h5 id=&#34;搭建-nacos-环境&#34;&gt;搭建 nacos 环境&lt;/h5&gt;
&lt;p&gt;在 nacos 官网下载 nacos-docker 到主机上，编辑 &lt;code&gt;docker-compose.yaml&lt;/code&gt; 文件。&lt;/p&gt;
&lt;p&gt;根据官网说明，在 nacos2 中需要额外暴露两个端口，分别偏移 8848 这个端口 1000 和 1001。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;services&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;nacos1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;hostname&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos-server-1
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos1
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos/nacos-server:${NACOS_VERSION}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;      - ./cluster-logs/nacos1:/home/nacos/logs
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;      - ./init.d/custom.properties:/home/nacos/init.d/custom.properties
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;8848:8848&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;9848:9848&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 偏移 1000&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;9849:9849&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 偏移 1001&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;9555:9555&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;env_file&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;      - ../env/nacos-hostname.env
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; always
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;      - mysql
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;nacos2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;hostname&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos-server-2
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos/nacos-server:${NACOS_VERSION}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos2
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;      - ./cluster-logs/nacos2:/home/nacos/logs
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;      - ./init.d/custom.properties:/home/nacos/init.d/custom.properties
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;8858:8848&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;9858:9848&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;9859:9849&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;env_file&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;      - ../env/nacos-hostname.env
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; always
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;      - mysql
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;38&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;nacos3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;39&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;hostname&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos-server-3
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;40&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos/nacos-server:${NACOS_VERSION}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;41&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos3
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;42&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;43&lt;/span&gt;      - ./cluster-logs/nacos3:/home/nacos/logs
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;44&lt;/span&gt;      - ./init.d/custom.properties:/home/nacos/init.d/custom.properties
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;45&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;46&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;8868:8848&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;47&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;9868:9848&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;48&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;9869:9849&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;49&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;env_file&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;50&lt;/span&gt;      - ../env/nacos-hostname.env
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;51&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;restart&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; always
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;52&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;depends_on&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;53&lt;/span&gt;      - mysql
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;54&lt;/span&gt;      
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;55&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;mysql&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;56&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;container_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; mysql
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;57&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos/nacos-mysql:5.7
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;58&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;env_file&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;59&lt;/span&gt;      - ../env/mysql.env
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;60&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;volumes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;61&lt;/span&gt;      - ./mysql:/var/lib/mysql
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;62&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;ports&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;63&lt;/span&gt;      - &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3307:3306&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;配置数据库信息&#34;&gt;配置数据库信息&lt;/h5&gt;
&lt;p&gt;通过官网提供的 sql 脚本在主机建好数据库。&lt;/p&gt;
&lt;p&gt;接着指定 mysql 数据库源信息，编辑 &lt;code&gt;env/nacos-hostname.env&lt;/code&gt; 文件如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;PREFER_HOST_MODE=hostname # hostname 模式
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;NACOS_SERVERS=nacos-server-1 nacos-server-2 nacos-server-3
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;MYSQL_SERVICE_HOST=192.168.1.127
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;MYSQL_SERVICE_DB_NAME=nacos_config
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;MYSQL_SERVICE_PORT=3306
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;MYSQL_SERVICE_USER=****
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;MYSQL_SERVICE_PASSWORD=******
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意填写好主机的 mysql 账号密码。&lt;/p&gt;
&lt;p&gt;最后指定 docker 中 mysql 信息，编辑 &lt;code&gt;env/mysql.env&lt;/code&gt; 文件即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;MYSQL_ROOT_PASSWORD=******
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;MYSQL_DATABASE=nacos_config
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;MYSQL_USER=****
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;MYSQL_PASSWORD=******
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;运行-docker&#34;&gt;运行 docker&lt;/h5&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;docker-compose up
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;nacos2  &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; 2022-08-07 07:05:41,147 INFO Nacos started successfully in cluster mode. use external storage
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;nacos2  &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;nacos1  &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; 2022-08-07 07:05:41,194 INFO Nacos is starting...
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;nacos1  &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;nacos1  &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; 2022-08-07 07:05:41,240 INFO Nacos started successfully in cluster mode. use external storage
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;nacos1  &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;nacos3  &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; 2022-08-07 07:05:42,097 INFO Nacos is starting...
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;nacos3  &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;nacos3  &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; 2022-08-07 07:05:42,135 INFO Nacos started successfully in cluster mode. use external storage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;搭建-nginx-环境&#34;&gt;搭建 nginx 环境&lt;/h5&gt;
&lt;p&gt;首先安装 nginx，接着编辑 &lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt; 文件如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;...
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;http {
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    ...
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    upstream nacos-servers {
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;            server 192.168.1.127:8848;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;            server 192.168.1.127:8858;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;            server 192.168.1.127:8868;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    }
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    server {
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;            location / {
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;                    proxy_pass http://nacos-servers;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;            }
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;            listen 8080;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    }
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;监听 8080 端口，通过 upstream 转发到三台机器上。&lt;/p&gt;
&lt;p&gt;接着运行 nginx 即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;nginx -c /etc/nginx/nginx.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;创建微服务&#34;&gt;创建微服务&lt;/h5&gt;
&lt;p&gt;依赖导入：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.alibaba.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-alibaba-nacos-config&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.alibaba.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-alibaba-nacos-discovery&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;基本配置。编辑 &lt;code&gt;bootstarp.yaml&lt;/code&gt; 如下：（nacos 的地址即 nginx 配置好的地址 192.168.1.127:8080）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;spring&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;cloud&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;nacos&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;discovery&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;server-addr&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;192.168.1.127&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;8080&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;config&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;server-addr&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;192.168.1.127&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;8080&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;file-extension&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; yaml
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;profiles&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;active&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; prod
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos-config-client
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;server&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;port&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;9669&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;编写服务&#34;&gt;编写服务&lt;/h5&gt;
&lt;p&gt;启动类开启 &lt;code&gt;@EnableDiscoveryClient&lt;/code&gt; 注解，然后编写接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@RefreshScope&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@RestController&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Slf4j&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;ConfigController&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Value&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;${config.version}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; String version&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@GetMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/v&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;getVersion&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; version&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;完成测试&#34;&gt;完成测试&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;访问 192.168.1.127:8080，成功访问并登录；&lt;/li&gt;
&lt;li&gt;查看集群管理的节点列表，三个前缀名为 nacos-server 的节点都处在 UP 状态；&lt;/li&gt;
&lt;li&gt;编写 &lt;code&gt;nacos-config-client-prod.yaml&lt;/code&gt; 文件，为微服务名+环境的格式，新增变量 &lt;code&gt;config.version&lt;/code&gt; 为 1.0；&lt;/li&gt;
&lt;li&gt;开启微服务，再查看服务列表，名为 nacos-config-client 的服务已经成功注册，访问接口 /v，返回 1.0；&lt;/li&gt;
&lt;li&gt;修改配置，version 改为 2.0，再次访问 /v 接口，返回 2.0。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;api-网关&#34;&gt;API 网关&lt;/h2&gt;
&lt;h3 id=&#34;网关的作用&#34;&gt;网关的作用&lt;/h3&gt;
&lt;p&gt;如图所示，网关介于外部请求和具体微服务之间，在不暴露内部微服务端口的情况下，通过一个或者多个指定的网关端口统一地处理外部各种请求。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/organizing-knowledge-related-to-microservices/image/gateway-1.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;springcloud-gateway-实践&#34;&gt;SpringCloud Gateway 实践&lt;/h3&gt;
&lt;h4 id=&#34;依赖引入&#34;&gt;依赖引入&lt;/h4&gt;
&lt;p&gt;除了基本依赖以外，引入下列依赖：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-netflix-eureka-client&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-gateway&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意不能引入 web 相关依赖，因为 Gateway 是基于 WebFlux 的。&lt;/p&gt;
&lt;h4 id=&#34;文件配置&#34;&gt;文件配置&lt;/h4&gt;
&lt;p&gt;列出部分重要配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;server&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;port&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;9669&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cloud&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;gateway&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;discovery&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;locator&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;enabled&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 开启从注册中心动态创建路由的功能，利用微服务名进行路由&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;routes&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        - &lt;span style=&#34;color:#81a1c1&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; path_route
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;uri&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; lb://CLOUD-PAYMENT-SERVICE &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# lb：负载均衡&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;predicates&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;            - Path=/payment/**
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;            - After=2022-07-26T17:33:52.449+08:00[Asia/Shanghai] &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# ZonedDateTime.now()&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;            - Cookie=username,jzh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意点如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;9669 端口作为网关端口；&lt;/li&gt;
&lt;li&gt;uri 中 http 改为了 lb，用于负载均衡；&lt;/li&gt;
&lt;li&gt;predicates，即断言，上述断言为：
&lt;ul&gt;
&lt;li&gt;匹配路径：/payment/**；&lt;/li&gt;
&lt;li&gt;开始允许访问时间：&lt;code&gt;ZonedDateTime.now()&lt;/code&gt;（Java函数获取该格式时间）&lt;/li&gt;
&lt;li&gt;携带cookie：&lt;code&gt;key=username, value=jzh&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;过滤器配置&#34;&gt;过滤器配置&lt;/h4&gt;
&lt;p&gt;实现 GlobalFilter，Ordered，重写方法即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Component&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Slf4j&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;MyGlobalFilter&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; GlobalFilter&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; Ordered &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; Mono&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Void&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;filter&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;ServerWebExchange exchange&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; GatewayFilterChain chain&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        String username &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; exchange&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getRequest&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getQueryParams&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getFirst&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;username &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;            log&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;info&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;username lost&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;            exchange&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getResponse&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setStatusCode&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;HttpStatus&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;NOT_ACCEPTABLE&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; exchange&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getResponse&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;setComplete&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; chain&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;filter&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;exchange&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getOrder&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;定义了 url 中携带必须携带一个 key 为 username 的参数。&lt;/p&gt;
&lt;h4 id=&#34;测试&#34;&gt;测试&lt;/h4&gt;
&lt;p&gt;注意先开启指定的微服务，访问&lt;code&gt;http://localhost:9669/payment/get/11?username=aaa&lt;/code&gt;（同时配好cookie），成功返回结果：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;serial&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;8asd8sa2j&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;},&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;查询成功，访问端口：8001&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再刷新，发现端口动态变化为8002，负载均衡功能也测试成功。&lt;/p&gt;
&lt;h2 id=&#34;分布式配置&#34;&gt;分布式配置&lt;/h2&gt;
&lt;h3 id=&#34;基本概念&#34;&gt;基本概念&lt;/h3&gt;
&lt;p&gt;分布式配置 是一种在分布式系统或微服务架构中，用于集中管理和分发应用配置的机制。它解决了多服务、多节点环境下配置管理的复杂性，确保各服务实例能够动态获取和更新所需的配置数据。&lt;/p&gt;
&lt;p&gt;常用分布式配置工具有 Spring Cloud Config、Consul、以及之前提到的 Nacos。&lt;/p&gt;
&lt;h3 id=&#34;spring-cloud-config&#34;&gt;Spring Cloud Config&lt;/h3&gt;
&lt;p&gt;这里结合 Bus 来实现分布式配置。当全局配置修改时，需要通知各个微服务，一个一个地通知是非常耗时的，如果可以通过广播的方式快速将消息传递出去就轻松多了，而通过 Bus 即可实现这一点。&lt;/p&gt;
&lt;h4 id=&#34;操作方法&#34;&gt;操作方法&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;在 6996 端口通过 git 拉取全局配置，相当于一个 ConfigServer；&lt;/li&gt;
&lt;li&gt;6886 和 6776 端口作为 ConfigClient；&lt;/li&gt;
&lt;li&gt;Bus 结合 RabbitMQ 实现，修改配置时，只通知 ConfigServer，达到消息广播的效果。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;依赖引入-1&#34;&gt;依赖引入&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- ConfigServer 端 --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-bus-amqp&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-config-server&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- ConfigClient 端 --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-bus-amqp&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-config&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;基础配置&#34;&gt;基础配置&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# ConfigServer 端&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# application.yaml&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;spring&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;cloud&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;config&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;server&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;git&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;          &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# github 项目地址&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;          &lt;span style=&#34;color:#81a1c1&#34;&gt;uri&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; https://github.com/akynazh/SpringCloud-Demo.git
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;          &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 指定搜索项目下 config 文件夹中的内容&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;          &lt;span style=&#34;color:#81a1c1&#34;&gt;search-paths&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;            - config
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;          &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 指定分支&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;          &lt;span style=&#34;color:#81a1c1&#34;&gt;default-label&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;rabbitmq&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;host&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; localhost
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;port&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;5672&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;username&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; guest
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;password&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; guest
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;management&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;endpoints&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;web&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;exposure&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 通过 /actuator/bus-refresh 可进行事件通知&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;include&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;bus-refresh&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以后，运维人员修改 config 时，即可通过 &lt;code&gt;http://localhost:6996/actuator/bus-refresh&lt;/code&gt; 发送 POST 请求进行消息通知。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# ConfigClient 端&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# bootstrap.yml | 可以加载全局配置&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;spring&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; cloud-config-client
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;cloud&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;config&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;label&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; master &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 分支&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; config &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 文件名&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;profile&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; dev &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 环境&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;uri&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; http://localhost:6996 &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 全局配置加载地址&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;rabbitmq&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;host&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; localhost
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;port&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;5672&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;username&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; guest
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;password&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; guest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;值得注意的地方：&lt;/p&gt;
&lt;p&gt;第一，config 文件名编写需要遵循一定规则，我选择的是 {name}-{profile}.yml 的格式，然后如上配置文件应该填写对应内容。&lt;/p&gt;
&lt;p&gt;第二，application-name 可以用于后续选择性通知，如只想通知 6776，可通过 POST 请求访问如下地址：http://localhost:6996/actuator/bus-refresh/cloud-config-client:6776。&lt;/p&gt;
&lt;h4 id=&#34;编写相关接口&#34;&gt;编写相关接口&lt;/h4&gt;
&lt;p&gt;在 ConfigServer 添加 &lt;code&gt;@EnableConfigServer&lt;/code&gt; 注解，在 ConfigClient 端编写接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@RestController&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Slf4j&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;MyController&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Resource&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; Environment env&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Value&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;${server.port}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    String port&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@GetMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/v&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;getVersion&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;port: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; port &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;\t &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; env&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getProperty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;config.version&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;测试-1&#34;&gt;测试&lt;/h4&gt;
&lt;p&gt;启动 RabbitMQ:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;.sbin&lt;span style=&#34;color:#ebcb8b&#34;&gt;\r&lt;/span&gt;abbitmq-service.bat start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;默认启动在 5672 端口。（图形界面在 15672 端口）&lt;/p&gt;
&lt;p&gt;加载配置测试。访问：http://localhost:6996/master/config-dev.yml，会从 github 加载得到：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;config&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;label&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; master
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;profile&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; dev
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;version&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问：http://localhost:6776/v，得到：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;port: 6776 3.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;6886 得到相同结果，证明成功加载全局配置。&lt;/p&gt;
&lt;p&gt;修改配置测试。修改配置 version 为 3.6，提交，发送请求如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;curl -X POST &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://localhost:6996/actuator/bus-refresh&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;发现三个端口 version 均改为 3.6，测试通过。&lt;/p&gt;
&lt;p&gt;修改配置 version 为 3.9，提交，发送请求如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;curl -X POST &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;http://localhost:6996/actuator/bus-refresh/cloud-config-client:6776&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;发现 6996 和 6776 的 version 为 3.9，而 6886 的 version 仍为 3.6，测试通过。&lt;/p&gt;
&lt;h2 id=&#34;服务通信&#34;&gt;服务通信&lt;/h2&gt;
&lt;h3 id=&#34;采用协议&#34;&gt;采用协议&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;HTTP&lt;/li&gt;
&lt;li&gt;RPC&lt;/li&gt;
&lt;li&gt;gRPC&lt;/li&gt;
&lt;li&gt;Dubbo&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;grpc-协议介绍&#34;&gt;gRPC 协议介绍&lt;/h3&gt;
&lt;p&gt;gRPC 是 Google 基于 HTTP/2 以及 protobuf 的开发的协议：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;gRPC 是高性能的，由于是基于 HTTP/2，支持多路复用、头部压缩、低延迟和二进制传输，大幅提高了数据传输效率。&lt;/li&gt;
&lt;li&gt;Protobuf 采用高效的二进制序列化，比 JSON 或 XML 更快且数据更小，Protobuf 一方面选用了 VarInts 对数字进行编码，解决了效率问题；另一方面给每个字段指定一个整数编号，传输的时候只传字段编号，解决了冗余问题。&lt;/li&gt;
&lt;li&gt;使用 Protobuf 定义服务接口，提供强类型约束，减少通信中的解析错误并简化代码生成。&lt;/li&gt;
&lt;li&gt;gRPC 支持全双工通信，支持客户端流式、服务端流式和双向流式通信，适用于需要实时或高频数据传输的场景。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;dubbo-协议介绍&#34;&gt;Dubbo 协议介绍&lt;/h3&gt;
&lt;p&gt;Dubbo 缺省协议采用单一长连接和 NIO 异步通讯，适合于小数据量大并发的服务调用，以及服务消费者机器数远大于服务提供者机器数的情况。dubbo RPC 是 dubbo 体系中最核心的一种高性能、高吞吐量的远程调用方式。&lt;/p&gt;
&lt;h2 id=&#34;负载均衡&#34;&gt;负载均衡&lt;/h2&gt;
&lt;h3 id=&#34;基本思想-1&#34;&gt;基本思想&lt;/h3&gt;
&lt;p&gt;负载均衡（LB），即是对于用户的某个请求，将有多个相同功能的服务点服务该请求，某个服务点挂了，其他服务点还是可以进行服务，这样就实现了系统的高可用。&lt;/p&gt;
&lt;h3 id=&#34;关于集中式-lb-和进程内-lb&#34;&gt;关于集中式 LB 和进程内 LB&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;集中式 LB&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在服务的消费方和提供方之间使用独立的 LB 设施，（软硬件均可，软件如 Nginx，硬件如 F5），由该设施负责把访问请求通过某种策略（可自行指定）转发至服务的提供方。&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;进程内 LB&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;将 LB 逻辑集成到消费方，消费方从服务注册中心获知有哪些地址可用，然后自己再从这些地址中选择出一个合适的服务点进行服务。&lt;/p&gt;
&lt;p&gt;Ribbon 属于进程内 LB，它只是一个类库，集成于消费方进程，消费方通过它获取服务提供方的地址。&lt;/p&gt;
&lt;h3 id=&#34;dubbo&#34;&gt;Dubbo&lt;/h3&gt;
&lt;p&gt;Dubbo 内置了 client-based 负载均衡机制，如下是当前支持的负载均衡算法，结合上文提到的自动服务发现机制，消费端会自动使用 Weighted Random LoadBalance 加权随机负载均衡策略 选址调用。&lt;/p&gt;
&lt;p&gt;如果要调整负载均衡算法，以下是 Dubbo 框架内置的负载均衡策略：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;加权随机：默认算法，默认权重相同&lt;/li&gt;
&lt;li&gt;加权轮询：借鉴于 Nginx 的平滑加权轮询算法，默认权重相同&lt;/li&gt;
&lt;li&gt;最少活跃优先 + 加权随机：背后是能者多劳的思想&lt;/li&gt;
&lt;li&gt;最短响应优先 + 加权随机：更加关注响应速度&lt;/li&gt;
&lt;li&gt;一致性哈希：确定的入参，确定的提供者，适用于有状态请求&lt;/li&gt;
&lt;li&gt;Power of Two Choice：随机选择两个节点后，继续选择“连接数”较小的那个节点&lt;/li&gt;
&lt;li&gt;自适应负载均衡：在 P2C 算法基础上，选择二者中 load 最小的那个节点&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Dubbo 框架的默认策略是 random 加权随机负载均衡。如果要调整策略，只需要设置 loadbalance 相应取值即可。为所有服务调用指定全局配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;dubbo&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;consumer&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;loadbalance&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; roundrobin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;ribbon&#34;&gt;Ribbon&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Ribbon&lt;/strong&gt; 是一个用于微服务架构的 &lt;strong&gt;客户端负载均衡工具&lt;/strong&gt;。它的核心功能是通过客户端侧的负载均衡，帮助微服务在调用其他服务时动态选择最优的实例。&lt;/p&gt;
&lt;h4 id=&#34;具体功能&#34;&gt;具体功能&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;客户端负载均衡&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ribbon 会维护目标服务实例列表，并根据配置的负载均衡策略（如轮询、随机等）在这些实例间分发请求。&lt;/li&gt;
&lt;li&gt;例如，当一个服务需要访问其他服务的多个实例时，Ribbon 会动态决定使用哪一个实例。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;服务发现集成&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ribbon 可以与服务注册中心（如 Eureka）集成，动态获取服务实例列表，无需手动更新配置。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;自定义负载均衡策略&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提供多种内置策略（如轮询、随机、加权轮询等）。&lt;/li&gt;
&lt;li&gt;允许开发者实现自定义策略以满足特定业务需求。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;故障检测与重试&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ribbon 支持健康检查，可在目标服务实例不可用时自动排除。&lt;/li&gt;
&lt;li&gt;提供自动重试功能，增加请求成功的可能性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;基本架构-1&#34;&gt;基本架构&lt;/h4&gt;
&lt;p&gt;Ribbon 是一个完全在客户端运行的负载均衡器。其基本工作流程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;客户端通过 Ribbon 请求目标服务。&lt;/li&gt;
&lt;li&gt;Ribbon 查询服务实例列表（可能来自配置文件，也可能通过 Eureka 动态获取）。&lt;/li&gt;
&lt;li&gt;根据负载均衡策略选择一个实例。&lt;/li&gt;
&lt;li&gt;将请求发送到选定的实例。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;实践测试-1&#34;&gt;实践测试&lt;/h4&gt;
&lt;p&gt;Ribbon 通常与 Spring Cloud 一起使用，在微服务环境中，服务消费者通过 Ribbon 调用服务提供者。&lt;/p&gt;
&lt;p&gt;如果与 Eureka 集成，则导入依赖如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-netflix-eureka-client&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- 已经包含了ribbon --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后开启注解：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Configuration&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;ApplicationContextConfig&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Bean&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@LoadBalanced&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 赋予负载均衡能力
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; RestTemplate &lt;span style=&#34;color:#88c0d0&#34;&gt;getRestTemplate&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; RestTemplate&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;访问相同服务名地址即可。下面来指定 Ribbon 负载均衡规则，所有规则均实现了 IRule 接口，通过查看接口实现类即可知道规则的种类。&lt;/p&gt;
&lt;p&gt;默认是 RoundRobinRule（轮询）这一规则。下面修改为 RandomRule（随机）这一规则，在启动类扫描不到的包下创建规则：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Configuration&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;MyRibbonRule&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Bean&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; IRule &lt;span style=&#34;color:#88c0d0&#34;&gt;myRule&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; RandomRule&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后在启动类指定规则：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@SpringBootApplication&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@EnableEurekaClient&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@RibbonClient&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;name&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;CLOUD-PAYMENT-SERVICE&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; configuration &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; MyRibbonRule&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;OrderMain80&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;String&lt;span style=&#34;color:#81a1c1&#34;&gt;[]&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;        SpringApplication&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;OrderMain80&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; args&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;自己实现负载均衡&#34;&gt;自己实现负载均衡&lt;/h3&gt;
&lt;h4 id=&#34;编写-lb-接口即实现类&#34;&gt;编写 LB 接口即实现类&lt;/h4&gt;
&lt;p&gt;要实现负载均衡，首先应获取得到所有的服务实例 &lt;code&gt;ServiceInstance&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;LoadBalancer&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    ServiceInstance &lt;span style=&#34;color:#88c0d0&#34;&gt;getServiceInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;List&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;ServiceInstance&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; instances&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过自旋锁获取新值，取余 ServiceInstance 个数，得到目标 ServiceInstance 下标。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Component&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;MyLoadBalancer&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; LoadBalancer &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; AtomicInteger aint &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; AtomicInteger&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;0&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;myCAS&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; expect&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; next&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(;;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;            expect &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; aint&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;get&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;            next &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;expect &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;%&lt;/span&gt; Integer&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;MAX_VALUE&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;aint&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;compareAndSet&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;expect&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; next&lt;span style=&#34;color:#81a1c1&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; next&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; ServiceInstance &lt;span style=&#34;color:#88c0d0&#34;&gt;getServiceInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;List&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;ServiceInstance&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; instances&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;instances &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;||&lt;/span&gt; instances&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;size&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;=&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; instances&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;get&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;myCAS&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;%&lt;/span&gt; instances&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;size&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;编写-controller&#34;&gt;编写 Controller&lt;/h4&gt;
&lt;p&gt;注意需要通过获取得到的 ServiceInstance 的 uri 作为访问前缀。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Resource&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; RestTemplate restTemplate&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Resource&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; EurekaDiscoveryClient discoveryClient&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Resource&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; LoadBalancer loadBalancer&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@GetMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/consumer/payment/lb&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;lbTest&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    List&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;ServiceInstance&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; instances &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; discoveryClient&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getInstances&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;CLOUD-PAYMENT-SERVICE&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    ServiceInstance instance &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; loadBalancer&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getServiceInstance&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;instances&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    log&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;info&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;lbtest: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; instance&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getUri&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;toString&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;());&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; restTemplate&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getForObject&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;instance&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getUri&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/payment/lb&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; String&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着访问 &lt;code&gt;/consumer/payment/lb&lt;/code&gt; 接口即可完成负载均衡的测试。&lt;/p&gt;
&lt;h2 id=&#34;容错机制服务熔断&#34;&gt;容错机制：服务熔断&lt;/h2&gt;
&lt;h3 id=&#34;基本思想-2&#34;&gt;基本思想&lt;/h3&gt;
&lt;p&gt;应对微服务雪崩效应的一种链路保护机制，类似保险丝。&lt;/p&gt;
&lt;p&gt;关于雪崩效应：&lt;/p&gt;
&lt;p&gt;微服务之间的数据交互是通过远程调用来完成的。服务 A 调用服务，服务 B 调用服务 C，某一时间链路上对服务 C 的调用响应时间过长或者服务 C 不可用，随着时间的增长，对服务 C 的调用也越来越多，然后服务 C 崩溃了，但是链路调用还在，对服务 B 的调用也在持续增多，然后服务 B 崩溃，随之 A 也崩溃，导致&lt;strong&gt;雪崩效应&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;实现机制&#34;&gt;实现机制&lt;/h3&gt;
&lt;p&gt;当某服务出现不可用或响应超时的情况时，为了防止整个系统出现雪崩，暂时停止对该服务的调用。&lt;/p&gt;
&lt;p&gt;通过 Hystrix 实现服务熔断，Hystrix 会监控微服务间调用的状况，当失败的调用到一定阈值，就会启动熔断机制，断路器打开。而在一段时间之后，断路器会变为半开状态，此时允许部分微服务调用，如果都成功了，即不超过设定好的阈值，那么断路器将恢复为关闭状态。&lt;/p&gt;
&lt;p&gt;如下图所示：（来自&lt;a href=&#34;https://martinfowler.com/bliki/CircuitBreaker.html&#34;&gt;Martin Fowler大神的博客&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/organizing-knowledge-related-to-microservices/image/1.jpg&#34; loading=&#34;lazy&#34; alt=&#34;hystrix&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;hystrix-实践&#34;&gt;Hystrix 实践&lt;/h3&gt;
&lt;p&gt;这里实现一下服务监控和熔断。&lt;/p&gt;
&lt;h4 id=&#34;依赖导入&#34;&gt;依赖导入&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- 服务熔断 --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-netflix-hystrix&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-netflix-eureka-client&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- 服务监控 --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-netflix-hystrix-dashboard&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;基本配置&#34;&gt;基本配置&lt;/h4&gt;
&lt;p&gt;启动类添加 &lt;code&gt;@EnableHystrix&lt;/code&gt; 注解，表示使用熔断器，添加 &lt;code&gt;@EnableHystrixDashboard&lt;/code&gt; 注解，表示使用监控面板。&lt;/p&gt;
&lt;p&gt;在要监控的服务的配置文件中添加：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# hystrix 9001 监控配置&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;management&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;endpoints&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;web&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;exposure&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;include&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; hystrix.stream, info, health
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;方法实现&#34;&gt;方法实现&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// PaymentService.java
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PaymentService&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    String &lt;span style=&#34;color:#88c0d0&#34;&gt;circuitBreaker&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Integer id&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在实现类设置服务熔断的核心配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// （1）启用断路器: 
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@HystrixProperty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;name &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;circuitBreaker.enabled&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// （2）设置请求次数: 
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@HystrixProperty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;name &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;circuitBreaker.requestVolumeThreshold&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// （3）设置时间窗口期: 
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@HystrixProperty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;name &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;circuitBreaker.sleepWindowInMilliseconds&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;10000&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// （4）设置失败率: 
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@HystrixProperty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;name &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;circuitBreaker.errorThresholdPercentage&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;60&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如上设置的值，如果在 10 秒内，失败率达到请求次数（10）的百分之 60，也就是 6 次，就会打开断路器，否则断路器依然关闭。&lt;/p&gt;
&lt;p&gt;断路器打开后，在一定时间之后，断路器变为半开状态，允许部分请求访问，如果这些请求满足要求，不超阈值，则断路器恢复为关闭状态。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Service&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PaymentServiceImpl&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; PaymentService &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@HystrixCommand&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;fallbackMethod &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;circuitBreaker_fallback&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;            commandProperties &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;                    &lt;span style=&#34;color:#d08770&#34;&gt;@HystrixProperty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;name &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;circuitBreaker.enabled&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;),&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;                    &lt;span style=&#34;color:#d08770&#34;&gt;@HystrixProperty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;name &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;circuitBreaker.requestVolumeThreshold&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;),&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;                    &lt;span style=&#34;color:#d08770&#34;&gt;@HystrixProperty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;name &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;circuitBreaker.sleepWindowInMilliseconds&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;10000&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;),&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;                    &lt;span style=&#34;color:#d08770&#34;&gt;@HystrixProperty&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;name &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;circuitBreaker.errorThresholdPercentage&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;60&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;})&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;circuitBreaker&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Integer id&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;id &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; RuntimeException&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;id 不能小于0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        String uuid &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; IdUtil&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;simpleUUID&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; Thread&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;currentThread&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;().&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;getName&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;\t&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;uuid:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; uuid&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;circuitBreaker_fallback&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@PathVariable&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; Integer id&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;id 不能小于0, 请重试~ id: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; id&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着编写接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// PaymentController.java
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@RestController&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Slf4j&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PaymentController&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Resource&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; PaymentService paymentService&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@GetMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/payment/cir/{id}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;paymentCircuitBreaker&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@PathVariable&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; Integer id&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; paymentService&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;circuitBreaker&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;id&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;测试-2&#34;&gt;测试&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;打开：&lt;code&gt;http://{ip}:{port}/hystrix&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;监控：&lt;code&gt;http://{ip}:{port}/actuator/hystrix.stream&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;访问 &lt;code&gt;http://localhost:8001/payment/cir/1&lt;/code&gt;，可以正常访问；&lt;/li&gt;
&lt;li&gt;多次访问&lt;code&gt;http://localhost:8001/payment/cir/-1&lt;/code&gt;, 返回系统繁忙信息，发现断路器开启了：&lt;/li&gt;
&lt;li&gt;此时，再访问&lt;code&gt;http://localhost:8001/payment/cir/1&lt;/code&gt;，发现返回了系统繁忙信息；&lt;/li&gt;
&lt;li&gt;多次访问&lt;code&gt;http://localhost:8001/payment/cir/1&lt;/code&gt;，发现断路器关闭，恢复正常访问。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/organizing-knowledge-related-to-microservices/image/2.jpg&#34; loading=&#34;lazy&#34; alt=&#34;hystrix&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;容错机制服务降级&#34;&gt;容错机制：服务降级&lt;/h2&gt;
&lt;h3 id=&#34;基本思想-3&#34;&gt;基本思想&lt;/h3&gt;
&lt;p&gt;服务降级是指在服务器压力剧增的时候，根据实际业务使用情况以及流量，对一些服务和页面有策略的不处理或者用一种简单的方式进行处理，从而释放服务器资源的资源以保证核心业务的正常高效运行。&lt;/p&gt;
&lt;p&gt;多用于微服务架构中，一般当整个微服务架构整体的负载超出了预设的上限阈值（和服务器的配置性能有关系），或者即将到来的流量预计会超过预设的阈值时。&lt;/p&gt;
&lt;h3 id=&#34;实现机制-1&#34;&gt;实现机制&lt;/h3&gt;
&lt;p&gt;为了预防某些功能出现负荷过载或者响应慢的情况，在其内部暂时舍弃对一些非核心的接口和数据的请求，而直接返回一个提前准备好的 fallback（退路）错误处理信息。&lt;/p&gt;
&lt;p&gt;这样，虽然提供的是一个有损的服务，但却保证了整个系统的稳定性和可用性。&lt;/p&gt;
&lt;h3 id=&#34;hystrix-实践-1&#34;&gt;Hystrix 实践&lt;/h3&gt;
&lt;p&gt;本实践配合了 Feign 实现，利用 Feign 通过接口的方式解耦服务这一特点，通过在实现服务接口的类来编写方法对应的 fallback 方法。&lt;/p&gt;
&lt;h4 id=&#34;依赖导入-1&#34;&gt;依赖导入&lt;/h4&gt;
&lt;p&gt;在消费方实现服务降级，除了基本包导入外，导入以下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-netflix-hystrix&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-openfeign&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-netflix-eureka-server&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;基本配置-1&#34;&gt;基本配置&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yml&#34; data-lang=&#34;yml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 设置feign超时时间（默认为1秒）&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;feign&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;hystrix&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;enabled&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;client&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;config&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;default&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;ConnectTimeOut&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;5000&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;ReadTimeOut&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;5000&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 设置hystrix超时时间（默认为1秒）&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;hystrix&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;default&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;execution&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;isolation&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;thread&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;timeoutInMilliseconds&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其他关于 Feign 的环境配置省略了。&lt;/p&gt;
&lt;h4 id=&#34;方法实现-1&#34;&gt;方法实现&lt;/h4&gt;
&lt;p&gt;在使用了 Feign 的基础上使用 Hystrix 功能，指定 fallback 对应的实现类。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// PaymentService.java
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Service&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@FeignClient&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;CLOUD-HYSTRIX-PAYMENT-SERVICE&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; fallback &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; PaymentHystrixService&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PaymentService&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;   &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;//  ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@GetMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/payment/tt&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    CommonResult&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Object&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;timeoutTest&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// PaymentServiceImpl.java
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Service&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PaymentHystrixService&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; PaymentService &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;   &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;//  ...
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; CommonResult&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Object&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;timeoutTest&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; CommonResult&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&amp;gt;(&lt;/span&gt;500&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着编写接口：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// PaymentController.java
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@RestController&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Slf4j&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PaymentController&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Resource&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; PaymentService paymentService&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;/**
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;    * @description: 访问一个耗时超过3秒的服务
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;    * @author Jiang Zhihang
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;    * @date 2022/7/26 11:16
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;    */&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@GetMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/consumer/payment/tt&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; CommonResult&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;Object&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;timeoutTest&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; paymentService&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;timeoutTest&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;测试-3&#34;&gt;测试&lt;/h4&gt;
&lt;p&gt;一、访问 &lt;code&gt;http://localhost:8001/payment/tt&lt;/code&gt;，由于 hystrix 配置最小超时时间为 2 秒，而访问时间超 3 秒，所以得到如下结果：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;500&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以发现调用了 fallback 方法。&lt;/p&gt;
&lt;p&gt;二、修改 hystrix 超时时间为 4 秒，再次访问得到：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;timeout test&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;得到成功返回的数据。&lt;/p&gt;
&lt;h2 id=&#34;容错机制服务限流&#34;&gt;容错机制：服务限流&lt;/h2&gt;
&lt;h3 id=&#34;实现目标&#34;&gt;实现目标&lt;/h3&gt;
&lt;p&gt;当系统的处理能力不能应对外部请求的突增流量时，为了不让系统奔溃，必须采取限流的措施。限流目标：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;防止被突发流量冲垮&lt;/li&gt;
&lt;li&gt;防止恶意请求和攻击&lt;/li&gt;
&lt;li&gt;保证集群服务中心的健康稳定运行（流量整形）&lt;/li&gt;
&lt;li&gt;API 经济的细粒度资源量（请求量）控制&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;限流算法&#34;&gt;限流算法&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;计数限流算法&lt;/li&gt;
&lt;li&gt;固定窗口限流算法（采样时间窗）&lt;/li&gt;
&lt;li&gt;滑动窗口限流（记录每个请求到达的时间点）&lt;/li&gt;
&lt;li&gt;漏桶算法（定速流出）：宽进严出，按照固定速率处理&lt;/li&gt;
&lt;li&gt;令牌桶算法（定速流入）：每个请求分配一个令牌，只有拿到了令牌才能进入服务器处理&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;容错机制sentinel&#34;&gt;容错机制：Sentinel&lt;/h2&gt;
&lt;p&gt;通过 Sentinel 同时完成实现服务熔断、降级和限流。&lt;/p&gt;
&lt;h3 id=&#34;基本概念-1&#34;&gt;基本概念&lt;/h3&gt;
&lt;p&gt;Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件，主要以流量为切入点，从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。&lt;/p&gt;
&lt;h3 id=&#34;架构说明&#34;&gt;架构说明&lt;/h3&gt;
&lt;p&gt;两个生产者服务运行在 9001 和 9002 端口，一个消费者服务运行在 80 端口，均注册到 nacos，消费者调用两个生产者的服务。&lt;/p&gt;
&lt;p&gt;将消费者服务注册到 sentinel 中，通过修改一些规则进行测试：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;controller 下的方法指定好处理服务限流，降级或熔断等的方法 blockHandler，以及处理未知异常的 fallback 方法，通过指定 class 的方法避免代码膨胀。&lt;/li&gt;
&lt;li&gt;service 下的方法指定好关于生产者的服务限流，降级或熔断等的处理方法。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;代码实现生产者端&#34;&gt;代码实现（生产者端）&lt;/h3&gt;
&lt;h4 id=&#34;基本配置-2&#34;&gt;基本配置&lt;/h4&gt;
&lt;p&gt;关于 nacos 的配置省略，只记录 sentinel 的配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;spring&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos-payment-provider
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;cloud&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;sentinel&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;transport&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;dashboard&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; localhost:8080
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;port&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;8179&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;方法实现-2&#34;&gt;方法实现&lt;/h4&gt;
&lt;p&gt;返回对应端口，方便测试负载均衡：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@RestController&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Slf4j&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PaymentController&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Value&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;${server.port}&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;private&lt;/span&gt; String port&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@GetMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/payment/nacos/info&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;paymentInfo&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;port: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; port&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;代码实现消费者端&#34;&gt;代码实现（消费者端）&lt;/h3&gt;
&lt;h4 id=&#34;依赖导入-2&#34;&gt;依赖导入&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.alibaba.cloud&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-alibaba-sentinel&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;基本配置-3&#34;&gt;基本配置&lt;/h4&gt;
&lt;p&gt;注意要开启 feign 的 sentinel 支持：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;spring&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; nacos-order-consumer
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;sentinel&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;transport&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;dashboard&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; localhost:8080
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;port&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;8179&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;feign&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;sentinel&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;enabled&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;方法实现-3&#34;&gt;方法实现&lt;/h4&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@FeignClient&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;nacos-payment-provider&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; fallback &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; PaymentFallbackService&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Service&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PaymentService&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@GetMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/payment/nacos/info&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    String &lt;span style=&#34;color:#88c0d0&#34;&gt;paymentInfo&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对应实现类：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Service&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;PaymentFallbackService&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;implements&lt;/span&gt; PaymentService&lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Override&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;paymentInfo&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;feign::fallback&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里处理关于生产者的服务限流，降级或熔断问题。&lt;/p&gt;
&lt;p&gt;两个服务问题 Hanlder 的编写。根据官方文档，这里的方法都需指明为 static，否者无法识别：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Component&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;GlobalBlockHandler&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;block1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;BlockException e&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;block1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;block2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;BlockException e&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;block2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个用于消费者端处理服务限流，降级或熔断等问题。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Component&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;GlobalFallbackHandler&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;fallback1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;fallback1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;static&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;fallback2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;fallback2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个用于消费者端处理未知异常。&lt;/p&gt;
&lt;p&gt;最后编写 controller，指定处理方式：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@RestController&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#d08770&#34;&gt;@Slf4j&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;OrderController&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@Resource&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    PaymentService paymentService&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@GetMapping&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/consumer/payment/nacos/info&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#d08770&#34;&gt;@SentinelResource&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;            value &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;paymentInfo&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;            fallbackClass &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; GlobalFallbackHandler&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; fallback &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;fallback1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;            blockHandlerClass &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; GlobalBlockHandler&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;,&lt;/span&gt; blockHandler &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;block1&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#88c0d0&#34;&gt;paymentInfo&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; 1 &lt;span style=&#34;color:#81a1c1&#34;&gt;/&lt;/span&gt; 0&lt;span style=&#34;color:#81a1c1&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; paymentService&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;paymentInfo&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;();&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;指定好 class 的同时，需用 fallback 和 blockHandler 分别指定好具体的方法名。&lt;/p&gt;
&lt;h3 id=&#34;测试-4&#34;&gt;测试&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;测试除 0 错误是否正确进入 fallback1：直接访问接口，返回 “fallback1”，正确；&lt;/li&gt;
&lt;li&gt;测试消费者端服务限流：sentinel 指定流控规则，QPS 设置阈值为 1，连续访问接口，返回 “block1”，正确；&lt;/li&gt;
&lt;li&gt;测试生产者端除 0 错误是否正确进入 fallback：给生产者 controller 添加除 0 错误，访问接口，返回 “feign::fallback”，正确；&lt;/li&gt;
&lt;li&gt;测试其他服务规则：指定熔断规则，熔断策略选为慢调用比例，最大 RT（Round Trip Time，也叫响应时间）设置为 200ms，比例阈值设置为 0.5，最小请求数设置为 5。为模拟慢调用，手动增大发出接口请求到收到结果的延迟，在 controller 中添加 &lt;code&gt;Thread.sleep(1000)&lt;/code&gt;，延迟 1 秒：连续访问接口，首先返回了“9001”，即访问正常时得到的结果，然而发现在 5 次以上的请求以后，返回了 “block1”，成功熔断。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://chatgpt.com&#34;&gt;ChatGPT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://juejin.cn/post/7000152990501847048&#34;&gt;微服务 —— 常见的5种限流方案&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://dubbo.apache.org/zh-cn/overview/mannual/java-sdk/tasks/&#34;&gt;Dubbo 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cnblogs.com/wzh2010/p/13588833.html&#34;&gt;系统服务熔断、限流&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
    
      
      <item>
        <title>数据库重要知识整理</title>
        <link>https://zhihang.org/posts/knowledge-collation-of-database-system/</link>
        <pubDate>Wed, 22 Feb 2023 22:35:25 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>knowledge-collation-of-database-system</guid>
        <description>&lt;h2 id=&#34;toc&#34;&gt;TOC&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#toc&#34;&gt;TOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%B3%E7%B3%BB%E6%95%B0%E6%8D%AE%E5%BA%93%E7%90%86%E8%AE%BA&#34;&gt;关系数据库理论&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%B3%E7%B3%BB%E8%AF%AD%E8%A8%80%E7%9A%84%E7%A7%8D%E7%B1%BB&#34;&gt;关系语言的种类&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%B3%E7%B3%BB%E7%9A%84%E5%AE%9A%E4%B9%89&#34;&gt;关系的定义&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%B3%E7%B3%BB%E8%BF%90%E7%AE%97&#34;&gt;关系运算&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%B3%E7%B3%BB%E6%BC%94%E7%AE%97&#34;&gt;关系演算&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%83%E7%BB%84%E6%BC%94%E7%AE%97%E4%BE%8B%E5%AD%90&#34;&gt;元组演算例子&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%9F%E6%BC%94%E7%AE%97%E4%BE%8B%E5%AD%90&#34;&gt;域演算例子&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%8C%83%E5%BC%8F&#34;&gt;范式&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%AC%AC%E4%B8%80%E8%8C%83%E5%BC%8F1nf&#34;&gt;第一范式（1NF）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%AC%AC%E4%BA%8C%E8%8C%83%E5%BC%8F2nf&#34;&gt;第二范式（2NF）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%AC%AC%E4%B8%89%E8%8C%83%E5%BC%8F3nf&#34;&gt;第三范式（3NF）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%B7%B4%E6%96%AF-%E7%A7%91%E5%BE%B7%E8%8C%83%E5%BC%8Fbcnf&#34;&gt;巴斯-科德范式（BCNF）&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E5%BA%93%E6%8E%88%E6%9D%83&#34;&gt;数据库授权&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AD%98%E5%82%A8%E8%BF%87%E7%A8%8B%E5%8F%8A%E8%A7%A6%E5%8F%91%E5%99%A8&#34;&gt;存储过程及触发器&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AD%98%E5%82%A8%E8%BF%87%E7%A8%8B&#34;&gt;存储过程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%A6%E5%8F%91%E5%99%A8&#34;&gt;触发器&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BA%8B%E5%8A%A1&#34;&gt;数据库事务&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#acid-%E7%89%B9%E6%80%A7&#34;&gt;ACID 特性&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%B9%B6%E5%8F%91%E5%AF%BC%E8%87%B4%E7%9A%84%E9%97%AE%E9%A2%98&#34;&gt;并发导致的问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9B%9B%E4%B8%AA%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB&#34;&gt;四个隔离级别&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mvcc-%E5%A4%9A%E7%89%88%E6%9C%AC%E5%B9%B6%E5%8F%91%E6%8E%A7%E5%88%B6&#34;&gt;MVCC 多版本并发控制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#2pl-%E4%B8%A4%E9%98%B6%E6%AE%B5%E9%94%81&#34;&gt;2PL 两阶段锁&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%97%B4%E9%9A%99%E9%94%81&#34;&gt;间隙锁&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%AD%BB%E9%94%81&#34;&gt;死锁&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AE%BE%E8%AE%A1&#34;&gt;数据库设计&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%9C%80%E6%B1%82%E5%88%86%E6%9E%90&#34;&gt;需求分析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%A6%82%E5%BF%B5%E6%A8%A1%E5%9E%8B%E8%AE%BE%E8%AE%A1&#34;&gt;概念模型设计&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%80%BB%E8%BE%91%E7%BB%93%E6%9E%84%E8%AE%BE%E8%AE%A1&#34;&gt;逻辑结构设计&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E5%BA%93%E6%81%A2%E5%A4%8D%E6%8A%80%E6%9C%AF&#34;&gt;数据库恢复技术&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%85%E9%9A%9C%E7%A7%8D%E7%B1%BB&#34;&gt;故障种类&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E8%BD%AC%E5%82%A8backup&#34;&gt;数据转储（backup）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%99%BB%E8%AE%B0%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6logging&#34;&gt;登记日志文件（logging）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%81%A2%E5%A4%8D%E7%AD%96%E7%95%A5&#34;&gt;恢复策略&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E5%BA%93-sql-%E6%93%8D%E4%BD%9C&#34;&gt;数据库 SQL 操作&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A1%A8%E8%BF%9E%E6%8E%A5&#34;&gt;表连接&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%9F%A5%E8%AF%A2%E6%93%8D%E4%BD%9C&#34;&gt;查询操作&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E5%BA%93%E6%97%A5%E5%BF%97&#34;&gt;数据库日志&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#redolog&#34;&gt;RedoLog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#undolog&#34;&gt;UndoLog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#binlog&#34;&gt;BinLog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#binlog-%E5%92%8C-redolog-%E7%9A%84%E4%B8%80%E8%87%B4%E6%80%A7&#34;&gt;BinLog 和 RedoLog 的一致性&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mysql-%E9%9B%86%E7%BE%A4%E6%96%B9%E6%A1%88&#34;&gt;MySQL 集群方案&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%80%E4%B8%BB%E5%A4%9A%E4%BB%8E%E6%9E%B6%E6%9E%84&#34;&gt;一主多从架构&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6&#34;&gt;异步复制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8D%8A%E5%90%8C%E6%AD%A5%E5%A4%8D%E5%88%B6&#34;&gt;半同步复制&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BB%84%E5%A4%8D%E5%88%B6mgr&#34;&gt;组复制(MGR)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mmm-%E6%9E%B6%E6%9E%84%E5%8F%8C%E4%B8%BB%E5%A4%9A%E4%BB%8E&#34;&gt;MMM 架构(双主多从)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mha-%E6%9E%B6%E6%9E%84%E5%A4%9A%E4%B8%BB%E5%A4%9A%E4%BB%8E&#34;&gt;MHA 架构(多主多从)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B4%A2%E5%BC%95&#34;&gt;数据库索引&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%B4%A2%E5%BC%95%E7%9A%84%E5%88%86%E7%B1%BB&#34;&gt;索引的分类&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%B4%A2%E5%BC%95%E4%B8%8B%E6%8E%A8&#34;&gt;索引下推&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%B4%A2%E5%BC%95%E7%BB%93%E6%9E%84&#34;&gt;索引结构&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#b-%E6%A0%91&#34;&gt;B 树&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#b-%E6%A0%91-1&#34;&gt;B+ 树&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%B7%B3%E8%A1%A8&#34;&gt;跳表&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%B4%A2%E5%BC%95%E5%91%BD%E4%B8%AD%E4%B8%8E%E5%90%A6&#34;&gt;索引命中与否&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%B4%A2%E5%BC%95%E5%A4%B1%E6%95%88%E7%9A%84%E5%9C%BA%E6%99%AF&#34;&gt;索引失效的场景&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8&#34;&gt;分库分表&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reference&#34;&gt;Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;关系数据库理论&#34;&gt;关系数据库理论&lt;/h2&gt;
&lt;p&gt;关系数据库理论为关系数据库的设计和实现提供了理论基础和指导原则。&lt;/p&gt;
&lt;h3 id=&#34;关系语言的种类&#34;&gt;关系语言的种类&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;关系代数&lt;/li&gt;
&lt;li&gt;关系演算（元组演算和域演算）&lt;/li&gt;
&lt;li&gt;SQL&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;关系的定义&#34;&gt;关系的定义&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;候选码 (Candidate Key)：能&lt;strong&gt;唯一标识&lt;/strong&gt;元组的属性(组)。&lt;/li&gt;
&lt;li&gt;主码 (Primary Key)：多个候选码中&lt;strong&gt;选定一个&lt;/strong&gt;作主码。&lt;/li&gt;
&lt;li&gt;主属性 (Prime Attribute)：候选码中的诸属性。&lt;/li&gt;
&lt;li&gt;非主属性 (Non-Key Attribute)：不出现在任何候选码中的属性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;关系运算&#34;&gt;关系运算&lt;/h3&gt;
&lt;p&gt;5 种基本关系代数运算：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;并 ($\cup$)&lt;/li&gt;
&lt;li&gt;差 ($-$)&lt;/li&gt;
&lt;li&gt;投影 ($\pi$): 从某个关系中选择出若干属性列组成新的关系&lt;/li&gt;
&lt;li&gt;选择 ($\sigma$): 在某个关系中选择满足给定条件的诸元组&lt;/li&gt;
&lt;li&gt;笛卡尔积 ($\times$)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其它运算：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;连接 ($\bowtie$): 从两个关系的笛卡尔积中选取属性间满足一定条件的元组&lt;/li&gt;
&lt;li&gt;除 ($\div$): 设关系 R 除以关系 S 的结果为关系 T，则 T 包含所有在 R 但不在 S 中的属性及其值，且 T 的元组与 S 的元组的所有组合都在 R 中&lt;/li&gt;
&lt;li&gt;重命名 ($\rho$): 将某个关系重命名为其它关系名&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;关系演算&#34;&gt;关系演算&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;关系演算&lt;/strong&gt;就是用谓词来描述关系的构成(查询的结果)。按照谓词变元的不同分为元组关系演算和域关系演算，分别简称为元组演算和域演算。&lt;/p&gt;
&lt;h4 id=&#34;元组演算例子&#34;&gt;元组演算例子&lt;/h4&gt;
&lt;p&gt;给出关系模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;S (Sno, Sname, Ssex, Sage, Sdep)&lt;/li&gt;
&lt;li&gt;C (Cno, Cname, Ccredit, Cpno)&lt;/li&gt;
&lt;li&gt;SC (Sno, Cno, Grade)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;查询选修学号为“95002”的学生所选全部课程的学生学号。&lt;/p&gt;
&lt;p&gt;$\{ t|\exists u(SC(u) \land \forall v(SC(v) \land v[&#39;Sno&#39;]=&#39;95002&#39; \rightarrow \exists w(SC(w) \land w[&#39;Sno&#39;]=u[&#39;Sno&#39;] \land w[&#39;Cno&#39;]=v[&#39;Cno&#39;])) \land t[&#39;Sno&#39;]=u[&#39;Sno&#39;]) \}$&lt;/p&gt;
&lt;h4 id=&#34;域演算例子&#34;&gt;域演算例子&lt;/h4&gt;
&lt;p&gt;同上关系模式，查询选修了 C2 课程的学生学号和成绩。&lt;/p&gt;
&lt;p&gt;$\{t_1, t_2 | \exists u_1 \exists u_2 \exists u_3 (SC(u_1, u_2, u_3) \land u_2=&#39;c2&#39; \land t_1=u_1 \land t_2=u_3)\}$&lt;/p&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;p&gt;$\{t_1, t_2 | SC(t_1, &#39;C2&#39;, t_2)\}$&lt;/p&gt;
&lt;h3 id=&#34;范式&#34;&gt;范式&lt;/h3&gt;
&lt;p&gt;数据库范式是用于规范化数据库表结构的规则，旨在减少冗余和提高数据完整性。下面具体介绍这几个范式。&lt;/p&gt;
&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;BCNF: 关系模式 $R \in 3NF$，且对于 R 的每个函数依赖 $X \rightarrow Y (Y \nsubseteq X)$，X 必包含码&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;第一范式1nf&#34;&gt;第一范式（1NF）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：关系模式 R 的所有属性都是不可分的基本数据项。即表中的每个字段都必须是&lt;strong&gt;原子&lt;/strong&gt;的，即每个字段只能包含单一值，不能有重复的行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;目的&lt;/strong&gt;：消除重复组，确保数据的原子性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：如果一个表中有一个字段存储多个电话号码，需要将其拆分成多个独立的记录。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;第二范式2nf&#34;&gt;第二范式（2NF）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：关系模式 $R \in 1NF$，且每一个非主属性都完全函数依赖于 R 的码（而不是部分依赖）。即在满足 1NF 的基础上，表中的每个非主属性必须完全依赖于候选键的整个组成部分，而不是部分依赖。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;目的&lt;/strong&gt;：消除部分依赖，确保所有非主属性&lt;strong&gt;完全依赖于主键&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：如果一个表的主键由两个字段组成，而一个非主属性只依赖于其中一个字段，就需要将其分拆成两个表。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;第三范式3nf&#34;&gt;第三范式（3NF）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：关系模式 $R \in 2NF$，且不存在非主属性对码的传递依赖。即在满足 2NF 的基础上，表中的每个非主属性必须直接依赖于候选键，而不是通过其他非主属性间接依赖（即消除传递依赖）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;目的&lt;/strong&gt;：消除传递依赖，确保非主属性仅依赖于主键。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：如果一个表主键为 AB，AB → C，但存在 A → B 和 B → C 的依赖关系，需要将其分拆成两个表，以消除 B → C 的传递依赖。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&#34;巴斯-科德范式bcnf&#34;&gt;巴斯-科德范式（BCNF）&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：在满足 3NF 的基础上，表中的每个决定因素都必须是候选键。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;目的&lt;/strong&gt;：进一步消除依赖异常，确保所有决定因素都是候选键。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;示例&lt;/strong&gt;：如果一个表中存在非主属性对主属性的依赖关系，需要将其分拆，以确保每个决定因素都是候选键。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;通过遵循这些范式，可以设计出结构良好的数据库，提高数据的完整性和一致性。&lt;/p&gt;
&lt;h2 id=&#34;数据库授权&#34;&gt;数据库授权&lt;/h2&gt;
&lt;p&gt;将数据库中的某些对象的某些操作权限赋予某些用户&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;GRANT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;权限&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;权限&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]...&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ON&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;对象类型&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;对象名&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;TO&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;用户&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;用户&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]...&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WITH&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;GRANT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;OPTION&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;指定了 WITH GRANT OPTION 子句, 获得某种权限的用户还可以把这种权限再授予别的用户。&lt;/p&gt;
&lt;p&gt;一些例子：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;GRANT&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ALL&lt;/span&gt;  PRIVILIGES &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;/* 所有权限 */&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ON&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;TABLE&lt;/span&gt;  Student&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; Course 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;TO&lt;/span&gt;  U2&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; U3
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WITH&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;GRANT&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;OPTION&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;GRANT&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ON&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;TABLE&lt;/span&gt;  SC 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;TO&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;PUBLIC&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;/* 所有用户 */&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;GRANT&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;UPDATE&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;Sno&lt;span style=&#34;color:#eceff4&#34;&gt;),&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ON&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;TABLE&lt;/span&gt;  Student 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;TO&lt;/span&gt;  U4&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从指定用户那里收回对指定对象的指定权限：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;REVOKE&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;权限&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;权限&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]...&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ON&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;对象类型&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;对象名&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;用户&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[,&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;用户&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]...;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;存储过程及触发器&#34;&gt;存储过程及触发器&lt;/h2&gt;
&lt;h3 id=&#34;存储过程&#34;&gt;存储过程&lt;/h3&gt;
&lt;p&gt;存储过程（Stored Procedure） 是一组为了完成特定功能的 SQL 语句集，经编译后存储在服务器端数据库中，用户通过指定存储过程的名字并给定参数（如果该存储过程带有参数）来执行它。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;OR&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ALTER&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; PROC &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;PROCEDURE&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;schema_name&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.]&lt;/span&gt; procedure_name &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;number&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;@&lt;/span&gt;parameter_name &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; type_schema_name&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; data_type &lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;VARYING&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;NULL&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;OUT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;OUTPUT&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;READONLY&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;,...&lt;/span&gt;n &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WITH&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;procedure_option&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;,...&lt;/span&gt;n &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FOR&lt;/span&gt; REPLICATION &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;AS&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;BEGIN&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; sql_statement &lt;span style=&#34;color:#eceff4&#34;&gt;[;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;...&lt;/span&gt;n &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;END&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;procedure_option&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; ENCRYPTION &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; RECOMPILE &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;EXECUTE&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;AS&lt;/span&gt; Clause &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一个例子：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;USE pubs
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;GO&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;exists&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; name  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; sysobjects
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; name &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;titles_sum&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;AND&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;p &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;DROP&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;PROCEDURE&lt;/span&gt; titles_sum
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;GO&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;PROCEDURE&lt;/span&gt; titles_sum &lt;span style=&#34;color:#81a1c1&#34;&gt;@&lt;/span&gt;stor_id &lt;span style=&#34;color:#81a1c1&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;),&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;smallint&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;OUTPUT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;AS&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;  ord_num&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; ord_date&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; payterms&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; title_id&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; qty
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; sales
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt;  stor_id &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;@&lt;/span&gt;stor_id
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;sum&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;qty&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; sales
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt;  stor_id &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;@&lt;/span&gt;stor_id
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;Return&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;GO&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;触发器&#34;&gt;触发器&lt;/h3&gt;
&lt;p&gt;触发器是一种特殊类型的存储过程。它与存储过程的区别：触发器主要是&lt;strong&gt;通过事件进行触发&lt;/strong&gt;而被执行的，而存储过程可以通过存储过程名字被直接调用执行。&lt;/p&gt;
&lt;p&gt;当对某一表进行诸如 UPDATE、 INSERT、DELETE 这些操作时，SQL Server 就会自动执行触发器所定义的 SQL 语句。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;OR&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ALTER&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;TRIGGER&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;schema_name&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;trigger_name&lt;/span&gt;   
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ON&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;table&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;view&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;   
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WITH&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;dml_trigger_option&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;,...&lt;/span&gt;n &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FOR&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;AFTER&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;INSTEAD&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;OF&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;   
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;INSERT&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;UPDATE&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;DELETE&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;   
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WITH&lt;/span&gt; APPEND &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FOR&lt;/span&gt; REPLICATION &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;   
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;AS&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt; sql_statement  &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;,...&lt;/span&gt;n &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;EXTERNAL&lt;/span&gt; NAME &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;method&lt;/span&gt; specifier &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;dml_trigger_option&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; ENCRYPTION &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;EXECUTE&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;AS&lt;/span&gt; Clause &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;method_specifier&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;  
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    assembly_name&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;class_name&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;method_name
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一个例子：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;CREATE&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;TRIGGER&lt;/span&gt;  utitle1 &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ON&lt;/span&gt; titles
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FOR&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;UPDATE&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;AS&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;declare&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;rows&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=@@&lt;/span&gt;rowcount
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;rows&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;     &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;RETURN&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;UPDATE&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;title_id&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;BEGIN&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;@&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;rows&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;BEGIN&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;            raiserror&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;update to primary keys of multiple row is not permitted&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;\\&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;		&lt;span style=&#34;color:#b48ead&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ROLLBACK&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;TRANSACTION&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;RETURN&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;     &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;END&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;     &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;UPDATE&lt;/span&gt;  t &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SET&lt;/span&gt; t&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;title_id&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;i&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;title_id
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;     &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt;  titleauthor  t&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;  inserted  i&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; deleted  d
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;     &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt;   t&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;title_id&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;d&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;title_id
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;END&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;RETURN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;原理解析：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在触发器的执行过程中，系统会自动建立和管理两个逻辑表：插入表（inserted）和删除表（deleted）。&lt;/p&gt;
&lt;p&gt;这两个表与触发器所对应的基本表有着完全相同的结构，但为只读表，驻留于内存之中，直到触发器执行完毕，系统会自动删除。&lt;/p&gt;
&lt;p&gt;这两个表是事务回滚的重要依据。&lt;/p&gt;
&lt;h2 id=&#34;数据库事务&#34;&gt;数据库事务&lt;/h2&gt;
&lt;p&gt;事务 (Transaction) 是用户定义的一个数据库操作序列，这些操作要么全做，要么全不做，是一个不可分割的工作单位。&lt;/p&gt;
&lt;h3 id=&#34;acid-特性&#34;&gt;ACID 特性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;原子性（Atomicity）：事务中包括的诸操作要么都做，要么都不做。&lt;/li&gt;
&lt;li&gt;一致性（Consistency）：事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。&lt;/li&gt;
&lt;li&gt;隔离性（Isolation）：一个事务的执行不能被其他事务干扰，而影响它对数据的正确使用和修改。&lt;/li&gt;
&lt;li&gt;持久性（Durability）：一个事务一旦提交，它对数据库中数据的改变就应该是永久性的，接下来的其他操作或故障不应该对其执行结果有任何影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;并发导致的问题&#34;&gt;并发导致的问题&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;丢失修改：当两个事务并发执行但没有锁的控制，可能导致其中一个事务的处理结果被覆盖&lt;/li&gt;
&lt;li&gt;脏读：某一事务发生回滚，另一事务读到的数据和数据库中的不一致&lt;/li&gt;
&lt;li&gt;不可重复读：某一事务修改了数据，可能导致另一事务中前后读取到的数据不一致&lt;/li&gt;
&lt;li&gt;幻读：某一事务插入或删除了部分记录，另一事务前后读取数据发现记录多或少了&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;四个隔离级别&#34;&gt;四个隔离级别&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;读未提交：允许读到未提交的事务，解决了丢失修改问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一个事务读的时候允许其他事务操作，写的时候其他事务只能读不能写。&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;读已提交：只允许读已提交的事务，再解决了脏读问题。（PostgreSQL 默认隔离级别）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一个事务读的时候允许其他事务操作，写事务的时候禁止其他任何事务。&lt;/p&gt;
&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;可重复读：再解决了不可重复读问题。（MySQL 默认隔离级别）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一个事务读取的时候其他事务不可修改（允许读），写事务的时候禁止其他任何事务。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;串行化：再解决了幻读问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;事务串行化执行，使用表级锁。&lt;/p&gt;
&lt;h3 id=&#34;mvcc-多版本并发控制&#34;&gt;MVCC 多版本并发控制&lt;/h3&gt;
&lt;p&gt;MVCC, Multiversion Concurrency Control, 多版本并发控制，解决读写并发问题。&lt;/p&gt;
&lt;p&gt;没有写的情况下发读-读并发是不会出现问题的，而写-写并发这种情况比较常用的就是通过加锁的方式实现。那么，&lt;strong&gt;读-写并发&lt;/strong&gt;则可以通过 MVCC 的机制解决，它可通过无锁的方案来实现并发控制。&lt;/p&gt;
&lt;p&gt;首先我们需要理解&lt;strong&gt;快照读和当前读&lt;/strong&gt;，普通的 select 语句在加锁的情况下（for update）就是当前读，反之即快照读，而快照即是 UndoLog 中所记录的更新前的数据。当存在多个快照时，要读哪个呢，这时我们需要知道快照的存储方式。&lt;/p&gt;
&lt;p&gt;数据库中的每行记录都存在着隐式字段：&lt;strong&gt;隐藏主键&lt;/strong&gt;，对这条记录做了最新一次修改的事务 ID，以及回滚指针，它指向这条记录的上一个版本，即 UndoLog 中的上一个版本的快照的地址。当发生数据更新时，将会将当前行记录存为一个快照，当有多个快照时，多个快照将会通过回滚指针连成一个链表。&lt;/p&gt;
&lt;p&gt;有了&lt;strong&gt;快照链表&lt;/strong&gt;的概念，我们还需理解 &lt;strong&gt;ReadView&lt;/strong&gt;，数据库通过它来决定快照链表中哪条记录是可见的，即会被某个 select 查出。不同隔离级别下，ReadView 的产生有差异。在读已提交隔离级别下，每一条 SELECT 都重新构建一个 ReadView，可以看到其他已经提交的事务对数据的修改，只要事务产生了，其结果都可见，与事务开始的先后顺序无关，也因此无法解决不可重复读的问题。而在可重复读隔离级别下，由第一条 SELECT 生成 ReadView，以后的 SELECT 将复用该 ReadView，这时只有已完成事务的修改可见，即在事务内部不会出现不一致的问题。&lt;/p&gt;
&lt;p&gt;那么回到 MVCC，InnoDB 中的 MVCC 就是通过 ReadView + Undolog 来实现的。举个例子，当某个时刻只存在两个事务，一个写操作，一个读操作，这时读写均无需加锁，读操作直接根据 Read View 拿到合适的快照，而写操作直接写并且记录快照即可。&lt;/p&gt;
&lt;p&gt;总的来讲，MVCC 是一种&lt;strong&gt;作用于读写并发时的无锁并发控制方案&lt;/strong&gt;，通过 ReadView + Undolog 来实现，读写并发时读操作读 ReadView，写操作写 UndoLog 形成快照链表，此外，MVCC 在 Innodb 中是默认开启的。&lt;/p&gt;
&lt;p&gt;注意，快照读的存在，使得读取数据不需要加锁，提高了读操作的性能，但这也意味着数据有可能是历史版本的，是弱一致的，如果同一事务中后续存在 Update 操作，并且基于本次读出来的数据，那么 Update 写入的数据实际上是错误的。&lt;/p&gt;
&lt;p&gt;对于这类场景，可以通过在业务上使用乐观锁，在每条记录增加一个版本号字段，每次更新前比对，也可以手动加锁（悲观锁），将快照读升级为当前读：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;table&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; id &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;lock&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;share&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;mode&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 加读锁
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;table&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; id &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;update&lt;/span&gt;	&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 加写锁
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于 &lt;code&gt;for update&lt;/code&gt;, 它会锁定行或者表，上的是排他锁，不同情况锁的行会有差异：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当 for update 的字段为索引或者主键的时候，锁住索引或者主键对应的行&lt;/li&gt;
&lt;li&gt;当没有匹配的行，则无锁&lt;/li&gt;
&lt;li&gt;除此之外，则上表锁&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果出现无锁，innodb 将通过间隙锁解决 Insert + Update 并发问题。&lt;/p&gt;
&lt;h3 id=&#34;2pl-两阶段锁&#34;&gt;2PL 两阶段锁&lt;/h3&gt;
&lt;p&gt;2PL 是数据库事务处理时的并发控制方法，以保证可串行化，解决写写并发问题。&lt;/p&gt;
&lt;p&gt;操作数据必须读取当前版本数据的，叫做当前读，包括显式加锁的 SELECT 和隐式加写锁的 INSERT、UPDATE、DELETE。&lt;/p&gt;
&lt;p&gt;在 2PL 的加锁阶段，只允许加锁操作，已有读锁可以加读锁但不能再加写锁，已有写锁则不能再加任何锁，无法获取锁的事务只能阻塞等待，直到持锁事务在解锁阶段（事务提交）释放锁后才能继续竞争锁并执行。&lt;/p&gt;
&lt;h3 id=&#34;间隙锁&#34;&gt;间隙锁&lt;/h3&gt;
&lt;p&gt;事务 A 加行锁 update 某个范围的数据后，事务 B 在这个范围内插入一条记录，这时事务 A 发现多了一条数据，而且没有被自己 update。&lt;/p&gt;
&lt;p&gt;MySQL 的实现中，利用了间隙锁在一定索引区间内加锁，锁住甚至不需要的数据，防止其他事务往其中插入数据，这样行锁+间隙锁组成的 &lt;strong&gt;Next-Key 锁&lt;/strong&gt; 就同时防止别的事务修改、删除和插入，解决了幻读的问题。&lt;/p&gt;
&lt;h3 id=&#34;死锁&#34;&gt;死锁&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;产生原因&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;两个事务持有相反的锁顺序。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;innodb_lock_wait_timeout&lt;/code&gt;&lt;/strong&gt; 设置超时回滚。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;避免大事务，减少锁范围&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;数据库设计&#34;&gt;数据库设计&lt;/h2&gt;
&lt;p&gt;数据库设计是指对于一个给定的应用环境，构造最优的数据库模式，建立数据库及其应用系统，使之能够有效地存储数据，满足各种用户的应用需求（信息要求和处理要求）。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1677306003225.png&#34; loading=&#34;lazy&#34; alt=&#34;1677306003225&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;需求分析&#34;&gt;需求分析&lt;/h3&gt;
&lt;p&gt;需求分析就是通过详细调查现实世界要处理的对象（现实业务），充分了解原系统（手工系统或计算机系统），明确用户的各种需求，并在此基础上确定新系统的功能。需求分析包括两个步骤：需求信息的收集和分析。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需求信息的收集&lt;/strong&gt;又称为系统调查，即了解用户的组织机构设置、主要业务活动和职能，以及对新系统的要求。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需求信息的分析&lt;/strong&gt;就是对收集到的需求信息进行加工整理，以数据流图和数据字典的形式进行描述，作为需求分析阶段的成果，这也是下一步设计的基础。&lt;/p&gt;
&lt;h3 id=&#34;概念模型设计&#34;&gt;概念模型设计&lt;/h3&gt;
&lt;p&gt;概念结构设计就是将现实事物以不依赖于任何数据模型的方式加以描述，目的在于以符号化的形式正确地反映现实事物及事物与事物之间的联系。&lt;/p&gt;
&lt;p&gt;概念结构设计的内容就是建立概念模型。&lt;/p&gt;
&lt;p&gt;这是一个通过 E-R 图构建概念模型的例子：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1677305887153.png&#34; loading=&#34;lazy&#34; alt=&#34;1677305887153&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;E-R 图三要素：实体，属性，联系。&lt;/p&gt;
&lt;h3 id=&#34;逻辑结构设计&#34;&gt;逻辑结构设计&lt;/h3&gt;
&lt;p&gt;逻辑结构设计是对数据在计算机中的组织形式的设计，即依照 DBMS 支持的数据模型，设计用户数据的组织形式(模式设计)。同样，逻辑结构设计也是建立在概念结构设计的基础上，为下一步数据的存储设计(物理设计)作准备。&lt;/p&gt;
&lt;h2 id=&#34;数据库恢复技术&#34;&gt;数据库恢复技术&lt;/h2&gt;
&lt;p&gt;恢复操作的基本原理是&lt;strong&gt;冗余&lt;/strong&gt;，即利用存储在系统其它地方的冗余数据来重建数据库中已被破坏或不正确的那部分数据。&lt;/p&gt;
&lt;h3 id=&#34;故障种类&#34;&gt;故障种类&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;事务故障：某个事务在运行过程中，由于种种原因未运行至正常，终止点就夭折了&lt;/li&gt;
&lt;li&gt;系统故障：整个系统的正常运行突然被破坏，所有正在运行的事务都非正常终止，内存中数据库缓冲区的信息全部丢失，外部存储设备上的数据未受影响&lt;/li&gt;
&lt;li&gt;介质（硬件）故障：存储数据库的设备（如硬盘）发生故障，使存储在其上的数据部分丢失或全部丢失&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;数据转储backup&#34;&gt;数据转储（backup）&lt;/h3&gt;
&lt;p&gt;转储是指 DBA 将整个数据库复制到磁带或另一个磁盘上保存起来的过程。
这些备用的数据文本称为后备副本或后援副本。&lt;/p&gt;
&lt;p&gt;转储操作的分类：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;静态转储：在系统中无运行事务时进行转储，转储开始时数据库处于一致性状态，转储期间不允许对数据库的任何存取、修改活动。&lt;/li&gt;
&lt;li&gt;动态转储：转储操作与用户事务并发进行，转储期间允许对数据库进行存取或修改。&lt;/li&gt;
&lt;li&gt;海量转储：每次转储全部数据库。&lt;/li&gt;
&lt;li&gt;增量转储: 只转储上次转储后更新过的数据。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;登记日志文件logging&#34;&gt;登记日志文件（logging）&lt;/h3&gt;
&lt;p&gt;日志文件（log）是用来记录事务对数据库的更新操作的文件。&lt;/p&gt;
&lt;p&gt;日志文件的格式及内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以记录为单位的日志文件
&lt;ul&gt;
&lt;li&gt;各个事务的开始标记(BEGIN TRANSACTION)&lt;/li&gt;
&lt;li&gt;各个事务的结束标记(COMMIT或ROLLBACK)&lt;/li&gt;
&lt;li&gt;各个事务的所有更新操作&lt;/li&gt;
&lt;li&gt;与事务有关的内部更新操作&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;以数据块为单位的日志文件
&lt;ul&gt;
&lt;li&gt;事务标识&lt;/li&gt;
&lt;li&gt;操作类型（插入、删除或修改）&lt;/li&gt;
&lt;li&gt;操作对象（记录ID、Block NO.）&lt;/li&gt;
&lt;li&gt;更新前数据的旧值（对插入操作而言，此项为空值）&lt;/li&gt;
&lt;li&gt;更新后数据的新值（对删除操作而言, 此项为空值）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;恢复策略&#34;&gt;恢复策略&lt;/h3&gt;
&lt;p&gt;数据恢复就是在发生故障、数据被破坏时，根据后被副本和事务日志文件，将数据库恢复到故障前的正确状态（一致性状态）。&lt;/p&gt;
&lt;p&gt;根据故障各类的不同，有不同的恢复方法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事务故障：由恢复子系统应利用日志文件撤消（UNDO）此事务已对数据库进行的修改。&lt;/li&gt;
&lt;li&gt;系统故障：Undo 故障发生时未完成的事务，Redo 已完成的事务。&lt;/li&gt;
&lt;li&gt;介质故障：重装数据库，使数据库恢复到一致性状态，重做已完成的事务。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;数据库-sql-操作&#34;&gt;数据库 SQL 操作&lt;/h2&gt;
&lt;h3 id=&#34;表连接&#34;&gt;表连接&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ALL&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;DISTINCT&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;目标列表达式&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;目标列表达式&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#bf616a&#34;&gt;…&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;table_source1&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- 不指定则默认使用内连接
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;INNER&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;LEFT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;RIGHT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FULL&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;OUTER&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;JOIN&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;table_source2&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ON&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;search_condition &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;条件表达式&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;[INNER] JOIN 内连接：普通连接操作只输出满足连接条件的元组&lt;/li&gt;
&lt;li&gt;LEFT [OUTER] JOIN 左外连接（⟕）：左表为主体，连接条件右边出现空行&lt;/li&gt;
&lt;li&gt;RIGHT [OUTER] JOIN 右外连接（⟖）：右表为主体，连接条件左边出现空行&lt;/li&gt;
&lt;li&gt;FULL [OUTER] JOIN 左右外连接（全外连接，⟗）：在连接条件的左右两边出现空行&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1735194538488.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;外连接与内连接的区别：普通连接操作只输出满足连接条件的元组，外连接操作以指定表为连接主体，将主体表中不满足连接条件的元组一并输出。&lt;/p&gt;
&lt;p&gt;“左”外连接，即以“左”表为主表。&lt;/p&gt;
&lt;h3 id=&#34;查询操作&#34;&gt;查询操作&lt;/h3&gt;
&lt;p&gt;MySQL 执行一条 SELECT 语句的流程大致如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1731657263350.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;数据库日志&#34;&gt;数据库日志&lt;/h2&gt;
&lt;p&gt;以 MySQL 为例，日志分类如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;错误日志：记录 MySQL 启动、运行和停止时的错误信息&lt;/li&gt;
&lt;li&gt;查询日志：记录所有的 SQL 查询，包括连接和断开连接的信息&lt;/li&gt;
&lt;li&gt;慢查询日志：记录执行时间超过指定阈值的查询，用于性能调优&lt;/li&gt;
&lt;li&gt;事务日志（RedoLog、UndoLog）&lt;/li&gt;
&lt;li&gt;二进制日志（BinLog）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;redolog&#34;&gt;RedoLog&lt;/h3&gt;
&lt;p&gt;RedoLog，即重做日志，是物理日志, 记录内容是“在某个数据页上做了什么修改”, 记录的是&lt;strong&gt;物理数据页面&lt;/strong&gt;修改的信息, 其 RedoLog 是顺序写入 RedoLogFile 物理文件中去的。&lt;/p&gt;
&lt;p&gt;RedoLog 是 InnoDB 存储引擎独有的，它让 MySQL 拥有了崩溃恢复能力：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1693757664121.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;当 &lt;code&gt;innodb_flush_log_at_trx_commit == 1&lt;/code&gt; 时, 会进行主动进行刷盘；当为 0 时不会主动进行刷盘, 如果 MySQL 挂了或宕机可能会有 1 秒数据的丢失；当为 2 时, 只要事务提交成功，RedoLogBuffer 中的内容只写入文件系统缓存, 如果仅仅只是 MySQL 挂了不会有任何数据丢失，但是宕机可能会有 1 秒数据的丢失。&lt;/p&gt;
&lt;h3 id=&#34;undolog&#34;&gt;UndoLog&lt;/h3&gt;
&lt;p&gt;UndoLog，即回滚日志，记录数据修改之前的原始值（即“前镜像”），所有事务进行的修改都会先记录到这个回滚日志中，然后再执行相关的操作。&lt;/p&gt;
&lt;p&gt;我们知道如果想要保证事务的原子性，就需要在异常发生时，对已经执行的操作进行回滚，在 MySQL 中，恢复机制是通过回滚日志实现的。&lt;/p&gt;
&lt;p&gt;如果执行过程中遇到异常的话，我们直接利用回滚日志中的信息将数据回滚到修改之前的样子。并且，回滚日志会先于数据持久化到磁盘上。这样就保证了即使遇到数据库突然宕机等情况，当用户再次启动数据库的时候，数据库还能够通过查询回滚日志来回滚将之前未完成的事务。&lt;/p&gt;
&lt;h3 id=&#34;binlog&#34;&gt;BinLog&lt;/h3&gt;
&lt;p&gt;BinLog 是逻辑日志, 记录内容是语句的原始逻辑, 类似于 &amp;ldquo;给 ID=2 这一行的 c 字段加 1&amp;rdquo;, 属于 MySQL Server 层。不管用什么存储引擎, 只要发生了表数据更新, 都会产生 BinLog 日志。MySQL 数据库的&lt;strong&gt;数据备份、主备、主主、主从模式&lt;/strong&gt; 都离不开 BinLog，需要依靠 BinLog 来同步数据，保证数据一致性。&lt;/p&gt;
&lt;p&gt;BinLog 的写入时机也非常简单，事务执行过程中，先把日志写到 BinLog Cache，事务提交的时候，再把 BinLog Cache 写到 BinLog 文件中。因为一个事务的 BinLog 不能被拆开，无论这个事务多大，也要确保一次性写入，所以系统会给每个线程分配一个块内存作为 BinLog Cache。&lt;/p&gt;
&lt;p&gt;我们可以通过 BinLog_cache_size 参数控制单个线程 BinLog cache 大小，如果存储内容超过了这个参数，就要暂存到磁盘（Swap）。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1693759755436.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;上图的 write，是指把日志写入到文件系统的 page cache，并没有把数据持久化到磁盘，所以速度比较快。上图的 fsync 才是将数据持久化到磁盘的操作。 write 和 fsync 的时机可以由参数 sync_binLog 控制，默认是 1。sync_binLog 为 0 的时候，表示每次提交事务都只 write，由系统自行判断什么时候执行 fsync。虽然性能得到提升，但是机器宕机，page cache 里面的 BinLog 会丢失。为了安全起见，可以设置为 1，表示每次提交事务都会执行 fsync，就如同 RedoLog 日志刷盘流程 一样。&lt;/p&gt;
&lt;p&gt;最后还有一种折中方式，可以设置为N(N&amp;gt;1)，表示每次提交事务都 write，但累积 N 个事务后才 fsync。&lt;/p&gt;
&lt;h3 id=&#34;binlog-和-redolog-的一致性&#34;&gt;BinLog 和 RedoLog 的一致性&lt;/h3&gt;
&lt;p&gt;RedoLog 两阶段提交原理？&lt;/p&gt;
&lt;p&gt;首先需要了解 RedoLog 两阶段提交原理，其实就是把 RedoLog 的写入拆分成了两个步骤：prepare 和 commit。&lt;/p&gt;
&lt;p&gt;SQL 更新语句执行顺序如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先，存储引擎将执行更新好的新数据存到内存中，同时将这个更新操作记录到 RedoLog 里面，此时 RedoLog 处于 prepare 状态。然后告知执行器执行完成了，随时可以提交事务。&lt;/li&gt;
&lt;li&gt;然后执行器生成这个操作的 BinLog，并把 BinLog 写入磁盘。&lt;/li&gt;
&lt;li&gt;最后执行器调用存储引擎的提交事务接口，存储引擎把刚刚写入的 RedoLog 状态改成 commit 状态，更新完成。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;崩溃发生点及其相应造成的结果：&lt;/p&gt;
&lt;p&gt;p1: 如果数据库在写入 RedoLog(prepare) 阶段之后、写入 BinLog 之前，发生了崩溃：&lt;/p&gt;
&lt;p&gt;此时 RedoLog 里面的事务处于 prepare 状态，BinLog 还没写，之后从库进行同步的时候，无法执行这个操作，但是实际上主库已经完成了这个操作，所以为了主备一致，MySQL 崩溃时会在主库上&lt;strong&gt;回滚这个事务&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;p2: 如果数据库在写入 BinLog 之后，RedoLog 状态修改为 commit 前发生崩溃：&lt;/p&gt;
&lt;p&gt;此时 RedoLog 里面的事务仍然是 prepare 状态，BinLog 存在并完整，这样之后就会被从库同步过去，但是实际上主库并没有完成这个操作，所以为了主备一致，即使在这个时刻数据库崩溃了，主库上事务仍然会被&lt;strong&gt;正常提交&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;mysql-集群方案&#34;&gt;MySQL 集群方案&lt;/h2&gt;
&lt;h3 id=&#34;一主多从架构&#34;&gt;一主多从架构&lt;/h3&gt;
&lt;p&gt;在 MySQL 的一主多从架构中，类似于 Redis 的主从架构，一个主节点负责处理所有的写操作，而多个从节点负责读取操作，从而提高数据库的读取性能和可用性。一主多从架构有多种复制模式。&lt;/p&gt;
&lt;h4 id=&#34;异步复制&#34;&gt;异步复制&lt;/h4&gt;
&lt;p&gt;应用发起更新请求，即进行增加、删除、修改数据的操作时，主实例完成操作后会立即响应应用，同时主实例向备实例异步复制数据。因此，在异步数据复制方式下，备实例不可用时不会影响主实例上的操作，而主实例不可用时可能会导致主备实例数据不一致。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1733390429694.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h4 id=&#34;半同步复制&#34;&gt;半同步复制&lt;/h4&gt;
&lt;p&gt;为解决异步同步 Binlog 复制数据会产生主从数据不一致的情况，MySQL 在 5.6 版本中推出半同步复制，在同步数据协议中添加了一个 ACK 同步操作，这样意味主节点在 commit 操作，需要确认&lt;strong&gt;最少一个从节点&lt;/strong&gt;确认接收到并且返回 ACK，只有这样主节点才能正确提交数据。&lt;/p&gt;
&lt;p&gt;应用发起的更新在主实例执行完成后，会将日志同步传输到备实例，备实例收到日志，事务就算完成了提交，不需要等待备实例执行日志内容。当备实例不可用或者主备实例间出现网络异常时，半同步会退化为异步。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1733390492126.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h4 id=&#34;组复制mgr&#34;&gt;组复制(MGR)&lt;/h4&gt;
&lt;p&gt;组复制基于分布式一致性协议（Paxos），事务在主节点提交之前，会将事务的数据发送到各个备节点上(而不是先写入 Binlog)，确保超过半数备节点收到事务的数据后，事务才能在主节点提交。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1733390717713.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;组复制支持单主和多主两种部署模式。&lt;/p&gt;
&lt;h3 id=&#34;mmm-架构双主多从&#34;&gt;MMM 架构(双主多从)&lt;/h3&gt;
&lt;p&gt;两主多从架构，还是基于主从复制，增加了 master 备用机制。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1733390278415.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;mha-架构多主多从&#34;&gt;MHA 架构(多主多从)&lt;/h3&gt;
&lt;p&gt;MHA 基于标准的主从复制提供了故障转换功能。MHA 节点分为管理节点和数据节点。管理节点会定时探测集群中的 master 节点，当 master 节点出现故障时，它可以自动将拥有最新数据的 slave 节点提升为新的 master 节点。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1733391122846.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;数据库索引&#34;&gt;数据库索引&lt;/h2&gt;
&lt;h3 id=&#34;索引的分类&#34;&gt;索引的分类&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;聚集索引：又称&lt;strong&gt;主键索引&lt;/strong&gt;，主键索引的叶子节点存的是&lt;strong&gt;整行数据&lt;/strong&gt;，根据主键查询可以直接查询出记录；&lt;/li&gt;
&lt;li&gt;非聚集索引：又称&lt;strong&gt;普通索引&lt;/strong&gt;，叶子节点内容是索引字段值和对应主键的值，如果需要查询的字段全部命中则无需回表（即&lt;strong&gt;覆盖索引&lt;/strong&gt;），否则需要根据主键进行回表获取目标字段；&lt;/li&gt;
&lt;li&gt;唯一索引：相比于普通索引增加了唯一性约束，更新操作会先判断是否违反唯一性约束，查找操作取到第一个满足条件的值就会停止；&lt;/li&gt;
&lt;li&gt;联合索引：相比于普通索引，区别是联合索引由多个字段组成。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;索引下推&#34;&gt;索引下推&lt;/h3&gt;
&lt;p&gt;以联合索引（name, age）为例。如果现在有一个需求：检索出表中“名字第一个字是张，而且年龄是 10 岁的所有男孩”。那么，SQL 语句是这么写的：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;mysql&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;select&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;from&lt;/span&gt; tuser &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;where&lt;/span&gt; name &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;like&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;张%&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;and&lt;/span&gt; age&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;and&lt;/span&gt; ismale&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;根据前缀索引规则，所以这个语句在搜索索引树的时候，只能用 &amp;ldquo;张%&amp;quot;，age 索引失效，只能找到符合 &amp;ldquo;张%&amp;rdquo; 的列，在 MySQL5.6 之前，会逐个根据主键回表，找到符合 &lt;code&gt;age=10 and ismale=1&lt;/code&gt; 的数据。&lt;/p&gt;
&lt;p&gt;而 MySQL 5.6 引入的索引下推优化 (index condition pushdown)，可以在索引遍历过程中，对索引中包含的字段先做判断，直接过滤掉不满足条件的记录，减少回表次数，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1693302216828.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h3 id=&#34;索引结构&#34;&gt;索引结构&lt;/h3&gt;
&lt;h4 id=&#34;b-树&#34;&gt;B 树&lt;/h4&gt;
&lt;p&gt;B 树的出现是为了弥合不同的存储级别之间的访问速度上的巨大差异，实现高效的 I/O。&lt;/p&gt;
&lt;p&gt;平衡二叉树的查找效率是非常高的，并可以通过降低树的深度来提高查找的效率。但是当数据量非常大，树的存储的元素数量是有限的，这样会导致二叉查找树结构由于树的深度过大而造成磁盘 I/O 读写过于频繁，进而导致查询效率低下。另外数据量过大会导致内存空间不够容纳平衡二叉树所有结点的情况。B 树是解决这个问题的很好的结构。&lt;/p&gt;
&lt;p&gt;B 树是一种自平衡树数据结构，B 即 Balance。B 树是二叉搜索树的一般化，因为节点可以有两个以上的子节点。B 树非常适合读取和写入相对较大的数据块（如光盘）的存储系统，通常用于数据库和文件系统。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/knowledge-collation-of-database-system/image/1731558378264.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;B 树的每个节点的元素可以视为一次 I/O 读取，树的高度表示最多的 I/O 次数，在相同数量的总元素个数下，每个节点的元素个数越多，高度越低，查询所需的 I/O 次数越少。这也是 B 树相比于 B+ 树的一个缺点，因为 B 树不管叶子节点还是非叶子节点，都会保存数据，这样导致在非叶子节点中能保存的指针数量变少（有些资料也称为扇出），指针少的情况下要保存大量数据，只能增加树的高度，导致 IO 操作变多，查询性能变低。&lt;/p&gt;
&lt;h4 id=&#34;b-树-1&#34;&gt;B+ 树&lt;/h4&gt;
&lt;p&gt;B+ 树是应文件系统所需而产生的 B 树的变形树。B+ 树相比于 B树的差异及优缺点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;B+ 树的磁盘读写代价更低，内部节点只存索引，更小，但单点查询不如 B 树&lt;/li&gt;
&lt;li&gt;B+ 树查询效率稳定，树高即是路径长度&lt;/li&gt;
&lt;li&gt;B+ 树便于范围查询，叶子通过双向循环链表连成，在链表上遍历即可&lt;/li&gt;
&lt;li&gt;B+ 树便于插入和删除，冗余节点的存在使得不会出现复杂的树结构变化&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;MySQL 的不同数据存储引擎所构造的索引 B+ 树有所不同：&lt;/p&gt;
&lt;p&gt;对于 InnoDB 引擎，每一个表会存在一棵叶子节点存储所有数据的索引树，这个树一般是主键索引构造的，但如果没有主键，那么会选择一个唯一键作为主键，如果没有唯一键，那么会生成一个 6 位的 row_id 来作为隐式主键。除了这棵树，其他索引字段所构建的索引树，叶子节点只存储主键索引和索引列的值，如果是覆盖索引则无需回表，否则需要通过主键索引再搜一遍主索引树，拿到目标数据。&lt;/p&gt;
&lt;p&gt;对于 MyISAM 引擎，任何索引树的叶子节点都是存的数据的地址，需要根据这个地址去数据文件拿到数据，也就是都是二级索引。注意 InnoDB 的数据文件本身就是索引文件，而 MyISAM 索引文件和数据文件是分离的，索引文件仅保存数据记录的地址。&lt;/p&gt;
&lt;p&gt;对于树高和记录数：&lt;/p&gt;
&lt;p&gt;在 MySQL 中 InnoDB 存储引擎的最小存储单元是页（大小默认是 16k，可通过参数设置）。页可用于存放 B+ 树叶节点数据，也可用于存放 B+ 树非叶节点的 &amp;ldquo;键+指针&amp;rdquo;。在查找数据时一次页的查找代表一次 IO，一般 B+ 树高大约为 1-3 层，所以通过主键索引查询通常只需要 1-3 次 IO 操作即可查找到数据。&lt;/p&gt;
&lt;p&gt;索引组织表通过非叶节点的二分查找法以及指针确定数据在下一层的哪个页中，进而再去叶节点的数据页中查找到所需数据。一个非叶节点可容纳约 1170 个指针。假设一行记录数据大小为 1k，那么底层叶节点一页 16k 就能存 16 条记录。所以：&lt;/p&gt;
&lt;p&gt;在 2 层 B+ 树中，叶节点数 * 一个叶节点能存放的记录数 = 1170 * 16 = 18720 条记录数。&lt;/p&gt;
&lt;p&gt;在 3 层 B+ 树中，叶节点数 * 叶节点数 * 一个叶节点能存放的记录数 = 1170 * 1170 * 16 = 21902400，2190w 条记录数。&lt;/p&gt;
&lt;h4 id=&#34;跳表&#34;&gt;跳表&lt;/h4&gt;
&lt;p&gt;跳表时间复杂度和 B+ 树差不多，为什么一般采用 B+ 树不采用跳表？&lt;/p&gt;
&lt;p&gt;B+ 树是多叉平衡搜索树，扇出高，只需要 3 层左右就能存放 2kw 左右的数据，同样情况下跳表则需要 24 层左右，假设层高对应磁盘 IO，那么 B+ 树的读性能会比跳表要好。&lt;/p&gt;
&lt;p&gt;而对于 Redis，它读写全在内存里进行操作，不涉及磁盘 IO，同时跳表实现简单，相比 B+ 树、AVL 树、少了旋转树结构的开销，因此 redis 使用跳表来实现 ZSET，而不是树结构。&lt;/p&gt;
&lt;h3 id=&#34;索引命中与否&#34;&gt;索引命中与否&lt;/h3&gt;
&lt;p&gt;例如有表 t(a,b,c), 建立了联合索引 (a,b)，有 sql 语句如下:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;select&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;from&lt;/span&gt; t &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;where&lt;/span&gt; b &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这时候是用不了联合索引 (a,b) 的，因为 (a,b) 规定 b 有序的前提是 a 有序，如果 a 不能确定，那 b 在 b+ 树里肯定是无序的，所以无法使用索引 (a,b)。&lt;/p&gt;
&lt;p&gt;如果 sql 为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;select&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;from&lt;/span&gt; t &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;where&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;and&lt;/span&gt; b &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如何建立索引?&lt;/p&gt;
&lt;p&gt;此题正确答法是，建立联合索引 (a,b,c) 或 (c,b,a) 或者 (b,a,c) 都可以，重点要的是将区分度高的字段孜在前面，区分度低的字段放后面。&lt;/p&gt;
&lt;p&gt;例如假设区分度由大到小为 b,a,c。那么我们就对 (b,a,c) 建立索引。在执行 sql 的时候，优化器会帮我们调整 where 后 a,b,c 的顺序，让我们用上索引。&lt;/p&gt;
&lt;h3 id=&#34;索引失效的场景&#34;&gt;索引失效的场景&lt;/h3&gt;
&lt;p&gt;数据库索引可能会失效（即查询无法利用索引，而是进行全表扫描 FULL TABLE SCAN），常见的失效场景包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 LIKE 模糊匹配且模式以通配符 % 开头&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; users &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; name &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;LIKE&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;%abc&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;% 开头会导致索引失效，因为数据库无法使用 B+ 树索引进行范围查找。&lt;/li&gt;
&lt;li&gt;解决方案：避免 % 开头，可以使用 FULLTEXT 索引（如 MySQL 的 FULLTEXT 索引）。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;计算、函数或类型转换导致索引列失效&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; orders &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;YEAR&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;order_date&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2023&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;YEAR(order_date) 使索引列 order_date 需要逐行计算，导致索引无法被利用。&lt;/li&gt;
&lt;li&gt;解决方案：转换查询逻辑，避免对索引列进行计算：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; orders &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; order_date &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;2023-01-01&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;AND&lt;/span&gt; order_date &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;2024-01-01&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;OR 连接多个条件，且没有合适的索引&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; products &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; category &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;A&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;OR&lt;/span&gt; price &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;100&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;OR 连接的字段 category 和 price 没有都建立索引，可能会导致索引失效。&lt;/li&gt;
&lt;li&gt;解决方案：为 category 和 price 都建立索引，或使用 UNION ALL 替代 OR：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; products &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; category &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;A&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;UNION&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ALL&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; products &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; price &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;100&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;!=、&amp;lt;&amp;gt;、NOT IN 可能导致索引失效&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; employees &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; department_id &lt;span style=&#34;color:#81a1c1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;!= 或 &amp;lt;&amp;gt; 使索引无法高效过滤数据，数据库通常会进行全表扫描。&lt;/li&gt;
&lt;li&gt;解决方案：使用 BETWEEN 或 IN 进行改写：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; employees &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; department_id &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;OR&lt;/span&gt; department_id &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;5&#34;&gt;
&lt;li&gt;IS NULL 或 IS NOT NULL&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; users &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; last_login &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;IS&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;NULL&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;B+ 树索引通常不会索引 NULL 值，导致索引失效。&lt;/li&gt;
&lt;li&gt;解决方案：
&lt;ul&gt;
&lt;li&gt;在 last_login 列上创建索引时，指定 NOT NULL。&lt;/li&gt;
&lt;li&gt;使用默认值（如 1970-01-01）代替 NULL 并查询时改写：&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; users &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; last_login &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;1970-01-01&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;6&#34;&gt;
&lt;li&gt;ORDER BY 与索引顺序不匹配&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; orders &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;ORDER&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;BY&lt;/span&gt; user_id &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;DESC&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;如果索引 user_id 是 升序（ASC），但查询要求降序（DESC），可能导致索引失效。&lt;/li&gt;
&lt;li&gt;解决方案：如果 ORDER BY 频繁使用 DESC，可以创建降序索引：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CREATE INDEX idx_user_id_desc ON orders(user_id DESC);&lt;/p&gt;
&lt;ol start=&#34;7&#34;&gt;
&lt;li&gt;过度使用索引导致优化器选择全表扫描&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;索引在低基数（重复值多）字段上，如 status 只有 0 和 1 两种值：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;SELECT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;FROM&lt;/span&gt; users &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;WHERE&lt;/span&gt; status &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;由于 status 只有两个值，索引效果不明显，优化器可能选择全表扫描。&lt;/li&gt;
&lt;li&gt;解决方案：索引适用于高基数字段，低基数字段可以通过联合索引优化。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;分库分表&#34;&gt;分库分表&lt;/h2&gt;
&lt;p&gt;拆分方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;水平拆分：把一个表的数据给分到多个库的多个表里去，但是每个库的表结构都一样&lt;/li&gt;
&lt;li&gt;垂直拆分：把一个有很多字段的表给拆分成多个表，或者是多个库上去&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;迁移为分库分表方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;双写迁移：增删改操作同时作用在新库老库上&lt;/li&gt;
&lt;li&gt;停机迁移&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;萨师煊，王珊：《数据库系统概论-第四版》&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/wardseptember/notes/blob/master/docs/B%E6%A0%91%E5%92%8CB+%E6%A0%91%E8%AF%A6%E8%A7%A3.md&#34;&gt;B树和B+树详解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.cnblogs.com/three-fighter/p/15246577.html&#34;&gt;五分钟搞懂MySQL索引下推&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://xiaolincoding.com/mysql/log/how_update.html&#34;&gt;MySQL 日志：undo log、redo log、binlog 有什么用？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://doocs.github.io/advanced-java/#/docs/high-concurrency/database-shard-dynamic-expand&#34;&gt;分库分表&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://help.aliyun.com/zh/rds/apsaradb-rds-for-mysql/change-the-data-replication-method/?spm=a2c4g.11186623.help-menu-26090.d_3_3_9.1e4e45b63uupQH&#34;&gt;阿里云 - 变更数据复制方式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://juejin.cn/post/7156150605067599886&#34;&gt;浅析 MySQL 集群部署方案&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Shell 重要用法整理</title>
        <link>https://zhihang.org/posts/shell-basic-operation-summary/</link>
        <pubDate>Fri, 03 Feb 2023 22:44:10 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>shell-basic-operation-summary</guid>
        <description>&lt;h2 id=&#34;shell-参数&#34;&gt;shell 参数&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$#&lt;/code&gt; 参数个数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$@&lt;/code&gt; / &lt;code&gt;$*&lt;/code&gt; 取出所有参数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$0&lt;/code&gt; 取出命令中第一个字符串&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$1&lt;/code&gt; 取出第一个参数&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$1&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;-u&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; update
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; $0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ans:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&amp;gt; ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;$ ./test.sh
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;./test.sh
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&amp;gt; ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;$ ./test.sh -u
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;update
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;./test.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;$@&lt;/code&gt; 与 &lt;code&gt;$*&lt;/code&gt; 的区别：（from &lt;a href=&#34;https://stackoverflow.com/questions/4341630/checking-for-the-correct-number-of-arguments&#34;&gt;stackoverflow&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$@&lt;/code&gt; behaves like &lt;code&gt;$*&lt;/code&gt; except that when quoted the arguments are broken up properly if there are spaces in them.&lt;/p&gt;
&lt;p&gt;Take this script for example (taken from the linked answer):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; var in &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$@&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$var&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Gives this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;$ sh test.sh &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;3 4&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now change &lt;code&gt;$@&lt;/code&gt; to &lt;code&gt;$*&lt;/code&gt;, And you get this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;$ sh test.sh &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;3 4&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;个人觉得使用 &lt;code&gt;$@&lt;/code&gt; 更为妥当。&lt;/p&gt;
&lt;h2 id=&#34;关于数组&#34;&gt;关于数组&lt;/h2&gt;
&lt;h3 id=&#34;取值&#34;&gt;取值&lt;/h3&gt;
&lt;p&gt;根据下标取值，下标从 0 开始：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;arr&lt;span style=&#34;color:#eceff4&#34;&gt;[0]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;arr&lt;span style=&#34;color:#eceff4&#34;&gt;[1]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;arr&lt;span style=&#34;color:#eceff4&#34;&gt;[2]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;获取所有值：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;arr&lt;span style=&#34;color:#eceff4&#34;&gt;[@]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 常用于：&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;/bin/bash test.sh &lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;arr&lt;span style=&#34;color:#eceff4&#34;&gt;[@]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;获取长度：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${#&lt;/span&gt;args&lt;span style=&#34;color:#eceff4&#34;&gt;[@]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;${#&lt;/span&gt;args&lt;span style=&#34;color:#eceff4&#34;&gt;[@]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt; -eq &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;	&lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;length=0&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;切片&#34;&gt;切片&lt;/h3&gt;
&lt;p&gt;数组切片：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 从 $start 开始到 $end&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;arr&lt;span style=&#34;color:#81a1c1&#34;&gt;=(&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;$(&lt;/span&gt;arr&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;@&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;:$start:$end&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 从 $start 开始到最后，两侧必须加括号&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;arr&lt;span style=&#34;color:#81a1c1&#34;&gt;=(&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;$(&lt;/span&gt;arr&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;@&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;:$start&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一个简单的测试：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;root@Server-Debian-Jzh:~# arr&lt;span style=&#34;color:#81a1c1&#34;&gt;=(&lt;/span&gt;1, 2, 3, 4, 5&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;root@Server-Debian-Jzh:~# &lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;arr&lt;span style=&#34;color:#eceff4&#34;&gt;[@]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;1, 2, 3, 4, &lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;root@Server-Debian-Jzh:~# &lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;arr&lt;span style=&#34;color:#eceff4&#34;&gt;[@]:&lt;/span&gt;1&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;2, 3, 4, &lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;root@Server-Debian-Jzh:~# s&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;1&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;e&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;root@Server-Debian-Jzh:~# &lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;arr&lt;span style=&#34;color:#eceff4&#34;&gt;[@]:&lt;/span&gt;$s&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;$e&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;2, 3,
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 切片后不加括号的后果：&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;root@Server-Debian-Jzh:~# tarr&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;arr&lt;span style=&#34;color:#eceff4&#34;&gt;[@]:&lt;/span&gt;$s&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;$e&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;root@Server-Debian-Jzh:~# &lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;tarr&lt;span style=&#34;color:#eceff4&#34;&gt;[0]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;2, 3,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;-和-数组&#34;&gt;$@ 和 数组&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;$@&lt;/code&gt; 不是真正的数组，如需使用上述取值和切片特性，需将其转换为数组：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;args&lt;span style=&#34;color:#81a1c1&#34;&gt;=(&lt;/span&gt; $@ &lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# convert to array&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;$@&lt;/code&gt; 可以直接嵌入命令中而数组不可以：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;/bin/bash t.sh $val1 $@
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关于 $@ 的数据结构，这是一段 chatgpt 的回答，挺不错的：&lt;/p&gt;
&lt;p&gt;&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;Q: but what i want to know is the data structure of &lt;code&gt;$@&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A: As I mentioned earlier, &lt;code&gt;$@&lt;/code&gt; is a special shell parameter in Bash that holds the positional parameters passed to the script or function. It is not technically an array in Bash, although it behaves like one in many ways.&lt;/p&gt;
&lt;p&gt;Under the hood, &lt;code&gt;$@&lt;/code&gt; is actually a space-separated list of strings, with each string representing an individual positional parameter. When the shell expands &lt;code&gt;$@&lt;/code&gt;, it splits this list into separate words, treating each space as a delimiter.&lt;/p&gt;
&lt;p&gt;So you can think of the data structure of &lt;code&gt;$@&lt;/code&gt; as a simple list or sequence of strings, where each string represents an argument passed to the script or function. While it doesn&amp;rsquo;t have all the advanced functionality of a true array, such as indexed access and manipulation, it is still a very useful and versatile tool in Bash scripting.&lt;/p&gt;
&lt;h2 id=&#34;算术运算&#34;&gt;算术运算&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# a=1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# b=$((a*12))&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# echo $b&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;12&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;比较运算&#34;&gt;比较运算&lt;/h2&gt;
&lt;p&gt;指令：-eq -ne -lt -gt -ge -le&lt;/p&gt;
&lt;p&gt;注：字符串比较直接用 “==” 而不是上述指令。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# a=10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [ $a -eq 10 ] &amp;amp;&amp;amp; echo yes&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;yes
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [ $a -ge 11 ] &amp;amp;&amp;amp; echo yes || echo no&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;no
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;指令：-a -o&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# a=10;b=12;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [ $a -lt 11 -a $b -lt 13 ] &amp;amp;&amp;amp; echo yes || echo no&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;yes
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [ $a -lt 11 -a $b -lt 11 ] &amp;amp;&amp;amp; echo yes || echo no&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;no
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;字符串运算&#34;&gt;字符串运算&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;-z（即 zero）检测字符串长度是否为 0，为 0 返回 true。&lt;/li&gt;
&lt;li&gt;str 检测字符串是否为空，不为空返回 true。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [ -z &amp;#34;jzh&amp;#34; ] &amp;amp;&amp;amp; echo yes || echo no&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;no
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [ &amp;#34;jzh&amp;#34; == &amp;#34;zh&amp;#34; ] &amp;amp;&amp;amp; echo yes || echo no&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;no
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;字符串的引号使用&#34;&gt;字符串的引号使用&lt;/h2&gt;
&lt;p&gt;双引号与单引号效果不一样，如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;root@ubuntu2004:~# &lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$PATH&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;/usr/local/java/jdk1.8.0_311/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:...
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;root@ubuntu2004:~# &lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;$PATH&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;$PATH
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;获取时间&#34;&gt;获取时间&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 输出格式化时间&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# date &amp;#39;+%Y-%m-%d %H:%M:%S&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;2022-04-10 13:22:04
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 输出当前时间戳&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# date +%s&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1649568128&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;条件判断&#34;&gt;条件判断&lt;/h2&gt;
&lt;p&gt;注：中括号两端要有空白符。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos tmp&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [ &amp;#34;a&amp;#34; == &amp;#34;b&amp;#34; ] &amp;amp;&amp;amp; echo hello || echo bye&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;bye
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos tmp&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [ &amp;#34;a&amp;#34; == &amp;#34;a&amp;#34; ] &amp;amp;&amp;amp; echo hello || echo bye&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;hello
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;文件运算&#34;&gt;文件运算&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;-r 即 read&lt;/li&gt;
&lt;li&gt;-w 即 write&lt;/li&gt;
&lt;li&gt;-x 即 exec&lt;/li&gt;
&lt;li&gt;-s 即文件不为空&lt;/li&gt;
&lt;li&gt;-e 即 exist&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# touch t.sh&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [ -s ./t.sh ] &amp;amp;&amp;amp; echo yes || echo no&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;no
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# [ -e ./t.sh ] &amp;amp;&amp;amp; echo yes || echo no&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;yes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;读取输入&#34;&gt;读取输入&lt;/h2&gt;
&lt;p&gt;read -p &amp;ldquo;prompt words&amp;rdquo; var_name&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# read -p &amp;#34;age:&amp;#34; age&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;age:12
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos ~&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# echo $age&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;12&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;read -a variable_name （读取数组）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos tmp&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# read -a arr&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;root@VM-0-11-centos tmp&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# echo ${arr[4]}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;条件判断语句&#34;&gt;条件判断语句&lt;/h2&gt;
&lt;h3 id=&#34;if-else&#34;&gt;if else&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;	do_something
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;elif&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;	do_something
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;	do_something
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;case&#34;&gt;case&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;var&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt; in
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;condition1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;do_something
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;condition2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;do_something
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;*&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;#anything&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;do_something
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;esac&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;循环语句&#34;&gt;循环语句&lt;/h2&gt;
&lt;h3 id=&#34;while&#34;&gt;while&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt; condition &lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;	do_something
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;when meet the condition, start the loop.&lt;/p&gt;
&lt;h3 id=&#34;until&#34;&gt;until&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;until&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt; condition &lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;	do_something
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;when meet the condition, end the loop.&lt;/p&gt;
&lt;h3 id=&#34;for&#34;&gt;for&lt;/h3&gt;
&lt;p&gt;遍历数组：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; $var in &lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;array&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;	do_something
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;遍历指定数字序列：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; $var in &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;1..100&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;	do_something
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;条件遍历：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;i&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;1&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; i&amp;lt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;var&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; i++&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;	do_something
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;sh-命令&#34;&gt;sh 命令&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;-n 不执行，只检查语法 not execute but check&lt;/li&gt;
&lt;li&gt;-v 执行前输出脚本内容 view the script&lt;/li&gt;
&lt;li&gt;-x 将使用到脚本内容输出&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Hugo 实现深浅主题的切换</title>
        <link>https://zhihang.org/posts/hugo-realizes-switching-between-deep-and-shallow-themes/</link>
        <pubDate>Thu, 02 Feb 2023 18:49:54 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>hugo-realizes-switching-between-deep-and-shallow-themes</guid>
        <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;实现深浅主题切换的方法不只一种，这里记录我所使用的一种。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%89%8D%E8%A8%80&#34;&gt;前言&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%94%9F%E6%88%90%E6%B7%B1%E6%B5%85%E4%B8%BB%E9%A2%98%E5%AF%B9%E5%BA%94%E7%9A%84-css-%E6%96%87%E4%BB%B6&#34;&gt;生成深浅主题对应的 css 文件&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%85%8D%E7%BD%AE%E5%85%A5%E5%8F%A3%E6%96%87%E4%BB%B6&#34;&gt;配置入口文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%80%9A%E8%BF%87-hugo-%E7%94%9F%E6%88%90%E7%9B%AE%E6%A0%87%E6%96%87%E4%BB%B6&#34;&gt;通过 hugo 生成目标文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BF%9D%E5%AD%98%E5%9C%B0%E5%9D%80%E5%8F%98%E9%87%8F%E5%88%B0%E9%9A%90%E8%97%8F%E5%9F%9F&#34;&gt;保存地址变量到隐藏域&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%AE%BE%E5%AE%9A%E5%88%9D%E5%A7%8B%E4%B8%BB%E9%A2%98&#34;&gt;设定初始主题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%80%9A%E8%BF%87-js-%E5%8A%A8%E6%80%81%E8%AE%BE%E7%BD%AE%E4%B8%BB%E9%A2%98&#34;&gt;通过 js 动态设置主题&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8A%A0%E8%BD%BD%E4%B8%BB%E9%A2%98&#34;&gt;加载主题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BF%AE%E6%94%B9%E4%B8%BB%E9%A2%98&#34;&gt;修改主题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%B0%86%E8%84%9A%E6%9C%AC%E6%94%BE%E5%9C%A8%E5%90%88%E9%80%82%E7%9A%84%E4%BD%8D%E7%BD%AE&#34;&gt;将脚本放在合适的位置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BB%91%E5%AE%9A%E4%BA%8B%E4%BB%B6%E5%88%B0%E6%8C%89%E9%92%AE&#34;&gt;绑定事件到按钮&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;生成深浅主题对应的-css-文件&#34;&gt;生成深浅主题对应的 css 文件&lt;/h2&gt;
&lt;h3 id=&#34;配置入口文件&#34;&gt;配置入口文件&lt;/h3&gt;
&lt;p&gt;我的博客通过 &lt;a href=&#34;https://github.com/sass/sass&#34;&gt;sass&lt;/a&gt; 构建样式，可以将写好的 scss 文件组合生成一个 css 文件。&lt;/p&gt;
&lt;p&gt;而组合成为 css 文件需要一个入口文件，在入口文件里指定主题。&lt;/p&gt;
&lt;p&gt;比如我在 &lt;code&gt;assets/scss/colors&lt;/code&gt; 中指定了两种色调 &lt;code&gt;dark.scss&lt;/code&gt; 和 &lt;code&gt;light.scss&lt;/code&gt;, 那么可以在对应的入口文件中 import:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;// assets/scss/styles_dark.scss
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;@import &amp;#34;colors/dark&amp;#34;;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;@import &amp;#34;variables&amp;#34;;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;@import &amp;#34;util&amp;#34;;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;@import &amp;#34;mixins&amp;#34;;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;// ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;// assets/scss/styles_light.scss
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;@import &amp;#34;colors/light&amp;#34;;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;@import &amp;#34;variables&amp;#34;;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;@import &amp;#34;util&amp;#34;;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;@import &amp;#34;mixins&amp;#34;;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;// ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样，就有了 &lt;code&gt;styles_dark.scss&lt;/code&gt; 和 &lt;code&gt;styles_light.scss&lt;/code&gt; 这两个入口文件。&lt;/p&gt;
&lt;h3 id=&#34;通过-hugo-生成目标文件&#34;&gt;通过 hugo 生成目标文件&lt;/h3&gt;
&lt;p&gt;接着，在 &lt;code&gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&lt;/code&gt; 中指定入口文件进行操作：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- head.html --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;{{ $opts := (dict &amp;#34;targetPath&amp;#34; &amp;#34;css/styles_dark.css&amp;#34; &amp;#34;outputStyle&amp;#34; &amp;#34;compressed&amp;#34;) }}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;{{ $styles_dark := resources.Get &amp;#34;scss/styles_dark.scss&amp;#34; | resources.ExecuteAsTemplate &amp;#34;scss/styles_dark.scss&amp;#34; . | resources.ToCSS $opts }}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;{{ $opts := (dict &amp;#34;targetPath&amp;#34; &amp;#34;css/styles_light.css&amp;#34; &amp;#34;outputStyle&amp;#34; &amp;#34;compressed&amp;#34;) }}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;{{ $styles_light := resources.Get &amp;#34;scss/styles_light.scss&amp;#34; | resources.ExecuteAsTemplate &amp;#34;scss/styles_light.scss&amp;#34; . | resources.ToCSS $opts }}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里通过 hugo 操作之后，即可生成深浅主题对应的两个 css 文件，位置在 &lt;code&gt;css&lt;/code&gt; 目录下。&lt;/p&gt;
&lt;p&gt;接着，将地址赋值到 &lt;code&gt;$dark&lt;/code&gt; 和 &lt;code&gt;$light&lt;/code&gt; 中：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- head.html --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;{{ $dark := $styles_dark.Permalink }}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;{{ $light := $styles_light.Permalink }}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;保存地址变量到隐藏域&#34;&gt;保存地址变量到隐藏域&lt;/h3&gt;
&lt;p&gt;接着，通过隐藏域保存这两个地址以便后续使用：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- head.html --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{{ $dark }}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;styles-dark&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;style&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;display: none;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{{ $light }}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;styles-light&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;style&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;display: none;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;设定初始主题&#34;&gt;设定初始主题&lt;/h2&gt;
&lt;p&gt;一开始的主题应由网站发布者指定，读取 config 文件中的变量即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&amp;lt;!-- head.html --&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;{{ if eq .Site.Params.colortheme &amp;#34;dark&amp;#34; }}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;dark&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;theme-current&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;style&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;display: none;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;theme-css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;rel&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{{ $dark }}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;{{ else if eq .Site.Params.colortheme &amp;#34;light&amp;#34; }}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;value&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;light&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;theme-current&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;style&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;display: none;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;theme-css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;rel&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;{{ $light }}&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;{{ end }}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里又配置了一个隐藏域，用于后续确认和修改主题。&lt;/p&gt;
&lt;h2 id=&#34;通过-js-动态设置主题&#34;&gt;通过 js 动态设置主题&lt;/h2&gt;
&lt;h3 id=&#34;加载主题&#34;&gt;加载主题&lt;/h3&gt;
&lt;p&gt;加载步骤如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;读取用户 localStorage 中保存的主题变量；&lt;/li&gt;
&lt;li&gt;读取当前主题隐藏域值；&lt;/li&gt;
&lt;li&gt;读取 css 文件地址隐藏域值；&lt;/li&gt;
&lt;li&gt;修改主题 css 标签中的地址以加载主题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中，用户 localStorage 中保存的主题变量是在用户首次切换主题之后生成的，在下一步中进行介绍。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// theme.js
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; setTheme&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;theme&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; stylesDark &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;styles-dark&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;value&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; stylesLight &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;styles-light&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;value&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; themeCss &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;theme-css&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; setThemeStyle &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; theme &lt;span style=&#34;color:#81a1c1&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;dark&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;?&lt;/span&gt; stylesDark &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; stylesLight&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;  themeCss&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;setAttribute&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;href&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; setThemeStyle&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; getCurrentTheme&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// user theme
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; userTheme &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; localStorage&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getItem&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;userTheme&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; userThemeExpire &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; localStorage&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getItem&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;userThemeExpire&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    userTheme &lt;span style=&#34;color:#81a1c1&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;    userTheme &lt;span style=&#34;color:#81a1c1&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    userThemeExpire &lt;span style=&#34;color:#81a1c1&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;    userThemeExpire &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Date&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;().&lt;/span&gt;getTime&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;theme-current&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;setAttribute&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; userTheme&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;theme-current&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;value&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;setTheme&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;getCurrentTheme&lt;span style=&#34;color:#eceff4&#34;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;修改主题&#34;&gt;修改主题&lt;/h3&gt;
&lt;p&gt;每次修改主题都需要修改当前主题隐藏域中的值，并且在用户 localStorage 中存储或修改用户选择的主题，而设置超时时间则是一个可选项：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// theme.js
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; changeTheme&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;theme&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;  setTheme&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;theme&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;document&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;getElementById&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;theme-current&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;setAttribute&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; theme&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;  localStorage&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;setItem&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;userTheme&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; theme&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 设置超时时间： 24 小时
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; expire &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Date&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;().&lt;/span&gt;getTime&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1000&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3600&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;  localStorage&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;setItem&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;userThemeExpire&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; expire&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;将脚本放在合适的位置&#34;&gt;将脚本放在合适的位置&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;theme.js&lt;/code&gt; 脚本需要在脚本所用到的元素加载完毕后，才能正确执行，否则将导致主题修改失败。&lt;/p&gt;
&lt;p&gt;由于浏览器加载页面是从上到下按顺序执行的，所以只要不将脚本放在任一依赖项的上方即可让脚本顺利执行。&lt;/p&gt;
&lt;h3 id=&#34;绑定事件到按钮&#34;&gt;绑定事件到按钮&lt;/h3&gt;
&lt;p&gt;脚本编写完毕后，则将其绑定到某个按钮上即可，示例如下：&lt;/p&gt;
&lt;p&gt;定义一个按钮：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;icon&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;theme-change&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;fas fa-adjust&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;a&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;绑定事件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// main.js
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// button: change theme
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;$&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;#theme-change&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;click&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt; newTheme&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;getCurrentTheme&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;light&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    newTheme &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;dark&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    newTheme &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;light&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;  changeTheme&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;newTheme&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;p&gt;抚摸主页上的猫猫，美妙的事情会发生哦~&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Apple 产品和服务使用记录</title>
        <link>https://zhihang.org/posts/mac-important-software-installation-and-configuration-record/</link>
        <pubDate>Sun, 08 Jan 2023 18:51:27 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>mac-important-software-installation-and-configuration-record</guid>
        <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;Welcome to the world of Apple. If you&amp;rsquo;re also a fan of Apple, we might just become friends.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%89%8D%E8%A8%80&#34;&gt;前言&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-%E6%9C%8D%E5%8A%A1&#34;&gt;Apple 服务&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#apple-%E5%B8%90%E5%8F%B7%E9%97%AE%E9%A2%98&#34;&gt;Apple 帐号问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-%E6%9C%8D%E5%8A%A1%E4%B8%8E%E4%BB%A3%E7%90%86%E5%88%86%E6%B5%81%E9%97%AE%E9%A2%98&#34;&gt;Apple 服务与代理分流问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-map-%E6%B2%A1%E6%9C%89%E5%90%8C%E6%AD%A5%E6%8C%87%E5%8D%97%E7%AD%89%E4%BF%A1%E6%81%AF&#34;&gt;Apple Map 没有同步指南等信息&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-music-%E8%87%AA%E5%8A%A8%E5%8F%96%E6%B6%88%E6%94%B6%E8%97%8F%E4%B8%93%E8%BE%91&#34;&gt;Apple Music 自动取消收藏专辑&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-music-%E4%B8%93%E8%BE%91%E9%87%8D%E5%A4%8D%E9%97%AE%E9%A2%98&#34;&gt;Apple Music 专辑重复问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-%E5%AE%98%E6%96%B9%E8%8A%82%E5%81%87%E6%97%A5%E6%97%A5%E5%8E%86%E5%9C%B0%E5%9D%80&#34;&gt;Apple 官方节假日日历地址&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-fitness-%E6%89%8B%E5%8A%A8%E6%9B%B4%E6%96%B0%E6%B4%BB%E5%8A%A8%E5%9C%86%E7%8E%AF&#34;&gt;Apple Fitness 手动更新活动圆环&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#airpods-%E7%9B%B8%E5%85%B3&#34;&gt;Airpods 相关&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%B8%8D%E5%85%85%E7%94%B5%E9%97%AE%E9%A2%98&#34;&gt;不充电问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8A%9F%E8%83%BD%E7%89%B9%E6%80%A7&#34;&gt;功能特性&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-watch-%E7%9B%B8%E5%85%B3&#34;&gt;Apple Watch 相关&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%9C%82%E7%AA%9D%E7%BD%91%E7%BB%9C&#34;&gt;蜂窝网络&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%AC%E4%BA%A4%E5%9C%B0%E9%93%81%E5%8D%A1%E7%9B%B8%E5%85%B3&#34;&gt;公交地铁卡相关&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#iphone-%E7%9B%B8%E5%85%B3&#34;&gt;iPhone 相关&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#wallet&#34;&gt;Wallet&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%A6%99%E6%B8%AF%E5%85%AB%E8%BE%BE%E9%80%9A&#34;&gt;香港八达通&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%97%A5%E6%9C%AC-suica&#34;&gt;日本 Suica&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%97%A8%E7%A6%81%E5%8D%A1&#34;&gt;门禁卡&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%9C%BA%E5%9E%8B%E9%87%8D%E5%A4%A7%E5%8F%98%E5%8C%96&#34;&gt;机型重大变化&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#ipad-%E7%9B%B8%E5%85%B3&#34;&gt;iPad 相关&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mac-%E7%B3%BB%E7%BB%9F%E9%81%87%E5%88%B0%E7%9A%84%E9%97%AE%E9%A2%98&#34;&gt;Mac 系统遇到的问题&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#desktop-%E6%96%87%E4%BB%B6%E5%A4%B9%E9%87%8C%E6%9C%89%E4%B8%9C%E8%A5%BF%E4%BD%86%E6%98%AF%E6%A1%8C%E9%9D%A2%E4%B8%8D%E6%98%BE%E7%A4%BA%E8%80%8C%E4%B8%94%E6%97%A0%E6%B3%95%E6%8B%96%E5%8A%A8%E4%BB%BB%E4%BD%95%E6%96%87%E4%BB%B6%E5%88%B0%E6%A1%8C%E9%9D%A2&#34;&gt;desktop 文件夹里有东西，但是桌面不显示，而且无法拖动任何文件到桌面&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%98%BB%E6%AD%A2-anydesk-%E5%BC%80%E6%9C%BA%E8%87%AA%E5%90%AF&#34;&gt;阻止 Anydesk 开机自启&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mac-%E7%B3%BB%E7%BB%9F%E9%87%8D%E8%A6%81%E6%93%8D%E4%BD%9C%E5%92%8C%E9%85%8D%E7%BD%AE%E8%AE%B0%E5%BD%95&#34;&gt;Mac 系统重要操作和配置记录&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%98%BB%E6%AD%A2%E7%9D%A1%E7%9C%A0&#34;&gt;阻止睡眠&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9B%9E%E9%80%80%E7%B3%BB%E7%BB%9F&#34;&gt;回退系统&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%B6%E4%BD%9C%E5%90%AF%E5%8A%A8%E7%9B%98&#34;&gt;制作启动盘&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%A4%87%E4%BB%BD%E7%B3%BB%E7%BB%9F%E6%95%B0%E6%8D%AE&#34;&gt;备份系统数据&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BB%8E%E5%90%AF%E5%8A%A8%E7%9B%98%E5%AE%89%E8%A3%85-ventura&#34;&gt;从启动盘安装 Ventura&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%81%A2%E5%A4%8D%E7%B3%BB%E7%BB%9F%E6%95%B0%E6%8D%AE&#34;&gt;恢复系统数据&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%BF%81%E7%A7%BB%E5%90%8E%E9%81%87%E5%88%B0%E7%9A%84%E9%97%AE%E9%A2%98&#34;&gt;迁移后遇到的问题&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-music-%E5%AF%BC%E5%85%A5%E4%B8%93%E8%BE%91&#34;&gt;Apple Music 导入专辑&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-map-%E4%BF%AE%E6%94%B9%E8%AF%AD%E8%A8%80&#34;&gt;Apple Map 修改语言&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#apple-book-%E5%B0%86%E5%AF%BC%E5%87%BA%E7%9A%84-epub-%E6%96%87%E4%BB%B6%E5%A4%B9%E8%BD%AC%E4%B8%BA-epub-%E6%96%87%E4%BB%B6&#34;&gt;Apple Book 将导出的 epub 文件夹转为 epub 文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mac-%E7%A6%81%E7%94%A8%E7%B3%BB%E7%BB%9F%E8%BE%93%E5%85%A5%E6%B3%95&#34;&gt;MAC 禁用系统输入法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mac-ventura-%E7%9C%9F%E6%AD%A3%E8%BF%9B%E5%85%A5-recovery&#34;&gt;MAC Ventura 真正进入 Recovery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%96%87%E4%BB%B6%E5%A4%B9%E9%BB%98%E8%AE%A4%E6%98%BE%E7%A4%BA%E9%9A%90%E8%97%8F%E6%96%87%E4%BB%B6&#34;&gt;文件夹默认显示隐藏文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%85%8D%E7%BD%AE%E5%BC%80%E6%9C%BA%E5%90%AF%E5%8A%A8%E7%A8%8B%E5%BA%8F&#34;&gt;配置开机启动程序&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%A6%81%E6%AD%A2%E7%B3%BB%E7%BB%9F%E6%9B%B4%E6%96%B0%E5%92%8C%E6%8F%90%E7%A4%BA&#34;&gt;禁止系统更新和提示&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hostname&#34;&gt;Hostname&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#smb-%E5%85%B1%E4%BA%AB&#34;&gt;SMB 共享&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%B0%86%E5%BF%AB%E9%80%9F%E6%93%8D%E4%BD%9C%E5%92%8C%E5%BF%AB%E6%8D%B7%E6%8C%87%E4%BB%A4%E6%B7%BB%E5%8A%A0%E5%88%B0%E5%8F%B3%E9%94%AE&#34;&gt;将快速操作和快捷指令添加到右键&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#steam-%E4%B8%8B%E8%BD%BD-windows-%E6%B8%B8%E6%88%8F%E6%96%87%E4%BB%B6&#34;&gt;Steam 下载 Windows 游戏文件&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mac-%E9%87%8D%E8%A6%81%E8%BD%AF%E4%BB%B6&#34;&gt;Mac 重要软件&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#yutto-bilibili-downloader&#34;&gt;yutto (bilibili downloader)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#xml-%E5%BC%B9%E5%B9%95%E6%A0%B7%E5%BC%8F&#34;&gt;XML 弹幕样式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#yt-dlp&#34;&gt;yt-dlp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9B%BE%E7%89%87%E8%BD%AC%E6%8D%A2%E5%B7%A5%E5%85%B7&#34;&gt;图片转换工具&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rest-%E6%B5%8B%E8%AF%95%E6%8F%92%E4%BB%B6&#34;&gt;REST 测试插件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#textutil&#34;&gt;textutil&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#dart&#34;&gt;dart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#jenkins&#34;&gt;Jenkins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rocketmq&#34;&gt;RocketMQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#alist&#34;&gt;alist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#applite&#34;&gt;Applite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#graphviz&#34;&gt;graphviz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#ffmpeg&#34;&gt;ffmpeg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#pngpaste&#34;&gt;Pngpaste&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#ftp&#34;&gt;ftp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#vsce&#34;&gt;Vsce&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mysql&#34;&gt;MySQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#github-cli&#34;&gt;Github CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hugo&#34;&gt;Hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#steamcmd&#34;&gt;SteamCMD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#influxdb&#34;&gt;InfluxDb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%A3%E5%8E%8B%E7%BC%A9%E5%B7%A5%E5%85%B7&#34;&gt;解压缩工具&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#python%E5%A4%9A%E7%89%88%E6%9C%AC&#34;&gt;python(多版本)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#bat&#34;&gt;bat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#ripgrep&#34;&gt;ripgrep&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#fzf&#34;&gt;fzf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rclone-mount&#34;&gt;rclone mount&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#pikpakcli&#34;&gt;pikpakcli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#hiddenbar&#34;&gt;hiddenbar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#node&#34;&gt;node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#maven&#34;&gt;maven&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#brew&#34;&gt;brew&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#docker&#34;&gt;docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#syncthing&#34;&gt;syncthing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#redis&#34;&gt;redis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#man-zh-page&#34;&gt;man zh page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#postgresql&#34;&gt;postgresql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#jq&#34;&gt;jq&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#lux&#34;&gt;lux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;apple-服务&#34;&gt;Apple 服务&lt;/h2&gt;
&lt;h3 id=&#34;apple-帐号问题&#34;&gt;Apple 帐号问题&lt;/h3&gt;
&lt;p&gt;Apple 分为两个帐号，iCloud 帐号和 AppStore 帐号，一般建议 iCloud 帐号使用国区，AppStore 帐号使用美区帐号，搭配使用 Apple One 服务。美区 Apple Music 曲库最全，AppStore 软件最全，Apple Fitness 很有用，Apple Arcade 的游戏也挺丰富的。&lt;/p&gt;
&lt;p&gt;对于帐号具体功能，iCloud 帐号用于同步相簿、联系人、备忘录、日历等存放在 iCloud 的信息。AppStore 帐号和软件购买、Apple Music、Apple TV、Apple Books 相关。&lt;/p&gt;
&lt;p&gt;这里注意，所有自己上传的文件，都属于 iCloud 内容，比如 Apple Music 自己上传的音乐，但是 Apple Music 收藏的音乐则属于 AppStore 帐号，同步随 AppStore 帐号。注意切换 AppStore 帐号会导致下载的 Apple Music 下载的音乐被删除，但是播放列表、播放历史不回被删除，而是正常的云同步状态。&lt;/p&gt;
&lt;h3 id=&#34;apple-服务与代理分流问题&#34;&gt;Apple 服务与代理分流问题&lt;/h3&gt;
&lt;p&gt;有些代理软件的分流操作会错误将 Apple 服务加入代理。下面从一个论坛上的关于 Apple Map 的例子引入：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;解决 China IP List 分流导致 iPad 和 Mac 的 Maps App 提供商为 TomTom 的问题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你和我一样在使用透明代理和 China IP List 的组合，iPad 和 Mac 上的 Maps App 会使用 TomTom 作为地图提供商，而在不使用代理的设备上应该是高德地图。&lt;/p&gt;
&lt;p&gt;由于 Mac 和 iPad 是根据 IP 地址判断地区的，而判断的域名只有国外的解析，所以如果单纯使用 China IP List 会导致判断为国外用户。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如果你是 Surge 用户，请将 *.ls.apple.com 加上 DIRECT 的规则。&lt;/li&gt;
&lt;li&gt;如果是透明代理和 China IP List 的组合，无法对域名进行单独处理，可以添加一段 host，将请求转发到国内的 SNI Proxy 处理。具体的域名是 gsp[0-64]-ssl.ls.apple.com 和 gspe[0-64]-ssl.ls.apple.com。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以，从这个 Apple Map 的例子可以知道 *.ls.apple.com 应该直连。下面是一个 Qx 的配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;[filter_local]
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;host-wildcard, *.ls.apple.com, direct
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;另外，测试发现其实 iPhone 并不需要这个配置，这里判断 iPhone 应该是根据 SIM 卡判断地区。&lt;/p&gt;
&lt;h3 id=&#34;apple-map-没有同步指南等信息&#34;&gt;Apple Map 没有同步指南等信息&lt;/h3&gt;
&lt;p&gt;Mac 上设置 - icloud，关闭 Apple Map 同步，退出后重新打开 Apple Map，然后打开 Apple Map 同步。&lt;/p&gt;
&lt;h3 id=&#34;apple-music-自动取消收藏专辑&#34;&gt;Apple Music 自动取消收藏专辑&lt;/h3&gt;
&lt;p&gt;目前的解决方法是首先收藏专辑中喜欢的歌曲，然后收藏专辑，之后不再变更专辑中的歌曲收藏情况。&lt;/p&gt;
&lt;h3 id=&#34;apple-music-专辑重复问题&#34;&gt;Apple Music 专辑重复问题&lt;/h3&gt;
&lt;p&gt;当不同设备使用不同语言时，专辑呈现的语言不同导致的，所有设备使用同一语言可以解决。&lt;/p&gt;
&lt;h3 id=&#34;apple-官方节假日日历地址&#34;&gt;Apple 官方节假日日历地址&lt;/h3&gt;
&lt;p&gt;Apple 日历可以订阅 ics 日历：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 大陆节日&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;webcal://p10-calendars.icloud.com/holiday/CN_zh.ics
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 台湾节日&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;webcal://p10-calendars.icloud.com/holiday/TW_zh.ics
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 香港节日&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;webcal://p10-calendars.icloud.com/holiday/HK_zh.ics
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 美国节假&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;webcal://p10-calendars.icloud.com/holiday/US_en.ics
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 日本节假&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;webcal://p10-calendars.icloud.com/holiday/JP_ja.ics
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 澳大利亚&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;webcal://p10-calendars.icloud.com/holiday/AU_en.ics
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 法国节假&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;webcal://p10-calendars.icloud.com/holiday/FR_fr.ics
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 德国节假&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;webcal://p10-calendars.icloud.com/holiday/DE_de.ics
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 英国节假&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;webcal://p10-calendars.icloud.com/holiday/GB_en.ics
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;apple-fitness-手动更新活动圆环&#34;&gt;Apple Fitness 手动更新活动圆环&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;Apple Health &amp;gt; Workouts &amp;gt; Add Data&lt;/code&gt; 处手动添加 Workout 即可。实测支持更新当天和过去的圆环，如果有时候忘记戴 Apple Watch 或者忘记记录，可以通过此方式 Close Ring。&lt;/p&gt;
&lt;h2 id=&#34;airpods-相关&#34;&gt;Airpods 相关&lt;/h2&gt;
&lt;h3 id=&#34;不充电问题&#34;&gt;不充电问题&lt;/h3&gt;
&lt;p&gt;可参考：&lt;a href=&#34;https://www.zhihu.com/question/63605841&#34;&gt;关于AirPods的一些问题，你们有遇到过放在耳机盒子里面，一个耳机没有充上电的状态么？&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我是 Airpods 的左耳机充不上电了，用牙线棒轻戳了一下左耳机仓的金属片，就成功解决了。&lt;/p&gt;
&lt;h3 id=&#34;功能特性&#34;&gt;功能特性&lt;/h3&gt;
&lt;p&gt;AirPods Max 2 (2024) 相比于 2020 年的第一代差异只在于换了一个 TypeC 口，没有任何音质、ANC 主动降噪功能上的升级，仍搭载 H1 芯片。&lt;/p&gt;
&lt;p&gt;AirPods3 并不支持主动降噪，AirPods4 普通版也不支持，AirPods4 ANC 版支持。&lt;/p&gt;
&lt;h2 id=&#34;apple-watch-相关&#34;&gt;Apple Watch 相关&lt;/h2&gt;
&lt;h3 id=&#34;蜂窝网络&#34;&gt;蜂窝网络&lt;/h3&gt;
&lt;p&gt;如果需要脱离 iPhone 使用，只需要在 Apple Watch 应用内开通蜂窝网络（注意 Watch 需要时蜂窝版），移动是每月多交 10 元，和话费一起交，流量也是一起算的。&lt;/p&gt;
&lt;p&gt;蜂窝网络的意义在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;救急，iPhone 没电了，无法坐地铁，看地图&lt;/li&gt;
&lt;li&gt;运动时无需携带 iPhone，无需担心错过电话和消息&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;公交地铁卡相关&#34;&gt;公交地铁卡相关&lt;/h3&gt;
&lt;p&gt;同一张 NFC 卡无法同时绑定在 iPhone 和 Watch。我的操作是 iPhone 一个城市的卡，Watch 另一个城市的卡，国内各个城市的卡其实都是通用的。&lt;/p&gt;
&lt;h2 id=&#34;iphone-相关&#34;&gt;iPhone 相关&lt;/h2&gt;
&lt;h3 id=&#34;wallet&#34;&gt;Wallet&lt;/h3&gt;
&lt;h4 id=&#34;香港八达通&#34;&gt;香港八达通&lt;/h4&gt;
&lt;p&gt;Wallet 开通的八达通和实体卡八达通完全一样，测试在香港可以坐地铁、购物。&lt;/p&gt;
&lt;h4 id=&#34;日本-suica&#34;&gt;日本 Suica&lt;/h4&gt;
&lt;p&gt;Wallet 开通的 Suica 和实体卡 Suica 完全一样，测试在东京可以坐地铁、购物。&lt;/p&gt;
&lt;h4 id=&#34;门禁卡&#34;&gt;门禁卡&lt;/h4&gt;
&lt;p&gt;目前 iPhone 无法复制任何形式的门禁卡，受限于 Apple 自身的安全政策。而支持 NFC 的安卓机型可以复制门禁卡，但部分加密门卡可能无法成功刷卡。&lt;/p&gt;
&lt;h3 id=&#34;机型重大变化&#34;&gt;机型重大变化&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;15 开始支持 TypeC&lt;/li&gt;
&lt;li&gt;14p 开始支持灵动岛&lt;/li&gt;
&lt;li&gt;13，14 刘海较 12 窄一截&lt;/li&gt;
&lt;li&gt;16 多了一个快捷拍照按钮&lt;/li&gt;
&lt;li&gt;16 标准版仍为 60HZ&lt;/li&gt;
&lt;li&gt;16p 是钛合金&lt;/li&gt;
&lt;li&gt;13p 开始有 120HZ&lt;/li&gt;
&lt;li&gt;15p 静音键更新&lt;/li&gt;
&lt;li&gt;17 改回铝合金&lt;/li&gt;
&lt;li&gt;17 也有快捷拍照按钮了&lt;/li&gt;
&lt;li&gt;17p 采用横向长方形相机模组&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;ipad-相关&#34;&gt;iPad 相关&lt;/h2&gt;
&lt;p&gt;我的 iPad 只用来看书和论文，基本没有遇到什么问题。&lt;/p&gt;
&lt;h2 id=&#34;mac-系统遇到的问题&#34;&gt;Mac 系统遇到的问题&lt;/h2&gt;
&lt;h3 id=&#34;desktop-文件夹里有东西但是桌面不显示而且无法拖动任何文件到桌面&#34;&gt;desktop 文件夹里有东西，但是桌面不显示，而且无法拖动任何文件到桌面&lt;/h3&gt;
&lt;p&gt;原因是一些破解软件修改了系统配置造成的。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;defaults write com.apple.finder CreateDesktop -bool true&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; killall Finder
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;阻止-anydesk-开机自启&#34;&gt;阻止 Anydesk 开机自启&lt;/h3&gt;
&lt;p&gt;删除该文件:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;/Library/LaunchAgents/com.philandro.anydesk.Frontend.plist
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;mac-系统重要操作和配置记录&#34;&gt;Mac 系统重要操作和配置记录&lt;/h2&gt;
&lt;h3 id=&#34;阻止睡眠&#34;&gt;阻止睡眠&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;caffeinate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;终端运行，ctrl-c 即取消，仅开盖锁屏时可用。&lt;/p&gt;
&lt;h3 id=&#34;回退系统&#34;&gt;回退系统&lt;/h3&gt;
&lt;p&gt;从 Ventura 升级到 Sonoma 后发现有些问题，部分重要功能有小 bug，所以决定回退到 Ventura，记录下流程和恢复后遇到的问题，方便后续参考。&lt;/p&gt;
&lt;h4 id=&#34;制作启动盘&#34;&gt;制作启动盘&lt;/h4&gt;
&lt;p&gt;首先在 store 搜索 MacOS Ventura，点击下载即可。&lt;/p&gt;
&lt;p&gt;接着插入外接盘，我用的是一个容量为 32 G 的小 U 盘，其实大概 15 G 即可。&lt;/p&gt;
&lt;p&gt;接着打开磁盘工具, 选择该 U 盘，抹掉它(选择目标文件系统为 MacOS 扩展), 命名为 T(也可以是其他，下面用得到)。&lt;/p&gt;
&lt;p&gt;接着打开控制台，执行命令如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;sudo /Applications/Install&lt;span style=&#34;color:#ebcb8b&#34;&gt;\ &lt;/span&gt;macOS&lt;span style=&#34;color:#ebcb8b&#34;&gt;\ &lt;/span&gt;Ventura.app/Contents/Resources/createinstallmedia --volume /Volumes/T       
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 &amp;ldquo;/Applications/Install\ macOS\ Ventura.app&amp;rdquo; 即为从 store 下载好的 Ventura，通过 createinstallmedia 命令即可制作启动盘，通过 &amp;ndash;volume 参数指定启动盘位置为 /Volumes 下的 &amp;ldquo;T&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;然后等待启动盘制作完成即可。&lt;/p&gt;
&lt;h4 id=&#34;备份系统数据&#34;&gt;备份系统数据&lt;/h4&gt;
&lt;p&gt;这里我使用了时间机器备份数据，比较方便且安全。&lt;/p&gt;
&lt;p&gt;备份数据也需要一个数据盘，大小的话，据官方文档建议的话是要略大于当前 mac 系统大小。&lt;/p&gt;
&lt;p&gt;我使用的是西数的 1T SSD，由于我系统大小 256G，因此划分了一个大概 300 G 的分区给它，接着，将其抹掉，格式化为 APFS 文件系统。&lt;/p&gt;
&lt;p&gt;然后在时间机器界面点击选择备份盘，然后就可以开始备份了，确认备份完成了，继续执行下面的操作。&lt;/p&gt;
&lt;h4 id=&#34;从启动盘安装-ventura&#34;&gt;从启动盘安装 Ventura&lt;/h4&gt;
&lt;p&gt;关机，长按开机键即可进入恢复模式（m1 系统是这样，其他系统可能有差异）。&lt;/p&gt;
&lt;p&gt;接着打开磁盘工具，抹去原系统（这里如果不放心，建议用另外一块盘安装恢复试试看先）。&lt;/p&gt;
&lt;p&gt;然后退出磁盘工具，点击制作好的启动盘，根据提示进行安装即可。&lt;/p&gt;
&lt;h4 id=&#34;恢复系统数据&#34;&gt;恢复系统数据&lt;/h4&gt;
&lt;p&gt;安装完成后，点击完成一系列的初始化操作后，将会出现迁移助手，恢复数据选项选择时间机器，选择之前的备份进行恢复即可。&lt;/p&gt;
&lt;p&gt;我这里大概 200 G 数据，花了不到 1 小时就完成了。&lt;/p&gt;
&lt;h4 id=&#34;迁移后遇到的问题&#34;&gt;迁移后遇到的问题&lt;/h4&gt;
&lt;p&gt;从高版本系统退回低版本系统后，多少会出现一些问题，这里持续记录下。&lt;/p&gt;
&lt;p&gt;部分软件崩溃: runtime library is newer than runtime&lt;/p&gt;
&lt;p&gt;LogiHub 和 maven 出现了类似问题：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;$ /usr/local/maven/3.6.3/bin/mvn    
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;assertion failed &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;header-&amp;gt;version &amp;lt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; kProjectSourceVersion&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;: runtime library is newer than runtime
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;(&lt;/span&gt;Library.cpp:99 init&lt;span style=&#34;color:#81a1c1&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;1&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;5714&lt;/span&gt; abort      /usr/local/maven/3.6.3/bin/mvn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;google 一番后大概查出问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The app crashing problem appears to happen only when attempting to open apps that use Rosetta, the translator that allows Intel apps to run on Apple Silicon architecture.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;大概就是因为 Rosetta 这个 translator 的问题，估计不同版本有差异，总之，实测重新安装 Rosetta 即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;/usr/sbin/softwareupdate --install-rosetta --agree-to-license
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;apple-music-导入专辑&#34;&gt;Apple Music 导入专辑&lt;/h3&gt;
&lt;p&gt;Import the folder, sort the songs by date added, select the latest songs, edit the Album field in the properties.&lt;/p&gt;
&lt;p&gt;另外建议可以勾选 compliation。&lt;/p&gt;
&lt;h3 id=&#34;apple-map-修改语言&#34;&gt;Apple Map 修改语言&lt;/h3&gt;
&lt;p&gt;系统语言为英文时修改内置地图软件语言为中文。&lt;/p&gt;
&lt;p&gt;先将 [View]-&amp;gt; [Labels]-&amp;gt; [Always Show Labels in English] 取消即可在地图上显示中文。&lt;/p&gt;
&lt;p&gt;如果需要将搜索内容也改成中文，需要设置 macOS 特定 app 的语言。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;defaults write com.apple.maps AppleLanguages &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;(zh-CN)&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# defaults write com.apple.maps AppleLanguages &amp;#39;(en-US)&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以将菜单栏，搜索内容变为中文。（想变回英文只需将最后改成’(“en-US”)’）&lt;/p&gt;
&lt;h3 id=&#34;apple-book-将导出的-epub-文件夹转为-epub-文件&#34;&gt;Apple Book 将导出的 epub 文件夹转为 epub 文件&lt;/h3&gt;
&lt;p&gt;注：导出方法是拖动 Book 到 Finder。&lt;/p&gt;
&lt;p&gt;Right click on the .epub file and click on Show Package Contents.&lt;/p&gt;
&lt;p&gt;Select all the contents (CMD + A) → Right click → Compress.&lt;/p&gt;
&lt;p&gt;This will create a .zip file. Simply change the extension from .zip to .epub and voila! The file has become an ePub document.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;ap_book_to_epub&lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    filename&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;$(&lt;/span&gt;basename -- &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$*&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;    filename&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;filename&lt;span style=&#34;color:#eceff4&#34;&gt;%.*&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; $*
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;    zip -r &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$filename&lt;span style=&#34;color:#a3be8c&#34;&gt;.zip&amp;#34;&lt;/span&gt; *
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;    mv &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$filename&lt;span style=&#34;color:#a3be8c&#34;&gt;.zip&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/Users/zh/Library/Mobile Documents/com~apple~CloudDocs/Books/&lt;/span&gt;$filename&lt;span style=&#34;color:#a3be8c&#34;&gt;.epub&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Move &lt;/span&gt;$filename&lt;span style=&#34;color:#a3be8c&#34;&gt;.epub to icloud &amp;gt; Books&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;mac-禁用系统输入法&#34;&gt;MAC 禁用系统输入法&lt;/h3&gt;
&lt;p&gt;sudo open ~/Library/Preferences/com.apple.HIToolbox.plist&lt;/p&gt;
&lt;p&gt;AppleEnabledInputSources -&amp;gt; remove {KeyboardLayout=ABC} -&amp;gt; save&lt;/p&gt;
&lt;p&gt;访达 -&amp;gt; 进入文件夹 ~/Library/Preferences/com.apple.HIToolbox.plist -&amp;gt; 右键显示简介 -&amp;gt; 已锁定 v&lt;/p&gt;
&lt;p&gt;PS: 在 Ventura 版本下成功&lt;/p&gt;
&lt;h3 id=&#34;mac-ventura-真正进入-recovery&#34;&gt;MAC Ventura 真正进入 Recovery&lt;/h3&gt;
&lt;p&gt;进入恢复模式操作步骤为：1.长按电源键 2.长按直到启动选项出现 3.正在载入启动选项 4.选项界面&lt;/p&gt;
&lt;p&gt;而如果在【3.正在载入启动选项】页面时就松开电源键了，在选项界面后续操作中，虽然是在恢复模式的界面，但是系统却认为不是在恢复模式。&lt;/p&gt;
&lt;p&gt;解决方式：&lt;/p&gt;
&lt;p&gt;长按电源键直到【4.选项界面 】出现后再松手即可！&lt;/p&gt;
&lt;h3 id=&#34;文件夹默认显示隐藏文件&#34;&gt;文件夹默认显示隐藏文件&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;defaults write com.apple.finder AppleShowAllFiles -bool &lt;span style=&#34;color:#81a1c1&#34;&gt;true&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;killall Finder
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;配置开机启动程序&#34;&gt;配置开机启动程序&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;chmod +x startup.sh
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 访达右键 startup.sh &amp;gt; 显示详情 &amp;gt; 打开方式选终端&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 设置 &amp;gt; 通用 &amp;gt; 登录项添加 startup.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;禁止系统更新和提示&#34;&gt;禁止系统更新和提示&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# /etc/hosts&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;127.0.0.1 swdist.apple.com
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;127.0.0.1 swscan.apple.com
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;127.0.0.1 swcdn.apple.com  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;#optional, download url&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;127.0.0.1 gdmf.apple.com
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;127.0.0.1 mesu.apple.com
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;127.0.0.1 xp.apple.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;alias&lt;/span&gt; fkred&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;defaults delete com.apple.systempreferences AttentionPrefBundleIDs; defaults delete com.apple.systempreferences DidShowPrefBundleIDs; killall Dock&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;fkred
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;hostname&#34;&gt;Hostname&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;sudo scutil --set HostName MacBookPro-Jzh
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;scutil --get HostName
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# setting -&amp;gt; general -&amp;gt; sharing -&amp;gt; Local hostname&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;sudo scutil --set LocalHostName MacBookPro-Jzh
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;scutil --get LocalHostName
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;smb-共享&#34;&gt;SMB 共享&lt;/h3&gt;
&lt;p&gt;mac 通用 -&amp;gt; 共享 -&amp;gt; 文件共享开启 -&amp;gt; 指定共享文件夹和权限控制(可选)&lt;/p&gt;
&lt;p&gt;iphone 文件 -&amp;gt; 连接服务器 -&amp;gt; 输入 Mac-Jzh.local(本机名称 + .local) -&amp;gt; 输入 Mac 账号密码(或以客人模式登录)&lt;/p&gt;
&lt;h3 id=&#34;将快速操作和快捷指令添加到右键&#34;&gt;将快速操作和快捷指令添加到右键&lt;/h3&gt;
&lt;p&gt;Automator 创建快速操作（注意输入类型和适用 APP），然后设置 -&amp;gt; 键盘 -&amp;gt; 键盘快捷键 -&amp;gt; 服务 -&amp;gt; 勾选&lt;/p&gt;
&lt;p&gt;快捷指令详细信息勾选快速操作, 编辑快捷指令，然后设置 -&amp;gt; 隐私与安全性 -&amp;gt; 扩展 -&amp;gt; 访达 -&amp;gt; 勾选&lt;/p&gt;
&lt;h3 id=&#34;steam-下载-windows-游戏文件&#34;&gt;Steam 下载 Windows 游戏文件&lt;/h3&gt;
&lt;p&gt;Navigate to /Users/YOUR_USERNAME_HERE/Library/Application Support/Steam/steamapps/. Create a file called appmanifest_22320.acf (the number is based on its &lt;a href=&#34;https://steamdb.info/app/22320/&#34;&gt;Steam App ID&lt;/a&gt;). If using TextEdit, make sure that your document is in plain text mode by going to the menu bar and choosing “Format” -&amp;gt; “Make Plain Text”. Also, ensure that it’s not named with the extension .acf.txt. Add the following into that file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;AppState&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;AppID&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;22320&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Universe&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;StateFlags&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;1026&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;installdir&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;The Elder Scrolls III - Morrowind&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Launch the Steam client and let it download. You can then find Morrowind.esm at ~/Library/Application Support/Steam/steamapps/common/The Elder Scrolls III - Morrowind/Data Files/&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://openmw.readthedocs.io/en/latest/manuals/installation/install-game-files.html&#34;&gt;SRC&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;mac-重要软件&#34;&gt;Mac 重要软件&lt;/h2&gt;
&lt;h3 id=&#34;yutto-bilibili-downloader&#34;&gt;yutto (bilibili downloader)&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;brew tap siguremo/tap
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;brew install yutto
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# -c 指定 cookie:sessdata&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 下载番剧&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;yutto -c &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;xxx&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--danmaku-display-region-ratio 0.25 &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--danmaku-font-size &lt;span style=&#34;color:#b48ead&#34;&gt;28&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;-b -p 201~400 &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;https://www.bilibili.com/bangumi/play/ep109726
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 下载合集&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;yutto -c &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;xxx&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--no-subtitle &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--danmaku-display-region-ratio 0.25 &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;--danmaku-font-size &lt;span style=&#34;color:#b48ead&#34;&gt;28&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;-b &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;https://space.bilibili.com/13199099/lists/700383?type&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;season
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;xml-弹幕样式&#34;&gt;XML 弹幕样式&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;pip install biliass
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# one&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;biliass &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;xxx.xml&amp;#34;&lt;/span&gt; -s 1920x1080 -o &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;xxx.ass&amp;#34;&lt;/span&gt; --display-region-ratio 0.25 -dm &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt; -a 0.75 -fn &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;黑体&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# batch&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;find &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; -type f -name &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;*.xml&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;read&lt;/span&gt; -r xml_file&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    ass_file&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;${&lt;/span&gt;xml_file&lt;span style=&#34;color:#eceff4&#34;&gt;%.xml&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;.ass&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    biliass &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$xml_file&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;        -s 1920x1080 &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;        -o &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$ass_file&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;        --display-region-ratio 0.25 &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;        -dm &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;        -a 0.75 &lt;span style=&#34;color:#ebcb8b&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;&lt;/span&gt;        -fn &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;黑体&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;✅ Done: &lt;/span&gt;$xml_file&lt;span style=&#34;color:#a3be8c&#34;&gt; -&amp;gt; &lt;/span&gt;$ass_file&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 删除弹幕：&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# batch delete .ass files&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;find . -type f -name &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;*.ass&amp;#34;&lt;/span&gt; -delete
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;yt-dlp&#34;&gt;yt-dlp&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install yt-dlp
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# yt-dlp &amp;#34;https://youtu.be/15ezpwCHtJs\?si\=95fukd8TRH3ZtbnA&amp;#34; -x --audio-quality 0 --audio-format alac&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;图片转换工具&#34;&gt;图片转换工具&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install imagemagick
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;brew install ghostscript
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;magick image.jpg image.png
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;rest-测试插件&#34;&gt;REST 测试插件&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;vsc: rest client&lt;/li&gt;
&lt;li&gt;idea: http client&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;环境变量分别写在:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;.vscode/settings.json&lt;/li&gt;
&lt;li&gt;.http 同一目录下&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;http 文件内字符串变量统一不加引号&lt;/p&gt;
&lt;h3 id=&#34;textutil&#34;&gt;textutil&lt;/h3&gt;
&lt;p&gt;用于转换 webarchive 为文件夹，好像是内置的。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;textutil -convert html /Users/USERNAME/NAME.webarchive
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;dart&#34;&gt;dart&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew tap dart-lang/dart
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;brew install dart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;jenkins&#34;&gt;Jenkins&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;java -jar jenkins.war --httpPort&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;8080&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;open http://localhost:8080 &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# and then set up in browser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;rocketmq&#34;&gt;RocketMQ&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;wget https://dist.apache.org/repos/dist/release/rocketmq/5.1.4/rocketmq-all-5.1.4-bin-release.zip
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;unzip rocketmq-all-5.1.4-bin-release.zip
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;sudo mkdir -p /usr/local/share/rocketmq &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo mv rocketmq-all-5.1.4-bin-release /usr/local/share/rocketmq/
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# start&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; /usr/local/share/rocketmq/rocketmq-all-5.1.4-bin-release/bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;alist&#34;&gt;alist&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; $dld
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;wget https://github.com/alist-org/alist/releases/download/v3.30.0/alist-darwin-arm64.tar.gz
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;tar -zxvf alist-darwin-arm64.tar.gz
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;chmod +x alist
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;sudo mv alist /Applications/Bin/alist
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;export PATH=&amp;#34;$PATH:/Applications/Bin&amp;#34;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.zprofile
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;source&lt;/span&gt; ~/.zprofile
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;data_dir&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/Users/zh/.alist&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# mkdir data folder&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;mkdir &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$data_dir&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# start server&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$data_dir&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; alist server
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# get admin info&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$data_dir&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; alist admin
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# add some storages&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;后台服务，开机自启，&lt;code&gt;vim ~/Library/LaunchAgents/ci.nn.alist.plist&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;&amp;lt;!DOCTYPE plist PUBLIC &amp;#34;-//Apple//DTD PLIST 1.0//EN&amp;#34; &amp;#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;#34;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;plist&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;version=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Label&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;ci.nn.alist&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;KeepAlive&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;ProcessType&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;Background&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;RunAtLoad&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;WorkingDirectory&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/Users/zh/.alist&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;ProgramArguments&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/Applications/Bin/alist&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;server&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;launchctl load ~/Library/LaunchAgents/ci.nn.alist.plist
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 开启: launchctl start ~/Library/LaunchAgents/ci.nn.alist.plist&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 关闭: launchctl stop ~/Library/LaunchAgents/ci.nn.alist.plist&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 卸载配置: launchctl unload ~/Library/LaunchAgents/ci.nn.alist.plist&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;applite&#34;&gt;Applite&lt;/h3&gt;
&lt;p&gt;一个方便地卸载、安装、更新 Mac 各类软件（含 brew 源）的工具。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install --cask applite
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;graphviz&#34;&gt;graphviz&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install libtool
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;brew link libtool
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;brew install graphviz
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;brew link --overwrite graphviz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By default, the dot executable is expected:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Firstly in: /usr/local/bin/dot&lt;/li&gt;
&lt;li&gt;Then in: /usr/bin/dot&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can also specify the environment variable &lt;code&gt;GRAPHVIZ_DOT&lt;/code&gt; to set the exact location of your GraphViz executable.&lt;/p&gt;
&lt;h3 id=&#34;ffmpeg&#34;&gt;ffmpeg&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install ffmpeg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;pngpaste&#34;&gt;Pngpaste&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install pngpaste 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;ftp&#34;&gt;ftp&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install inetutils
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;vsce&#34;&gt;Vsce&lt;/h3&gt;
&lt;p&gt;Vscode 扩展开发工具，用于打包和发布等。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;npm install -g vsce
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# usage&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;vsce package
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;mysql&#34;&gt;MySQL&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;brew search mysql     
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# ==&amp;gt; Formulae&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# automysqlbackup       mysql-client          mysql-client@8.4      mysql@5.7             mysqltuner&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# mysql                 mysql-client@5.7      mysql-connector-c++   mysql@8.0             qt-mysql&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# mysql++               mysql-client@8.0      mysql-search-replace  mysql@8.4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# ==&amp;gt; Casks&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# mysql-connector-python              mysqlworkbench                      sqlpro-for-mysql&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# mysql-shell                         navicat-for-mysql&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;brew install mysql@8.4
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;brew services start mysql@8.4
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;export PATH=&amp;#34;/opt/homebrew/opt/mysql@8.4/bin:$PATH&amp;#34;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.zprofile &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;source&lt;/span&gt; ~/.zprofile
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;mysql_secure_installation
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;mysql -u root -p
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;github-cli&#34;&gt;Github CLI&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install gh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;hugo&#34;&gt;Hugo&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install hugo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;steamcmd&#34;&gt;SteamCMD&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; /usr/local/share
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;curl -sqL &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;https://steamcdn-a.akamaihd.net/client/installer/steamcmd_osx.tar.gz&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt; tar zxvf -
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;./steamcmd
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;login &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;username&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;password&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 下载创意工坊物品&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;workshop_download_item &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;game-id&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;id&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# Wallpaper Engine&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;workshop_download_item &lt;span style=&#34;color:#b48ead&#34;&gt;431960&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;{&lt;/span&gt;id&lt;span style=&#34;color:#81a1c1&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;influxdb&#34;&gt;InfluxDb&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install influxdb influxdb-cli
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# start influxdb&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;influxdb
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# setup a bucket&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;influx setup
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# currently v2, use v1 shell by:&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;influx v1 shell
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;解压缩工具&#34;&gt;解压缩工具&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;p7zip&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install p7zip
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;7za x test.7z
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 分卷解压【其他格式类似】&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;cat t1.7z &amp;gt; t.7z
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;cat t1.7z.001 &amp;gt;&amp;gt; t.7z
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;cat t1.7z.002 &amp;gt;&amp;gt; t.7z
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;7za x t.7z
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;unzip&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install unzip
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;unzip test.zip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;rar&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install rar
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;unrar x test.rar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;tar&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;tar -zxf test.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;python多版本&#34;&gt;python(多版本)&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;brew update
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;brew install pyenv
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# add to .zprofile&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;export&lt;/span&gt; PYENV_ROOT&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$HOME&lt;span style=&#34;color:#a3be8c&#34;&gt;/.pyenv&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;[[&lt;/span&gt; -d $PYENV_ROOT/bin &lt;span style=&#34;color:#81a1c1&#34;&gt;]]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;export&lt;/span&gt; PATH&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;$PYENV_ROOT&lt;span style=&#34;color:#a3be8c&#34;&gt;/bin:&lt;/span&gt;$PATH&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;eval&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;$(&lt;/span&gt;pyenv init - zsh&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;v&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3.10.9&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;pyenv install $v
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;pyenv versions
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;pyenv global $v
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;python -V
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;pip -V
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 针对某个项目指定 python 版本&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;v&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3.9.13&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;pyenv install $v
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; your_project
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;~/.pyenv/versions/$v/bin/python -m venv venv
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;source&lt;/span&gt; ./venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;bat&#34;&gt;bat&lt;/h3&gt;
&lt;p&gt;加强版 cat。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install bat
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;ripgrep&#34;&gt;ripgrep&lt;/h3&gt;
&lt;p&gt;加强版 grep。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install ripgrep
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;fzf&#34;&gt;fzf&lt;/h3&gt;
&lt;p&gt;命令行模糊搜索工具。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install fzf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;rclone-mount&#34;&gt;rclone mount&lt;/h3&gt;
&lt;p&gt;首先安装 &lt;a href=&#34;https://github.com/osxfuse/osxfuse/releases&#34;&gt;macfuse&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;文档需知: &amp;ldquo;rclone will locate the macFUSE libraries without any further intervention&amp;rdquo;&lt;/p&gt;
&lt;p&gt;接着:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# 后台运行时不可使用 kill 操作，需要使用 umount ~/Pikpak 操作&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;nnohup rclone mount --vfs-cache-mode writes pikpak: ~/Pikpak
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;pikpakcli&#34;&gt;pikpakcli&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;wget https://github.com/52funny/pikpakcli/releases/download/v0.15/pikpakcli_0.15_Darwin_arm64.tar.gz
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;tar -zxvf pikpakcli_0.15_Darwin_arm64.tar.gz
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;mv ./pikpakcli /usr/local/bin/
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;pikpakcli -h
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;mkdir -p ~/.config/pikpakcli
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;username:&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; ~/.config/pikpakcli/config.yml
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;password:&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; ~/.config/pikpakcli/config.yml
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;vim ~/.config/pikpakcli/config.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;hiddenbar&#34;&gt;hiddenbar&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install --cask hiddenbar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;node&#34;&gt;node&lt;/h3&gt;
&lt;p&gt;同 linux, 详见 &lt;a href=&#34;https://zhihang.org/posts/linux-important-software-installation-and-configuration-records/#node&#34;&gt;Linux 重要软件安装和配置记录&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id=&#34;maven&#34;&gt;maven&lt;/h3&gt;
&lt;p&gt;若需要特定版本，操作方法同 linux, 详见 &lt;a href=&#34;https://zhihang.org/posts/linux-important-software-installation-and-configuration-records/#maven&#34;&gt;Linux 重要软件安装和配置记录&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;否则可直接通过 brew：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install maven
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;brew&#34;&gt;brew&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;/bin/zsh -c &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;$(&lt;/span&gt;curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# use mirror&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# disable proxy first&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;export&lt;/span&gt; HOMEBREW_BOTTLE_DOMAIN&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;docker&#34;&gt;docker&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install --cask docker
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;open /Applications/Docker.app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;syncthing&#34;&gt;syncthing&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install syncthing
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;brew services start syncthing
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;redis&#34;&gt;redis&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install redis
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;brew services start redis
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;redis-cli
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;vim /opt/homebrew/etc/redis.conf
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;requirepass xxx
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;brew services restart redis
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;man-zh-page&#34;&gt;man zh page&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/manpages-zh/manpages-zh-1.5.1.tar.gz --no-check-certificate
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;tar -zxvf manpages-zh-1.5.1.tar.gz
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;cd&lt;/span&gt; manpages-zh-1.5.1 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;./configure --disable-zhtw
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;sudo make &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; sudo make install
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;man -M /usr/local/share/man/zh_CN grep
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;alias&lt;/span&gt; mann&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;man -M /usr/local/share/man/zh_CN&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;postgresql&#34;&gt;postgresql&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install postgresql@15
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;brew services start postgresql@15
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;## vim ~/.zprofile&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;export&lt;/span&gt; PATH&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/opt/homebrew/opt/postgresql@15/bin:&lt;/span&gt;$PATH&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;export&lt;/span&gt; LDFLAGS&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;-L/opt/homebrew/opt/postgresql@15/lib&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;export&lt;/span&gt; CPPFLAGS&lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;-I/opt/homebrew/opt/postgresql@15/include&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;psql postgres
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;jq&#34;&gt;jq&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install jq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;lux&#34;&gt;lux&lt;/h3&gt;
&lt;p&gt;一个视频下载器&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;brew install lux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      </item>
      
    
      
    
      
      <item>
        <title>汇编语言重要知识整理</title>
        <link>https://zhihang.org/posts/8086-assembly-learning-record/</link>
        <pubDate>Tue, 04 Oct 2022 23:18:24 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>8086-assembly-learning-record</guid>
        <description>&lt;h2 id=&#34;toc&#34;&gt;TOC&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#toc&#34;&gt;TOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#8086-pc-%E6%9C%BA%E5%86%85%E5%AD%98%E5%9C%B0%E5%9D%80%E7%A9%BA%E9%97%B4%E5%88%86%E9%85%8D&#34;&gt;8086 PC 机内存地址空间分配&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%AE%B5%E5%AF%84%E5%AD%98%E5%99%A8&#34;&gt;段寄存器&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%85%B3%E4%BA%8E-sssp&#34;&gt;关于 SS，SP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BC%AA%E6%8C%87%E4%BB%A4&#34;&gt;伪指令&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AF%BB%E5%9D%80%E6%96%B9%E5%BC%8F&#34;&gt;寻址方式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#debug&#34;&gt;Debug&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E6%A8%A1%E5%BC%8F%E5%92%8C%E4%BF%9D%E6%8A%A4%E6%A8%A1%E5%BC%8F&#34;&gt;实模式和保护模式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#mul-%E4%B8%8E-div&#34;&gt;Mul 与 Div&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%9C%89%E7%AC%A6%E5%8F%B7%E5%92%8C%E6%97%A0%E7%AC%A6%E5%8F%B7%E6%AF%94%E8%BE%83&#34;&gt;有符号和无符号比较&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%A0%87%E5%BF%97%E4%BD%8D&#34;&gt;标志位&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#in-%E5%92%8C-out&#34;&gt;In 和 Out&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%97%AE%E9%A2%98&#34;&gt;问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%AE%9E%E8%B7%B5-%E8%87%AA%E6%97%8B%E9%94%81&#34;&gt;实践: 自旋锁&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#intel-%E8%AF%AD%E6%B3%95&#34;&gt;Intel 语法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#att-%E8%AF%AD%E6%B3%95&#34;&gt;AT&amp;amp;T 语法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B5%8B%E8%AF%95%E8%87%AA%E6%97%8B%E9%94%81&#34;&gt;测试自旋锁&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%BF%90%E8%A1%8C%E7%BB%93%E6%9E%9C&#34;&gt;运行结果&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8F%82%E8%80%83&#34;&gt;参考&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;8086-pc-机内存地址空间分配&#34;&gt;8086 PC 机内存地址空间分配&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;00000~9FFFF: 主存储器地址空间（RAM）&lt;/li&gt;
&lt;li&gt;A0000~BFFFF: 显存地址空间&lt;/li&gt;
&lt;li&gt;C0000~FFFFF: 各类ROM地址空间&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;段寄存器&#34;&gt;段寄存器&lt;/h2&gt;
&lt;p&gt;8086CPU 不支持将数据直接送入段寄存器的操作，ds 是一个段寄存器，所以 &lt;code&gt;mov ds，1000H&lt;/code&gt; 这条指令是非法的。&lt;/p&gt;
&lt;p&gt;要将 1000H 送入 ds，只好用一个寄存器来进行中转，即先将 1000H 送入一个一般的寄存器，如 bx，再将 bx 中的内容送入 ds。&lt;/p&gt;
&lt;h2 id=&#34;关于-sssp&#34;&gt;关于 SS，SP&lt;/h2&gt;
&lt;p&gt;8086CPU 中，有两个寄存器，段寄存器 SS 和寄存器 SP，栈顶的段地址存放在 SS 中，偏移地址存放在 SP 中。&lt;/p&gt;
&lt;p&gt;任意时刻，SS:SP 指向栈顶元素。push 指令和 pop 指令执行时，CPU 从 SS 和 SP 中得到栈顶的地址。&lt;/p&gt;
&lt;h2 id=&#34;伪指令&#34;&gt;伪指令&lt;/h2&gt;
&lt;p&gt;在汇编语言源程序中，包含两种指令，一种是汇编指令，一种是伪指令。&lt;/p&gt;
&lt;p&gt;汇编指令是有对应的机器码的指令，可以被编译为机器指令，最终为 CPU 所执行。&lt;/p&gt;
&lt;p&gt;而伪指令&lt;strong&gt;没有对应的机器指令&lt;/strong&gt;，最终不被 CPU 所执行。那么谁来执行伪指令呢?&lt;/p&gt;
&lt;p&gt;伪指令是由&lt;strong&gt;编译器&lt;/strong&gt;来执行的指令，编译器根据伪指令来进行相关的编译工作。&lt;/p&gt;
&lt;h2 id=&#34;寻址方式&#34;&gt;寻址方式&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;立即寻址：&lt;code&gt;mov ax, 1234H&lt;/code&gt; or &lt;code&gt;mov ax, VARW&lt;/code&gt; or &lt;code&gt;mov ax, [VARW]&lt;/code&gt; （VARW 是内存字变量）&lt;/li&gt;
&lt;li&gt;直接寻址：&lt;code&gt;mov ax, [1234H]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;寄存器直接寻址：&lt;code&gt;mov ax, bx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;寄存器间接寻址：&lt;code&gt;mov ax, [bx]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;寄存器相对寻址：&lt;code&gt;mov ax, [bx+1]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;基址+变址寻址：&lt;code&gt;mov ax, [bx+si]&lt;/code&gt; or &lt;code&gt;mov ax, [bx][si]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;基址+变址+相对寻址：&lt;code&gt;mov ax, [bx+si+1]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注：在汇编源程序中，数据不能以字母开头，所以要在前面加 0。比如，9138h 在汇编源程序中可以直接写为 9138h，而 A000h 在汇编源程序中要写为 0A000h。&lt;/p&gt;
&lt;h2 id=&#34;debug&#34;&gt;Debug&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;R命令：查看、改变 CPU 寄存器的内容；&lt;/li&gt;
&lt;li&gt;D命令：查看内存中的内容；&lt;/li&gt;
&lt;li&gt;E命令：改写内存中的内容；&lt;/li&gt;
&lt;li&gt;U命令：将内存中的机器指令翻译成汇编指令；&lt;/li&gt;
&lt;li&gt;T命令：执行一条机器指令；&lt;/li&gt;
&lt;li&gt;A命令：以汇编指令的格式在内存中写入一条机器指令；&lt;/li&gt;
&lt;li&gt;P命令：可用于快速结束一段LOOP，遇到loop时使用；&lt;/li&gt;
&lt;li&gt;G命令：可以让指令直接执行到某个地址处，如&lt;code&gt;-g 0016&lt;/code&gt;执行到0016处代码。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;实模式和保护模式&#34;&gt;实模式和保护模式&lt;/h2&gt;
&lt;p&gt;实模式是 Intel 80286 和之后的 x86 兼容 CPU 操作模式。&lt;/p&gt;
&lt;p&gt;实模式的特性是一个 20 位元的区段存储器地址空间（意思为只有1MB的存储器可以被寻址），软件可以直接访问 BIOS 例程以及周边硬件，没有任何硬件等级的存储器保护观念或多任务。&lt;/p&gt;
&lt;p&gt;保护模式是一种 80286 系列和之后的 x86 兼容CPU的运行模式。&lt;/p&gt;
&lt;p&gt;保护模式有一些新的特性，如存储器保护，标签页系统以及硬件支持的虚拟内存，能够增强多任务处理和系统稳定度。&lt;/p&gt;
&lt;p&gt;现今大部分的 x86 操作系统都在保护模式下运行，包含 Linux、FreeBSD、以及微软 Windows 2.0 和之后版本。&lt;/p&gt;
&lt;p&gt;在纯 DOS 方式（实模式）下，可以不理会 DOS，直接用汇编语言去操作真实的硬件。&lt;/p&gt;
&lt;p&gt;因为运行在 CPU 实模式下的 DOS，没有能力对硬件系统进行全面、严格的管理。&lt;/p&gt;
&lt;p&gt;但在 Windows 2000、Unix 这些运行于 CPU 保护模式下的操作系统中，不理会操作系统，用汇编语言去操作真实的硬件，是根本不可能的。硬件已被这些操作系统利用 CPU 保护模式所提供的功能全面而严格地管理了。&lt;/p&gt;
&lt;h2 id=&#34;mul-与-div&#34;&gt;Mul 与 Div&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;mul bl ; al * bl =&amp;gt; ax&lt;/li&gt;
&lt;li&gt;mul bx ; ax * bx =&amp;gt; dx(H) ax(L)&lt;/li&gt;
&lt;li&gt;div bl ; ax / bl =&amp;gt; ah(余) al(商)&lt;/li&gt;
&lt;li&gt;div bx ; dx(H) ax(L) / bx =&amp;gt; dx(余) ax(商)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;有符号和无符号比较&#34;&gt;有符号和无符号比较&lt;/h2&gt;
&lt;p&gt;cmp:&lt;/p&gt;
&lt;p&gt;无符号比较：&lt;/p&gt;
&lt;p&gt;JA JB JNAE: above | below | equal | not&lt;/p&gt;
&lt;p&gt;有符号比较：&lt;/p&gt;
&lt;p&gt;JG JL JNGE: great | low | equal | not&lt;/p&gt;
&lt;p&gt;如果是立即数的比较，cmp 不会识别是 8 位还是 16 位。如果通过 &lt;code&gt;word ptr&lt;/code&gt; 或 &lt;code&gt;byte ptr&lt;/code&gt; 进行指定：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;cmp byte ptr[di], 55h
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;标志位&#34;&gt;标志位&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;OF overflow，溢出标志，针对有符号数，1 =&amp;gt; 溢出&lt;/li&gt;
&lt;li&gt;DF direction，方向标志，控制数据串操作指令的步进方向，1 =&amp;gt; 递减&lt;/li&gt;
&lt;li&gt;IF interupt，中断允许标志，1 =&amp;gt; 开中断&lt;/li&gt;
&lt;li&gt;TF trap，陷阱标志，1 =&amp;gt; CPU 单步执行指令（程序调试）&lt;/li&gt;
&lt;li&gt;SF sign，符号标志，最高位为 0/1&lt;/li&gt;
&lt;li&gt;ZF zero，零标志，1 =&amp;gt; 结果为零&lt;/li&gt;
&lt;li&gt;AF auxiliary carry，辅助进位标志，供 BCD 码使用，1 =&amp;gt; D3 位出现进位或借位&lt;/li&gt;
&lt;li&gt;PF parity，奇偶标志，1 =&amp;gt; 有偶个“1”出现&lt;/li&gt;
&lt;li&gt;CF carry，进位标志，针对无符号数，1 =&amp;gt; 进位&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;in-和-out&#34;&gt;In 和 Out&lt;/h2&gt;
&lt;p&gt;在 in 和 out 指令中，只能使用 ax 或 al 来存放从端口中读入的数据或要发送到端口中的数据。&lt;/p&gt;
&lt;p&gt;访问 8 位端口时用al，访问 16 位端口时用 ax。&lt;/p&gt;
&lt;p&gt;对 0~255 以内的端口进行读写时：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;in al, 20h ; 从 20h 端口读入一个字节
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;out 20h, al ; 往 20h 端口写入一个字节
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对 256~65535 的端口进行读写时，端口号放在 dx 中：（超出 8 位的接口地址必须用 dx 提供）&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;mov dx, 3f8h ; 将端口号 3f8h 送入dx
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;in al, dx ; 从 3f8h 端口读入一个字节
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;out dx, al ; 向 3f8h 端口写入一个字节
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;问题&#34;&gt;问题&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;向内存 0:200~0:23F 依次传送 0~63(3FH)：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;注意 0:200~0:23F 等同于 0020:0~0020:3f，它们描述的是同一内存单元。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;assume cs:code
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;code segment
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    mov  bx, 20h
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    mov  ds, bx
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    mov  bx, 0
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    mov  cx, 40h
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;  s:mov  [bx], bx
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    inc  bx
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    loop s
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    mov  ax, 4c00h
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    int  21h
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;code ends
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将 &lt;code&gt;mov ax, 4c00h&lt;/code&gt; 之前的指令复制到内存 0:200 处：&lt;/p&gt;
&lt;p&gt;CX寄存器在debug调试一个可执行程序时，初始值为该程序的字节尺寸大小，要复制 &lt;code&gt;mov ax, 4c00h&lt;/code&gt; 之前的指令，需要减去 &lt;code&gt;mov ax,4c00h&lt;/code&gt; 和 &lt;code&gt;int 21h&lt;/code&gt; 包含的 5 个字节。而由于程序指令的起始地址由 CS:IP 指定，所以将 ds 赋值为 cs。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;assume cs:code
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;code segment
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    mov ax, cs ; 程序指令的起始地址由CS:IP指定
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    mov ds, ax
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    mov ax, 0020h
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;    mov es, ax
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;    mov bx, 0
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    sub cx, 5 ; 减去5个字节 mov ax, 4c00h 和 int 21h
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;  s:mov al, [bx]
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    mov es:[bx], al
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;    inc bx
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    loop s
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    mov ax, 4c00h
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;    int 21h
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;code ends
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;实践-自旋锁&#34;&gt;实践: 自旋锁&lt;/h2&gt;
&lt;p&gt;自旋锁，顾名思义，即自己不断旋转重复进行的锁，当多个线程访问同一资源时，为实现互斥访问，必须给目标资源加锁，此时只允许一个线程访问，此时其他线程无法访问，并且一直重复请求访问，直到该锁被释放。访问完资源的线程及时释放锁以供其他资源访问。&lt;/p&gt;
&lt;p&gt;自旋锁可以通过比较替换算法实现：设锁为1时被占用，为0时空闲。当一个线程请求锁时，即进入请求锁循环“spinlock”，设预期值为 0，修改值为 1，让锁值与预期值比较，若锁值等于预期值，则锁空闲，将锁值置为修改值，退出 spinlock 循环；若锁值不等于预期值，则证明锁被占用，继续 spinlock 循环。&lt;/p&gt;
&lt;p&gt;为验证是否成功实现自旋，开启一个释放锁线程，请求锁线程自旋一段时间后，释放锁线程进行锁的释放，即把锁值置为预期值0。此时，请求锁线程成功获得锁并退出 spinlock 循环。&lt;/p&gt;
&lt;p&gt;下面使用 x86_64 汇编实现自旋锁。&lt;/p&gt;
&lt;h3 id=&#34;intel-语法&#34;&gt;Intel 语法&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 尝试获取锁
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;lock&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; c &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    printf&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;try to get lock...&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    __asm__&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;push rax &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;push rcx &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;spin_lock: &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;mov rcx, %[c] &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;mov rax, %[a] &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 比较并替换算法，若p==rax==0则获得锁并使p=rcx(==1)，若p(==1)!=rax则进入自旋。
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;lock cmpxchg %[p], rcx &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;jne spin_lock &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;pop rcx &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;pop rax &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;+m&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;a&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;a&lt;span style=&#34;color:#eceff4&#34;&gt;),&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;c&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;c&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;rcx&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;rax&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 释放锁
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;unlock&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;    __asm__&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;mov %[p], 0; &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;+m&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;att-语法&#34;&gt;AT&amp;amp;T 语法&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;lock&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; c &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;    printf&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;try to get lock...&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;    __asm__&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;pushq %%rax &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;pushq %%rcx &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;spin_lock: &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;movq %1, %%rcx &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;movq %2, %%rax &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;lock cmpxchg %%rcx, %0 &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;jne spin_lock &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;popq %%rcx &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;popq %%rax &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;+m&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;c&lt;span style=&#34;color:#eceff4&#34;&gt;),&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;a&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;%rcx&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;%rax&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;unlock&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;    __asm__&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;movq $0, %0; &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;+r&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;测试自旋锁&#34;&gt;测试自旋锁&lt;/h3&gt;
&lt;p&gt;初始化锁值为 1，主线程尝试获取锁，进入自旋，子线程在一段时间后释放锁，锁值置为 0，接着，主线程获得锁并把锁置为 1。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;&lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;&amp;lt;pthread.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;&lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;&lt;span style=&#34;color:#5e81ac;font-style:italic&#34;&gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// intel语法实现自旋锁 &amp;gt; gcc -pthread -masm=intel -o s spinlock.c
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 尝试获取锁
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;lock&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; c &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    printf&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;try to get lock...&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;    __asm__&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;push rax &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;push rcx &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;spin_lock: &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;mov rcx, %[c] &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;mov rax, %[a] &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 比较并替换算法，若p==rax==0则获得锁并使p=rcx(==1)，若p(==1)!=rax则进入自旋。
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;lock cmpxchg %[p], rcx &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;jne spin_lock &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;pop rcx &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;pop rax &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;+m&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;a&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;a&lt;span style=&#34;color:#eceff4&#34;&gt;),&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;c&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;c&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;rcx&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;rax&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 释放锁
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;unlock&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;    __asm__&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;29&lt;/span&gt;        &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;mov %[p], 0; &lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;30&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;+m&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;31&lt;/span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;32&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;33&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;34&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 释放锁线程
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;35&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;mythread&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; args&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;36&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; p &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; args&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;37&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 推迟释放锁，此时自旋在进行中
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;38&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    sleep&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;39&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 释放锁
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;40&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    unlock&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;41&lt;/span&gt;    printf&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;after unlock: %ld&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;42&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;43&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;44&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;45&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 设刚开始锁已被获取
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;46&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;long&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&lt;/span&gt;a&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;47&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 开启一个用于释放锁的线程
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;48&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    pthread_t t1&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;49&lt;/span&gt;    pthread_create&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;amp;&lt;/span&gt;t1&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;NULL&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; mythread&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;50&lt;/span&gt;    printf&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;before lock: %ld&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;51&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// 主线程尝试获取
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;52&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;&lt;/span&gt;    lock&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;53&lt;/span&gt;    pthread_join&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;t1&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;NULL&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;    
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;54&lt;/span&gt;    printf&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;after lock: %ld&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;p&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;55&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;56&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里采用 intel 语法编写的自旋锁进行测试，执行命令 &lt;code&gt;gcc -pthread -masm=intel -o s spinlock.c&lt;/code&gt; 进行编译。&lt;/p&gt;
&lt;p&gt;若采用 AT&amp;amp;T，执行命令 &lt;code&gt;gcc -pthread -o s spinlock.c&lt;/code&gt; 进行编译，无需 &lt;code&gt;-masm=intel&lt;/code&gt;，因为 gcc 底层默认采用 AT&amp;amp;T。&lt;/p&gt;
&lt;h3 id=&#34;运行结果&#34;&gt;运行结果&lt;/h3&gt;
&lt;p&gt;运行结果如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;before &lt;span style=&#34;color:#8fbcbb&#34;&gt;lock&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;try to get lock&lt;span style=&#34;color:#eceff4&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;after &lt;span style=&#34;color:#8fbcbb&#34;&gt;unlock&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;after &lt;span style=&#34;color:#8fbcbb&#34;&gt;lock&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一开始锁值为 1，请求锁线程（即主线程）请求获得锁，进入自旋。2s 后释放锁线程进行锁的释放，接着请求锁线程成功获得锁，锁值又被置为 1，成功实现自旋与锁的释放。&lt;/p&gt;
&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;维基百科&lt;/li&gt;
&lt;li&gt;王爽《汇编语言》&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>作为忍者狼的战斗记忆</title>
        <link>https://zhihang.org/posts/sekiro-battle-memory/</link>
        <pubDate>Mon, 15 Aug 2022 16:11:17 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>sekiro-battle-memory</guid>
        <description>&lt;p&gt;在这篇博客记录下沉浸在只狼的世界中的那段时光里，让我印象深刻的一些地方。&lt;/p&gt;
&lt;p&gt;我在只狼中一共经历了六次轮回，在六周目下以双难模式通关，也击败了 DLC 狼心中的所有头目。只狼流程不长，算是一部小而美的作品，在我心中，它是一部精美的艺术品，值得反复游玩。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/sekiro-battle-memory/image/1.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;这是白雪覆盖之下的苇名城，颇具美感。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;第一个感觉难缠的 BOSS 是赤鬼，但凡多贪一刀就很容易被抓住干掉，同时如果不知道红眼怪怕火这个特点，那么只能跟它一来一回磨血量了。&lt;/p&gt;
&lt;p&gt;后面双难模式下打赤鬼，虽然被抓到就是秒杀，但是知道使用火刀了，所以可以轻松拿下。和赤鬼的战斗十分刺激，也十分绝望，当时花了不少时间，在一次又一次的死亡中，吸取教训，提高熟练度，最终战胜强敌。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;之后打完赤鬼往前走，在悬崖峭壁之间，我初遇白蛇，开始真正被这个游戏所吸引：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/sekiro-battle-memory/image/2.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;这是一条巨大无比的白蛇，据考证应该是一条双头蛇，要么就是有两条这样的蛇，因为后期忍杀了一条后，还能发现在洞窟里发现另一个蛇头在动。它曾经是当地人信仰的白蛇神。遇见这条蛇时，我欣赏了许久（也挂了不少次），颇有趣味，感觉来到了一个奇异的世界。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;对战义父，父慈子孝。选择了保护神子，坚持自己的信念，就必须和义父反目成仇。此时的天守阁正是黄昏时刻，一场艰苦卓绝的战斗即将开始：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/sekiro-battle-memory/image/3.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;这是一场无比艰难的战斗。义父的攻击时快时慢，各种招数层出不穷。他的韧性很高，想把他逼入绝境，必须不断地进攻。&lt;/p&gt;
&lt;p&gt;最后，狼是从背后忍杀了义父，留下一句“落影，物归原主”，取回落樱。而同时也是狼还给义父的一刀，还的是三年前义父背刺狼的那一刀。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;在前往狮子猿所在地的路上，悬崖绝壁之间，筑有许多巨大佛雕，额外有意思，也令人生畏：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/sekiro-battle-memory/image/4.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/sekiro-battle-memory/image/5.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;置身源之宫，如梦如画。满湖落樱，清水如镜。第一次来时的确感觉来到了世外桃源。但是后来慢慢深入内部，才发现这华美的景象背后潜藏着多么丑陋的东西&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/sekiro-battle-memory/image/6.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;初见樱龙，气势凌人，这虽然只是一场表演战，但是还是特别有意思。第一次见的时候完全被樱龙的气势震撼到：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/sekiro-battle-memory/image/7.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;拿到龙泪后，便回到苇名城，准备最后的对决了。此时的苇名城已经混乱不堪，战斗愈演愈烈。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;最后对战剑圣苇名一心。它无疑是只狼中难度仅次于怨恨之鬼的 BOSS 了。但在一周目时感觉和义父也五五开吧，在双难模式下就比义父难多了。&lt;/p&gt;
&lt;p&gt;第一次遇见一心，很难不为他的剑圣风范所震慑到：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/sekiro-battle-memory/image/8.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;最后作为介错人处死一心，也能感受到他无比的剑圣气质。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;在三周目尝试堕为修罗，这的确算是是最坏的结局，狼最后甚至把义父也杀了&amp;hellip;&amp;hellip;在高周目玩了一次这个结局，感觉没有动力再玩一次修罗结局了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/sekiro-battle-memory/image/9.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;于火光中结束一切&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;个人最满意的结局，也是官方指定结局，龙之还乡：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/sekiro-battle-memory/image/10.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;狼和皇子都活了下来，和神子一道前往西方，送还樱龙，断绝不死之诅咒，走向新的征程：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/sekiro-battle-memory/image/11.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;到此结束。感谢 FS 社给我带来的这一段珍贵的经历！&lt;/p&gt;
</description>
      </item>
      
    
      
    
      
    
      
      <item>
        <title>挪威的森林与披头士</title>
        <link>https://zhihang.org/posts/the-beatles-in-norwegian-forest/</link>
        <pubDate>Sat, 14 May 2022 11:47:43 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>the-beatles-in-norwegian-forest</guid>
        <description>&lt;blockquote&gt;
&lt;p&gt;飞机一着陆，禁烟显示牌倏然消失，天花板扩音器中低声流出背景音乐，那是一个管弦乐队自鸣得意地演奏的甲壳虫乐队的《挪威的森林》。那旋律一如往日地使我难以自已，不，比往日还要强烈地摇撼着我的身心。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;《挪威的森林》—— &lt;em&gt;Norwegian Wood&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;她一边这样说着，一边弹起《米歇尔》，弹得极其精彩。
“好曲子，我，无比喜欢！”说完，玲子喝了一口葡萄酒，吸了口烟，“简直就像霏霏细雨轻轻洒在无边无际的草原。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;《米歇尔》—— &lt;em&gt;Michelle&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;接着，她弹了《没有归宿的人》，弹了《朱丽娅》。有时边弹边闭上眼摇着头，然后又呷口酒吸口烟。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;《没有归宿的人》—— &lt;em&gt;Nowhere Man&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;《朱丽娅》—— &lt;em&gt;Julia&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;店里的女孩说，如果肯弹甲壳虫乐队的《太阳从这里升起》，冷藏牛奶可算店里请客。玲子伸出拇指，做出OK的表示，随即边哼歌词边弹《太阳从这里升起》。音量并不大，而且大概由于过度吸烟的关系，嗓音有些沙哑，但很有厚度，娓娓动人。我喝着啤酒，望着远山，耳听她的歌声，恍惚觉得太阳会再次从那里探出脸来，那心境实在太温馨、太平和了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;《太阳从这里升起》—— &lt;em&gt;Here Comes The Sun&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;“我也喜爱，非常委婉感人。”她又轻轻弹了几小节《宝贝儿》的旋律，呷了口葡萄酒。“喝醉之前能弹上几首呢。嗯，这样的葬礼不凄凉，还可以吧？”
玲子转向甲壳虫。弹了《挪威的森林》，弹了《昨日》，弹了《米歇尔》，弹了《有一件事》，边唱边弹了《太阳从这里升起》，弹了《山峰上的傻子》。我排出了七根火柴。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;《昨日》—— &lt;em&gt;Yesterday&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;《有一件事》—— &lt;em&gt;Something&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;《山峰上的傻子》—— &lt;em&gt;The Fool On The Hill&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;“七首，”玲子说着，呷口酒，吸口烟。“这几个人对人生的伤感和温情确实深有体会啊。”
这几个人当然是Ｊ．列农、Ｐ．麦卡特尼，加上Ｇ．哈里森。
她换了口气，熄掉烟，又抱起吉他。弹了《细雨》，弹了《黑鸟》，弹了《朱莉娅》，弹了《年届六十四》，弹了《没有归宿的人》，弹了《而且我爱她》，弹了《喂，乔德》。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;《细雨》—— &lt;em&gt;Penny Lane&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;《黑鸟》—— &lt;em&gt;Black Bird&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;《年届六十四》—— &lt;em&gt;When I&amp;rsquo;m Sixty Four&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;《而且我爱她》—— &lt;em&gt;And I Love Her&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;《喂，乔德》—— &lt;em&gt;Hey, Jude&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;我放上唱片，第一张听完便把唱针移到第二张。全部听完之后，又从头听起。唱片只有六张。第一张是《佩珀军士寂寞的心俱乐部乐队》，最后是比尔·埃文斯的《献给黛比的华尔兹》。窗外雨下个不停，时间缓缓流逝，直子一个人絮絮不止。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;《佩珀军士寂寞的心俱乐部乐队》—— &lt;em&gt;Sgt. Pepper&amp;rsquo;s Lonely Hearts Club Band&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      </item>
      
    
      
      <item>
        <title>山脉游览录</title>
        <link>https://zhihang.org/posts/mountain-tour/</link>
        <pubDate>Mon, 21 Mar 2022 18:02:04 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>mountain-tour</guid>
        <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;每一座山都有独特的感觉，每一座山都有自己的故事。&lt;/p&gt;
&lt;h2 id=&#34;圭峰山&#34;&gt;圭峰山&lt;/h2&gt;
&lt;p&gt;攀登于二三年四月份。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/1701872421726.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;圭峰山属于秦岭支脉，海拔 1528 米，因其外形就像汉字“圭”，故得名圭峰山。此山有“天上一轮月，圭峰十二圆”的美誉，范仲淹曾在此处饮酒赏月，“圭峰明月”为鄠邑八大景之一。&lt;/p&gt;
&lt;p&gt;此次登山印象很深刻。圭峰山是一座自然山，途中没有任何台阶，攀登过程较为艰难。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/1701872120557.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;山顶上有一座小庙，空旷的蓝天和茂密的绿叶相得益彰。&lt;/p&gt;
&lt;h2 id=&#34;翠华山&#34;&gt;翠华山&lt;/h2&gt;
&lt;p&gt;攀登于二二年二月冬日之时。&lt;/p&gt;
&lt;p&gt;翠华山系终南山的一个支峰，位于秦岭北麓，主峰终南山海拔 2604 米。因汉武帝曾在这里祭祀过太乙神，故又名太乙山。山腰有翠华庙，内供翠华姑娘塑像。民间传说翠华姑娘为争取自由婚姻，逃奔这里，后来成仙而去，此山便得名翠华山。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/9.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;寒假时前去游览，这也是我第一次爬雪山。由于是淡季，山上很安静，只能听见风的声音，以及细碎的脚步声。此时，一只孤独的鸟飞了过去。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/11.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;步行至天池附近，仿佛进入了画中世界，在这里驻足观赏许久才肯离去。&lt;/p&gt;
&lt;h2 id=&#34;南五台&#34;&gt;南五台&lt;/h2&gt;
&lt;p&gt;攀登于二一年十月秋日之时。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/1701872712280.png&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;南五台为秦岭终南山中段的一个支脉，海拔 1688 米。因山上有清凉、文殊、舍身、灵应、观音五个台，故名五台山。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/1.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;蓝天白云，清风拂面，一切都很好。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/2.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;百二邱田&#34;&gt;百二邱田&lt;/h2&gt;
&lt;p&gt;攀登数次，也曾骑行上山。&lt;/p&gt;
&lt;p&gt;山中的藏莲寺历史悠久，创建于明朝隆庆四年，距今已有 430 多年。建有慈悲娘殿、三圣殿、地藏阁、珍秀阁、半天娘殿、南天门伯公庙等宗教建筑。&lt;/p&gt;
&lt;p&gt;这是一个清晨时的山顶，是一种朦胧而梦幻的感觉：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/3.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;这是一次雨后的山景，白云密密麻麻的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/4.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;h2 id=&#34;华山&#34;&gt;华山&lt;/h2&gt;
&lt;p&gt;攀登于二一年五月。&lt;/p&gt;
&lt;p&gt;华山，古称“西岳”，为五岳之一。南接秦岭山脉，北瞰黄渭，自古以来就有“奇险天下第一山”的说法。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/5.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;攀登后果真感受到了华山的险与奇。行至对弈亭，仿佛进入仙境：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/6.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;攀登之日风云突变，天气转阴，有点扫兴。幸运的是在山雨来临之前就登顶了，赶上了最后一班缆车下山。&lt;/p&gt;
&lt;h2 id=&#34;铁山&#34;&gt;铁山&lt;/h2&gt;
&lt;p&gt;曾攀登数次。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://zhihang.org/posts/mountain-tour/image/7.jpg&#34; loading=&#34;lazy&#34; alt=&#34;&#34;  /&gt;&lt;/p&gt;
&lt;p&gt;铁山，又名铁尖山、铁嶂。清乾隆十年《普宁县志》载：“铁山，以崖石俱作铁色，故名”。&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;持续更新本文中&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;强风吹拂，步履不停。呐，你喜欢登山吗？&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>开发工具重要使用记录</title>
        <link>https://zhihang.org/posts/important-configuration-and-usage-records-of-development-tools/</link>
        <pubDate>Sun, 17 Jan 2021 21:46:42 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>important-configuration-and-usage-records-of-development-tools</guid>
        <description>&lt;h2 id=&#34;toc&#34;&gt;TOC&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#toc&#34;&gt;TOC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#vscode&#34;&gt;VSCode&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#nginx-%E5%B5%8C%E5%A5%97%E9%97%AE%E9%A2%98&#34;&gt;Nginx 嵌套问题&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#code-%E5%91%BD%E4%BB%A4&#34;&gt;Code 命令&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%87%AA%E5%8A%A8%E6%8D%A2%E8%A1%8C%E8%A7%84%E5%88%99&#34;&gt;配置文件自动换行规则&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%BD%93%E5%89%8D%E5%B7%A5%E4%BD%9C%E5%8C%BA%E4%B8%8D%E6%98%BE%E7%A4%BA-gitignore-%E4%B8%AD%E5%BF%BD%E7%95%A5%E7%9A%84%E6%96%87%E4%BB%B6&#34;&gt;当前工作区不显示 .gitignore 中忽略的文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8D%95%E5%87%BB%E6%96%87%E4%BB%B6%E5%9C%A8%E6%96%B0%E6%A0%87%E7%AD%BE%E9%A1%B5%E6%89%93%E5%BC%80&#34;&gt;单击文件在新标签页打开&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BD%BF%E7%94%A8%E5%A4%9A%E6%A0%87%E7%AD%BE%E6%A8%A1%E5%BC%8F&#34;&gt;使用多标签模式&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#tabs-%E5%A4%9A%E8%A1%8C%E6%A8%A1%E5%BC%8F&#34;&gt;tabs 多行模式&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#idea&#34;&gt;IDEA&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E6%B3%A8%E9%87%8A&#34;&gt;自动生成注释&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BD%BF%E7%94%A8-n-%E4%BD%9C%E4%B8%BA%E6%8D%A2%E8%A1%8C%E7%AC%A6&#34;&gt;使用 \n 作为换行符&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BD%BF%E7%94%A8-tab-%E7%BC%A9%E8%BF%9B&#34;&gt;使用 tab 缩进&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%8E%A7%E5%88%B6%E5%8F%B0%E4%B8%AD%E6%96%87%E4%B9%B1%E7%A0%81%E8%A7%A3%E5%86%B3&#34;&gt;控制台中文乱码解决&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#idea-%E5%BC%80%E5%90%AFrundashboard&#34;&gt;IDEA 开启RunDashboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#idea-%E5%85%B3%E9%97%AD%E6%8B%BC%E5%86%99&#34;&gt;IDEA 关闭拼写&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#idea-%E9%85%8D%E7%BD%AE%E5%BF%AB%E6%8D%B7%E8%BE%93%E5%85%A5&#34;&gt;IDEA 配置快捷输入&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#idea-%E5%B8%B8%E7%94%A8%E5%BF%AB%E6%8D%B7%E9%94%AE&#34;&gt;IDEA 常用快捷键&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%A6%81%E7%94%A8-double-shift&#34;&gt;禁用 double shift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%BF%BD%E7%95%A5%E6%96%87%E4%BB%B6%E6%88%96%E7%9B%AE%E5%BD%95&#34;&gt;忽略文件或目录&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%8D%95%E5%87%BB%E6%96%87%E4%BB%B6%E4%B8%8D%E8%A6%81%E5%9C%A8%E6%96%B0%E6%A0%87%E7%AD%BE%E9%A1%B5%E6%89%93%E5%BC%80&#34;&gt;单击文件不要在新标签页打开&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;vscode&#34;&gt;VSCode&lt;/h2&gt;
&lt;h3 id=&#34;nginx-嵌套问题&#34;&gt;Nginx 嵌套问题&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;不支持嵌套 IF&lt;/li&gt;
&lt;li&gt;嵌套的 Location 不会应用外层 IF，但是 root、index、add_header 可以应用&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;code-命令&#34;&gt;Code 命令&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;command&lt;/span&gt; palette -&amp;gt; shell &lt;span style=&#34;color:#81a1c1&#34;&gt;command&lt;/span&gt; -&amp;gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;select&lt;/span&gt;: install &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;code&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;command&lt;/span&gt; in PATH
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;配置文件自动换行规则&#34;&gt;配置文件自动换行规则&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;editor.wordWrap&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;off&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;快速变换：cmd -&amp;gt; wordWrap -&amp;gt; toggle&lt;/p&gt;
&lt;p&gt;单独配置 markdown 自动换行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;[markdown]&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;editor.wordWrap&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;on&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#bf616a&#34;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;当前工作区不显示-gitignore-中忽略的文件&#34;&gt;当前工作区不显示 .gitignore 中忽略的文件&lt;/h3&gt;
&lt;p&gt;编辑: &lt;code&gt;.vscode/settings.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#34;explorer.excludeGitIgnore&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;单击文件在新标签页打开&#34;&gt;单击文件在新标签页打开&lt;/h3&gt;
&lt;p&gt;单击文件在新标签页打开 &lt;code&gt;workbench.editor.enablePreview&lt;/code&gt; 为 false&lt;/p&gt;
&lt;h3 id=&#34;使用多标签模式&#34;&gt;使用多标签模式&lt;/h3&gt;
&lt;p&gt;Windows -&amp;gt; Native Tabs [v]&lt;/p&gt;
&lt;h3 id=&#34;tabs-多行模式&#34;&gt;tabs 多行模式&lt;/h3&gt;
&lt;p&gt;workbench.editor.wrapTabs [v]&lt;/p&gt;
&lt;h2 id=&#34;idea&#34;&gt;IDEA&lt;/h2&gt;
&lt;h3 id=&#34;自动生成注释&#34;&gt;自动生成注释&lt;/h3&gt;
&lt;p&gt;File | Settings | Editor | File and Code Templates | Includes&lt;/p&gt;
&lt;p&gt;Add File Header:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;/**
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt; * @Author jiangzhh
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt; * @Description: 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt; * @Date: Create in ${TIME} ${DATE}
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt; */
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;使用-n-作为换行符&#34;&gt;使用 \n 作为换行符&lt;/h3&gt;
&lt;p&gt;Editor | Code Style.&lt;/p&gt;
&lt;p&gt;From the Line separator list, select the line separator style you want to apply.&lt;/p&gt;
&lt;p&gt;选择 Unix and macOS (\n)。&lt;/p&gt;
&lt;h3 id=&#34;使用-tab-缩进&#34;&gt;使用 tab 缩进&lt;/h3&gt;
&lt;p&gt;根据阿里巴巴 Java 开发手册：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;【强制】采用 4 个空格缩进，禁止使用 tab 字符。&lt;/p&gt;
&lt;p&gt;说明：如果使用 tab 缩进，必须设置 1 个 tab 为 4 个空格。IDEA 设置 tab 为 4 个空格时，请勿勾选 Use tab character；而在 eclipse 中，必须勾选 insert spaces for tabs。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Uncheck:&lt;/p&gt;
&lt;p&gt;File &amp;gt; Settings &amp;gt; Editor &amp;gt; Code Style &amp;gt; Java &amp;gt; Tabs and Indents &amp;gt; Use tab character&lt;/p&gt;
&lt;h3 id=&#34;控制台中文乱码解决&#34;&gt;控制台中文乱码解决&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;菜单栏HELP-&amp;gt;Edit Custom VM OPtions中加 &lt;code&gt;-Dfile.encoding=utf-8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;重启idea&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;idea-开启rundashboard&#34;&gt;IDEA 开启RunDashboard&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;# .idea/workspace.xml
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;component&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;RunDashboard&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;option&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;configurationTypes&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;set&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;            &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;option&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;SpringBootApplicationConfigurationType&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/set&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;/component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;idea-关闭拼写&#34;&gt;IDEA 关闭拼写&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;Settings -&amp;gt; Editor -&amp;gt; Inspection -&amp;gt; Proofreading -&amp;gt; 关闭Typo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;idea-配置快捷输入&#34;&gt;IDEA 配置快捷输入&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;editor -&amp;gt; live template
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;idea-常用快捷键&#34;&gt;IDEA 常用快捷键&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;alt + 上下键：将当前行移到上或下一层
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;alt + 左右键：代码阅读必备，回到上或下一层代码
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;禁用-double-shift&#34;&gt;禁用 double shift&lt;/h3&gt;
&lt;p&gt;对于2021.2.2之前的版本，方法如下：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Ctrl+Shift+A&lt;/code&gt; (Mac下为 &lt;code&gt;Comand+Shift+A&lt;/code&gt;) =&amp;gt; 输入 &lt;code&gt;Registry&lt;/code&gt; =&amp;gt; 找到 &lt;code&gt;&amp;quot;ide.suppress.double.click.handler&amp;quot;&lt;/code&gt; 并勾选，再 Apply 即可。&lt;/p&gt;
&lt;p&gt;对于2021.2.2及之后的版本，可以这么做：&lt;/p&gt;
&lt;p&gt;菜单栏依次点击 File =&amp;gt; Settings =&amp;gt; Advanced Settings =&amp;gt; User Interface =&amp;gt; 勾选 &lt;code&gt;&amp;quot;Disable double modifier key shortcuts&amp;quot;&lt;/code&gt;，或者打开设置之后搜索 disable，可快速定位。&lt;/p&gt;
&lt;h3 id=&#34;忽略文件或目录&#34;&gt;忽略文件或目录&lt;/h3&gt;
&lt;p&gt;忽略文件或目录：&lt;/p&gt;
&lt;p&gt;Editor -&amp;gt; File Types -&amp;gt; Ignored Files And Folders&lt;/p&gt;
&lt;p&gt;忽略目录，并可以方便的显示和隐藏：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;隐藏：右键目录，Mark Directory As -&amp;gt; Excluded&lt;/li&gt;
&lt;li&gt;显示：右键Projects左侧空白处，Tree Apperance -&amp;gt; Show Excluded Files&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;单击文件不要在新标签页打开&#34;&gt;单击文件不要在新标签页打开&lt;/h3&gt;
&lt;p&gt;Editor - General - Editor Tabs - Opening Policy - Enable preview tabs [v]&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>Matlab 重要用法整理</title>
        <link>https://zhihang.org/posts/basic-usage-sorting-of-matlab/</link>
        <pubDate>Thu, 06 Feb 2020 20:41:12 +0800</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>basic-usage-sorting-of-matlab</guid>
        <description>&lt;h2 id=&#34;目录&#34;&gt;目录&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%9B%AE%E5%BD%95&#34;&gt;目录&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95&#34;&gt;基本语法&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%8F%90%E5%8F%96%E7%9F%A9%E9%98%B5%E6%9F%90%E8%A1%8C%E6%88%96%E6%9F%90%E5%88%97&#34;&gt;提取矩阵某行或某列&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%8E%B7%E5%8F%96%E9%9A%8F%E6%9C%BA%E6%95%B0&#34;&gt;获取随机数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%9D%E5%A7%8B%E5%8C%96%E6%95%B0%E7%BB%84&#34;&gt;初始化数组&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%8E%A7%E5%88%B6%E8%AF%AD%E5%8F%A5&#34;&gt;控制语句&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%A0%BC%E5%BC%8F%E5%8C%96%E8%BE%93%E5%87%BA&#34;&gt;格式化输出&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%88%9D%E7%AD%89%E6%95%B0%E5%AD%A6&#34;&gt;初等数学&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B1%82%E8%A7%A3%E6%96%B9%E7%A8%8B%E7%BB%84&#34;&gt;求解方程组&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B1%82%E5%B9%B3%E5%9D%87%E5%80%BC%E4%B8%AD%E5%80%BC%E4%B8%8E%E6%A0%87%E5%87%86%E5%B7%AE&#34;&gt;求平均值，中值与标准差&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%A7%A3%E4%B8%80%E9%98%B6%E5%AF%BC%E6%95%B0%E6%96%B9%E7%A8%8B&#34;&gt;解一阶导数方程&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%9F%BA%E7%A1%80%E7%BB%98%E5%9B%BE&#34;&gt;基础绘图&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BB%98%E5%88%B6%E4%BA%8C%E7%BB%B4%E5%9B%BE&#34;&gt;绘制二维图&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BB%98%E5%88%B6%E4%B8%89%E7%BB%B4%E5%9B%BE&#34;&gt;绘制三维图&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BB%98%E5%88%B6%E7%AD%89%E9%AB%98%E7%BA%BF&#34;&gt;绘制等高线&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E9%AB%98%E7%AD%89%E6%95%B0%E5%AD%A6&#34;&gt;高等数学&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B3%B0%E5%8B%92%E7%BA%A7%E6%95%B0%E7%AC%ACn%E9%A1%B9%E5%B1%95%E5%BC%80&#34;&gt;泰勒级数第n项展开&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E7%BA%BF%E6%80%A7%E4%BB%A3%E6%95%B0&#34;&gt;线性代数&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B1%82%E6%9E%81%E5%A4%A7%E7%BA%BF%E6%80%A7%E6%97%A0%E5%85%B3%E7%BB%84&#34;&gt;求极大线性无关组&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B1%82-ax--0-%E5%9F%BA%E7%A1%80%E8%A7%A3%E7%B3%BB&#34;&gt;求 Ax = 0 基础解系&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E5%B7%A6%E9%99%A4%E4%B8%8E%E5%8F%B3%E9%99%A4&#34;&gt;左除与右除&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E6%B1%82-ax--b-%E7%89%B9%E8%A7%A3&#34;&gt;求 Ax = b 特解&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%AE%A1%E7%AE%97%E7%89%B9%E5%BE%81%E5%A4%9A%E9%A1%B9%E5%BC%8F%E5%8F%8A%E7%89%B9%E5%BE%81%E5%80%BC&#34;&gt;计算特征多项式及特征值&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%AE%A1%E7%AE%97%E7%89%B9%E5%BE%81%E5%80%BC%E7%9A%84%E7%AE%80%E6%98%93%E6%96%B9%E6%B3%95&#34;&gt;计算特征值的简易方法&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E8%AE%A1%E7%AE%97%E7%89%B9%E5%BE%81%E5%80%BC%E5%8F%8A%E5%AF%B9%E5%BA%94%E7%89%B9%E5%BE%81%E5%90%91%E9%87%8F&#34;&gt;计算特征值及对应特征向量&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4-eig-%E6%8A%8A%E4%BA%8C%E6%AC%A1%E5%9E%8B%E6%A0%87%E5%87%86%E5%8C%96&#34;&gt;使用命令 eig 把二次型标准化&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4-eig-%E5%88%A4%E6%96%AD%E4%BA%8C%E6%AC%A1%E5%9E%8B%E7%9A%84%E6%AD%A3%E5%AE%9A%E6%80%A7&#34;&gt;使用命令 eig 判断二次型的正定性&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4-orth-%E6%8A%8A%E5%90%91%E9%87%8F%E7%BB%84%E6%AD%A3%E4%BA%A4%E8%A7%84%E8%8C%83%E5%8C%96&#34;&gt;使用命令 orth 把向量组正交规范化&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;基本语法&#34;&gt;基本语法&lt;/h2&gt;
&lt;h3 id=&#34;提取矩阵某行或某列&#34;&gt;提取矩阵某行或某列&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;(:,&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;])&lt;/span&gt; 返回第 &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; 和第 &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt; 列
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;获取随机数&#34;&gt;获取随机数&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;randi&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;100&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;% 1 到 100 之间的随机整数&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;初始化数组&#34;&gt;初始化数组&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;zeros&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;30&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;% 1 行 30 列的全 0 数组&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;控制语句&#34;&gt;控制语句&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;100&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;j&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;...) &lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;          &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;else&lt;/span&gt; 
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;          &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;...&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;格式化输出&#34;&gt;格式化输出&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;fprintf&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&amp;#34;若选手选择改变，则成功次数为：&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;%d, 成功率为：%f\n&amp;#34;, count, count / SUM);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;初等数学&#34;&gt;初等数学&lt;/h2&gt;
&lt;h3 id=&#34;求解方程组&#34;&gt;求解方程组&lt;/h3&gt;
&lt;p&gt;注：solve 已经改版，不可传入字符串&lt;/p&gt;
&lt;p&gt;实例：求解二元一次方程&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;syms x y&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;s &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; x &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; y &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;t &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; x &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; y &lt;span style=&#34;color:#81a1c1&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;result &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; solve&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;s&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; t&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;求平均值中值与标准差&#34;&gt;求平均值，中值与标准差&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;A &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;12&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;13&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;7&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;18&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;16&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;21&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;9&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;];&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;A &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; sort&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;ave &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; mean&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;md &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; median&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;sigma &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; std&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;解一阶导数方程&#34;&gt;解一阶导数方程&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;syms x y&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;y &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.0283&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; x^&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0.7387&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; x &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;8.9191&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;my_x &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; solve&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;diff&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;y&lt;span style=&#34;color:#eceff4&#34;&gt;));&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;% diff(A)用于求导数&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;my_y &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; subs&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;y&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; x&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; my_x&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;% 当x=my_x时求y的值&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;fprintf&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&amp;#34;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;%.2f, %.2f)\n&amp;#34;, my_x, my_y);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;基础绘图&#34;&gt;基础绘图&lt;/h2&gt;
&lt;h3 id=&#34;绘制二维图&#34;&gt;绘制二维图&lt;/h3&gt;
&lt;p&gt;绘制二维图并设置x,y轴通过坐标原点&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;x &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2.5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;pi&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2.5&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;pi&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;];&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;y &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;];&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;y &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;cos&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;plot&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;y&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;ax &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; gca&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;ax&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;XAxisLocation &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;origin&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;ax&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;YAxisLocation &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;origin&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;绘制三维图&#34;&gt;绘制三维图&lt;/h3&gt;
&lt;p&gt;使用 mesh 或 surf，subplot 进行分区&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;x&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; y&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;meshgrid&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;z &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; x&lt;span style=&#34;color:#81a1c1&#34;&gt;.^&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; y&lt;span style=&#34;color:#81a1c1&#34;&gt;.^&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;subplot&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;surf&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; y&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; z&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;subplot&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;mesh&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;y&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;z&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;绘制等高线&#34;&gt;绘制等高线&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;x&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; y&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;meshgrid&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;z &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; x&lt;span style=&#34;color:#81a1c1&#34;&gt;.^&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;+&lt;/span&gt; y&lt;span style=&#34;color:#81a1c1&#34;&gt;.^&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;%z就是高度&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;contour&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;y&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;z&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;%绘制等高线&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;subplot&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;C&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;h&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; contour&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;y&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;z&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;ShowText&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;on&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;% [M,c] = contour(___) 返回等高线矩阵和等高线对象 c。&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;% 显示等高线图后，使用 c 设置属性。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;高等数学&#34;&gt;高等数学&lt;/h2&gt;
&lt;h3 id=&#34;泰勒级数第n项展开&#34;&gt;泰勒级数第n项展开&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;T &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; taylor&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;f&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; x&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;Order&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; n&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;线性代数&#34;&gt;线性代数&lt;/h2&gt;
&lt;h3 id=&#34;求极大线性无关组&#34;&gt;求极大线性无关组&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;A &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;R &lt;span style=&#34;color:#81a1c1&#34;&gt;j&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; rref&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;R &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;%主元所在列数&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;j&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;% 即得到极大线性无关组&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; M &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; A&lt;span style=&#34;color:#eceff4&#34;&gt;(:,[&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;])&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;M &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;26&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;27&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;28&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;求-ax--0-基础解系&#34;&gt;求 Ax = 0 基础解系&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;A &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;%求出最小有理数解&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; r &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; rank&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; X &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; null&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;X &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.1250&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.1250&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.6250&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;1.3750&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;1.0000&lt;/span&gt;         &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;         &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;1.0000&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;%求出规范正交基&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; X &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; null&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;X &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;22&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.1293&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.1052&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;23&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.3860&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.7386&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;24&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.9041&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.2092&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;25&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.1302&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.6322&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;左除与右除&#34;&gt;左除与右除&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;右除正斜杠： A &lt;span style=&#34;color:#81a1c1&#34;&gt;/&lt;/span&gt; B &lt;span style=&#34;color:#81a1c1&#34;&gt;-&amp;gt;&lt;/span&gt; A &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; inv&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;B&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;左除反斜杠： A &lt;span style=&#34;color:#81a1c1&#34;&gt;\&lt;/span&gt; B &lt;span style=&#34;color:#81a1c1&#34;&gt;-&amp;gt;&lt;/span&gt; inv&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; B
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;求-ax--b-特解&#34;&gt;求 Ax = b 特解&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;A非方阵时，无法利用x &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; A^&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; b
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;应该使用x &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; A &lt;span style=&#34;color:#81a1c1&#34;&gt;\&lt;/span&gt; b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;计算特征多项式及特征值&#34;&gt;计算特征多项式及特征值&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; A &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;A &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;6&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; f &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; poly&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;f &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;1.0000&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;8.0000&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;9.0000&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.0000&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; lamda &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; roots&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;f&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;lamda &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;9.0000&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1.0000&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.0000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;计算特征值的简易方法&#34;&gt;计算特征值的简易方法&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; eig&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;ans&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;5&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1.0000&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;6&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.0000&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;7&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;9.0000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;计算特征值及对应特征向量&#34;&gt;计算特征值及对应特征向量&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;Q&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; D&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; eig&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;Q &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.7071&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.5774&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.4082&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.7071&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.5774&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.4082&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;         &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.5774&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.8165&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;D &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1.0000&lt;/span&gt;         &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;         &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;         &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.0000&lt;/span&gt;         &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;         &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;         &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;9.0000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;使用命令-eig-把二次型标准化&#34;&gt;使用命令 eig 把二次型标准化&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;同上，由D可得标准型，由Q可得正交变换法。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;使用命令-eig-判断二次型的正定性&#34;&gt;使用命令 eig 判断二次型的正定性&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;1&lt;/span&gt;同上，观察D对角线元素正负性即可。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;使用命令-orth-把向量组正交规范化&#34;&gt;使用命令 orth 把向量组正交规范化&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 1&lt;/span&gt;A &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 2&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 3&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 4&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;9&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;5&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#b48ead&#34;&gt;8&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 5&lt;/span&gt;   
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 6&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; B &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt; orth&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;A&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 7&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 8&lt;/span&gt;B &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt; 9&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;10&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.2982&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.9545&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;11&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.9545&lt;/span&gt;   &lt;span style=&#34;color:#81a1c1&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0.2982&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;12&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;13&lt;/span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;%满足B * B&amp;#39; == eye(rank(A))&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;14&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; B &lt;span style=&#34;color:#81a1c1&#34;&gt;*&lt;/span&gt; B&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;#39;&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;16&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;17&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;ans&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;=&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;18&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;19&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;1.0000&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.0000&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;20&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;0.0000&lt;/span&gt;    &lt;span style=&#34;color:#b48ead&#34;&gt;1.0000&lt;/span&gt;
&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6c6f74&#34;&gt;21&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      </item>
      
    
      
      <item>
        <title>网站变更日志</title>
        <link>https://zhihang.org/posts/notification-2025-06-27/</link>
        <pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid>notification-2025-06-27</guid>
        <description>&lt;h2 id=&#34;20250627&#34;&gt;2025/06/27&lt;/h2&gt;
&lt;p&gt;原域名 &lt;a href=&#34;https://akynazh.site&#34;&gt;akynazh.site&lt;/a&gt; 将停用，改用 &lt;a href=&#34;https://zhihang.org&#34;&gt;zhihang.org&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;19700101&#34;&gt;1970/01/01&lt;/h2&gt;
&lt;p&gt;本文 Slug 基于更新日期动态变更，用于实现 RSS 通知。&lt;/p&gt;
</description>
      </item>
      
    
      
      <item>
        <title>About</title>
        <link>https://zhihang.org/about/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        <author>akynazh@gmail.com (zhihang)</author>
        <guid></guid>
        <description>&lt;p&gt;本站由 &lt;a href=&#34;https://github.com/gohugoio/hugo&#34;&gt;Hugo&lt;/a&gt; 驱动，通过 &lt;a href=&#34;https://nginx.org&#34;&gt;Nginx&lt;/a&gt; 部署在个人服务器上，主要记录计算机技术、个人生活和音乐相关内容。&lt;/p&gt;
&lt;p&gt;本人目前从事软件后端开发工作，业余时间有在进行软件开源相关工作，具体可以访问我的 &lt;a href=&#34;https://github.com/akynazh&#34;&gt;Github&lt;/a&gt;。我主要的爱好是弹琴和游泳，目前在练习弹奏巴赫的哥德堡变奏曲，睡前弹奏一遍咏叹调是我治疗失眠问题的好方法。&lt;/p&gt;
&lt;p&gt;如果你对我的博客文章有任何问题，欢迎沟通交流。&lt;/p&gt;
</description>
      </item>
      
    
  </channel>
</rss>