<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>chify</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://cfyong.com/</id>
  <link href="https://cfyong.com/" rel="alternate"/>
  <link href="https://cfyong.com/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, chify</rights>
  <subtitle>记录 Linux、Java、数据库和服务器运维的实践，分享开发工具、系统配置与问题排查经验。</subtitle>
  <title>chify's blog</title>
  <updated>2022-08-09T15:35:58.422Z</updated>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Java" scheme="https://cfyong.com/categories/Java/"/>
    <category term="Hadoop" scheme="https://cfyong.com/tags/Hadoop/"/>
    <category term="CentOS" scheme="https://cfyong.com/tags/CentOS/"/>
    <content>
      <![CDATA[<h1 id="一-服务器准备"><a href="#一-服务器准备" class="headerlink" title="一. 服务器准备"></a>一. 服务器准备</h1><p>VMware 里安装四台 CentOS 7，需要配置如下内容</p><ol><li>服务器开启开机自动联网和设置静态IP</li><li>修改主机名且配置 hosts 映射</li><li>关闭防火墙和 selinux</li><li>设置 4 台机器相互之间的 ssh 互信免密登陆</li></ol><h2 id="服务器开机自动联网和静态IP"><a href="#服务器开机自动联网和静态IP" class="headerlink" title="服务器开机自动联网和静态IP"></a>服务器开机自动联网和静态IP</h2><p>编辑网卡设备 <code>vi /etc/sysconfig/network-scripts/ifcfg-ens33</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 将 ONBOOT 设置为YES</span></span><br><span class="line">ONBOOT=YES</span><br><span class="line"><span class="comment"># 设置 Linux 静态 ip</span></span><br><span class="line">BOOTPROTO=static</span><br><span class="line">IPADDR=192.168.44.129 </span><br><span class="line">GATEWAY=192.168.44.2</span><br><span class="line">NETMASK=255.255.255.0</span><br><span class="line">DNS1=192.168.44.2</span><br><span class="line">DNS2=114.114.114.114</span><br><span class="line"><span class="comment"># 重启网卡</span></span><br><span class="line">systemctl restart network</span><br></pre></td></tr></table></figure><p>注：xshell 建立完连接后可能会卡在 <code>[To escape to local shell, press &#39;Ctrl+Alt+]&#39;]</code> 无法操作，通过以下方式可解决此问题：<code>vi /etc/ssh/sshd_config</code>，找到 <code>UseDNS yes</code> 修改为 <code>UseDNS no</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 重启sshd</span></span><br><span class="line">systemctl restart sshd</span><br></pre></td></tr></table></figure><h2 id="修改主机名、配置-Hosts"><a href="#修改主机名、配置-Hosts" class="headerlink" title="修改主机名、配置 Hosts"></a>修改主机名、配置 Hosts</h2><ul><li>修改主机名</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 设置主机名称，四台服务器依次为 hadoop01、hadoop02、hadoop03、hadoop04</span></span><br><span class="line">hostnamectl set-hostname hadoop01、02、03、04</span><br><span class="line"><span class="comment"># 查看主机名</span></span><br><span class="line">hostname </span><br></pre></td></tr></table></figure><ul><li>hosts 域名 IP 映射配置<br><code>vi /etc/hosts</code> 添加如下配置：</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">192.168.44.129 hadoop01</span><br><span class="line">192.168.44.130 hadoop02</span><br><span class="line">192.168.44.131 hadoop03</span><br><span class="line">192.168.44.132 hadoop04</span><br></pre></td></tr></table></figure><h2 id="关闭防火墙和selinux"><a href="#关闭防火墙和selinux" class="headerlink" title="关闭防火墙和selinux"></a>关闭防火墙和selinux</h2><ul><li>防火墙</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">systemctl status firewalld</span><br><span class="line">systemctl stop firewalld</span><br><span class="line">systemctl <span class="built_in">disable</span> firewalld.service</span><br></pre></td></tr></table></figure><ul><li>selinux</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">vi /etc/selinux/config</span><br><span class="line">将 SELINUX=enforcing 改为 SELINUX=disabled，保存退出，重启生效</span><br></pre></td></tr></table></figure><h2 id="设置-ssh-互信免密登陆"><a href="#设置-ssh-互信免密登陆" class="headerlink" title="设置 ssh 互信免密登陆"></a>设置 ssh 互信免密登陆</h2><p>参考其他文章 -&gt; <a href="https://www.chifuyong.cn/archives/linux-xia-ssh-zhi-xing-yuan-cheng-fu-wu-qi-ming-ling">Linux SSH免密登陆</a></p><h1 id="二-Hadoop-安装"><a href="#二-Hadoop-安装" class="headerlink" title="二. Hadoop 安装"></a>二. Hadoop 安装</h1><p>Hadoop 是基于 Java 平台实现的，首先需要有 JDK 环境，然后再去搭建 Hadoop 集群，需要做如下配置：</p><ol><li>配置 JDK</li><li>下载安装 Hadoop</li><li>修改 Hadoop 集群配置文件</li><li><code>scp</code> 同步每台机器的 Hadoop 环境变量配置和软件目录</li><li>初始化 Hadoop 的 NameNode</li><li>启动 Hadoop </li><li>验证 Hadoop</li></ol><h2 id="安装JDK"><a href="#安装JDK" class="headerlink" title="安装JDK"></a>安装JDK</h2><p>需要每台服务器都装上 JDK，具体 JDK 如何安装可参考此文章 -&gt; <a href="https://www.chifuyong.cn/archives/linux-xia-jdkeclipse-an-zhuang-yu-pei-zhi-jian-ji">Linux下JDK、Eclipse安装与配置简记</a></p><h2 id="安装-hadoop"><a href="#安装-hadoop" class="headerlink" title="安装 hadoop"></a>安装 hadoop</h2><p>至 <a href="https://hadoop.apache.org/releases.html">Hadoop 官网</a> 下载 Haoop 软件包，然后使用 xftp 上传至服务器 hadoop01 中（hadoop02-04 在修改完集群配置文件后使用 <code>scp</code> 命令从 hadoop01 拷贝过去即可），解压软件至 <code>/opt</code> ，然后配置环境变量，新增 <code>vim /etc/profile.d/myself_env.sh</code> 文件，添加如下内容：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> JAVA_HOME=/opt/jdk1.8.0_261   <span class="comment"># 需要配置自己的JDK目录</span></span><br><span class="line"><span class="built_in">export</span> HADOOP_HOME=/opt/hadoop-3.2.1</span><br><span class="line"><span class="built_in">export</span> PATH=<span class="variable">$JAVA_HOME</span>/bin:<span class="variable">$HADOOP_HOME</span>/bin:<span class="variable">$PATH</span></span><br><span class="line"><span class="built_in">export</span> CLASSPATH=.:<span class="variable">$JAVA_HOME</span>/lib/dt.jar:<span class="variable">$JAVA_HOME</span>/lib/tools.jar</span><br></pre></td></tr></table></figure><p>更新环境变量后使用 <code>hadoop version</code> 查看是否安装成功，现实如下图则说明安装成功。</p><p><img src="/img/upload/2022/06/image.webp" alt="Hadoop 安装成功"></p><h2 id="Hadoop-集群配置文件修改"><a href="#Hadoop-集群配置文件修改" class="headerlink" title="Hadoop 集群配置文件修改"></a>Hadoop 集群配置文件修改</h2><p>进入 Hadoop 软件目录 <code>/opt/hadoop-3.2.1/etc/hadoop</code> 下，修改如下几个配置文件</p><ul><li><code>hadoop-env.sh</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> JAVA_HOME=/usr/java/jdk1.8.0_111</span><br><span class="line"><span class="built_in">export</span> HDFS_NAMENODE_USER=root</span><br><span class="line"><span class="built_in">export</span> HDFS_DATANODE_USER=root</span><br><span class="line"><span class="built_in">export</span> HDFS_SECONDARYNAMENODE_USER=root</span><br><span class="line"><span class="built_in">export</span> YARN_RESOURCEMANAGER_USER=root</span><br><span class="line"><span class="built_in">export</span> YARN_NODEMANAGER_USER=hadoop</span><br><span class="line">JAVA_HOME：指定JDK路径</span><br><span class="line">HDFS_NAMENODE_USER：指定操作NameNode进程的用户</span><br><span class="line">HDFS_DATANODE_USER：指定操作DataNode进程的用户</span><br><span class="line">HDFS_SECONDARYNAMENODE_USER：指定操作 Secondary NameNode进程的用户，我们这里指定的用户是 root ，具体应用时，据实际情况而定。</span><br><span class="line">这三个配置是hadoop3.x 为了提升安全性而引入的。</span><br><span class="line">日志信息默认在 <span class="variable">$&#123;HADOOP_HOME&#125;</span>/logs 中，也可以自行配置目录。</span><br></pre></td></tr></table></figure><ul><li><code>core-site.xml</code></li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 指定NameNode的地址 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">　　<span class="tag">&lt;<span class="name">name</span>&gt;</span>fs.defaultFS<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">　　<span class="tag">&lt;<span class="name">value</span>&gt;</span>hdfs://hadoop01:9820<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- 指定hadoop数据的存储目录 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">　　<span class="tag">&lt;<span class="name">name</span>&gt;</span>hadoop.tmp.dir<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">　　<span class="tag">&lt;<span class="name">value</span>&gt;</span>/opt/hadoop-3.2.1/data_file<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 配置HDFS网页登录使用的静态用户为chify --&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">&lt;property&gt;</span></span><br><span class="line"><span class="comment">        &lt;name&gt;hadoop.http.staticuser.user&lt;/name&gt;</span></span><br><span class="line"><span class="comment">        &lt;value&gt;chify&lt;/value&gt;</span></span><br><span class="line"><span class="comment">    &lt;/property&gt;</span></span><br><span class="line"><span class="comment">--&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure><ul><li><code>hdfs-site.xml</code></li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">　　<span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.replication<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">　　<span class="tag">&lt;<span class="name">value</span>&gt;</span>3<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- nn web端访问地址--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.namenode.http-address<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>hadoop01:9870<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 2nn web端访问地址--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>dfs.namenode.secondary.http-address<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>hadoop02:9868<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure><ul><li><code>mapred-site.xml</code></li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 指定MapReduce程序运行在Yarn上 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">　　<span class="tag">&lt;<span class="name">name</span>&gt;</span>mapreduce.framework.name<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">　　<span class="tag">&lt;<span class="name">value</span>&gt;</span>yarn<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 历史服务器端地址 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">name</span>&gt;</span>mapreduce.jobhistory.address<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>hadoop04:10020<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 历史服务器web端地址 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">name</span>&gt;</span>mapreduce.jobhistory.webapp.address<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>hadoop04:19888<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure><ul><li><code>yarn-site.xml</code></li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 指定MR走shuffle --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">　　<span class="tag">&lt;<span class="name">name</span>&gt;</span>yarn.nodemanager.aux-services<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">　　<span class="tag">&lt;<span class="name">value</span>&gt;</span>mapreduce_shuffle<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span> </span><br><span class="line"><span class="comment">&lt;!-- 环境变量的继承 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;<span class="name">name</span>&gt;</span>yarn.nodemanager.env-whitelist<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME<span class="tag">&lt;/<span class="name">value</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span> </span><br><span class="line"><span class="comment">&lt;!-- 指定ResourceManager的地址(2NN)--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>yarn.resourcemanager.hostname<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>hadoop03<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 开启日志聚集功能，新设置的话需要重新启动NodeManager 、ResourceManager和HistoryServer。--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">name</span>&gt;</span>yarn.log-aggregation-enable<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>true<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 设置日志聚集服务器地址 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;<span class="name">name</span>&gt;</span>yarn.log.server.url<span class="tag">&lt;/<span class="name">name</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>http://hadoop04:19888/jobhistory/logs<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 设置日志保留时间为7天 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">name</span>&gt;</span>yarn.log-aggregation.retain-seconds<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>604800<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure><ul><li><code>workers</code></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">hadoop01</span><br><span class="line">hadoop02</span><br><span class="line">hadoop03</span><br><span class="line">hadoop04</span><br></pre></td></tr></table></figure><h2 id="scp-拷贝数据至-hadoop02-04-服务器"><a href="#scp-拷贝数据至-hadoop02-04-服务器" class="headerlink" title="scp 拷贝数据至 hadoop02-04 服务器"></a>scp 拷贝数据至 hadoop02-04 服务器</h2><p>注：需要上面的集群配置文件修改完后才可再进行拷贝，</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 拷贝环境变量文件</span></span><br><span class="line">scp -rv /etc/profile.d/myself_env.sh root@hadoop02:/etc/profile.d/myself_env.sh</span><br><span class="line">scp -rv /etc/profile.d/myself_env.sh root@hadoop02:/etc/profile.d/myself_env.sh</span><br><span class="line">scp -rv /etc/profile.d/myself_env.sh root@hadoop02:/etc/profile.d/myself_env.sh</span><br><span class="line"><span class="comment"># 拷贝 hadoop 软件目录</span></span><br><span class="line">scp -rv <span class="variable">$HADOOP_HOME</span> root@hadoop02:<span class="variable">$HADOOP_HOME</span></span><br><span class="line">scp -rv <span class="variable">$HADOOP_HOME</span> root@hadoop03:<span class="variable">$HADOOP_HOME</span></span><br><span class="line">scp -rv <span class="variable">$HADOOP_HOME</span> root@hadoop04:<span class="variable">$HADOOP_HOME</span></span><br></pre></td></tr></table></figure><h2 id="初始化-namenode"><a href="#初始化-namenode" class="headerlink" title="初始化 namenode"></a>初始化 namenode</h2><p>初始化目录<br><code>bin/hdfs namenode -format</code></p><p>注：首次启动要 format, 如果想重新 format 的话，所有机器的 data_file 目录都需要删除，否则会出问题。</p><h2 id="启动-Hadoop"><a href="#启动-Hadoop" class="headerlink" title="启动 Hadoop"></a>启动 Hadoop</h2><ul><li><p>启动&#x2F;关闭 HDFS<br><code>/opt/hadoop-3.2.1/sbin/start-dfs.sh</code>    or  <code>stop-dfs.sh</code></p></li><li><p>启动 YARN<br><code>/opt/hadoop-3.2.1/sbin/start-yarn.sh</code>    or   <code>stop-yarn.sh</code></p></li><li><p>启动&#x2F;关闭历史服务<br><code>mapred --daemon start/stop historyserver</code></p></li></ul><h2 id="验证-Hadoop"><a href="#验证-Hadoop" class="headerlink" title="验证 Hadoop"></a>验证 Hadoop</h2><ul><li><p>NameNode 页面<br><code>http://hadoop01:9870/</code></p></li><li><p>SecondaryNamenode 页面<br><code>http://hadoop02:9868/</code></p></li><li><p>YARN 页面<br><code>http://hadoop03:8088/</code></p></li><li><p>JobHistory 页面<br><code>http://hadoop04:19888/</code></p></li><li><p>日志聚集页面<br><code>http://hadoop04:19888/jobhistory/logs</code></p></li></ul><p>注：宿主机电脑的 hosts 文件也需要加上 hadoop01-04 的映射配置</p><h1 id="三-时间同步"><a href="#三-时间同步" class="headerlink" title="三. 时间同步"></a>三. 时间同步</h1><p>如果服务器可以连接互联网且本身会自动同步时间，则可以不用配置。但是如果是内网无法连接互联网或者无法同步时间的时候，则需要配置下 Hadoop01-04 这几台服务器之间的时间同步，否则时间久了就会导致时间偏差，导致集群执行任务时时间不同步。尤其是如果后面还需要部署 Hbase 的话，时间同步时必须要做的，否则一旦时间出现误差，将会出现大问题。</p><p>首先先设置好 hadoop01-04 所有机器的时区：<code>timedatectl set-timezone Asia/Shanghai</code></p><h2 id="可以连接互联网时的配置"><a href="#可以连接互联网时的配置" class="headerlink" title="可以连接互联网时的配置"></a>可以连接互联网时的配置</h2><p>可以连接互联网，但是服务器默认没有去同步时间时，可以先 yum 安装 ntpd 服务，然后配置所有机器与互联网上的时间服务器进行时间同步。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 安装 ntpd 时间同步服务</span></span><br><span class="line">yum -y install ntp</span><br><span class="line"><span class="comment"># 开启时间同步服务</span></span><br><span class="line">systemctrl start ntpd</span><br><span class="line"><span class="comment"># 查看时间同步服务状态</span></span><br><span class="line">systemctrl status ntpd</span><br><span class="line"><span class="comment"># 时间同步服务开机自启动</span></span><br><span class="line">systemctrl <span class="built_in">enable</span> ntpd</span><br></pre></td></tr></table></figure><h2 id="内网配置-hadoop01-04-同步时间"><a href="#内网配置-hadoop01-04-同步时间" class="headerlink" title="内网配置 hadoop01-04 同步时间"></a>内网配置 hadoop01-04 同步时间</h2><p>以 hadoop01 为时间同步服务器，其他服务器以 hadoop01 时间为准进行同步，修改 hadoop01 的 <code>/etc/ntp.conf</code> 文件（vim），修改如下内容：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 授权 hadoop01所在网段上的所有机器可以从 hadoop01 查询和同步时间</span></span><br><span class="line">restrict 192.168.44.0 mask 255.255.255.0 nomodify notrap</span><br><span class="line"></span><br><span class="line"><span class="comment"># 注释掉以下内容，hadoop01不从服务器上同步时间</span></span><br><span class="line"><span class="comment">#server 0.centos.pool.ntp.org iburst</span></span><br><span class="line"><span class="comment">#server 1.centos.pool.ntp.org iburst</span></span><br><span class="line"><span class="comment">#server 2.centos.pool.ntp.org iburst</span></span><br><span class="line"><span class="comment">#server 3.centos.pool.ntp.org iburst</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加如下配置，当该 hadoop01 连接不上互联网时，依然可以采用本地时间作为时间服务器为其他服务器提供时间同步</span></span><br><span class="line">server 127.127.1.0</span><br><span class="line">fudge 127.127.1.0 stratum 10</span><br></pre></td></tr></table></figure><p>修改 hadoop01 下 <code>/etc/sysconfig/ntpd</code> 文件（vim），设置硬件与系统时间进行同步，添加一行：<code>SYNC_HWCLOCK=yes</code> 保存，<code>systemctl restart ntpd</code> 重启时间服务。</p><p>进入 hadoop02-04 服务器，添加定时任务，每隔一段时间去同步 hadoop01 时间，如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 编辑定时任务</span></span><br><span class="line">crontab -e</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置每分钟定时一次，因为时虚拟机，这里设置一分钟</span></span><br><span class="line">*/1 * * * * /usr/sbin/ntpdate hadoop01</span><br><span class="line"></span><br><span class="line"><span class="comment"># 也可以设置 每个月1号，或者其他时间更新一次</span></span><br><span class="line">* * 1 * * /usr/sbin/ntpdate hadoop01</span><br></pre></td></tr></table></figure><p>至此，hadoop02-04 服务器就会按规定的时间定期去同步 hadoop01 的时间，大功告成。</p>]]>
    </content>
    <id>https://cfyong.com/java/hadoop-centos-7-cluster-deployment/</id>
    <link href="https://cfyong.com/java/hadoop-centos-7-cluster-deployment/"/>
    <published>2022-08-09T14:56:27.071Z</published>
    <summary>Hadoop 3.2.1分布式集群部署完整教程，涵盖CentOS服务器准备、HDFS配置、YARN集群搭建及测试验证。</summary>
    <title>大数据 Hadoop-3.2.1 分布式集群部署</title>
    <updated>2022-08-09T15:35:58.422Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Linux" scheme="https://cfyong.com/categories/Linux/"/>
    <category term="Docker" scheme="https://cfyong.com/tags/Docker/"/>
    <category term="Oracle" scheme="https://cfyong.com/tags/Oracle/"/>
    <content>
      <![CDATA[<p>首先需要装好 <strong>Docker</strong>，<strong>CentOS 7</strong> 安装 Docker 可<a href="https://www.chifuyong.cn/archives/centos7-an-zhuang-docker-jian-ji">点击参考此文章</a></p><h1 id="下载-Docker-Oracle-镜像"><a href="#下载-Docker-Oracle-镜像" class="headerlink" title="下载 Docker Oracle 镜像"></a>下载 Docker Oracle 镜像</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull jaspeen/oracle-11g</span><br></pre></td></tr></table></figure><p>注：此镜像没有 Oracle 安装包，里面有自动安装数据库的脚本，启动镜像容器时，需要容器卷下有相应的安装包（官网下载），所以大小才 281MB，需要自行下载 Oracle 11g 安装包。</p><h1 id="Oracle-官方安装包获取"><a href="#Oracle-官方安装包获取" class="headerlink" title="Oracle 官方安装包获取"></a>Oracle 官方安装包获取</h1><ul><li><p>下载地址：<a href="https://www.oracle.com/cn/database/enterprise-edition/downloads/oracle-db11g-linux.html">Oracle 11g 官网下载</a>，下载 <code>linux.x64_11gR2_database_1of2.zip</code><br> 和 <code>linux.x64_11gR2_database_2of2.zip</code> 两个文件。如下图：<br><img src="/img/upload/2022/06/image-1656002887051.webp" alt="Oracle 官网下载页面"></p></li><li><p>将下载完的文件，使用 <strong>xftp</strong> 传输到装有 Docker 的 Linux 服务器上，并解压至 <code>/root/oracleinstall</code>，解压后目录如下图：<br><img src="/img/upload/2022/06/image-1656240800368.webp" alt="Oracle 安装包目录"></p></li></ul><h1 id="启动-jaspeen-oracle-11g-镜像容器实例"><a href="#启动-jaspeen-oracle-11g-镜像容器实例" class="headerlink" title="启动 jaspeen/oracle-11g 镜像容器实例"></a>启动 <code>jaspeen/oracle-11g</code> 镜像容器实例</h1><p>使用如下命令启动容器，注：<code>-v /root/oracleinstall:/install</code> 此容器卷必须添加，且安装包必须解压到对应容器卷宿主机的目录中。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --privileged --name docker-oracle -p 1521:1521 -v /root/oracleinstall:/install jaspeen/oracle-11g</span><br></pre></td></tr></table></figure><p>启动日志出现 <code>100% complete</code> 则说明安装成功。<br><img src="/img/upload/2022/06/image-1656003230520.webp" alt="Oracle 安装成功日志"></p><h1 id="进入-Oracle-容器内部修改用户名密码"><a href="#进入-Oracle-容器内部修改用户名密码" class="headerlink" title="进入 Oracle 容器内部修改用户名密码"></a>进入 Oracle 容器内部修改用户名密码</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 进入容器</span></span><br><span class="line">docker <span class="built_in">exec</span> -it 1c00 bin/bash</span><br><span class="line"><span class="comment"># 使用 oracle 用户 </span></span><br><span class="line">su oracle </span><br><span class="line"><span class="comment"># 使用 sysdba 登陆</span></span><br><span class="line">sqlplus / as sysdba</span><br><span class="line"><span class="comment"># 新增/修改用户 guang 密码为 ******</span></span><br><span class="line">create/alter user guang identified by ******;</span><br><span class="line"><span class="comment">#查看 Oracle 数据库的所有用户</span></span><br><span class="line"><span class="keyword">select</span> * from all_users;</span><br><span class="line"><span class="comment"># 授予其相应数据库权限</span></span><br><span class="line">grant connect,resource,dba to guang;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 修改数据库密码永不过期</span></span><br><span class="line"><span class="comment">#查看用户的proifle是哪个，一般是default：</span></span><br><span class="line">SELECT username,PROFILE FROM dba_users;</span><br><span class="line"><span class="comment">#查看指定概要文件（如default）的密码有效期设置：</span></span><br><span class="line">SELECT * FROM dba_profiles s WHERE s.profile=<span class="string">&#x27;DEFAULT&#x27;</span> AND resource_name=<span class="string">&#x27;PASSWORD_LIFE_TIME&#x27;</span>;</span><br><span class="line"><span class="comment">#将密码有效期由默认的180天修改成&quot;无限制&quot;：</span></span><br><span class="line">ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED;</span><br><span class="line">修改之后不需要重启动数据库，会立即生效。</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://cfyong.com/linux/docker/oracle-11g-deployment/</id>
    <link href="https://cfyong.com/linux/docker/oracle-11g-deployment/"/>
    <published>2022-06-27T15:43:47.667Z</published>
    <summary>Docker环境下安装Oracle 11c数据库的完整教程，包括镜像拉取、容器创建、数据卷配置与数据库初始化。</summary>
    <title>Docker 环境安装 Oracle 11c</title>
    <updated>2022-12-29T02:39:00.750Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="读书笔记" scheme="https://cfyong.com/categories/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    <category term="苏菲的世界" scheme="https://cfyong.com/tags/%E8%8B%8F%E8%8F%B2%E7%9A%84%E4%B8%96%E7%95%8C/"/>
    <category term="哲学" scheme="https://cfyong.com/tags/%E5%93%B2%E5%AD%A6/"/>
    <content>
      <![CDATA[<h1 id="第一章-伊甸园"><a href="#第一章-伊甸园" class="headerlink" title="第一章 伊甸园"></a>第一章 伊甸园</h1><h2 id="你是谁？"><a href="#你是谁？" class="headerlink" title="你是谁？"></a>你是谁？</h2><p>她（苏菲）想：”我现在是活在这世上，但有一天我会死去。”人死之后还 会有生命吗？这个问题猫咪也不会去想，这倒是它的福气。</p><h2 id="世界从何而来？"><a href="#世界从何而来？" class="headerlink" title="世界从何而来？"></a>世界从何而来？</h2><p>生在这个世界上却连”世界从何而来”这样本质的问题都不问一问，实在是对这个世界很不恭敬。</p><p>在某一时刻，事物必然曾经从无到有，有开端，如果把开端比作 God，可万物都由 God 创造的话，那 God 又是谁创造的呢？</p><blockquote><p>注：哲学经典问题，我是谁？我从哪来来？我要到哪里去？未上大学之前谈论起这些问题总是带着玩笑，从未曾好好思考过这些问题，只觉有趣。自大学入学以来，人生就开启了迷茫 1.0 模式（年轻人，迷茫是好事，至少又是一次自我认识，自我剖析得开始），也是在此时自己开始真正得去寻找自我，思考和认识自己，感谢《苏菲的世界》，让我受益颇丰，让我真正的开始思考起了一些看似平平无奇的人类终极问题。</p></blockquote><h1 id="第二章-魔术师的礼帽"><a href="#第二章-魔术师的礼帽" class="headerlink" title="第二章 魔术师的礼帽"></a>第二章 魔术师的礼帽</h1><p>要成为一个优秀的哲学家，只有一个条件：要有好奇心。</p><h2 id="哲学是什么？"><a href="#哲学是什么？" class="headerlink" title="哲学是什么？"></a>哲学是什么？</h2><p>假如我自己对马或宝石有兴趣，我也不能期望别人都和我一样。假如我看电视体育节目看得津津有味，就必须忍受有些人认为体育节目很无聊的事实。</p><p>每个人都需要食物，爱和关怀，当所有的基本需求都满足后，每个人都需要：明白我们是谁，我们为何会在这里！</p><p>没有一种文化不关心”人是谁”，”世界从何而来”这样的问题。</p><h2 id="好奇心"><a href="#好奇心" class="headerlink" title="好奇心"></a>好奇心</h2><p>婴儿有好奇心，但是随着时间的成长，这种好奇心似乎也逐渐减少。</p><p>在孩童学会如何讲话得体、如何从事哲学性思考前，他就已经习惯这个世界了。希望未来的你不会成为一个把这个世界视为理所当然的人。</p><p>对于孩子而言，世上种种都是新鲜而令人惊奇的，对于大人则不然，大多成人都把这个世界当做理所当然的存在。</p><p>尽管我们都想过哲学性的问题，却并不一定每个人都会成为哲学家。由于种种理由，大多数人都忙于日常生活的琐事，因此他们对于这世界的好奇心都受到压抑。（就像那些微生虫一般，爬进兔子的毛皮深处，在那儿怡然自得地待上一辈予，从此不再出来）</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>这世界就像魔术师从他的帽子里拉出的一只白兔。只是这白兔的体积极其庞大，因此这场戏法要数十亿年才变得出来。全部的生物都出生于这只兔予的细毛顶端，他们刚开始对于这场令人不可置信的戏法都感到惊异。然而当他们年纪愈长，也就愈深入兔子的毛皮，并且待了下来。他们在那儿觉得非常安适，因此不愿再冒险爬回脆弱的兔毛顶端。唯有哲学家才会踏上此一危险的旅程，迈向语言与存在所能达到的顶峰。其中有些人掉了下来，但也有些人死命攀住兔毛不放，并对那些窝在舒适柔软的兔毛的深处、尽情吃喝的人们大声吼叫。</p><p>他们喊：”各位先生女士们，我们正飘浮在太空中呢！”但下面的人可不管这些哲学家们在嚷些什么。</p><p>这些人只会说：”哇！真是一群捣蛋鬼！”然后又继续他们原先的谈话：请你把奶油递过来好吗，我们今天的股价涨了多少，番茄现在是什么价钱，你有没有听说黛安娜王妃又怀孕了….</p><blockquote><p>注：婴儿时期，这个世界上任何一件事情都会引发我们强烈的好奇心，可随着时间的推移，父母一遍一遍的教导，以至于我们都已习惯了这个世界，再也没有婴儿时期对这个世界的好奇，丧失了孩童时期强大的学习能力。此篇着重强调好奇心的重要性，和刘慈欣《朝闻道》中所提到的人类的好奇心，都引发了我自己对自我的一个剖析，确实在不知不觉中，自己婴儿时期的好奇心都消散于生活的琐事之中……<br>谨记：于世界而言，人类所知只是冰山一角；而于我而言，在人类目前认知的事物面前，所知道的也只是九牛一毛。希望未来的自己继续保持着婴儿时期的好奇心，不指望自己能成为哲学家，但却也要对这个奇妙的世界能有自己的思考，保持自己独立的人格。认清自己，带领人类去认知人类还未曾知晓的事物是科学家、哲学家做的事情，你所能做的就是站在巨人的肩膀上，学习人类已知知识，对所学知识也一定要保持好奇心，知其然而知其所以然，未来希望你能成为一个卓越的工程师。</p></blockquote><h1 id="第三章-神话"><a href="#第三章-神话" class="headerlink" title="第三章 神话"></a>第三章 神话</h1><h2 id="神话的作用"><a href="#神话的作用" class="headerlink" title="神话的作用"></a>神话的作用</h2><p>为了要了解古代哲学家的想法，我们必须先了解神话中显现的世界是何种面貌。我们可以拿一些北欧神话来做例子。</p><p>神话中对雨的解释便是：索尔挥动锤子时，就会下雨。而一旦下雨，田里的玉米便会开始发芽、茁长。</p><p>当干旱、瘟疫等灾害发生时，凡人不能光是呆坐在那儿，等着神明来解救。他们必须在这场对抗邪恶的战争中出力，而他们出力的方法则是举行种种宗教仪式。</p><p>当旱灾发生时，人们便思考天空之所以不下雨的原因，是因为巨人们偷了索尔的锤予吗？也许这则神话之缘起，是人们试图解释一年中季节更替的现象：冬天时大自然死亡，是因为索尔的铁锤被偷到约腾海，但是到春天时索尔便将它取回。如此这般，神话的作用便是为人们不了解的事物寻求一令解释。然而，一则神话可不只是一个解释而已，人们同时也进行与神话有关的宗教仪式。</p><p>类似这类神话式的观念遍布全球，有数不清得神话故事，直到哲学家们开始提出疑问为止，他们不满足这些牵强的解释。</p><h2 id="早期哲学家的思考"><a href="#早期哲学家的思考" class="headerlink" title="早期哲学家的思考"></a>早期哲学家的思考</h2><p>公元前七百年左右，有一大部分希腊神话被荷马与贺西欧德以文字记录下来。至此情况大不相同，因为神话既然以文字的形式存在，也就可以加以讨论了。于是，最早的希腊哲学家对于荷马的神话提出批评，理由是神话里的天神与人类太过相似了。他们与人一样自大、狡诈。这是破天荒第一遭有人说神话只不过是人们想象出来的。在这段期间，希腊人在希腊本土与意大利南部、小亚细亚等希腊殖民地建立了许多城市。在这些城市中，全部的劳力工作都由奴隶担任，因此市民有充分的空闲，可以将全部时间都投注在政治与文化上。</p><p>从神话的思维模式发展到以经验与理性为基础的思考模式，早期希腊哲学家的目标乃是为大自然的变化寻找自然的，而非超自然的解释。</p><h1 id="第四章-自然派哲学家"><a href="#第四章-自然派哲学家" class="headerlink" title="第四章 自然派哲学家"></a>第四章 自然派哲学家</h1><h2 id="三个问题"><a href="#三个问题" class="headerlink" title="三个问题"></a>三个问题</h2><ul><li>万事万物是否由一种基本物质组成？</li><li>水能变成酒吗？</li><li>泥土和水何以能制造出一只活生生的青蛙？</li></ul><h2 id="小亚细亚米雷斯特三位哲学家"><a href="#小亚细亚米雷斯特三位哲学家" class="headerlink" title="小亚细亚米雷斯特三位哲学家"></a>小亚细亚米雷斯特三位哲学家</h2><p>最早的希腊哲学家有时被称为”自然派哲学家”，因为他们关切的主题是大自然与它的循环与变化。他们相信，世上必定有某种 “东西”，万物皆由此衍生，而且最终仍然回归于此。就这样，哲学逐渐脱离了宗教的范畴，我们可以说自然派的哲学家朝科学推理的方向迈出了第一步，成为后来科学的先驱。</p><h3 id="泰勒斯（Thals）"><a href="#泰勒斯（Thals）" class="headerlink" title="泰勒斯（Thals）"></a>泰勒斯（Thals）</h3><p>水是万物之源，他相信全部的生命源自于水，而全部的生命在消融后也仍然变成水。</p><h3 id="安奈克西曼德（Anaximander）"><a href="#安奈克西曼德（Anaximander）" class="headerlink" title="安奈克西曼德（Anaximander）"></a>安奈克西曼德（Anaximander）</h3><p>他认为我们的世界只是他所谓的”无限定者”（注：世界由无限定者元素所构成）中无数个生生灭灭的世界之一。</p><h3 id="安那西梅尼斯（Anaximenes）"><a href="#安那西梅尼斯（Anaximenes）" class="headerlink" title="安那西梅尼斯（Anaximenes）"></a>安那西梅尼斯（Anaximenes）</h3><p>他认为万物之源必定是”空气”或”气体”。毫无疑问，安那西梅尼斯必定熟知泰利斯有关水的理论。然而水从何来？安那西梅尼斯认为水是空气凝聚后形成的。我们也可看到下雨时，水是从空气中挤出来的。安那西梅尼斯认为当水再进一步受到挤压时，就会变成泥土。他可能曾经注意到冰雪融解时，会有泥土、沙石出现，他并认为火是比较精纯的空气，因此他主张空气是泥土、水、火的源头。</p><p>他和泰利斯一样，认为自然界的一切事物必定是由一种基本物质造成的。</p><h3 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h3><p>没有任何事物会来自虚无。这三位米雷特斯的哲学家都相信，宇宙间有一种基本物质是全部事物的源头。</p><h2 id="变化问题"><a href="#变化问题" class="headerlink" title="变化问题"></a>变化问题</h2><p>一种物质又如何会忽然变成另外一种东西？我们可以把这个问题称为”变化的问题”。</p><h3 id="帕梅尼德斯"><a href="#帕梅尼德斯" class="headerlink" title="帕梅尼德斯"></a>帕梅尼德斯</h3><p>他认为现有的万物是一直都存在的，没有任何事物会来自虚无，而已经存在的事物中也不会消失于无形。</p><p>你听过”眼见为信”这句话。不过帕梅尼德斯甚至在亲眼见到后仍不相信。他认为我们的感官使我们对世界有不准确的认识，这种认识与我们的理智不符。身为一个哲学家，他认为他的使命就是要揭穿各种形式的”感官幻象”。这里坚决相信人的理智的态度被称为理性主义。所谓理性主义者就是百分之百相信人类的理智是世间全部知识泉源的人。</p><h3 id="赫拉克里特斯"><a href="#赫拉克里特斯" class="headerlink" title="赫拉克里特斯"></a>赫拉克里特斯</h3><p>全部事物都是流动的，每一件事物都在不停变化、移动，没有任何事物是静止不变的，因此我们不可能”在同一条河流中涉水两次”。当我第二次涉水时，无论是我还 是河流都已经与从前不同了。</p><p>世间的事物都是相对的，在事物的秩序中，好与坏、善与恶都是不可或缺的。假如好坏、善恶两极之间没有不停的交互作用，则世界将不再存在。</p><h3 id="恩培窦可里斯"><a href="#恩培窦可里斯" class="headerlink" title="恩培窦可里斯"></a>恩培窦可里斯</h3><p><strong>四种基本元素</strong>。从某方面来看，帕梅尼德斯和赫拉克里特斯两人的看法正好相反。帕梅尼德斯说：1. 没有任何事物会改变。2. 因此我们的感官认知是不可靠的。赫拉克里特斯则说：1.万物都会改变（”一切事物都是流动的”）。2. 我们的感官认知是可靠的。</p><p>恩培窦可里斯认为他们两人各有一点是对的，也各有一点是错的。</p><p>他指出，大自然全部的变化都是因为这四种元素相互结合或分离的缘故。因为全部事物都是由泥土、空气、火与水混合而成，只是比例各不相同。他说，当一株花或一只动物死亡时，它们体内的这四种元素就再度分离了，这些变化是肉眼可见的。不过土、气、火与水却是永远不灭的，不受他们所组成事物的影响。因此，说”万物”都会改变是不准确的，基本上，没有任何一件事情有变化，世间发生的事不过是这四种元素的分合聚散罢了。</p><p>恩培窦可里斯将自然界的变化解释为四个”根”的分合聚散之后，仍有一件事情有待解释，是什么因素使得这些元素聚合在一起，创造了新的生命？又是什么因素使得这些聚合物——例如花——再度分解？恩培窦可里斯认为自然界有两种力量。他称之为”爱”与”恨”，爱使得事物聚合，而恨则使他们分散。</p><blockquote><p>注：个人认为这里的意思指的是：微观上，组成物质的基本元素不会变化（帕梅尼德斯），宏观上，物质是一直在变化的（赫拉克里特斯）。</p></blockquote><h3 id="安纳萨哥拉斯"><a href="#安纳萨哥拉斯" class="headerlink" title="安纳萨哥拉斯"></a>安纳萨哥拉斯</h3><p>安纳萨哥拉斯主张大自然是由无数肉眼看不见的微小粒子所组成，而全部事物都可以被分割成更小的部分。然而，即使是在最小的部分中也有其他每种事物的成分存在。他认为，假如皮肤与骨头不是由其他东西变成，则我们喝的牛奶与吃的食物中也必定有皮肤与骨头的成分。</p><p>恩培寞可里斯认为”爱”凝结各种元素组成整体的力量。安纳哥拉斯也认为”秩序”是一种力量，可以创造动物与人、花与树等，他称这个力量为”心灵”或”睿智”。</p><p>安纳萨哥拉斯之所以引起我们的兴趣，一方面也是因为他是我们所知第一个住在雅典的哲学家，他生长于小亚细亚，但在四十岁时迁居雅典，他后来被责为无神论者，因此最后被迫离开雅典。他还说过，太阳不是一个神，而是一块红热的石头，比希腊的培洛彭尼索斯半岛还 大。</p><p>安纳萨哥拉斯对天文学很感兴趣，他相信天上全部物体的成分都与地球相同，这是他研究一块陨石后达成的结论。他因此想到别的星球上可能也有人类，他指出月亮自己并不会发光，它的光来自于地球，同时还解释了日蚀的现象。</p><blockquote><p>注：在没有现代科学的背景下，光靠头脑的逻辑推理就能思考出这些理论，称之为科学的先驱确实不为过。</p></blockquote><h1 id="第五章-德谟克里特斯"><a href="#第五章-德谟克里特斯" class="headerlink" title="第五章 德谟克里特斯"></a>第五章 德谟克里特斯</h1><p>积木为何是世界上最巧妙的玩具？</p><p>德谟克里特斯同意前面几位哲学家的看法，认为自然界的转变不是因为任何事物真的有所”改变”。他相信每一种事物都是由微小的积木所组成，而每一块积木都是永恒不变的。德谟克里特斯把这些最小的单位称为原子。</p>]]>
    </content>
    <id>https://cfyong.com/read/sophies-world-notes/</id>
    <link href="https://cfyong.com/read/sophies-world-notes/"/>
    <published>2022-05-03T15:00:54.609Z</published>
    <summary>读书笔记：《苏菲的世界》哲学启蒙读物笔记，梳理西方哲学发展脉络，探讨我是谁、世界从何而来等终极问题。</summary>
    <title>苏菲的世界——乔斯坦·贾德</title>
    <updated>2022-05-03T17:24:11.676Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Linux" scheme="https://cfyong.com/categories/Linux/"/>
    <category term="Linux" scheme="https://cfyong.com/tags/Linux/"/>
    <category term="Raspberry Pi" scheme="https://cfyong.com/tags/Raspberry-Pi/"/>
    <content>
      <![CDATA[<p>近期入手了一台 <strong>Raspberry Pi 4 8GB</strong> 版，打算为自己未来的新家整个智能家居平台和打造家庭网络做准备。树莓派的作用不多说，懂得都懂，以下记录下自己入手时的基本配置，买的是单主机版本，加上购买的其他基础配件，装好后如下图，真的是极为喜欢，爱不释手。</p><p><img src="/img/upload/2022/04/image-1651069131017.webp" alt="树莓派配件组装"></p><h1 id="安装-Raspberry-Pi-OS-操作系统"><a href="#安装-Raspberry-Pi-OS-操作系统" class="headerlink" title="安装 Raspberry Pi OS 操作系统"></a>安装 Raspberry Pi OS 操作系统</h1><p><strong>Raspberry Pi OS</strong> 是基于 <strong>Debian</strong> 的一个 Linux 发行版，安装系统极为简单，网上教程极多，不做详细记录，记录下需要用到的镜像及工具下载地址。</p><ul><li>工具准备：<strong>SD 内存卡</strong>，以及刻录系统需要使用到的 <strong>SD 读卡器</strong>。</li><li>系统镜像：<a href="https://www.raspberrypi.com/software/operating-systems/">点击此处</a>下载 <strong>Raspberry Pi OS</strong> 镜像，拿来做服务器的，不需要桌面，这里选择体积最小的 <strong>Raspberry Pi OS Lite</strong>。</li><li>镜像刻录工具：使用 <strong>Win32 Disk Imager</strong>，<a href="https://win32diskimager.org/">点击此处</a> 官网下载。</li></ul><h1 id="配置树莓派开机连接-WiFi-热点"><a href="#配置树莓派开机连接-WiFi-热点" class="headerlink" title="配置树莓派开机连接 WiFi 热点"></a>配置树莓派开机连接 WiFi 热点</h1><ul><li><p>刻录好系统镜像后，使用读卡器连接 SD 卡到电脑，<code>boot</code> 目录下创建一个 <code>ssh</code> 空文件（不要有任何后缀名），这样树莓派在系统开机时默认会开启 <strong>SSH</strong> 远程连接，方便后面 <strong>Xshell</strong> 连接。</p></li><li><p><code>boot</code> 目录下再创建 <code>wpa_supplicant.conf</code> 文件，文本编辑器打开添加如下 WiFi 配置信息。</p></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">country=CN</span><br><span class="line">ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev</span><br><span class="line">update_config=1</span><br><span class="line">network=&#123;</span><br><span class="line">ssid=&quot;demo1&quot;</span><br><span class="line">psk=&quot;passwd&quot;</span><br><span class="line">priority=100</span><br><span class="line">&#125;</span><br><span class="line">network=&#123;</span><br><span class="line">ssid=&quot;demo2&quot;</span><br><span class="line">psk=&quot;passwd&quot;</span><br><span class="line">priority=90</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>注：<code>ssid</code> 为热点名称，<code>psk</code> 为密码，<code>priority</code> 为多个热点信号都搜索的到时的连接优先级，具体其他配置作用可 google 另行搜索，这样开机后，树莓派就会自动连接上相应 WiFi，一连上 WiFi 后，除非此 WiFi 信号主动消失或者改密等骚操作，否则树莓派不会再切换 WiFi 网络。</p><h1 id="Xshell-远程连接-Raspberry-Pi-OS"><a href="#Xshell-远程连接-Raspberry-Pi-OS" class="headerlink" title="Xshell 远程连接 Raspberry Pi OS"></a>Xshell 远程连接 Raspberry Pi OS</h1><p>这里使用手机开热点，然后将树莓派插上电源，打开手机查看热点连接设备信息如下：</p><p><img src="/img/upload/2022/04/image-1651069241574.webp" alt="手机热点连接设备"></p><p>可知树莓派 IP 分配到的是 <code>192.168.43.81</code>，然后打开 <strong>Xshell</strong> 远程连接 Raspberry，找不到 IP 地址，可使用 Windows 执行以下命令，扫描局域网内设备的分配到的 IP，找到树莓派对应的 <strong>MAC 地址</strong>即可。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># ping 局域网相应 IP</span></span><br><span class="line"><span class="keyword">for</span> /L %i IN (1,1,254) DO ping -w 2 -n 1 192.168.0.%i</span><br><span class="line"><span class="comment"># 展示所有局域网通信过的设备</span></span><br><span class="line">arp -a</span><br></pre></td></tr></table></figure><p>以下为树莓派初始开机的默认密码及进去后的密码修改命令。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 默认账户及密码</span></span><br><span class="line">pi/raspberry</span><br><span class="line"><span class="comment"># 初始化修改 root 密码，系统第一次使用时 root 无密码，直接设置就行</span></span><br><span class="line"><span class="built_in">sudo</span> passwd root</span><br></pre></td></tr></table></figure><p>配置完成，接下来就可以无界面下 <strong>Xshell</strong> 远程尽情操作树莓派了。</p><h1 id="后续问题记录："><a href="#后续问题记录：" class="headerlink" title="后续问题记录："></a>后续问题记录：</h1><ul><li><p><code>pi/raspberry</code>，修改 root 密码：<code>sudo passwd root</code></p></li><li><p><strong>vi</strong> 键盘有问题，安装 <strong>vim</strong><br> <code>apt-get install vim</code></p></li><li><p>解决 <strong>Xshell</strong> 中 <strong>vim</strong> 无法复制粘贴问题<br> <code>vim ~/.vimrc</code>（默认无此文件） 添加 <code>set mouse=c syntax on</code><br> <img src="/img/upload/2022/12/image.webp" alt="vim 配置文件"></p></li><li><p>设置重启后自动连接 WiFi<br><code>sudo vim /etc/wpa_supplicant/wpa_supplicant.conf</code></p></li><li><p>设置开机自动开启 SSH<br><code>sudo raspi-config</code> 进入 <strong>Interfacing Options</strong>，选择 <strong>SSH enable</strong></p></li><li><p>root 权限开启远程连接<br><code>sudo vim /etc/ssh/sshd_config</code>（注意：是 <code>sshd_config</code> 不是 <code>ssh_config</code>），添加或修改 <code>PermitRootLogin yes</code></p></li><li><p>配置 <code>ll</code> 命令<br><code>vim ~/.bashrc</code>，<code>#alias ll=&#39;ls -l&#39;</code> 去掉 <code>#</code>，重新登录即可生效</p></li><li><p>切换 <strong>apt-get</strong> 清华源<br><a href="https://shumeipai.nxez.com/2013/08/31/raspbian-chinese-software-source.html">参考文章1</a>，<a href="https://mirror.tuna.tsinghua.edu.cn/help/raspbian/">参考文章2</a></p></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># sudo vim /etc/apt/sources.list ，注意系统版本，这里是 bullseye 替换如下：</span></span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ bullseye main non-free contrib rpi</span><br><span class="line">deb-src http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ bullseye main non-free contrib rpi</span><br><span class="line"><span class="comment"># sudo vim /etc/apt/sources.list.d/raspi.list，注意系统版本，这里是 bullseye 替换如下：</span></span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/raspberrypi/ bullseye main</span><br><span class="line"><span class="comment"># sudo apt-get update</span></span><br><span class="line"><span class="comment"># sudo apt-get upgrade</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 64位 sudo vim /etc/apt/sources.list</span></span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/debian buster main contrib non-free</span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/debian-security/ buster/updates main contrib non-free</span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/debian buster-updates main contrib non-free</span><br><span class="line"><span class="comment"># 64位 sudo vim /etc/apt/sources.list.d/raspi.list</span></span><br><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/raspberrypi buster main ui</span><br></pre></td></tr></table></figure><ul><li>配置 <strong>frp</strong>，且 <strong>frp</strong> 客户端开机自启<br>点击下载相应软件：<a href="https://github.com/fatedier/frp/releases/">frp_0.41.0_linux_arm64.tar.gz</a>，<br>编辑 <code>frpc.ini</code> 配置文件，移动至新建的目录 <code>mkdir /etc/frp</code> 中，文件夹和文件记得加权限 <code>chmod 777</code><br>进入 <code>cd /opt/frp_0.41.0_linux_arm/systemd</code>，修改 <code>frpc.service</code> 文件，相应执行命令替换成 <code>/opt/frp_0.41.0_linux_arm/frpc -c /etc/frp/frpc.ini</code><br>复制 <code>frpc.service</code> 文件至系统启动目录，<code>sudo cp /opt/frp_0.41.0_linux_arm/systemd/frpc.service /lib/systemd/system</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 启动 frp</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl start frpc.service</span><br><span class="line"><span class="comment"># 查看 frpc 执行状态</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl status frpc.service</span><br><span class="line"><span class="comment"># 开启开机自启动</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> frpc.service</span><br><span class="line"><span class="comment"># 关闭开机自启动</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl start frpc.service</span><br></pre></td></tr></table></figure><h3 id="Docker-安装"><a href="#Docker-安装" class="headerlink" title="Docker 安装"></a>Docker 安装</h3><p><a href="https://docs.docker.com/engine/install/debian/">官方网址参考</a>，切记 <strong>apt</strong> 软件源要更新对，才可做此操作。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 下载安装脚本</span></span><br><span class="line">curl -fsSL https://get.docker.com -o get-docker.sh</span><br><span class="line"><span class="comment"># 执行脚本，使用阿里镜像</span></span><br><span class="line">$ <span class="built_in">sudo</span> sh get-docker.sh  --mirror Aliyun</span><br><span class="line"><span class="comment"># 更新 阿里云容器源</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/docker/daemon.json &lt;&lt;-<span class="string">&#x27;EOF&#x27;</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;registry-mirrors&quot;</span>: [<span class="string">&quot;https://阿里云容器服务提取.mirror.aliyuncs.com&quot;</span>]</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line"><span class="comment"># 查看容器源是否生效</span></span><br><span class="line"><span class="built_in">sudo</span> docker info |grep Mirrors -A 1</span><br></pre></td></tr></table></figure><ul><li><strong>E: Sub-process &#x2F;usr&#x2F;bin&#x2F;dpkg returned an error code (1)</strong> 错误解决方法</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /var/lib/dpkg</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mv</span> info info.bak</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> info</span><br></pre></td></tr></table></figure><p><img src="/img/upload/2022/04/image-1651069278861.webp" alt="树莓派系统界面"></p>]]>
    </content>
    <id>https://cfyong.com/linux/raspberry-pi-headless-setup/</id>
    <link href="https://cfyong.com/linux/raspberry-pi-headless-setup/"/>
    <published>2021-10-15T17:23:05.000Z</published>
    <summary>树莓派4无显示器初始化配置教程，涵盖Raspberry Pi OS安装、SSH远程连接、网络配置及基础服务搭建。</summary>
    <title>树莓派无显示器初始化配置</title>
    <updated>2022-12-31T13:46:02.552Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Linux" scheme="https://cfyong.com/categories/Linux/"/>
    <category term="Linux" scheme="https://cfyong.com/tags/Linux/"/>
    <category term="CentOS" scheme="https://cfyong.com/tags/CentOS/"/>
    <category term="Docker" scheme="https://cfyong.com/tags/Docker/"/>
    <content>
      <![CDATA[<p><strong>Docker</strong> 容器技术应用越来越广泛，之前学习了一下 Docker 的使用，瞬间觉得怎么没有早点学会这项技术，这样自己学习其他中间件技术时就可以少折腾很多安装的问题，Docker 大法真香，这里记录一下 <strong>CentOS 7</strong> 下安装 Docker 过程，防止下次踩坑。<a href="https://docs.docker.com/engine/install/centos/">官网安装参考</a></p><h1 id="安装步骤"><a href="#安装步骤" class="headerlink" title="安装步骤"></a>安装步骤</h1><h2 id="1-确定-centos-版本"><a href="#1-确定-centos-版本" class="headerlink" title="1. 确定 centos 版本"></a>1. 确定 centos 版本</h2><p><code>cat /etc/redhat-release</code> 可查看 CentOS 版本，6 和 7 安装方式有所不同，这里要注意。</p><h2 id="2-安装-gcc-和-gcc-c"><a href="#2-安装-gcc-和-gcc-c" class="headerlink" title="2. 安装 gcc 和 gcc-c++"></a>2. 安装 gcc 和 gcc-c++</h2><p><code>yum -y install gcc</code><br><code>yum -y install gcc-c++</code><br>注：<code>yum</code> 默认服务器是国外的，速度太慢，可以配置阿里云源。</p><h2 id="3-删除旧版本"><a href="#3-删除旧版本" class="headerlink" title="3. 删除旧版本"></a>3. 删除旧版本</h2><p>随着 Docker 版本的更新，这里移除的依赖可能有所不同，具体可以看上面给出的官网地址。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> yum remove docker \</span><br><span class="line">                  docker-client \</span><br><span class="line">                  docker-client-latest \</span><br><span class="line">                  docker-common \</span><br><span class="line">                  docker-latest \</span><br><span class="line">                  docker-latest-logrotate \</span><br><span class="line">                  docker-logrotate \</span><br><span class="line">                  docker-engine</span><br></pre></td></tr></table></figure><h2 id="4-yum-设置"><a href="#4-yum-设置" class="headerlink" title="4. yum 设置"></a>4. yum 设置</h2><p>需要使用到 <code>yum</code> 的 <code>yum-config-manager</code> 工具添加 docker 的镜像库，没有这个工具需要提前安装：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> yum install -y yum-utils device-mapper-persistent-data lvm2</span><br></pre></td></tr></table></figure><p>有了 <code>yum-config-manager</code> 工具后执行如下命令添加阿里云的 docker 镜像仓库。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 不要使用官网的镜像仓库，服务器在境外网速慢，这里选择阿里云，速度快</span></span><br><span class="line"><span class="built_in">sudo</span> yum-config-manager \</span><br><span class="line">    --add-repo \</span><br><span class="line">    https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo</span><br><span class="line"><span class="comment">#官方源：https://download.docker.com/linux/centos/docker-ce.repo</span></span><br></pre></td></tr></table></figure><p>执行后，<code>/etc/yum.repos.d</code> 目录下有 <code>docker-ce.repo</code> 文件表示镜像添加成功：</p><p><img src="/img/upload/2022/04/image-1650993542412.webp" alt="docker-ce.repo 文件"></p><h2 id="5-yum-安装-Docker"><a href="#5-yum-安装-Docker" class="headerlink" title="5. yum 安装 Docker"></a>5. yum 安装 Docker</h2><p>使用如下命令安装最新版本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install docker-ce docker-ce-cli containerd.io</span><br></pre></td></tr></table></figure><p>也可以使用如下命令选定版本下载：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看版本</span></span><br><span class="line">yum list docker-ce --showduplicates | <span class="built_in">sort</span> -r</span><br><span class="line"><span class="comment"># 下载相应版本</span></span><br><span class="line"><span class="built_in">sudo</span> yum install docker-ce-&lt;VERSION_STRING&gt; docker-ce-cli-&lt;VERSION_STRING&gt; containerd.io</span><br></pre></td></tr></table></figure><h1 id="服务启动"><a href="#服务启动" class="headerlink" title="服务启动"></a>服务启动</h1><p>启动、重启、关闭 和查看 Docker 命令如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl start docker</span><br><span class="line"><span class="built_in">sudo</span> systemctl restart docker</span><br><span class="line"><span class="built_in">sudo</span> systemctl stop docker</span><br><span class="line"><span class="built_in">sudo</span> systemctl status docker</span><br></pre></td></tr></table></figure><p>也可以设置开机自启，虚拟机下会比较方便，省的每次手动启动：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 开机自启</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> docker</span><br><span class="line"><span class="comment"># 关闭开机自启</span></span><br><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">disable</span> docker</span><br></pre></td></tr></table></figure><h1 id="配置-Docker-镜像阿里源"><a href="#配置-Docker-镜像阿里源" class="headerlink" title="配置 Docker 镜像阿里源"></a>配置 Docker 镜像阿里源</h1><p>使用 Docker 官网的镜像源下载 Docker 镜像，因为服务器在境外，速度较慢，这里使用阿里云的 Docker 源，配置步骤如下：</p><h2 id="1-注册阿里云账号"><a href="#1-注册阿里云账号" class="headerlink" title="1. 注册阿里云账号"></a>1. 注册阿里云账号</h2><p>打开<a href="https://cr.console.aliyun.com/">阿里云容器镜像服务</a>，注册账号，然后拿到阿里云的加速地址，阿里云提供了命令，可以一步执行，命令如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/docker</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/docker/daemon.json &lt;&lt;-<span class="string">&#x27;EOF&#x27;</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;registry-mirrors&quot;</span>: [<span class="string">&quot;https://个人配置.mirror.aliyuncs.com&quot;</span>]</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line"><span class="built_in">sudo</span> systemctl daemon-reload</span><br><span class="line"><span class="built_in">sudo</span> systemctl restart docker</span><br></pre></td></tr></table></figure><p>效果图如下：<br><img src="/img/upload/2022/04/image-1650993561330.webp" alt="Docker 阿里源配置"></p><p>成功后，如下：<br><img src="/img/upload/2022/04/image-1650993568732.webp" alt="Docker 镜像加速"></p><p>重启 Docker 即可生效。使用 <code>sudo docker info |grep Mirrors -A 1</code> 查看是否生效<br><img src="/img/upload/2022/04/image-1650993575712.webp" alt="Docker 镜像源生效"></p>]]>
    </content>
    <id>https://cfyong.com/linux/docker-centos-7-installation/</id>
    <link href="https://cfyong.com/linux/docker-centos-7-installation/"/>
    <published>2020-09-16T08:15:10.000Z</published>
    <summary>CentOS 7系统安装Docker的详细步骤记录，包括环境准备、yum配置及Docker启动验证。</summary>
    <title>CentOS 7 安装 Docker 简记</title>
    <updated>2022-04-28T15:49:24.188Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Java" scheme="https://cfyong.com/categories/Java/"/>
    <category term="IntelliJ IDEA" scheme="https://cfyong.com/tags/IntelliJ-IDEA/"/>
    <content>
      <![CDATA[<p>很早之前就遇到了IDEA 和 cmd命令行里 Tomcat 日志中文乱码问题，但是 Tomcat log目录下的 <code>catalina.log</code> 文件却不是乱码，因为各种缘由没有及时去解决，这次做项目用到了 Activiti 工作流，学习过程中，遇到了 bpmn 流程图中文乱码问题，一并解决了这个问题，这里做个简记，防止下次踩坑。</p><h1 id="IDEA-启动文件配置"><a href="#IDEA-启动文件配置" class="headerlink" title="IDEA 启动文件配置"></a>IDEA 启动文件配置</h1><p>Google 得知，修改 IDEA bin 目录下 <code>idea64.exe.vmoptions</code> 文件，添加参数 <code>-Dfile.encoding=UTF-8</code>，即可解决问题，如下：</p><p><img src="/img/upload/2022/04/image-1651071140611.webp" alt="idea 启动文件配置"></p><p><img src="/img/upload/2022/04/image-1651071145115.webp" alt="idea 启动文件配置"></p><p>但是重启 IDEA 后发现，bpmn 还是有中文乱码，修改 IDEA 中的 File Encodings ，如下：</p><p><img src="/img/upload/2022/04/image-1651071152856.webp" alt="idea 启动文件配置"></p><p>最终还是无果，想起了之前遇到 Tomcat 在 IDEA 里中文日志乱码问题时，也配置了这个 <code>-Dfile.encoding=UTF-8</code> 参数，结果也是无效，应该是同个问题。</p><h1 id="使用-JvisualVM-分析问题"><a href="#使用-JvisualVM-分析问题" class="headerlink" title="使用 JvisualVM 分析问题"></a>使用 JvisualVM 分析问题</h1><p>打开 <code>jvisualvm</code> 查看 jvm 的运行情况，如下图： </p><p><img src="/img/upload/2022/04/image-1651071162597.webp" alt="使用 jvisualvm 分析问题"></p><p>发现 IDEA 启动时 <code>-Dfile.encoding</code> 参数还是 GBK，初步分析，在 IDEA bin 目录下 <code>idea64.exe.vmoptions</code> 文件中的 <code>-Dfile.encoding=UTF-8</code> 应该是被覆盖了，查阅了一下资料得知，在用户目录下，在 <code>C:\Users\用户名\.IntelliJIdea2019.3\config</code> 目录下的 <code>idea64.exe.vmoptions</code> 文件将会覆盖 IDEA bin 目录下的 <code>idea64.exe.vmoptions</code> 配置文件参数，打开用户目录下的 <code>idea64.exe.vmoptions</code>：</p><p><img src="/img/upload/2022/04/image-1651071169330.webp" alt="使用 jvisualvm 分析问题"></p><p>和预想的一致，<code>-Dfile.encoding=GBK</code>，这个的问题也就类似于全局系统变量会被用户级变量覆盖一样，只需要改好用户级别的配置即可。所以修改了用户目录下的 IDEA 启动配置文件，改为 <code>-Dfile.encoding=UTF-8</code>，重启 IDEA ，配置生效，中文乱码问题得以解决。</p><h1 id="CMD-启动-Tomcat-中文日志乱码解决"><a href="#CMD-启动-Tomcat-中文日志乱码解决" class="headerlink" title="CMD 启动 Tomcat 中文日志乱码解决"></a>CMD 启动 Tomcat 中文日志乱码解决</h1><p>CMD 命令中启动 Tomcat，也发现造成了中文乱码，但是 Tomcat log 目录下的 <code>catalina.log</code> 文件却不是乱码，应该也是因为 Win 10 默认 CMD 窗口使用的不是 UTF-8 编码，只要设置成 UTF-8 即可。配置如下：</p><p>使用 <code>chcp 65001</code> 命令可让本次打开的 cmd 窗口使用 UTF-8 编码，但是下次打开还是恢复默认的编码，永久配置需要修改注册表；</p><p>win + r ，输入 <code>regedit</code> ，找到 <code>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor</code> ，添加如下配置：</p><p><img src="/img/upload/2022/04/image-1651071176618.webp" alt="cmd 启动 tomcat 中文日志乱码解决"></p><p>重新打开 CMD ，启动 Tomcat ，中文乱码得以解决。</p>]]>
    </content>
    <id>https://cfyong.com/java/idea-tomcat-activiti-encoding/</id>
    <link href="https://cfyong.com/java/idea-tomcat-activiti-encoding/"/>
    <published>2020-09-08T15:44:11.000Z</published>
    <summary>解决IntelliJ IDEA中Tomcat日志乱码和Activiti bpmn流程图中文乱码问题的配置方法。</summary>
    <title>IDEA 中解决 Tomcat 日志乱码、Activiti bpmn流程图乱码问题</title>
    <updated>2022-04-28T15:24:44.698Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Java" scheme="https://cfyong.com/categories/Java/"/>
    <category term="IntelliJ IDEA" scheme="https://cfyong.com/tags/IntelliJ-IDEA/"/>
    <category term="Java" scheme="https://cfyong.com/tags/Java/"/>
    <category term="Maven" scheme="https://cfyong.com/tags/Maven/"/>
    <content>
      <![CDATA[<p>好记性不如烂笔头，记一篇 IDEA 中搭建 JDK 源码阅读工程的文章，防止下次踩坑，此次 JDK 版本为：1.8.0_261</p><h1 id="导入源码"><a href="#导入源码" class="headerlink" title="导入源码"></a>导入源码</h1><p>创建新的 Maven 项目工程，在 JDK 安装目录，找到 <code>src.zip</code> 源码文件，将其内容解压至 Maven 项目 <code>src/main/java</code> 目录下</p><p><img src="/img/upload/2022/04/image-1651071371574.webp" alt="导入源码"></p><p><img src="/img/upload/2022/04/image-1651071378304.webp" alt="导入源码"></p><h1 id="所遇问题"><a href="#所遇问题" class="headerlink" title="所遇问题"></a>所遇问题</h1><ul><li><code>Error:java: Compilation failed: internal java compiler error</code></li><li><code>Error:java: OutOfMemoryError: insufficient memory</code></li><li>程序包 <code>com.sun.tools.javac.api</code> 不存在</li><li><code>UNIXToolkit</code>、<code>FontConfigManager</code> 类不存在</li><li>Debug 无法 Step into 到 JDK 源码，即使可以也是不可修改源码文件（不利于学习 JDK 源码）。</li></ul><h1 id="问题解决方案"><a href="#问题解决方案" class="headerlink" title="问题解决方案"></a>问题解决方案</h1><ol><li><code>Error:java: Compilation failed: internal java compiler error</code><br>编译时，IDEA JDK 版本未选对原因，配好如下3个选项。</li></ol><p><img src="/img/upload/2022/04/image-1651071416294.webp" alt="问题解决方案"></p><ol start="2"><li><code>Error:java: OutOfMemoryError: insufficient memory</code><br>编译时，内存不够的原因，导致堆内存溢出，更改编译时的堆内存大小即可，IDEA 默认设置为 700M，这里改为 1024M 即可。</li></ol><p><img src="/img/upload/2022/04/image-1651071426170.webp" alt="问题解决方案"></p><ol start="3"><li>程序包 <code>com.sun.tools.javac.api</code> 不存在<br>缺失 <code>tools.jar</code> 包导致的问题，将 JDK lib 目录下的 <code>tool.jar</code> 配置进 Libraries 里。</li></ol><p><img src="/img/upload/2022/04/image-1651071436131.webp" alt="问题解决方案"></p><ol start="4"><li><code>UNIXToolkit</code>、<code>FontConfigManager</code> 类不存在<br>JDK 源码中无此类， 可<a href="https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/">点击此处</a> ，按如下操作，找到所需类：</li></ol><p><img src="/img/upload/2022/04/image-1651071449191.webp" alt="问题解决方案"></p><p><img src="/img/upload/2022/04/image-1651071459564.webp" alt="问题解决方案"></p><p>双击上图所示的类，复制其内容，在工程中相应包位置创建如上两个类，并将内容复制进去即可</p><p><img src="/img/upload/2022/04/image-1651071476572.webp" alt="问题解决方案"></p><ol start="5"><li>Debug 无法 Step into 到 JDK 源码，即使可以也是不可修改源码文件（不利于学习 JDK 源码）。<br>默认情况下，IDEA 设置 Debug 不让 Step into 到源码里，通过如下配置，将 <code>Do not  step into the classes</code> 取消打钩即可。</li></ol><p><img src="/img/upload/2022/04/image-1651071486017.webp" alt="问题解决方案"></p><p>修改完后即可 Step into 到源码，但此时并不可以修改其内容，按照如下方法重新修改源码路径即可：</p><p><img src="/img/upload/2022/04/image-1651071494826.webp" alt="问题解决方案"></p><p>以上，JDK源码工程搭建完成！</p>]]>
    </content>
    <id>https://cfyong.com/java/idea-jdk-source-project/</id>
    <link href="https://cfyong.com/java/idea-jdk-source-project/"/>
    <published>2020-09-08T14:09:52.000Z</published>
    <summary>在IntelliJ IDEA中搭建JDK源码阅读工程的方法记录，解决源码导入与编译过程中的常见问题。</summary>
    <title>IDEA 搭建 JDK 源码工程简记</title>
    <updated>2022-04-27T15:00:48.009Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Java" scheme="https://cfyong.com/categories/Java/"/>
    <category term="Java" scheme="https://cfyong.com/tags/Java/"/>
    <content>
      <![CDATA[<p>前几天同事遇到了一个很奇怪的 <code>NullPointExption</code> 异常，看她郁闷的蛮久都没有解决，也帮忙分析了一下，情况大致如下：</p><p><img src="/img/upload/2022/04/image-1651041040722.webp" alt="文章配图"></p><p>看得她一头雾水，在帮其初步分析也没想到是啥问题，因为是批量代码，没有相关文件不好本地测试，让其远程 debug 跟了一下代码，发现还是报空指针异常，最后怀疑是服务器上 jar 包没有更新到，拿下 jar 包反编译后，才恍然大悟（反编译如下图），是自己忽略 <code>Person</code> 类和 <code>Student</code> 类的类型了，一个是 <code>Integer</code> ，一个是 <code>int</code> 基本类型，1.5 之后的 JDK 在编译的时候会有自动拆装箱机制！这里记录一下 Java 中包装类型相关的知识点，做个小总结。</p><p><img src="/img/upload/2022/04/image-1651041051881.webp" alt="文章配图"></p><h1 id="基本类型和包装类"><a href="#基本类型和包装类" class="headerlink" title="基本类型和包装类"></a>基本类型和包装类</h1><p>Java 中 8 种基本类型对应的包装类型如下表：</p><table><thead><tr><th align="left">基本类型</th><th align="right">大小</th><th align="center">包装类型</th></tr></thead><tbody><tr><td align="left">boolean</td><td align="right">1 Byte</td><td align="center">Boolean</td></tr><tr><td align="left">char</td><td align="right">2 Byte</td><td align="center">Character</td></tr><tr><td align="left">byte</td><td align="right">1 Byte</td><td align="center">Byte</td></tr><tr><td align="left">short</td><td align="right">2 Byte</td><td align="center">Short</td></tr><tr><td align="left">int</td><td align="right">4 Byte</td><td align="center">Integer</td></tr><tr><td align="left">long</td><td align="right">8 Byte</td><td align="center">Long</td></tr><tr><td align="left">float</td><td align="right">4 Byte</td><td align="center">Float</td></tr><tr><td align="left">double</td><td align="right">8 Byte</td><td align="center">Double</td></tr></tbody></table><h1 id="自动装箱和拆箱"><a href="#自动装箱和拆箱" class="headerlink" title="自动装箱和拆箱"></a>自动装箱和拆箱</h1><p>以 <code>Integer</code> 包装类为例（其他的包装类也是类似），看看其自动拆装箱是如何实现的，写段  代码如下图：</p><p><img src="/img/upload/2022/04/image-1651041060488.webp" alt="自动装箱和拆箱"></p><p>由上图可知，自动装箱时，JDK 在编译的时候会调用 <code>Integer.valueOf(int)</code> 这个方法将 <code>int</code> 转为 <code>Integer</code>，而在自动拆箱的时候 <code>Integer</code> 对象会调用 <code>intValue()</code> 方法（<code>Short</code> 类则为 <code>shortValue()</code>），返回 <code>Integer</code> 所持有的 <code>int</code> 成员变量，<code>intValue()</code> 没什么好看的，就是返回了 <code>Integer</code> 对象所持有的 <code>int</code> 成员变量。<code>valueOf(int)</code> 函数倒是值得研究一下，截图如下：</p><p><img src="/img/upload/2022/04/image-1651041066734.webp" alt="自动装箱和拆箱"></p><p>可知在 <code>int</code> 值在 -127~ <code>IntegerCache.high</code>（VM 参数 <code>-Djava.lang.Integer.IntegerCache.high=***</code> 可以设置 <code>high</code> 的值）之间时，将会返回一个<code>Integer</code> 内部类 <code>IntegerCache</code> 里 <code>cache</code> 数组缓存下来的一个 <code>Integer</code> 对象，不是在这个范围外，才会返回一个新的 <code>Integer</code> 对象。<code>IntegerCache</code> 内部类如下图：</p><p><img src="/img/upload/2022/04/image-1651041078505.webp" alt="自动装箱和拆箱"></p><p><code>IntegerCache</code> 这个内部类，有个静态 <code>Integer</code> 类型 <code>cache</code> 数组，静态代码块会给 <code>cache</code> 数组初始化值，缓存符合要求的 <code>Integer</code> 值。这里也就引发了一个初级面试中经常会遇到的问题，如下图：</p><p><img src="/img/upload/2022/04/image-1651041085267.webp" alt="自动装箱和拆箱"></p><p>首先 <code>==</code> 在 Java 里，基本类型比较的是值是否相等，而引用型类型则是比较内存地址是否相同， <code>Integer</code> 是个引用类型，默认情况下，-128到127 范围内的 <code>int</code> 值在自动装箱时调用 <code>valueOf(int)</code>方法返回的都是 <code>cache</code> 里缓存好的对象，所以不管是 <code>i</code> ，还是 <code>i2</code> 引用，其实都是指向缓存数组 <code>cache</code> 早已经定义好的 <code>Integer</code> 对象，所以 <code>i == i2</code> 是 <code>true</code> ；而 128 不在 -128到127 的范围内，所以 <code>valueOf(int)</code> 返回的是 <code>new Integer(int)</code>，返回一个新的 <code>Integer</code> 对象，所以 <code>i3 == i4</code> 也就是 <code>false</code> 了。</p><p>还有另外一种情况，代码截图如下：</p><p><img src="/img/upload/2022/04/image-1651041093580.webp" alt="自动装箱和拆箱"></p><p>这里的 <code>i3</code> 引用其实就是和自动装箱无关了，它就是用 <code>Integer</code> 的构造方法生成了一个新的 <code>Integer</code> 对象，和 <code>cache</code> 数组缓存的又是不同的对象，<code>i2 == i3</code> 也就等于 <code>false</code> 了。</p><p><strong>注</strong>：除 <code>Integer</code> 包装类外，<code>Byte</code>、<code>Short</code>、<code>Long</code>、<code>Character</code>（<code>char</code>）包装类都是有类似于 <code>Integer</code> 的缓存机制的，<code>Float</code>、<code>Double</code> 由于是浮点类型的，JDK 中并未实现这种缓存机制。至于 <code>Boolean</code> 类型的的话又是一个例外，翻看它的实现大致就可以知道啥原理了，其实现如下：</p><p><img src="/img/upload/2022/04/image-1651041104283.webp" alt="自动装箱和拆箱"></p><p>其中包装类中拥有共同的方法如下：</p><blockquote><p>带有基本值参数并创建包装类对象的构造函数。如利用<code>Integer</code>包装类创建对象，<code>Integer obj=new Integer(145);</code><br>带有字符串参数并创建包装类对象的构造函数.如：<code>new Integer(&quot;-45.36&quot;);</code><br>可生成对象基本值的<code>typeValue</code>方法，如：<code>obj.intValue();</code><br>将字符串转换为基本值的<code>parseType</code>方法，如：<code>Integer.parseInt(args[0]);</code><br>生成哈稀表代码的<code>hashCode</code>方法，如：<code>obj.hasCode();</code><br>对同一个类的两个对象进行比较的<code>equals()</code>方法，如：<code>obj1.eauqls(obj2);</code><br>生成字符串表示法的<code>toString()</code>方法，如：<code>obj.toString()</code>.</p></blockquote>]]>
    </content>
    <id>https://cfyong.com/java/primitive-and-wrapper-types/</id>
    <link href="https://cfyong.com/java/primitive-and-wrapper-types/"/>
    <published>2020-05-25T06:31:05.000Z</published>
    <summary>Java八种基本类型与对应包装类详解，分析自动拆装箱机制及Integer缓存等常见面试知识点。</summary>
    <title>Java：基本类型和包装类</title>
    <updated>2022-04-28T15:50:35.141Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="IT技术" scheme="https://cfyong.com/categories/IT%E6%8A%80%E6%9C%AF/"/>
    <category term="Git" scheme="https://cfyong.com/tags/Git/"/>
    <content>
      <![CDATA[<p>项目开发中遇到了一个问题：代码中新增了 shell 脚本，打包放到服务器上执行时，因不同 OS 系统换行符不同而导致执行报错。粗略解决后，写篇博客记录一下。</p><h1 id="r-和-n-区别"><a href="#r-和-n-区别" class="headerlink" title="\r 和 \n 区别"></a><code>\r</code> 和 <code>\n</code> 区别</h1><ul><li><code>\r</code> (return)：回车，回到本行的行首</li><li><code>\n</code> (newline)：换行，到下一行的行首</li></ul><p>其历史渊源如下：</p><blockquote><p>在计算机还没有出现之前，有一种叫做电传打字机（Teletype Model 33）的玩意，每秒钟可以打 10 个字符。但是它有一个问题，就是打完一行换行的时候，要用去 0.2 秒，正好可以打两个字符。要是在这 0.2 秒里面，又有新的字符传过来，那么这个字符将丢失。<br>于是，研制人员想了个办法解决这个问题，就是在每行后面加两个表示结束的字符。一个叫做”回车”，告诉打字机把打印头定位在左边界；另一个叫做”换行”，告诉打字机把纸向下移一行。<br>这就是”换行”和”回车”的来历，从它们的英语名字上也可以看出一二。<br>后来，计算机发明了，这两个概念也就被搬到了计算机上。那时，存储器很贵，一些科学家认为在每行结尾加两个字符太浪费了，加一个就可以。于是，就出现了分歧。<br>Unix 系统里，每行结尾只有”&lt;换行&gt;”，即 <code>\n</code>；Windows 系统里面，每行结尾是”&lt;回车&gt;&lt;换行&gt;”，即 <code>\r\n</code>；Mac 系统里，每行结尾是”&lt;回车&gt;”。一个直接后果是，Unix&#x2F;Mac 系统下的文件在 Windows 里打开的话，所有文字会变成一行；而 Windows 里的文件在 Unix&#x2F;Mac 下打开的话，在每行的结尾可能会多出一个 <code>^M</code> 符号。</p></blockquote><p><a href="https://www.ruanyifeng.com/blog/2006/04/post_213.html">参考文章（阮一峰）</a></p><h1 id="不同-OS-中的换行符"><a href="#不同-OS-中的换行符" class="headerlink" title="不同 OS 中的换行符"></a>不同 OS 中的换行符</h1><ul><li><strong>Windows</strong> 中的文本文件换行符是 <code>\r\n</code>，也就是 <strong>CRLF</strong>，对应 ASCII 码表中的 <code>0x0D 0x0A</code></li><li><strong>类 Unix</strong> 系统中换行符为 <code>\n</code>，也就是 <strong>LF</strong>（line feed），ASCII 码为 <code>0x0A</code></li><li><strong>早期 Mac</strong> 操作系统则为 <code>\r</code>，也就是 <strong>CR</strong>（carriage return），ASCII 码为 <code>0x0D</code>，后来与 Unix 保持一致</li></ul><p>这次开发中遇到的问题就是：在 Windows 写完的 shell 脚本是 <strong>CRLF</strong> 换行符，打包解压到服务器上后，执行时因换行符问题报了语法错误。</p><h3 id="Notepad-解决办法"><a href="#Notepad-解决办法" class="headerlink" title="Notepad++ 解决办法"></a>Notepad++ 解决办法</h3><p>使用 Notepad++ 编辑打开文件，点击：视图 &gt; 显示符号 &gt; 显示所有符号，显示结果如下：</p><p><img src="/img/upload/2022/04/image-1650992837707.webp" alt="notepad++ 解决办法"></p><p>点击：编辑 &gt; 文档格式转换 &gt; 选择相应 OS 的换行符，Notepad++ 会自动替换换行符。</p><h1 id="Git-中的问题"><a href="#Git-中的问题" class="headerlink" title="Git 中的问题"></a>Git 中的问题</h1><p>Git 中有换行符转换功能：Windows 下，Git 会将 Unix 换行符（LF）替换为 Windows 的换行符（CRLF）；而在提交文件时，它又会将 CRLF 替换为 LF，据说有坑，详见 <a href="https://github.com/cssmagic/blog/issues/22">参考文章3</a>。Windows 下安装 Git 客户端时可以直接关掉自动转换功能，如下：</p><p><img src="/img/upload/2022/04/image-1650992852750.webp" alt="git 中的问题"></p><p>安装时没有关闭，也可以使用如下命令将换行符转换功能关闭，具体解释如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 提交时转换为 LF，检出时转换为 CRLF</span></span><br><span class="line">git config --global core.autocrlf <span class="literal">true</span></span><br><span class="line"><span class="comment"># 提交时转换为 LF，检出时不转换</span></span><br><span class="line">git config --global core.autocrlf input</span><br><span class="line"><span class="comment"># 提交检出均不转换</span></span><br><span class="line">git config --global core.autocrlf <span class="literal">false</span></span><br></pre></td></tr></table></figure><p><code>autocrlf</code> 设置为 <code>false</code> 时，提交和检出代码时都不会转换换行符，另一个配置 <code>safecrlf</code> 最好设置为 <code>true</code>，具体作用如下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 拒绝提交包含混合换行符的文件</span></span><br><span class="line">git config --global core.safecrlf <span class="literal">true</span></span><br><span class="line"><span class="comment"># 允许提交包含混合换行符的文件</span></span><br><span class="line">git config --global core.safecrlf <span class="literal">false</span></span><br><span class="line"><span class="comment"># 提交包含混合换行符的文件时给出警告</span></span><br><span class="line">git config --global core.safecrlf warn</span><br></pre></td></tr></table></figure><p>个人建议配成下面这个样子：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config --global core.autocrlf input</span><br><span class="line">git config --global core.safecrlf <span class="literal">true</span></span><br></pre></td></tr></table></figure><p><a href="https://kuanghy.github.io/2017/03/19/git-lf-or-crlf">参考文章4</a></p><h1 id="IDEA-中设置换行符"><a href="#IDEA-中设置换行符" class="headerlink" title="IDEA 中设置换行符"></a>IDEA 中设置换行符</h1><p>File &gt; Settings &gt; Editor &gt; Code Style &gt; 通过 Line separator 设置即可，设置完毕新建的文件都会以设置的换行符来换行。单个文件设置如下图（IDEA 右下角）：</p><p><img src="/img/upload/2022/04/image-1650992860584.webp" alt="idea 中设置换行符"></p>]]>
    </content>
    <id>https://cfyong.com/it/git-line-ending-configuration/</id>
    <link href="https://cfyong.com/it/git-line-ending-configuration/"/>
    <published>2020-05-14T13:30:57.000Z</published>
    <summary>解决Git中Windows与Linux换行符差异导致的脚本执行报错问题，介绍core.autocrlf配置方法。</summary>
    <title>Git 中换行符问题处理</title>
    <updated>2022-04-27T14:37:02.421Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Linux" scheme="https://cfyong.com/categories/Linux/"/>
    <category term="Linux" scheme="https://cfyong.com/tags/Linux/"/>
    <category term="SSH" scheme="https://cfyong.com/tags/SSH/"/>
    <category term="Shell" scheme="https://cfyong.com/tags/Shell/"/>
    <content>
      <![CDATA[<p>通常在 Windows 或者其他 OS 环境下使用远程连接客户端（例如：<strong>Xshell</strong>）登录服务器后就可以操作远程服务器，这次项目中接到了一项部署改造的任务，需求是：在服务器 A 上有个 <code>start.sh</code> 脚本，这个脚本会调用到另一台服务器 B 下的一个 <code>bootstrap.sh</code> 脚本，这里就需要使用到 <strong>SSH</strong> 远程执行的相关命令了，这里做个总结，方便下次快速回顾和翻阅。</p><h1 id="测试环境搭建"><a href="#测试环境搭建" class="headerlink" title="测试环境搭建"></a>测试环境搭建</h1><p>开启 <strong>VMware</strong> 虚拟机创建两台 <strong>CentOS7</strong> 系统的服务器，默认下开机两个服务器都不会自动获取 IP，没有 IP，<code>ssh</code> 命令就无法使用，<strong>Xshell</strong> 自然也就连不上，使用如下方式更改即可：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 使用如下命令，将 ONBOOT=no 改为 yes </span></span><br><span class="line">vi /etc/sysconfig/network-scripts/ifcfg-ens33 </span><br><span class="line"><span class="comment"># 2. 重启网络服务</span></span><br><span class="line"> service network restart</span><br><span class="line"><span class="comment"># 3. 查看 IP</span></span><br><span class="line">ip addr</span><br></pre></td></tr></table></figure><p>搭建好两台服务器，用户名分别为 <code>guan</code> 和 <code>tomcat</code>，IP 分别为 <code>192.168.209.129</code> 和 <code>192.168.209.131</code>。</p><h1 id="远程执行脚本"><a href="#远程执行脚本" class="headerlink" title="远程执行脚本"></a>远程执行脚本</h1><p>登录其中一台服务器（<code>guan</code>，<code>192.168.209.131</code>），执行如下命令即可在另一台服务器（<code>tomcat</code>，<code>192.168.209.129</code>）上显示 <code>tomcat</code> 用户家目录下的文件信息（<code>cd ~</code>；<code>ls</code>）：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh tomcat@192.168.209.129 <span class="string">&quot;cd ~ ;ls&quot;</span></span><br></pre></td></tr></table></figure><p><code>Are you sure you want to continue connecting (yes/no)?</code> 输入 <code>yes</code>，再输入密码即可，效果如下：</p><p><img src="/img/upload/2022/04/image-1651068709843.webp" alt="SSH 首次连接确认"></p><p>第一次执行的话，会在 <code>guan</code> 用户家目录下会生成一个 <code>.ssh/known_hosts</code> 文件，并添加相应主机的信息，第二次执行时就不会再提示 <code>Are you sure you want to continue connecting (yes/no)?</code> 如下：</p><p><img src="/img/upload/2022/04/image-1651068718043.webp" alt="known_hosts 文件"></p><p><img src="/img/upload/2022/04/image-1651068721654.webp" alt="SSH 连接成功"></p><h1 id="远程执行脚本-1"><a href="#远程执行脚本-1" class="headerlink" title="远程执行脚本"></a>远程执行脚本</h1><p>远程执行命令还不够，我们还需要做到在远程服务器上执行脚本，在 <code>tomcat</code> 那台服务器上写个 <code>Hello.sh</code> 脚本打印 <strong>HelloWorld</strong></p><p><img src="/img/upload/2022/04/image-1651068733221.webp" alt="远程脚本文件"></p><p>使用如下命令即可调用到 <code>tomcat</code> 服务器上的脚本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh tomcat@192.168.209.129 <span class="string">&quot;~/Hello.sh&quot;</span></span><br></pre></td></tr></table></figure><p>效果如下：</p><p><img src="/img/upload/2022/04/image-1651068740007.webp" alt="执行远程脚本"></p><p>在 <code>guan</code> 服务器下把 <code>ssh tomcat@192.168.209.129 &quot;~/Hello.sh&quot;</code> 写到 <code>Test.sh</code> 脚本里，<code>chmod</code> 权限后，执行 <code>Tesh.sh</code> 脚本效果一致，如下：</p><p><img src="/img/upload/2022/04/image-1651068746386.webp" alt="本地调用远程脚本"></p><h1 id="配置-ssh-互信"><a href="#配置-ssh-互信" class="headerlink" title="配置 ssh 互信"></a>配置 ssh 互信</h1><p>每次执行 <code>ssh</code> 远程命令时，都要输入密码，是很麻烦的事情，可以配置服务器之间的 <code>.ssh</code> 互信，免去输入密码的过程，配置过程步骤如下（原理见下一节）：</p><h2 id="1-生成秘钥和公钥"><a href="#1-生成秘钥和公钥" class="headerlink" title="1. 生成秘钥和公钥"></a>1. 生成秘钥和公钥</h2><p>两台服务器下都使用如下命令生成秘钥公钥，然后就会在 <code>guan</code> 用户目录下生成 <code>.ssh</code> 目录，目录下有私钥（<code>id_rsa</code>）和公钥（<code>id_rsa.pub</code>）文件。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t rsa </span><br><span class="line">ssh-keygen -m PEM -t rsa -b 4096</span><br></pre></td></tr></table></figure><h2 id="2-生成-authorized-keys-认证文件"><a href="#2-生成-authorized-keys-认证文件" class="headerlink" title="2. 生成 authorized_keys 认证文件"></a>2. 生成 <code>authorized_keys</code> 认证文件</h2><p>进入 <code>.ssh</code> 目录，将公钥拷贝一份，并命名为 <code>authorized_keys</code>，这个其实就是认证文件，从 <code>id_rsa.pub</code> 拷贝一份也就相当于把自身也给加进了 <code>authorized_keys</code> 文件里（自己也可以用 <code>ssh</code> 远程调用自己）。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> id_rsa.pub authorized_keys</span><br></pre></td></tr></table></figure><h2 id="3-配置-authorized-keys"><a href="#3-配置-authorized-keys" class="headerlink" title="3. 配置 authorized_keys"></a>3. 配置 <code>authorized_keys</code></h2><p>使用 <code>vi</code> 命令把两台服务器 <code>id_rsa.pub</code> 下的内容相互添加到彼此的 <code>authorized_keys</code> 文件上，此时互信配置完成，在 <code>tomcat</code> 服务器上执行 命令：<code>ssh guan@192.168.209.131 &quot;~/Test.sh&quot;</code>，就会执行 <code>guan</code> 服务器上的 <code>Test.sh</code> 脚本，然后又返回来调用 <code>tomcat</code> 下的 <code>Hello.sh</code> 脚本，效果如下：</p><p><img src="/img/upload/2022/04/image-1651068757545.webp" alt="ssh 互信配置"></p><p><img src="/img/upload/2022/04/image-1651068762346.webp" alt="互信执行结果"></p><h1 id="ssh-互信的原理"><a href="#ssh-互信的原理" class="headerlink" title="ssh 互信的原理"></a>ssh 互信的原理</h1><p>ssh 互信中用到了公钥和秘钥，还有认证文件 <code>authorized_keys</code>，那他们具体是做什么的用的呢？</p><p>这里涉及到了密码学的一点小知识，用到了非对称加密算法中的公钥加密算法，这种算法公钥和秘钥是成对出现的（上面使用 <code>ssh-keygen -t rsa</code> 后在 <code>.ssh</code> 下就生成了 <code>id_rsa.pub</code> 和 <code>id_rsa</code>），公钥是可以对外暴露，不用害怕别人知道，使用公钥加密的数据只能用对应的私钥才能解开，而私钥作为解开公钥加密数据的唯一一把钥匙，是不可对外暴露的。</p><p>在互信配置完成后，在 <code>guan</code> 服务器使用 <code>ssh tomcat@192.168.209.129 &quot;~/Hello.sh&quot;</code> 去让远程 <code>tomcat</code> 服务器执行对应命令时，<code>guan</code> 服务器会把自己的公钥发给 <code>tomcat</code> 服务器，<code>tomcat</code> 服务器此时就会在 <code>authorized_keys</code> 认证文件中去匹配看有没有 <code>guan</code> 服务器的公钥，如果有，就会用它的公钥加密认证数据发回给 <code>guan</code> 服务器，<code>guan</code> 服务器接到这个加密后的认证数据，就会用私钥进行解密，再发回给 <code>tomcat</code> 服务器，此时 <code>tomcat</code> 服务器就会进行核对解密后的数据是否和加密前的一致，一致则认证成功，不一致则认证失败。</p><h1 id="关于环境变量问题"><a href="#关于环境变量问题" class="headerlink" title="关于环境变量问题"></a>关于环境变量问题</h1><p>过程中遇到了一个环境变量导致的问题，在 <code>tomcat</code> 服务器下配置了 <code>JAVA_HOME</code> 环境变量的，是可以执行 <code>java</code> 命令，如下：</p><p><img src="/img/upload/2022/04/image-1651068771117.webp" alt="Java 环境变量配置"></p><p>但是在 <code>guan</code> 服务器上执行 <code>ssh tomcat@192.168.209.129 &quot;java&quot;</code>，远程在 <code>tomcat</code> 服务器上执行 <code>java</code> 命令则会提示 <code>java</code> 命令不存在，如下：</p><p><img src="/img/upload/2022/04/image-1651068777653.webp" alt="远程执行 java 命令"></p><p>可以确定是远程执行 <code>ssh</code> 命令时 <code>JAVA_HOME</code> 环境变量没有生效，解决办法是使用全路径去执行 <code>java</code> 命令，如下：</p><p><img src="/img/upload/2022/04/image-1651068783178.webp" alt="全路径执行 java 命令"></p>]]>
    </content>
    <id>https://cfyong.com/linux/ssh-remote-command-execution/</id>
    <link href="https://cfyong.com/linux/ssh-remote-command-execution/"/>
    <published>2020-04-25T12:35:19.000Z</published>
    <summary>Linux下使用SSH远程执行服务器命令的方法总结，包括免密登录配置和跨服务器脚本调用实践。</summary>
    <title>Linux 下 ssh 执行远程服务器命令</title>
    <updated>2022-04-27T14:15:44.823Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Java" scheme="https://cfyong.com/categories/Java/"/>
    <category term="Java" scheme="https://cfyong.com/tags/Java/"/>
    <category term="Maven" scheme="https://cfyong.com/tags/Maven/"/>
    <content>
      <![CDATA[<p>之前记录了maven：jar、dependency打包插件简记，这里再记录一下 maven-assembly打包插件的使用，方便日后回顾和查阅。</p><h1 id="maven-assembly-plugin"><a href="#maven-assembly-plugin" class="headerlink" title="maven-assembly-plugin"></a>maven-assembly-plugin</h1><p>assembly 也是 maven 下的一个打包插件，其可以将项目里的资源按照相应的配置（需要配置相应的 descriptor 描述文件）打包成一个包（支持 zip、jar、tar、tar.gz、tar.bz2包），其 pom 的配置和解释如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- maven-assembly-plugin 自定义打包貌似无法打可执行 Jar，这里用 maven-jar-plugin 来打可执行jar包--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-jar-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">archive</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">manifest</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">useUniqueVersions</span>&gt;</span>false<span class="tag">&lt;/<span class="name">useUniqueVersions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">mainClass</span>&gt;</span>com.chifuyong.TestDemo<span class="tag">&lt;/<span class="name">mainClass</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">addClasspath</span>&gt;</span>true<span class="tag">&lt;/<span class="name">addClasspath</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">classpathPrefix</span>&gt;</span>dependencies/<span class="tag">&lt;/<span class="name">classpathPrefix</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">manifest</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">archive</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- maven-assembly-plugin 打包配置，使用自定义文件描述来打包 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-assembly-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.2.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">executions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">execution</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">id</span>&gt;</span>assembly-test<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!-- 在 package 阶段执行 assembly:single --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">phase</span>&gt;</span>package<span class="tag">&lt;/<span class="name">phase</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">goals</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- 在 package 阶段执行 assembly:single --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">goal</span>&gt;</span>single<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- 打包后的文件名会以 finalName-id (id 为 descriptor xml 的 id ) --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">finalName</span>&gt;</span>$&#123;project.artifactId&#125;<span class="tag">&lt;/<span class="name">finalName</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">descriptors</span>&gt;</span></span><br><span class="line">                    <span class="comment">&lt;!-- 自定义描述文件(里面定义了如何打包)的路径 --&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">descriptor</span>&gt;</span>assemblies/assembly.xml<span class="tag">&lt;/<span class="name">descriptor</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">descriptors</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 如果还需要打另一个以不同方式打的包，可以再配置一个 execution --&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br></pre></td></tr></table></figure><p>这里使用了 <code>jar-plugin</code> 来将项目打包成可执行 Jar，再通过 <code>pom.xml</code> 下的 <code>&lt;descriptor&gt;</code> 标签配置的描述文件 ，对项目里的资源进行整合打包成一个包文件，此次示例中用到的描述文件为：<code>assemblies/assembly.xml</code> ，其具体配置和解释如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- maven-assembly-plugin 自定义打包配置--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">id</span>&gt;</span>$&#123;project.version&#125;<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">formats</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--打包的类型：zip、jar、tar、tar.gz、tar.bz2、war、dir--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">format</span>&gt;</span>tar.gz<span class="tag">&lt;/<span class="name">format</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">formats</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 打包后有无根路径目录,这边为true,</span></span><br><span class="line"><span class="comment">     根路径目录为 pom 文件中的&lt;finalName&gt;$&#123;project.artifactId&#125;&lt;/finalName&gt; --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">includeBaseDirectory</span>&gt;</span>true<span class="tag">&lt;/<span class="name">includeBaseDirectory</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 打包单个文件 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">files</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">file</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 把项目 jar 打包进去，并改名 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">source</span>&gt;</span>$&#123;project.build.directory&#125;/$&#123;project.artifactId&#125;-$&#123;project.version&#125;.jar<span class="tag">&lt;/<span class="name">source</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">outputDirectory</span>&gt;</span>/<span class="tag">&lt;/<span class="name">outputDirectory</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 可以修改打包后文件的名称--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">destName</span>&gt;</span>maven-plugin-example.jar<span class="tag">&lt;/<span class="name">destName</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">file</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">files</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--打包文件集--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">fileSets</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">fileSet</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 文件目录 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">directory</span>&gt;</span>$&#123;project.basedir&#125;/src/main/resources/bin<span class="tag">&lt;/<span class="name">directory</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 目标目录 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">outputDirectory</span>&gt;</span>/<span class="tag">&lt;/<span class="name">outputDirectory</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">fileSet</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- config文件打包 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">fileSet</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- $&#123;profile.env&#125; 为自定义的 profile --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">directory</span>&gt;</span>$&#123;project.basedir&#125;/src/main/resources/config/$&#123;profile.env&#125;<span class="tag">&lt;/<span class="name">directory</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">outputDirectory</span>&gt;</span>/conf<span class="tag">&lt;/<span class="name">outputDirectory</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">includes</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">include</span>&gt;</span>*.xml<span class="tag">&lt;/<span class="name">include</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">includes</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">fileSet</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">fileSets</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--打包依赖库--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependencySets</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencySet</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 依赖所属目录 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">outputDirectory</span>&gt;</span>/lib<span class="tag">&lt;/<span class="name">outputDirectory</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--是否把包解开，默认为 false--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">unpack</span>&gt;</span>false<span class="tag">&lt;/<span class="name">unpack</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 排除自身 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">useProjectArtifact</span>&gt;</span>false<span class="tag">&lt;/<span class="name">useProjectArtifact</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- scope 范围--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">scope</span>&gt;</span>runtime<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencySet</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencySets</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">assembly</span>&gt;</span></span><br></pre></td></tr></table></figure><p><code>mvn:package</code> 之后，打包后的会生成一个 <code>*.tar.gz</code> 文件，这个包里的文件就是按照描述里的配置而打包出来的，具体内容如下：</p><p><img src="/img/upload/2022/04/image-1651041773351.webp" alt="maven-assembly-plugin"></p><p><img src="/img/upload/2022/04/image-1651041808084.webp" alt="maven-assembly-plugin"></p><p>默认的话 assembly 也有四个内置的 assembly descriptor 可以使用，在 <code>maven-assembly-plugin.3.2.0.jar</code> 下可以看到，相应的描述文件及其作用，如下图 <code>bin.xml</code>、<code>jar-with-dependencies.xml</code> 、<code>src.xml</code>、<code>project.xml</code> 都是其内置的描述文件，可以点击查看其相应的配置。</p><p><img src="/img/upload/2022/04/image-1651041847945.webp" alt="maven-assembly-plugin"></p><p>如果想用内置描述文件进行打包也可以，这里用 <code>jar-with-dependencies.xml</code> （将项目代码和其所依赖的所有 jar 都打包到一个 jar 里）这个内置描述文件做例子，其配置如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- maven-assembly-plugin 打包配置:jar-with-dependencies --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-assembly-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.2.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">appendAssemblyId</span>&gt;</span>false<span class="tag">&lt;/<span class="name">appendAssemblyId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">descriptorRefs</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">descriptorRef</span>&gt;</span>jar-with-dependencies<span class="tag">&lt;/<span class="name">descriptorRef</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">descriptorRefs</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">archive</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">manifest</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">mainClass</span>&gt;</span>com.chifuyong.TestDemo<span class="tag">&lt;/<span class="name">mainClass</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">manifest</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">archive</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">executions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">execution</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">phase</span>&gt;</span>package<span class="tag">&lt;/<span class="name">phase</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">goals</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">goal</span>&gt;</span>single<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br></pre></td></tr></table></figure><p>打包后的 jar 进行反编译，内容如下：</p><p><img src="/img/upload/2022/04/image-1651041855422.webp" alt="maven-assembly-plugin"></p>]]>
    </content>
    <id>https://cfyong.com/java/maven-assembly-packaging/</id>
    <link href="https://cfyong.com/java/maven-assembly-packaging/"/>
    <published>2020-04-18T02:59:30.000Z</published>
    <summary>Maven assembly打包插件使用教程，介绍如何将项目资源打包成zip、tar.gz等多种格式的分发包。</summary>
    <title>maven：assembly打包插件简记</title>
    <updated>2022-04-27T06:45:13.934Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="IT技术" scheme="https://cfyong.com/categories/IT%E6%8A%80%E6%9C%AF/"/>
    <category term="Git" scheme="https://cfyong.com/tags/Git/"/>
    <content>
      <![CDATA[<p>虽然现在各种 Git 可视化工具都很好用，但是常用命令能熟练使用还是比较好的。好记性不如烂笔头，这里记下 git 命令，方便日后快速翻阅。</p><h1 id="初始配置"><a href="#初始配置" class="headerlink" title="初始配置"></a>初始配置</h1><h2 id="1-初始化目录"><a href="#1-初始化目录" class="headerlink" title="1. 初始化目录"></a>1. 初始化目录</h2><p>进入相应目录，使用命令 <code>git init</code>，会在目录下生成 <code>.git</code> 目录，里面都是 git 的记录信息，切不可乱删除。</p><h2 id="2-设置库级别签名"><a href="#2-设置库级别签名" class="headerlink" title="2. 设置库级别签名"></a>2. 设置库级别签名</h2><p>仅在当前本地库有效：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config user.name ChiFuYong</span><br><span class="line">git config user.email g3545616@gmail</span><br></pre></td></tr></table></figure><p>详细信息保存于当前库目录的 <code>.git/config</code> 中，使用 <code>cat conf</code> 即可查看。</p><h2 id="3-设置全局级签名"><a href="#3-设置全局级签名" class="headerlink" title="3. 设置全局级签名"></a>3. 设置全局级签名</h2><p>对登录系统的当前用户全局有效：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config --global user.name ChiFuYong</span><br><span class="line">git config --global user.email g3545616@gmail</span><br></pre></td></tr></table></figure><p>详细信息保存于 <code>~/.gitconfig</code> 中，使用 <code>cat ~/.gitconfig</code> 可看到如下信息。</p><p><strong>注：库级别优先于全局级别，二者都有时采用库级别。签名用于区分不同开发人员身份，与远程 Git 服务器上的账号密码无关。</strong></p><p><img src="/img/upload/2022/04/image-1650992383599.webp" alt="设置全局级签名"></p><h2 id="4-gitconfig-中配置忽略文件（java-gitignore）"><a href="#4-gitconfig-中配置忽略文件（java-gitignore）" class="headerlink" title="4. .gitconfig 中配置忽略文件（java.gitignore）"></a>4. <code>.gitconfig</code> 中配置忽略文件（<code>java.gitignore</code>）</h2><p>编辑 <code>vim ~/.gitconfig</code>，所有 git 库都会忽略相应文件，添加内容如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[core]</span><br><span class="line">    excludesfile = /home/guan/Java.gitignore</span><br></pre></td></tr></table></figure><p><code>java.gitignore</code> 内容如下（详细可参考 <a href="https://github.com/github/gitignore">Github 项目</a>）：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"># Compiled class file</span><br><span class="line">*.class</span><br><span class="line"># Log file</span><br><span class="line">*.log</span><br><span class="line"># BlueJ files</span><br><span class="line">*.ctxt</span><br><span class="line"># Mobile Tools for Java (J2ME)</span><br><span class="line">.mtj.tmp/</span><br><span class="line"># Package Files #</span><br><span class="line">*.jar</span><br><span class="line">*.war</span><br><span class="line">*.nar</span><br><span class="line">*.ear</span><br><span class="line">*.zip</span><br><span class="line">*.tar.gz</span><br><span class="line">*.rar</span><br><span class="line"># virtual machine crash logs</span><br><span class="line">hs_err_pid*</span><br><span class="line"># Eclipse ignore</span><br><span class="line">.classpath</span><br><span class="line">.project</span><br><span class="line">.settings</span><br><span class="line"># Maven Compiled Directory</span><br><span class="line">target</span><br><span class="line"># IDEA ignore</span><br><span class="line">.idea</span><br><span class="line">*.iml</span><br><span class="line">out</span><br></pre></td></tr></table></figure><h1 id="基本操作命令"><a href="#基本操作命令" class="headerlink" title="基本操作命令"></a>基本操作命令</h1><ul><li><strong><code>git init</code></strong>：初始化仓库</li><li><strong><code>git status</code></strong>：查看工作区、暂存区状态</li><li><strong><code>git add [file name]</code></strong>：将工作区的文件（新建或修改）添加到暂存区，<code>git add .</code> 表示添加所有修改过的文件到暂存区</li><li><strong><code>git commit -m &quot;commit message&quot; [file name]</code></strong>：将暂存区的文件提交到本地库，<code>-m</code> 表示此次提交的修改概述</li><li><strong><code>git log</code></strong>：查看 commit 的详细历史记录，其他常用命令参数如下：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span> --pretty=oneline</span><br><span class="line">git <span class="built_in">log</span> --oneline</span><br><span class="line">git reflog</span><br></pre></td></tr></table></figure><p>三者区别如下图：</p><p><img src="/img/upload/2022/04/image-1650992401299.webp" alt="基本操作命令"></p><ul><li><strong><code>git diff [file name]</code></strong>：比较工作区中文件和暂存区差别</li><li><strong><code>git diff [版本号] [file name]</code></strong>：工作区文件和本地库历史版本比较</li><li><strong><code>git reset</code></strong>：版本回退&#x2F;前进，有三种方式，参数作用如下：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">--soft    <span class="comment"># 仅仅在本地库移动 HEAD 指针</span></span><br><span class="line">--mixed   <span class="comment"># 1. 在本地库移动 HEAD 指针  2. 重置暂存区（默认方式）</span></span><br><span class="line">--hard    <span class="comment"># 1. 在本地库移动 HEAD 指针  2. 重置暂存区  3. 重置工作区</span></span><br></pre></td></tr></table></figure><p><code>git reset --hard [局部版本索引]</code> 可直接恢复到相应版本，<code>git reset --hard HEAD^</code> 表示回退到上个版本（多少个 <code>^</code> 代表回退多少个版本），<code>git reset --hard HEAD~n</code> 表示后退 n 步。</p><h1 id="分支管理命令"><a href="#分支管理命令" class="headerlink" title="分支管理命令"></a>分支管理命令</h1><ul><li><strong><code>git branch -v</code></strong>：查看全部分支</li><li><strong><code>git branch [branch name]</code></strong>：创建分支</li><li><strong><code>git branch -d [branch name]</code></strong>：删除分支</li><li><strong><code>git checkout [branch name]</code></strong>：切换分支</li><li><strong><code>git merge [branch name]</code></strong>：把指定分支合并到当前分支</li><li><strong><code>git rebase [branch name]</code></strong>：从当前分支合并指定分支，和 merge 有所区别，会把 commit 内容暂存起来然后再合并，合并后不会导致分叉</li></ul><h1 id="暂存操作命令"><a href="#暂存操作命令" class="headerlink" title="暂存操作命令"></a>暂存操作命令</h1><ul><li><strong><code>git stash save &quot;信息&quot;</code></strong>：暂存当前工作区和暂存区内容，工作区将会变干净，开发时在需要排查其他分支的 bug 问题时常用</li><li><strong><code>git stash list</code></strong>：显示暂存过的所有列表</li><li><strong><code>git stash pop</code></strong>：恢复到最新的暂存数据到工作区，默认会把工作区和暂存区的改动都恢复到工作区。<code>git stash pop stash@{X}</code> 可恢复到某个暂存记录，<code>@{X}</code> 通过 <code>git stash list</code> 命令可以看到。注：<code>git stash pop</code> 恢复暂存数据后，会删除恢复的那条暂存记录（类似于弹栈弹出去了）</li><li><strong><code>git stash apply</code></strong>：除了恢复后不会删除暂存记录，其他和 <code>git stash pop</code> 功能一样</li><li><strong><code>git stash drop stash@{X}</code></strong>：删除暂存的一条记录，<code>@{X}</code> 通过 <code>git stash list</code> 命令可以看到</li><li><strong><code>git stash clear</code></strong>：删除所有暂存的记录</li></ul><h1 id="远程相关命令"><a href="#远程相关命令" class="headerlink" title="远程相关命令"></a>远程相关命令</h1><ul><li><strong><code>git remote -v</code></strong>：查看当前所有远程地址别名</li><li><strong><code>git remote add [origin] [远程地址]</code></strong>：添加远程服务器关联地址，取名为 origin（默认）</li><li><strong><code>git remote remove [origin]</code></strong>：删除 origin 远程关联地址</li><li><strong><code>git clone [https://github.com/....]</code></strong>：克隆远程服务器仓库代码（默认拉取 master 分支），加上 <code>-b [branch name]</code> 参数可以拉取指定分支</li><li><strong><code>git fetch</code></strong>：更新本地的远程跟踪分支</li><li><strong><code>git pull</code></strong>：相当于 <code>fetch + merge</code>，先更新远程跟踪分支（例如 <code>origin/master</code>），再合并到本地分支，有冲突需要解决冲突</li><li><strong><code>git push [别名] [分支名]</code></strong>：推送代码到远程服务器，有冲突需要 pull 解决代码冲突后再 push 到远程服务器</li></ul>]]>
    </content>
    <id>https://cfyong.com/it/git-command-reference/</id>
    <link href="https://cfyong.com/it/git-command-reference/"/>
    <published>2020-04-16T16:40:11.000Z</published>
    <summary>Git常用命令速查笔记，涵盖初始化、提交、分支管理、合并、远程操作等日常开发高频命令。</summary>
    <title>Git 命令简记</title>
    <updated>2022-04-27T14:38:33.680Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Java" scheme="https://cfyong.com/categories/Java/"/>
    <category term="Java" scheme="https://cfyong.com/tags/Java/"/>
    <category term="Maven" scheme="https://cfyong.com/tags/Maven/"/>
    <content>
      <![CDATA[<p>因为运维要求，最近项目中需要将部署规范化，涉及到了使用 Maven 的打包插件对项目进行重新规范化打包，这里对 Maven 的几个打包插件：<code>maven-jar</code> &#x2F; <code>dependency</code> &#x2F; <code>assembly-plugin</code> 做个总结和简记，方便日后用到时及时翻阅和回顾。</p><h1 id="Java-包基本概念"><a href="#Java-包基本概念" class="headerlink" title="Java 包基本概念"></a>Java 包基本概念</h1><ul><li><strong>普通 jar 包</strong>：都是作为类库，作为给其他工程提供依赖而打出的 jar 包，Maven 中 <code>pom.xml</code> 文件添加的 dependency 都算是普通的 jar 包。</li><li><strong>可执行 jar 包</strong>：即 <code>java -jar</code> 命令就可运行的 jar 包，打包时需要设置入口类等信息。</li><li><strong>war 包</strong>：Java Web应用包，包含所有程序类、配置文件、jsp、js等资源文件，放到 Tomcat 的 <code>webapps</code> 下启动 Tomcat 即可部署 web 服务。</li></ul><h1 id="Maven-打包的几种方式"><a href="#Maven-打包的几种方式" class="headerlink" title="Maven 打包的几种方式"></a>Maven 打包的几种方式</h1><p>默认情况下，使用 <code>mvn package</code> 只会把项目自身的 class 文件打成 jar 包，并不包括工程依赖的其他 jar ，而且打出的也是普通 jar ，往往就是给其他工程做引用而打的 Jar 包。如果想要打出一个可执行的 jar 包，就需要在 <code>pom</code> 中 <code>&lt;build&gt;</code> 标签下做打包插件配置，配置 <code>maven-jar-plugin</code> ，其配置如下：</p><h2 id="maven-jar-plugin"><a href="#maven-jar-plugin" class="headerlink" title="maven-jar-plugin"></a>maven-jar-plugin</h2><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- Maven 打可执行 jar包 配置--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-jar-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">archive</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">manifest</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- 指定启动主类（Main-Class）--&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">mainClass</span>&gt;</span>com.com.chifuyong.TestDemo<span class="tag">&lt;/<span class="name">mainClass</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- 在 MANIFEST.MF 加上 Class-Path 项并配置依赖包 --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">addClasspath</span>&gt;</span>true<span class="tag">&lt;/<span class="name">addClasspath</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- 指定依赖包所在目录 --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">classpathPrefix</span>&gt;</span>dependencies/<span class="tag">&lt;/<span class="name">classpathPrefix</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">manifest</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">archive</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br></pre></td></tr></table></figure><p><code>mainClass</code> 可以设置主类，就是程序的入口类，<code>java -jar</code> 时就是以这个类为入口；<code>addClasspath</code> 表示增加工程所依赖 jar 包的 class-path 路径，设为 true ；<code>classpathPrefix</code> 就是工程依赖 jar class-path 的相对根路径，设为 <code>dependencies</code> ，执行 <code>mvn package</code> 打完包后的，解压 jar 包，其中 <code>MANIFEST.MF</code> 文件部分内容如下图：</p><p><img src="/img/upload/2022/04/image-1651041484915.webp" alt="maven-jar-plugin"></p><p><code>TestDemo</code> 入口类如下，调用了 <code>DruidDataSource</code> 这个类，依赖于 <code>druid-1.0.9.jar</code> 这个包</p><p><img src="/img/upload/2022/04/image-1651041494564.webp" alt="maven-jar-plugin"></p><p>此时做这个配置时，虽然打包打出来的是可执行 jar ，但是并没有把工程所依赖的 jar 包都打进去，<code>java -jar</code> 运行这个 jar 时肯定会因找不到类而报 <code>ClassNotFoundException</code> ，如下：</p><p><img src="/img/upload/2022/04/image-1651041503235.webp" alt="maven-jar-plugin"></p><p>这就需要配合 <code>maven-dependency-plugin</code> 的使用，来将工程所依赖的 jar 包复制到相应的目录，也就是上面 <code>maven-jar-plugin</code> 配置中的 <code>classpathPrefix</code>（<code>dependencies</code>），配置如下：</p><h2 id="maven-dependency-plugin"><a href="#maven-dependency-plugin" class="headerlink" title="maven-dependency-plugin"></a>maven-dependency-plugin</h2><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 可执行jar 相关依赖目录存放配置 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-dependency-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">executions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">execution</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">phase</span>&gt;</span>package<span class="tag">&lt;/<span class="name">phase</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">goals</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">goal</span>&gt;</span>copy-dependencies<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- 依赖的jar包输出目录 --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">outputDirectory</span>&gt;</span>$&#123;project.build.directory&#125;/dependencies<span class="tag">&lt;/<span class="name">outputDirectory</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- 排除 provide 范围--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--                            &lt;excludeScope&gt;provided&lt;/excludeScope&gt;--&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- 只包含 runtime --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">includeScope</span>&gt;</span>runtime<span class="tag">&lt;/<span class="name">includeScope</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">useBaseVersion</span>&gt;</span>true<span class="tag">&lt;/<span class="name">useBaseVersion</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br></pre></td></tr></table></figure><p><code>phase</code> 设置为 <code>package</code> ，<code>goal</code> 设置为 <code>copy-dependencies</code> ，表示在 Maven 的生命周期 <code>package</code> 阶段，会执行 <code>maven-dependency-plugin</code> 插件的 <code>copy-dependencies</code> 功能，也就是当 Maven 执行到 <code>package</code> 时会把工程所依赖的 jar 包复制到某个目录，<code>outputDirectory</code> 设置的就是这个目录，<code>excludeScope</code> 就是排除相应的 scope，排除不需要打包的 scope，而 <code>includeScope</code> 则相反；<code>mvn package</code> 打完包后结果如下，<code>${project.build.directory}</code> 也就是 Maven（约定大于配置理念）约定好了的编译目录 <code>target</code> ，结构如下图：</p><p><img src="/img/upload/2022/04/image-1651041513620.webp" alt="maven-dependency-plugin"></p><p>这个时候只需要将 jar 包和 <code>dependencies</code> 目录（里面有工程所依赖的 jar 包）放在同个目录下，之后，之后不管放哪里，<code>java -jar</code> 都不会再报 找不到类，如下：</p><p><img src="/img/upload/2022/04/image-1651041521647.webp" alt="maven-dependency-plugin"></p>]]>
    </content>
    <id>https://cfyong.com/java/maven-jar-dependency-packaging/</id>
    <link href="https://cfyong.com/java/maven-jar-dependency-packaging/"/>
    <published>2020-04-16T12:22:05.000Z</published>
    <summary>Maven打包插件使用总结，详解maven-jar-plugin和maven-dependency-plugin配置可执行jar包的方法。</summary>
    <title>maven：jar、dependency打包插件简记</title>
    <updated>2022-04-27T06:39:46.077Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="C/C++" scheme="https://cfyong.com/categories/C-C/"/>
    <category term="Windows" scheme="https://cfyong.com/tags/Windows/"/>
    <category term="MinGW-w64" scheme="https://cfyong.com/tags/MinGW-w64/"/>
    <content>
      <![CDATA[<p><strong>MinGW</strong>（Minimalist GNU on Windows）是 GCC 编译器的 Windows 移植版本，包含了 Win32 API，可以编译出可在 Windows 下运行的可执行文件，做个安装简记。</p><h1 id="下载包"><a href="#下载包" class="headerlink" title="下载包"></a>下载包</h1><p><a href="https://sourceforge.net/projects/mingw-w64/files/">点此下载解压包</a>，版本选择如下：</p><p><img src="/img/upload/2022/04/image-1651072203045.webp" alt="下载包"></p><p>其中 <code>GCC-8.1.0</code> 表示 GCC 版本为 8.1.0；<code>x86_64</code> 表示 64 位系统（<code>i686</code> 表示 32 位）；<code>win32</code> 表示内置有 Win32 API，用于开发 Windows 下的程序；<code>posix</code> 表示符合 POSIX 协议的操作系统 API，也就是类 Unix 的都算；<code>seh</code> 是异常处理模型，seh 只支持 64 位、性能好，<code>sjlj</code> 稳定性好、支持 32 位和 64 位，<code>dwarf</code> 只支持 32 位、性能好。这里选择 <strong>x86_64-win32-seh</strong>。</p><h1 id="配置环境变量"><a href="#配置环境变量" class="headerlink" title="配置环境变量"></a>配置环境变量</h1><p>将软件包解压到 <code>E:\Program Files (x86)\</code> 目录下，配置如下环境变量：</p><p><img src="/img/upload/2022/04/image-1651072250184.webp" alt="配置环境变量"></p><p>使用 <code>gcc HelloWorld.c -o HelloWorld</code> 编译 C 源码：</p><p><img src="/img/upload/2022/04/image-1651072265407.webp" alt="配置环境变量"></p><h1 id="配置-make-命令"><a href="#配置-make-命令" class="headerlink" title="配置 make 命令"></a>配置 make 命令</h1><p><code>make</code> 在 Linux&#x2F;Unix 下可直接使用，Windows 中还需做如下配置：</p><ul><li>复制 <code>bin</code> 目录下的 <code>gcc.exe</code>，改名为 <code>cc.exe</code></li></ul><p><img src="/img/upload/2022/04/image-1651072297815.webp" alt="配置 make 命令"></p><ul><li>复制 <code>bin</code> 目录下的 <code>mingw32-make.exe</code>，改名为 <code>make.exe</code></li></ul><p><img src="/img/upload/2022/04/image-1651072307039.webp" alt="配置 make 命令"></p><ul><li>使用 <code>make HelloWorld</code>（不需要 <code>.c</code> 文件后缀）即可编译出 <code>HelloWorld.exe</code></li></ul><p><img src="/img/upload/2022/04/image-1651072318897.webp" alt="配置 make 命令"></p>]]>
    </content>
    <id>https://cfyong.com/it/windows-mingw-w64-setup/</id>
    <link href="https://cfyong.com/it/windows-mingw-w64-setup/"/>
    <published>2020-03-29T12:54:20.000Z</published>
    <summary>MinGW-w64解压版安装配置教程，讲解GCC编译器在Windows环境下的下载、环境变量配置及编译测试。</summary>
    <title>mingGW Win32 64位解压版配置简记</title>
    <updated>2022-04-27T15:13:12.571Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="NoSQL" scheme="https://cfyong.com/categories/NoSQL/"/>
    <category term="Redis" scheme="https://cfyong.com/tags/Redis/"/>
    <category term="缓存" scheme="https://cfyong.com/tags/%E7%BC%93%E5%AD%98/"/>
    <content>
      <![CDATA[<h2 id="Redis-简介"><a href="#Redis-简介" class="headerlink" title="Redis 简介"></a>Redis 简介</h2><p>Redis 是一种典型的基于键值对的 NoSQL 数据库，使用 C 语言实现，数据主要存放在内存中，因此读写速度非常快。它非常适合作为缓存层使用，尤其适合存放访问频率高、更新频率低的数据，例如热点配置、会话信息、商品详情等。需要注意的是，Redis 不能完全替代关系型数据库，它更适合高性能缓存和消息队列等场景。</p><h2 id="Redis-数据流转总览"><a href="#Redis-数据流转总览" class="headerlink" title="Redis 数据流转总览"></a>Redis 数据流转总览</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">flowchart LR</span><br><span class="line">    A[客户端请求] --&gt; B[Redis Server]</span><br><span class="line">    B --&gt; C&#123;是否命中缓存&#125;</span><br><span class="line">    C --&gt;|命中| D[直接返回结果]</span><br><span class="line">    C --&gt;|未命中| E[查询数据库]</span><br><span class="line">    E --&gt; F[写回 Redis]</span><br><span class="line">    F --&gt; G[返回客户端]</span><br><span class="line">    B --&gt; H[持久化存储 RDB/AOF]</span><br></pre></td></tr></table></figure><h2 id="Redis-持久化"><a href="#Redis-持久化" class="headerlink" title="Redis 持久化"></a>Redis 持久化</h2><p>Redis 主要有两种持久化方式：</p><ul><li><p><strong>RDB（快照方式）</strong></p><ul><li>默认的持久化策略。</li><li>Redis 会在指定时间间隔内，将内存中的数据写入一个二进制快照文件，默认文件名为 <code>dump.rdb</code>。</li><li>可以使用 <code>SAVE</code> 或 <code>BGSAVE</code> 触发快照。</li><li>如果 Redis 崩溃，可能丢失最后一次快照之后发生的修改。</li></ul></li><li><p><strong>AOF（日志追加方式）</strong></p><ul><li>记录 Redis 执行的写命令，并以日志形式追加到文件中。</li><li>更适合数据恢复和较完整的数据保留。</li><li>但相对 RDB 来说，写入成本更高，性能也通常略低。</li></ul></li></ul><blockquote><p>Redis 作为缓存时，通常更关注高性能，因此很多场景会选择 RDB 或混合使用 AOF + RDB。</p></blockquote><h2 id="Redis-安装"><a href="#Redis-安装" class="headerlink" title="Redis 安装"></a>Redis 安装</h2><ul><li>安装 gcc，用于编译 Redis</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> yum install gcc c++</span><br><span class="line"><span class="built_in">sudo</span> apt-get install gcc c++</span><br></pre></td></tr></table></figure><ul><li>解压 Redis 软件包（以 5.0.7 为例）</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> tar -zxvf redis-5.0.7.tar.gz -C /opt</span><br></pre></td></tr></table></figure><ul><li>编译并安装</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /opt/redis-5.0.7/src</span><br><span class="line"><span class="built_in">sudo</span> make install PREFIX=/opt/redis</span><br></pre></td></tr></table></figure><blockquote><p>说明：<code>PREFIX=/opt/redis</code> 表示将 Redis 安装到 <code>/opt/redis</code> 目录。如果报错，可尝试加上 <code>MALLOC=libc</code> 参数。</p></blockquote><ul><li>配置守护进程（后台运行）</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> <span class="built_in">cp</span> ../../redis-5.0.7/redis.conf /opt/redis/bin/</span><br></pre></td></tr></table></figure><p>修改配置文件中的 <code>daemonize no</code> 为 <code>daemonize yes</code>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> vim redis.conf</span><br></pre></td></tr></table></figure><p><img src="/img/upload/2022/04/image-1651132890703.webp" alt="redis 安装"></p><ul><li>设置密码</li></ul><p>修改 <code>requirepass</code> 的值即可设置密码：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> vim redis.conf</span><br></pre></td></tr></table></figure><p><img src="/img/upload/2022/04/image-1651132899998.webp" alt="redis 安装"></p><ul><li>启动 Redis 服务</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./redis-server redis.conf</span><br></pre></td></tr></table></figure><ul><li>连接 Redis</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./redis-cli -h 192.168.139.132 -p 6379 -a password</span><br></pre></td></tr></table></figure><p>参数说明：</p><ul><li><code>-h</code>：主机地址</li><li><code>-p</code>：端口号</li><li><code>-a</code>：密码</li></ul><blockquote><p>如果 Redis 未设置密码，直接执行 <code>./redis-cli</code> 默认会连接 <code>6379</code> 端口。</p></blockquote><ul><li>关闭 Redis 服务</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./redis-cli -h 192.168.139.132 -p 6379 shutdown</span><br></pre></td></tr></table></figure><blockquote><p>关闭时务必带上 <code>-p</code> 参数，否则默认会关闭 <code>6379</code> 端口。</p></blockquote><p>如果 Redis 不是以 root 用户启动，需要注意 <code>/opt/redis</code> 目录的权限，否则可能无法创建 <code>dump.rdb</code>，进而导致关闭时报错。下图中的 <code>dump.rdb</code> 是由其他用户创建的，而不是 root 用户创建的：</p><p><img src="/img/upload/2022/04/image-1651132910971.webp" alt="redis 安装"></p><h2 id="Redis-主从配置"><a href="#Redis-主从配置" class="headerlink" title="Redis 主从配置"></a>Redis 主从配置</h2><p>为了减轻 Redis 的访问压力，可以实施主从复制，形成<strong>读写分离</strong>，从而降低主节点负载。一个 <code>master</code> 可以对应多个 <code>slave</code>，但一个 <code>slave</code> 只能对应一个 <code>master</code>。其中 <code>master</code> 支持读写，<code>slave</code> 一般只支持读操作。下面以单机伪集群为例说明：多个 Redis 实例使用不同端口。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">flowchart TD</span><br><span class="line">    A[客户端] --&gt; B[Master:6379]</span><br><span class="line">    B --&gt; C[Slave:6380]</span><br><span class="line">    B --&gt; D[Slave:6381]</span><br><span class="line">    B --&gt; E[Slave:6382]</span><br></pre></td></tr></table></figure><p>配置步骤：</p><ul><li>复制 slave 服务</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> -r /opt/redis/bin ../redis-c1</span><br></pre></td></tr></table></figure><ul><li>修改从节点配置文件</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim redis.conf</span><br></pre></td></tr></table></figure><p>将 <code>port</code> 修改为新的端口，例如 <code>3545</code>，并在 <code>replicaof</code> 中指定主节点 IP 和端口；如果主节点启用了密码，还需要设置 <code>masterauth</code>。</p><p><img src="/img/upload/2022/04/image-1651132920710.webp" alt="redis 主从配置"></p><ul><li>启动从服务器</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./redis-server redis.conf</span><br></pre></td></tr></table></figure><ul><li>验证配置是否生效</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">./redis-cli -p 3545</span><br><span class="line">./redis-cli -p 7000</span><br><span class="line">INFO</span><br></pre></td></tr></table></figure><p>如下图所示，可通过 <code>INFO</code> 命令观察主从复制状态：</p><p><img src="/img/upload/2022/04/image-1651132928907.webp" alt="redis 主从配置"></p><p><img src="/img/upload/2022/04/image-1651132936246.webp" alt="redis 主从配置"></p><h2 id="Jedis-API-使用"><a href="#Jedis-API-使用" class="headerlink" title="Jedis API 使用"></a>Jedis API 使用</h2><ul><li>Maven 依赖：</li></ul><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>redis.clients<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jedis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.1.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure><ul><li>使用示例：</li></ul><p><img src="/img/upload/2022/04/image-1651132949572.webp" alt="jedis api 使用"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Redis 的核心价值在于高性能读写和数据缓存能力，尤其适合热点数据缓存、会话管理和分布式计数等场景。掌握其持久化、主从复制和客户端 API 的基础用法后，才能更稳妥地在项目中使用它。</p>]]>
    </content>
    <id>https://cfyong.com/database/redis-installation-persistence-replication/</id>
    <link href="https://cfyong.com/database/redis-installation-persistence-replication/"/>
    <published>2020-03-14T09:47:36.000Z</published>
    <summary>Redis数据库全面总结，涵盖简介、数据类型、持久化机制、主从复制、哨兵模式及缓存穿透等问题。</summary>
    <title>Redis 总结</title>
    <updated>2022-04-28T15:23:55.185Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="数据库" scheme="https://cfyong.com/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    <category term="MySQL" scheme="https://cfyong.com/tags/MySQL/"/>
    <content>
      <![CDATA[<h1 id="事务概念"><a href="#事务概念" class="headerlink" title="事务概念"></a>事务概念</h1><p>事务在数据库里是很重要的概念，指的是用户定义的一组不可分割的数据库操作序列，这组操作要么全执行，要么全失败回滚，保证了数据操作前后持一致性。以 JDBC 操作数据库中的转账汇款为例，在没开启事务的情况下，假设 xm、xh各有 1000 块钱，总共 2000 块钱，当 xm 向 xh 汇款 100 块钱时，执行如下图的方法：</p><p><img src="/img/upload/2022/04/image-1651133151475.webp" alt="事务概念"></p><p>xm 账户先是减去了相应的 100 ，但是由于 <code>/by zero</code> 异常，xh 账户上却没有加上相应的 100，此时就是丢掉了数据前后的一致性，因为当上图 transfer 方法执行后，xm 还有 900，xh 还是 1000 块钱，总共 1900 块钱，与刚开始 xm、xh 共持有的钱 2000 不符，也就是 xm 平白无故的就消失了 100 块钱，这个要是在现实生活中换做谁都是接收不了的。</p><p>而事务开启后，上图中这两条 SQL 语句将会变成<strong>一荣俱荣，一损俱损</strong>的状态（原子性），只要事务还没提交，即使发生了 <code>/by zero</code> 错误，xm 减去 100 的那条 SQL 语句就会被回滚，xm 最终还是 1000 块钱，从而保证了 xm、xh 所持有总钱数的一致性。</p><h1 id="四大特性（ACID）"><a href="#四大特性（ACID）" class="headerlink" title="四大特性（ACID）"></a>四大特性（ACID）</h1><ul><li><strong>原子性（Atomicity）</strong>：用户定义的多条 SQL 语句是一个整体，要么全部执行，要么全部不执行。</li><li><strong>一致性（Consistency）</strong>：事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态，就像上面说的转完钱后 xm、xh 持有的总钱数应保持不变。</li><li><strong>隔离性（Isolation）</strong>：多个事务并发访问数据时，事务之间是相互隔离的，相互之间不会存在影响。数据库设立了不同的隔离级别，MySQL 有四个隔离级别：<code>Read uncommitted</code>、<code>Read committed</code>、<code>Repeatable read</code>（默认）、<code>Serializable</code>，详细后面分析。</li><li><strong>持久性（Durability）</strong>：只要事务提交，数据就会被保存至数据库并保证永不丢失。也就是从内存里保存到了磁盘里，即使是数据库宕机崩溃、断电，数据都不会丢失。</li></ul><h1 id="事务并发问题"><a href="#事务并发问题" class="headerlink" title="事务并发问题"></a>事务并发问题</h1><p>当多个事务并发访问数据时，若不对并发操作加以控制的话，就可能会造成查询和更新到不正确的数据，破坏事务前后的一致性，发生<strong>脏读</strong>、<strong>不可重复读</strong>、<strong>虚读</strong>。</p><ul><li><strong>脏读（dirty read）</strong>：一个事务读取到了另一个事务未提交时修改的数据。解析图如下：</li></ul><p><img src="/img/upload/2022/04/image-1651133163445.webp" alt="事务并发问题"></p><p>事务 B 先查询了 xm 的 money，接着事务 A 修改了 xm 的 money，A 并没有提交事务，事务 B 再次查询 xm 的 money 时就变为了事务 A 修改后的内容了，这个就是脏读。</p><ul><li><strong>不可重复读（unrepeatable read）</strong>：一个事务读取到了另一个事务提交后的数据。解析图如下：</li></ul><p><img src="/img/upload/2022/04/image-1651133178414.webp" alt="事务并发问题"></p><p>意思是指：事务 A 在 update 一行数据的时候，事务 B 在其 update 前后都访问了这行数据，导致事务 B 两次查询这行数据时结果不一致。注：这里是指 update 一行数据，与幻读中的 insert 数据不同。</p><ul><li><strong>幻读&#x2F;虚读（phantom read）</strong>：一个事务读取到了另一个事务提交后的数据，解析图如下：</li></ul><p><img src="/img/upload/2022/04/image-1651133186433.webp" alt="事务并发问题"></p><p>这个和不可重复读的概念很像，在事务 B insert 一行数据时，事务 A 在 insert 之前查了两次表中所有数据，导致两次结果集不一致，第二次查询时多了一条事务 B insert 的数据。注：这里是指 insert 一行数据，与幻读中的 update 数据不同。</p><ul><li><strong>丢失更新（lost update）</strong></li></ul><p><img src="/img/upload/2022/04/image-1651133195867.webp" alt="事务并发问题"></p><p><img src="/img/upload/2022/04/image-1651133202162.webp" alt="事务并发问题"></p><h1 id="MySQL-事务隔离级别"><a href="#MySQL-事务隔离级别" class="headerlink" title="MySQL 事务隔离级别"></a>MySQL 事务隔离级别</h1><p>事务隔离级别是事务并发控制的整体解决方案，它通过锁机制来实现。MySQL 有四个隔离级别，通过设置相应隔离级别可以防止脏读、不可重复读、幻读。</p><ul><li><strong>Read uncommitted（读未提交）</strong>：可以读取未提交的记录，会出现脏读、幻读、不可重复读，所有并发问题都可能遇到。</li><li><strong>Read committed（读已提交）</strong>：事务中只能读到已提交的修改，不会出现脏读现象，但是会出现幻读、不可重复读。</li><li><strong>Repeatable read（可重复读）</strong>：解决了不可重复读问题，但是仍然存在幻读问题，MySQL InnoDb 默认的隔离级别。</li><li><strong>Serializable（序列化）</strong>：最强级别的事务隔离，解决脏读、不可重复读、幻读问题，但是开启后会拖慢数据库并发效率，性能最低。</li></ul><p>查看隔离级别：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> @<span class="variable">@session</span>.tx_isolation, @<span class="variable">@global</span>.tx_isolation;</span><br></pre></td></tr></table></figure><blockquote><p><code>session</code> &#x2F; <code>local</code> 为会话变量，<code>global</code> 为全局变量。</p></blockquote><p>设置隔离级别：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SET</span> @<span class="variable">@session</span>.tx_isolation <span class="operator">=</span> <span class="number">0</span><span class="operator">/</span><span class="number">1</span><span class="operator">/</span><span class="number">2</span><span class="operator">/</span><span class="number">3</span>;</span><br></pre></td></tr></table></figure><blockquote><p>0~3 分别表示：Read uncommitted、Read committed、Repeatable read、Serializable</p></blockquote>]]>
    </content>
    <id>https://cfyong.com/database/mysql-transactions/</id>
    <link href="https://cfyong.com/database/mysql-transactions/"/>
    <published>2020-03-11T10:01:55.000Z</published>
    <summary>数据库事务概念详解，讲解ACID四大特性及隔离级别，通过转账案例说明事务的原子性和一致性。</summary>
    <title>数据库事务详解</title>
    <updated>2022-04-28T08:10:38.158Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Java" scheme="https://cfyong.com/categories/Java/"/>
    <category term="IntelliJ IDEA" scheme="https://cfyong.com/tags/IntelliJ-IDEA/"/>
    <content>
      <![CDATA[<p>自从开发环境从 Eclipse 切换至了 Itellij IDEA，越用越顺手，不愧是被称为Java开发最好用的IDE，写篇文章记录一下 IDEA 的日常配置，方便下次忘记时能够及时翻阅，以备不时之需。</p><h1 id="一、常用配置"><a href="#一、常用配置" class="headerlink" title="一、常用配置"></a>一、常用配置</h1><ul><li><p>Maven 构建工具设置：File &gt; Settings &gt; Build，Execution，Deployment &gt; Build Tools</p></li><li><p>JDK 选择：File &gt; Project Structure &gt; Project Settiongs &gt; Project  可添加 JDK 。</p></li><li><p>git、svn 设置：Settings &gt; Version Control &gt;  Git &#x2F; Subversion &gt; 添加 git &#x2F; svn 的 bin 目录下 <code>git.exe</code> &#x2F; <code>svn.exe</code>文件</p></li><li><p>设置忽略文件，隐藏相应文件和目录(可以防止 idea 产生的文件传到版本控制 VCS 中)：Settings &gt; Editor &gt; File Type &gt; Ignore files and folders 中添加 <code>.idea</code> 和 <code>*.iml</code> 。</p></li></ul><p><img src="/img/upload/2022/04/image-1651133520592.webp" alt="常用配置"></p><ul><li><p>IDEA 自动编译默认没开启，需自己开启：File &gt; Settings &gt; Build，Execution，Deployment &gt; Compiler &gt; - Build Project automatically </p></li><li><p>Ctrl + 鼠标滚轮放大字体：File &gt; Settings &gt; Editor &gt; General &gt; Change font size(Zoom) with Ctrl +Mouse Wheel</p></li><li><p>提示不区分大小写：File &gt; Settings &gt; Editor &gt; General &gt; Code Completion &gt; Match case 取消打钩</p></li><li><p>设置行号和方法分隔符：File &gt; Settings &gt; Editor &gt; General &gt; Appearance &gt; show line numbers 和 show method separators</p></li><li><p><del>鼠标悬浮提示：File &gt; Settings &gt; Editor &gt; General &gt; Show quick documentation on mouse move （已默认配置20230715）</del></p></li><li><p>项目文件编码修改（改完后properties文件可以消除乱码）：File &gt; Settings &gt; Editor &gt; File Encodings &gt; 如下图：</p></li></ul><p><img src="/img/upload/2022/04/image-1651133532460.webp" alt="常用配置"></p><p><img src="/img/upload/2022/04/image-1651133538967.webp" alt="常用配置"></p><ul><li><p>打开多个文件后文件名双行显示：File &gt; Settings &gt; Editor &gt; General &gt; Editor Tabs &gt;Show tabs in one now 取消打钩</p></li><li><p>自动导包和优化导入的包：File &gt; Settings &gt; Editor &gt; General &gt; Auto  Import</p></li></ul><p><img src="/img/upload/2022/04/image-1651133547930.webp" alt="常用配置"></p><ul><li><p>设置字体类型、大小、行间距：File &gt; Settings &gt; Editor &gt; Font &gt; Font、Size、Line spacing</p></li><li><p>修改文本各类字体颜色：File &gt; Settings &gt; Editor &gt; Color Scheme &gt; Language Defaults </p></li><li><p>代码智能模版：File &gt; Settings &gt; Editor &gt; Live Templates（见第四节）  或者  File &gt; Settings &gt; General &gt; Postfix Completion<br>二者区别：Live Templates 可自定义，Postfix Completion 不可以；有些操作二者都提供了模板；Postfix Templates 比 Live Templates 更快。</p></li><li><p>在线安装 JRebe l即可，开启热部署需做如下配置: Help &gt; Find Action(Ctrl + Shift + A) &gt; Registry… &gt; <code>compiler.automake.allow.when.app.running</code> 改为 true 。</p></li><li><p>换行符设置：File &gt; Settings &gt; Editor &gt; Code Style &gt; 通过 Line separator 设置</p></li><li><p>配置git stash 和 unstash 快捷按钮<br>  Appearance &amp; Behavior -&gt; Menu and Toolbars -&gt; Navigation Bar Toolbar -&gt; NavBarVcsGroup -&gt; VcsNavBarToolbarActions  打开到此后，点击 + 号选择 Add action…，搜索 stash ，输入 Compre with the same Repository Version、unstash changes… 、 stash changes…  将此三个操作添加进去即可。</p></li><li><p>debug 时跳过进入 spring 的 apo proxy 代理类，File &gt; Settings &gt; Build，Execution，Deployment &gt; Debugger &gt; Stepping 新增：<code>org.springframework.aop.*</code>、<code>org.springframework.transaction.*</code>、<code>org.springframework.cglib.proxy.*</code></p></li></ul><h1 id="三、插件"><a href="#三、插件" class="headerlink" title="三、插件"></a>三、插件</h1><ul><li>GitToolBox</li><li>Grep Console</li></ul><p><img src="/img/upload/2022/11/image.webp" alt="IDEA 插件配置"></p><table><thead><tr><th>日志级别</th><th>字体色</th><th>背景色</th></tr></thead><tbody><tr><td>Error</td><td>#FF0000</td><td>#370000</td></tr><tr><td>Warn</td><td>#FFC033</td><td>#1A0037</td></tr><tr><td>Info</td><td>#00FFF3</td><td>无</td></tr><tr><td>Debug</td><td>#808080</td><td>无</td></tr></tbody></table><ul><li>Translation<br>可配置有道翻译应用ID和密钥</li><li>JRebel</li><li>MyBatis Log Free</li><li>Free MyBatis Tool</li><li>GsonFormatPlus</li><li>Maven Helper</li><li>Rainbow Brackets</li><li>QAPlug-FindBugs<br>需要先安装QAPlug</li><li>Jclasslib Bytecode Viewer </li><li>BinDED</li><li>Vue</li><li>Scala</li></ul><h1 id="三、快捷键"><a href="#三、快捷键" class="headerlink" title="三、快捷键"></a>三、快捷键</h1><h4 id="代码编辑"><a href="#代码编辑" class="headerlink" title="代码编辑"></a>代码编辑</h4><p>Ctrl + D ：复制上一行至下一行（Eclipse 里的 Ctrl + Alt + ↓）<br>Ctrl + X ：删除行<br>Ctrl + O &#x2F; I ：重写 &#x2F; 实现 方法<br>Ctrl + P ：方法参数提示<br>CTRL + Q ：查看当前方法声明<br>Ctrl + Shift + U : 大小写转换<br>Ctrl + Shift + ↑↓：上下移动代码<br>Ctrl + Shfit + 左键：进入接口实现类实现方法<br>Ctrl + Alt + Enter：另起上一行<br>Shift + Enter ：另起下一行<br>Shift + F6 ：改名重构<br>Alt + &#x2F; ：代码提示<br>Alt + 回车 ： 导包自动修正<br>Alt + ←→：切换文件<br>Alt + ↑ ↓ ：方法之间快速切换<br>Ctrl + Shift + Backspace ：跳回上次修改的地方<br>Ctrl + Alt + ←→：浏览记录中位置的切换<br>Ctrl + &#x2F; ：单行注释<br>Ctrl + Alt + &#x2F; ：多行注释<br>&#x2F;** + Enter ：文档注释</p><h4 id="搜索类"><a href="#搜索类" class="headerlink" title="搜索类"></a>搜索类</h4><p>Double Shift：全局搜索所有匹配到的所有文件<br>Ctrl + F ：当前文件<br>Ctrl + Shift + F  ：全局搜索匹配的字符串<br>Ctrl + R：当前文件做相应替换<br>Ctrl + Shift + R ：全局文件替换<br>Ctrl + E ：最近打开的文件</p><h4 id="debug-类"><a href="#debug-类" class="headerlink" title="debug 类"></a>debug 类</h4><p>F7：<br>F8：下一行<br>F9：</p><h1 id="四、注释配置"><a href="#四、注释配置" class="headerlink" title="四、注释配置"></a>四、注释配置</h1><h2 id="1-类、接口、枚举、注解创建时生成注释"><a href="#1-类、接口、枚举、注解创建时生成注释" class="headerlink" title="1. 类、接口、枚举、注解创建时生成注释"></a>1. 类、接口、枚举、注解创建时生成注释</h2><p>Settings &gt; Editor &gt; File and Code Templates &gt; 配置如下：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* $&#123;todo&#125; </span></span><br><span class="line"><span class="comment">*</span></span><br><span class="line"><span class="comment">* <span class="doctag">@date</span>： $&#123;DATE&#125; $&#123;TIME&#125;</span></span><br><span class="line"><span class="comment">* <span class="doctag">@author</span>: chify</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><p><img src="/img/upload/2022/04/image-1651133560397.webp" alt="类、接口、枚举、注解创建时生成注释"></p><h2 id="2-方法注释"><a href="#2-方法注释" class="headerlink" title="2. 方法注释"></a>2. 方法注释</h2><p>之前版本不清楚，IDEA 2019.3 版本可使用  &#x2F;** + Enter 直接生成如下图注释，足矣使用，如需改动，可配置 Live  Template。</p><p><img src="/img/upload/2022/04/image-1651133567540.webp" alt="方法注释"></p><h1 id="五、Live-Template-配置"><a href="#五、Live-Template-配置" class="headerlink" title="五、Live Template 配置"></a>五、Live Template 配置</h1><p>Live Template 支持用户自定义配置一些常用代码字母缩写，在输入简写时可以出现自己预定义的固定模式的代码，最简单的例子就是在 Java 中输入 <code>sout</code> 就可以快速打出 <code>System.out.println();</code> 大大的提高了写代码的效率。以配置注释快捷键为例，先进入 File &gt; Settings &gt; Editor &gt; Live Templates &gt; 其余配置步骤如下：</p><ol><li>新增一个名为 guan 的 Template 组</li></ol><p><img src="/img/upload/2022/04/image-1651133578493.webp" alt="live template 配置"></p><ol start="2"><li>在 guan 组中添加 Live Template</li></ol><p><img src="/img/upload/2022/04/image-1651133585823.webp" alt="live template 配置"></p><ol start="3"><li>配置 Live Template</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * TODO：</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Date</span>: $date$ $time$</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>: chify</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><p><img src="/img/upload/2022/04/image-1651133596118.webp" alt="live template 配置"></p><ol start="4"><li>编辑变量<br>注：这里必须配置，要不然 <code>date</code> 变量会不生效，否则使用的时候不会生成日期。步骤如下：</li></ol><p><img src="/img/upload/2022/04/image-1651133604031.webp" alt="live template 配置"></p><ol start="5"><li>配置快捷键在 Java 编辑中生效<br>注：必须配置，否则写 Java 代码时会没有提示，也可以配置在 HTML 文件中生效。</li></ol><p><img src="/img/upload/2022/04/image-1651133612419.webp" alt="live template 配置"></p><p>配置完成，此后再写代码时，输入 <code>/c</code> ，再按 Tab 键就可以快速生成配置自定义模版代码。</p>]]>
    </content>
    <id>https://cfyong.com/java/idea-configuration-guide/</id>
    <link href="https://cfyong.com/java/idea-configuration-guide/"/>
    <published>2020-03-09T14:03:56.000Z</published>
    <summary>IntelliJ IDEA日常配置指南，记录Maven、JDK、Git、代码模板等常用设置的配置方法。</summary>
    <title>Intellij IDEA 配置简记</title>
    <updated>2023-07-15T06:21:58.881Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="IT技术" scheme="https://cfyong.com/categories/IT%E6%8A%80%E6%9C%AF/"/>
    <category term="Nmap" scheme="https://cfyong.com/tags/Nmap/"/>
    <content>
      <![CDATA[<p>读了吴翰清的《白帽子讲web安全》，对网络这块很感兴趣，于是了解到了<strong>NMAP</strong>这款开源的端口扫描工具，扫了一下局域网里的在线主机，做个简记。</p><h1 id="安装-nmap"><a href="#安装-nmap" class="headerlink" title="安装 nmap"></a>安装 nmap</h1><ul><li><strong>Windows</strong> 有客户端，直接去<a href="https://nmap.org/download.html">官网下载</a>安装即可。</li><li><strong>Debian</strong> 系列：<code>sudo apt-get install nmap</code></li><li><strong>Redhat</strong> 系列：<code>sudo yum install nmap</code></li></ul><h1 id="扫描局域网内在线主机"><a href="#扫描局域网内在线主机" class="headerlink" title="扫描局域网内在线主机"></a>扫描局域网内在线主机</h1><p>选择性使用如下命令即可扫描局域网内所有在线主机：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">nmap -sP 192.168.1.*       <span class="comment"># 扫描 192.168.1.* 网段内主机</span></span><br><span class="line">nmap 192.168.1.*            <span class="comment"># 扫描网段内所有主机对外开放的端口（也可扫描单机）</span></span><br><span class="line">nmap -p 8080,80 192.168.1.1-254  <span class="comment"># 查看网段内所有在线主机是否开放 8080,80 端口</span></span><br><span class="line"><span class="built_in">cat</span> /proc/net/arp           <span class="comment"># 查看扫描后信息（可看到 MAC 地址）</span></span><br></pre></td></tr></table></figure><p>示例如下图：</p><p><img src="/img/upload/2022/04/image-1651133845650.webp" alt="nmap 扫描结果"></p><p><img src="/img/upload/2022/04/image-1651133855720.webp" alt="ARP 表信息"></p><h1 id="其他参数"><a href="#其他参数" class="headerlink" title="其他参数"></a>其他参数</h1><ul><li><code>nmap -sV 192.168.1.1</code> 可检测到服务端<strong>软件版本信息</strong></li><li><code>nmap -O</code> 能识别主机的<strong>操作系统</strong>（需要 root 权限）</li><li><code>nmap -Pn</code> 假若远程主机屏蔽了 ping 功能，NMAP 就不会进一步做端口检测，可以使用这个参数禁止主机检测，NMAP 会直接认为主机已在线，再做进一步检测。</li></ul>]]>
    </content>
    <id>https://cfyong.com/it/network/nmap-lan-host-discovery/</id>
    <link href="https://cfyong.com/it/network/nmap-lan-host-discovery/"/>
    <published>2020-03-08T14:57:31.000Z</published>
    <summary>使用NMAP端口扫描工具发现局域网内在线主机的方法，介绍nmap安装及常用扫描命令。</summary>
    <title>NMAP扫描局域网内在线IP</title>
    <updated>2022-04-28T08:19:44.887Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="随笔" scheme="https://cfyong.com/categories/%E9%9A%8F%E7%AC%94/"/>
    <category term="杂谈" scheme="https://cfyong.com/tags/%E6%9D%82%E8%B0%88/"/>
    <content>
      <![CDATA[<p>疫情期间，看到了一篇关于人脉的文章，特别强调了弱关系的力量和作用，关于人脉问题，今天突然就是想写点什么，抒发一下情感。</p><p>大学的时候就经常遇见有这样一些想法的人：觉得认识人多就很厉害，认为这是人脉广的表现，以致这些人经常会以这个目标去结交朋友。仔细想想出现这种现象其实并不奇怪，毕竟现在社会上对于人脉的评判标准就是这样的，身边接触到的家人朋友和曾经的我也是抱有这种的想法的，但是经过长时间的思考，大学后期的我是一点都不赞成这种做法的，甚至是厌恶。所以现在的我认为人脉关系应该是这样的……</p><p>在我眼里人脉是吸引来的，而不是追求来的，弱关系作用很大，但它也并不是在鼓励一个人一味去追求要结识多少的朋友。英雄总是会惺惺相惜的，潜力股和金子都能分辨谁得出是潜力股和金子，相互之间都会产生引力，乐意成为彼此之间的弱关系。在你不能给你的弱关系有个等价交换的时候，你没有能力、潜力，你的弱关系真的会打心里帮助你吗？所以最重要的还是要不断的打磨自己，实现自身的价值，努力成为金子，发光发热之后，别人自然会很乐意和你交往，成为你的弱关系，因为双方都清楚，彼此都是有潜力成为金子或者本身就是金子的人，未来或者现在都有能力在别人需要帮忙的时候拉你一把，这也就是所谓的朋友之间的等价交换。</p><p>不管承不承认，人都是会有层次之分的，不同的人往往都只会与自己相同阶层的人相交，而一个金钱、身份地位在你之上的人想与你相交，要么你本身就是他的亲戚朋友，要么就是你自身有过人之处，这个过人之处也许需要多年的打磨与历练，以至于自己闪闪发光，被人慧眼识珠，形成了伯乐与千里马的弱关系。我想电影《肖生克的救赎里》的男主安迪就是这个样子的，入狱后的安迪可以说是变成了一无是处，但是凭借其坐牢前所掌握的能力，天台上抓住了一次机会，便在狱中发光发热，与监狱长和看守员形成了弱关系（虽然这个监狱长是个反派），在狱中得到了许许多多的特别关照，躲避掉了许多伤害。试想，假如安迪没有能力帮助监狱长和看守员，又如何有机会和他们形成弱关系，最终逃出囚笼，再一次成为人生赢家呢。</p><p>方以类聚物以群分，如果你不够优秀，我想你周围的人也将是如此，所以你的人脉是不值钱的。现如今在我眼里人一定要有成长性思维，摒弃固定型思维，不断打磨提升自己，而打磨自己和结交弱关系在我眼里是不冲突的，当你在慢慢变成金子的时候，你的弱关系自然而然的就被你吸引来了，而不是在自己一无是处的时候就去一味的追求人脉，这只会成为别人的笑料，人行于世，很多时候不要为了一个社会的评判标准去逼做自己不喜欢做的事情，因为这个评判标准也许本身就是畸形的。</p><p>做人要有原则，要有底线，交友也应当如此，子曰:有才无德，小人也；有德无才，君子也；然德才皆具者，圣人也。与没有德行的人相交，虚与委蛇可以，绝不可深交。不管如何，德行应该成为你交友信条里最严格的标准，没有之一。</p><p>最后，有能力时，一定要抓住身边机会展现自己，毕竟别人看不到你的实力，又如何被你吸引。</p>]]>
    </content>
    <id>https://cfyong.com/thoughts/relationships-and-personal-value/</id>
    <link href="https://cfyong.com/thoughts/relationships-and-personal-value/"/>
    <published>2020-03-07T09:45:08.000Z</published>
    <summary>关于人脉关系的个人思考，探讨弱关系的力量、自我价值提升与人际交往的本质，强调成长型思维。</summary>
    <title>我眼中的人脉</title>
    <updated>2022-05-03T17:20:19.282Z</updated>
  </entry>
  <entry>
    <author>
      <name>chify</name>
    </author>
    <category term="Java" scheme="https://cfyong.com/categories/Java/"/>
    <category term="Java" scheme="https://cfyong.com/tags/Java/"/>
    <content>
      <![CDATA[<p>Object 类是 Java 语言中所有类的根类。即使你没有显式写 <code>extends</code>，自定义类也会隐式继承 <code>Object</code>，因此它也常被称为“上帝类”。想要深入理解 Java 的类模型、集合实现以及对象行为，先弄清楚 <code>Object</code> 的常用方法是非常有帮助的。</p><h1 id="Object-类中常用方法解析"><a href="#Object-类中常用方法解析" class="headerlink" title="Object 类中常用方法解析"></a>Object 类中常用方法解析</h1><h2 id="getClass-方法"><a href="#getClass-方法" class="headerlink" title="getClass() 方法"></a>getClass() 方法</h2><p><code>getClass()</code> 由 <code>final</code> 修饰，不能被子类重写。它是一个本地方法，作用是返回当前运行时对象的 <code>Class</code> 类型对象。拿到这个 <code>Class</code> 对象之后，就能获取类的各种元信息，比如类名、包名、字段、方法等。常见调用方式如下：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Class</span>&lt;?&gt; <span class="variable">clazz</span> <span class="operator">=</span> obj.getClass();</span><br><span class="line"><span class="type">String</span> <span class="variable">className</span> <span class="operator">=</span> clazz.getName();</span><br></pre></td></tr></table></figure><p><img src="/img/upload/2022/04/image-1651040756874.webp" alt="getclass() 方法"></p><h2 id="hashCode-方法"><a href="#hashCode-方法" class="headerlink" title="hashCode() 方法"></a>hashCode() 方法</h2><p><code>hashCode()</code> 也是一个本地方法，返回一个 <code>int</code> 值。默认情况下，它通常是基于对象的内存地址进行哈希计算得到的结果。它的作用是为了让对象在哈希表、集合、映射中更容易定位。需要注意的是：</p><ul><li>如果两个对象的 <code>hashCode</code> 相等，不代表它们一定是同一个对象。</li><li>如果两个对象的 <code>hashCode</code> 不相等，那么它们通常不是同一个对象。</li><li>如果两个对象是同一个对象，那么它们的 <code>hashCode</code> 必定相等。</li></ul><p>这四条原则都很好理解。拿 <code>String</code> 为例，<code>String</code> 已经重写了 <code>hashCode()</code>。由于 <code>int</code> 只有 32 位，而字符串数量几乎是无限的，因此不同字符串对象出现相同 <code>hashCode</code> 的情况是可能的，这也就是哈希冲突。比如：<code>ABCDEa123abc</code> 与 <code>ABCDFB123abc</code> 可能有相同的哈希值，而真正区分这两个字符串是否相等，就依赖 <code>equals()</code>。</p><h2 id="equals-方法"><a href="#equals-方法" class="headerlink" title="equals() 方法"></a>equals() 方法</h2><p><code>equals()</code> 在 <code>Object</code> 中默认是用 <code>==</code> 来实现的。对基本类型而言，比较的是值是否相等；对引用类型而言，比较的是对象的内存地址是否相同。也就是说，默认情况下，只有同一个对象实例才会返回 <code>true</code>。</p><p>在重写 <code>hashCode()</code> 后，通常也需要重写 <code>equals()</code>，并且这两个方法之间有如下约定：</p><ul><li>如果两个对象 <code>equals()</code> 返回 <code>true</code>，那么它们的 <code>hashCode()</code> 返回值必须相同。</li><li>如果两个对象的 <code>hashCode()</code> 相同，不代表 <code>equals()</code> 一定为 <code>true</code>，因为可能存在哈希冲突。</li></ul><h3 id="为什么要同时重写-hashCode-和-equals-？"><a href="#为什么要同时重写-hashCode-和-equals-？" class="headerlink" title="为什么要同时重写 hashCode() 和 equals()？"></a>为什么要同时重写 hashCode() 和 equals()？</h3><p>这是因为在 Java 编程中，我们经常会把对象放进集合中，然后再根据某个 key 取出对应的 value。<code>Map</code> 是最典型的容器之一，<code>HashMap</code> 和 <code>HashTable</code> 都依赖哈希结构来提高查找效率。</p><p><code>HashMap</code> 的底层本质上是一个数组 + 链表（或红黑树）组成的结构，数组的长度通常是 2 的幂，默认值为 16。存入元素时，会先计算对象的 <code>hashCode</code>，再通过取模运算定位桶位置。这样做的好处是：</p><ul><li>如果桶位为空，直接放入。</li><li>如果桶位已经有元素，则发生哈希冲突。</li><li>此时会使用 <code>equals()</code> 判断当前对象和桶中对象是否“相同内容”。</li><li>如果相同，则覆盖旧值；如果不同，则在链表或红黑树中追加元素。</li></ul><p>因此：</p><ul><li><code>hashCode()</code> 负责快速定位元素所在桶位。</li><li><code>equals()</code> 负责保证内容唯一性和解决冲突。</li></ul><p>两者相辅相成，才能保证集合中 key 的唯一性和高效查询，元素put进HashMap流程如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">flowchart TD</span><br><span class="line">    A[对象被放入 HashMap] --&gt; B[&quot;调用 hashCode()&quot;]</span><br><span class="line">    B --&gt; C&#123;哈希桶是否有位置&#125;</span><br><span class="line">    C --&gt;|空| D[直接存入]</span><br><span class="line">    C --&gt;|冲突| E[&quot;调用 equals() 比较&quot;]</span><br><span class="line">    E --&gt;|相同| F[覆盖旧值]</span><br><span class="line">    E --&gt;|不同| G[&quot;链表/红黑树追加节点&quot;]</span><br></pre></td></tr></table></figure><blockquote><p>注：当元素数量越来越大时，哈希冲突不可避免。若数组长度较小，冲突会更多，链表长度也会增大，查询效率会下降；因此 <code>HashMap</code> 会在一定条件下自动扩容，扩容因子默认是 <code>0.75</code>。</p></blockquote><h2 id="clone-方法"><a href="#clone-方法" class="headerlink" title="clone() 方法"></a>clone() 方法</h2><p><code>clone()</code> 是 Java 中原型模式的一种实现。要调用 <code>clone()</code>，目标类必须实现 <code>Cloneable</code> 接口，否则会抛出 <code>CloneNotSupportedException</code>。这里涉及浅拷贝和深拷贝的内容，通常需要结合具体场景来理解，这里不展开深讲，读者可以结合实际代码和资料进一步学习。</p><h2 id="toString-方法"><a href="#toString-方法" class="headerlink" title="toString() 方法"></a>toString() 方法</h2><p><code>Object</code> 的默认 <code>toString()</code> 实现如下：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">String</span> <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> getClass().getName() + <span class="string">&quot;@&quot;</span> + Integer.toHexString(hashCode());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>默认实现并没有太大意义，所以很多类都会重写这个方法。<code>System.out.println(obj)</code> 时，默认打印的也就是对象的 <code>toString()</code> 返回值。</p><p><img src="/img/upload/2022/04/image-1651040777015.webp" alt="tostring() 方法"></p><p><img src="/img/upload/2022/04/image-1651040783140.webp" alt="tostring() 方法"></p><h1 id="Object-线程相关方法"><a href="#Object-线程相关方法" class="headerlink" title="Object 线程相关方法"></a>Object 线程相关方法</h1><p><code>wait</code> 和 <code>notify</code> 这类方法必须在同步代码块或同步方法中调用，否则会抛出 <code>IllegalMonitorStateException</code> 异常。</p><h2 id="wait"><a href="#wait" class="headerlink" title="wait()"></a>wait()</h2><p>调用 <code>wait()</code> 时，当前线程会进入等待状态，并且释放所持有的锁，直到被其他线程唤醒。</p><h2 id="wait-long-timeout"><a href="#wait-long-timeout" class="headerlink" title="wait(long timeout)"></a>wait(long timeout)</h2><p>带超时时间的等待方法，线程会在指定时间内等待，超时后自动醒来继续执行。</p><h2 id="wait-long-timeout-int-nanos"><a href="#wait-long-timeout-int-nanos" class="headerlink" title="wait(long timeout, int nanos)"></a>wait(long timeout, int nanos)</h2><p>更细粒度的等待重载版本，支持纳秒级小的等待控制。</p><h2 id="notify"><a href="#notify" class="headerlink" title="notify()"></a>notify()</h2><p>随机唤醒一个等待中的线程，具体唤醒哪个线程由 JVM 和操作系统实现决定。</p><h2 id="notifyAll"><a href="#notifyAll" class="headerlink" title="notifyAll()"></a>notifyAll()</h2><p>唤醒所有等待中的线程。</p><h1 id="其他方法"><a href="#其他方法" class="headerlink" title="其他方法"></a>其他方法</h1><h2 id="finalize-方法"><a href="#finalize-方法" class="headerlink" title="finalize() 方法"></a>finalize() 方法</h2><p><code>finalize()</code> 是 <code>Object</code> 提供的一个方法，用于在对象被垃圾回收前执行清理逻辑。由于它的执行时机不可预测，而且在 Java 9 之后逐步被更多机制替代，因此实际开发中通常不推荐依赖它做资源回收。</p><h2 id="registerNatives-方法"><a href="#registerNatives-方法" class="headerlink" title="registerNatives() 方法"></a>registerNatives() 方法</h2><p><code>registerNatives()</code> 是一个本地方法，用于注册本地 JVM 的实现代码。它通常在类初始化阶段被调用，用于桥接 Java 层和底层 C&#x2F;C++ 实现。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p><code>Object</code> 看似简单，但它真正构成了 Java 对象模型的基础。<code>hashCode()</code>、<code>equals()</code>、<code>toString()</code>、<code>clone()</code> 以及线程通信相关方法都是 Java 编程中必须理解的核心概念。真正掌握它们，才能更容易理解集合、并发、对象设计以及 JDK 源码中的实现细节。</p>]]>
    </content>
    <id>https://cfyong.com/java/object-equals-hashcode/</id>
    <link href="https://cfyong.com/java/object-equals-hashcode/"/>
    <published>2020-01-18T14:49:44.000Z</published>
    <summary>Java Object类常用方法详解，包括getClass、equals、hashCode、toString等核心方法的原理与使用。</summary>
    <title>Java：Object 上帝类</title>
    <updated>2022-04-28T15:52:34.822Z</updated>
  </entry>
</feed>
