<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>play a litle more!</title>
  
  
  <link href="/blog/atom.xml" rel="self"/>
  
  <link href="http://windpuller.github.io/blog/"/>
  <updated>2018-08-10T03:38:43.008Z</updated>
  <id>http://windpuller.github.io/blog/</id>
  
  <author>
    <name>windpuller</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Shutdown spring boot embedded jetty servlet container gracefully</title>
    <link href="http://windpuller.github.io/blog/2018/08/10/Shutdown-spring-boot-embedded-jetty-servlet-container-gracefully/"/>
    <id>http://windpuller.github.io/blog/2018/08/10/Shutdown-spring-boot-embedded-jetty-servlet-container-gracefully/</id>
    <published>2018-08-10T03:24:15.000Z</published>
    <updated>2018-08-10T03:38:43.008Z</updated>
    
    <content type="html"><![CDATA[<h4 id="1-不优雅的原因"><a href="#1-不优雅的原因" class="headerlink" title="1. 不优雅的原因"></a>1. 不优雅的原因</h4><p>一般情况下，spring-boot服务停机时先关闭application context然后关闭jetty，两者关闭的时间差期间jetty依然再接收新的请求，而此时能够处理请求的相关资源已经在逐步关闭，导致抛出大量异常，直至jetty完全关闭。</p><h4 id="2-优雅的步骤"><a href="#2-优雅的步骤" class="headerlink" title="2. 优雅的步骤"></a>2. 优雅的步骤</h4><p>spring-boot收到服务停机请求时：<br>(1) jetty停止接收新的请求<br>(2) jetty处理收到停机请求之前的请求并返回<br>(3) 关闭application context</p><h4 id="3-具体实现"><a href="#3-具体实现" class="headerlink" title="3. 具体实现"></a>3. 具体实现</h4><p>在application context关机事件发生时关闭jetty，<code>server.stop()</code>会实现以上(1)(2)两步的功能:<br><figure class="highlight vbscript"><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></pre></td><td class="code"><pre><span class="line">@Slf4j</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> GracefulShutdownBean implements ApplicationListener&lt;ContextClosedEvent&gt; &#123;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">private</span> static <span class="built_in">Server</span> <span class="built_in">server</span>;</span><br><span class="line"> </span><br><span class="line">    @Override</span><br><span class="line">    <span class="keyword">public</span> void onApplicationEvent(ContextClosedEvent event) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">server</span> == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="built_in">log</span>.<span class="keyword">error</span>(<span class="string">"Jetty server variable is null, this should not happen!"</span>);</span><br><span class="line">            return;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">log</span>.info(<span class="string">"Entering shutdown for Jetty."</span>);</span><br><span class="line">        <span class="keyword">if</span> (!(<span class="built_in">server</span>.getHandler() instanceof StatisticsHandler)) &#123;</span><br><span class="line">            <span class="built_in">log</span>.<span class="keyword">error</span>(<span class="string">"Root handler is not StatisticsHandler, graceful shutdown may not work at all!"</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="built_in">log</span>.info(<span class="string">"Active requests: "</span> + ((StatisticsHandler) <span class="built_in">server</span>.getHandler()).getRequestsActive());</span><br><span class="line">        &#125;</span><br><span class="line">        try &#123;</span><br><span class="line">            long begin = System.currentTimeMillis();</span><br><span class="line">            <span class="built_in">server</span>.<span class="keyword">stop</span>();</span><br><span class="line">            <span class="built_in">log</span>.info(<span class="string">"Shutdown took "</span> + (System.currentTimeMillis() - begin) + <span class="string">" ms."</span>);</span><br><span class="line">        &#125; catch (Exception e) &#123;</span><br><span class="line">            <span class="built_in">log</span>.<span class="keyword">error</span>(<span class="string">"Fail to shutdown gracefully."</span>, e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> static void setServer(<span class="built_in">Server</span> <span class="built_in">server</span>) &#123;</span><br><span class="line">        GracefulShutdownBean.<span class="built_in">server</span> = <span class="built_in">server</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>将<code>GracefulShutdownBean</code>声明为单例bean，交给spring管理:<br><figure class="highlight aspectj"><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="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> <span class="function">GracefulShutdownBean <span class="title">initGracefulShutdownBean</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> GracefulShutdownBean();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>将jetty的server交给GracefulShutdownBean管理：<br><figure class="highlight dart"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line">JettyServletWebServerFactory embeddedServletContainerFactory(<span class="meta">@Value</span>(<span class="string">"<span class="subst">$&#123;server.port&#125;</span>"</span>) <span class="built_in">int</span> port,</span><br><span class="line">                                                             <span class="meta">@Value</span>(<span class="string">"<span class="subst">$&#123;server.jetty.threadPool.maxThreads&#125;</span>"</span>) <span class="built_in">int</span> maxThreads,</span><br><span class="line">                                                             <span class="meta">@Value</span>(<span class="string">"<span class="subst">$&#123;server.jetty.threadPool.minThreads&#125;</span>"</span>) <span class="built_in">int</span> minThreads,</span><br><span class="line">                                                             <span class="meta">@Value</span>(<span class="string">"<span class="subst">$&#123;server.jetty.threadPool.idleTimeout&#125;</span>"</span>) <span class="built_in">int</span> idleTimeout,</span><br><span class="line">                                                             <span class="meta">@Value</span>(<span class="string">"<span class="subst">$&#123;server.jetty.shutdown.waitTime&#125;</span>"</span>) <span class="built_in">int</span> shutdownWaitTime) &#123;</span><br><span class="line"></span><br><span class="line">    JettyServletWebServerFactory <span class="keyword">factory</span> = <span class="keyword">new</span> JettyServletWebServerFactory(port);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">factory</span>.addServerCustomizers(server -&gt; &#123;</span><br><span class="line"></span><br><span class="line">        QueuedThreadPool threadPool = server.getBean(QueuedThreadPool.<span class="keyword">class</span>);</span><br><span class="line">        threadPool.setMaxThreads(maxThreads);</span><br><span class="line">        threadPool.setMinThreads(minThreads);</span><br><span class="line">        threadPool.setIdleTimeout(idleTimeout);</span><br><span class="line"></span><br><span class="line">        GracefulShutdownBean.setServer(server);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (shutdownWaitTime &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            StatisticsHandler handler = <span class="keyword">new</span> StatisticsHandler();</span><br><span class="line">            handler.setHandler(server.getHandler());</span><br><span class="line">            server.setHandler(handler);</span><br><span class="line">            log.info(<span class="string">"Shutdown wait time: "</span> + shutdownWaitTime + <span class="string">"ms"</span>);</span><br><span class="line">            server.setStopTimeout(shutdownWaitTime);</span><br><span class="line">            <span class="comment">// We will stop it through GracefulShutdownBean class.</span></span><br><span class="line">            server.setStopAtShutdown(<span class="keyword">false</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">factory</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><h4 id="参考文献："><a href="#参考文献：" class="headerlink" title="参考文献："></a>参考文献：</h4><ol><li><a href="https://github.com/spring-projects/spring-boot/issues/4657" target="_blank" rel="noopener">https://github.com/spring-projects/spring-boot/issues/4657</a></li></ol>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h4 id=&quot;1-不优雅的原因&quot;&gt;&lt;a href=&quot;#1-不优雅的原因&quot; class=&quot;headerlink&quot; title=&quot;1. 不优雅的原因&quot;&gt;&lt;/a&gt;1. 不优雅的原因&lt;/h4&gt;&lt;p&gt;一般情况下，spring-boot服务停机时先关闭application context
      
    
    </summary>
    
    
      <category term="spring-boot" scheme="http://windpuller.github.io/blog/tags/spring-boot/"/>
    
      <category term="jetty" scheme="http://windpuller.github.io/blog/tags/jetty/"/>
    
      <category term="gracefully shutdown" scheme="http://windpuller.github.io/blog/tags/gracefully-shutdown/"/>
    
  </entry>
  
  <entry>
    <title>RESTful note</title>
    <link href="http://windpuller.github.io/blog/2016/05/17/RESTful-note/"/>
    <id>http://windpuller.github.io/blog/2016/05/17/RESTful-note/</id>
    <published>2016-05-17T10:14:51.000Z</published>
    <updated>2016-09-02T10:39:38.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="1-RESTful"><a href="#1-RESTful" class="headerlink" title="1. RESTful"></a>1. RESTful</h2><p>RESTful，即Representational State Transfer的缩写，字面含义是<strong>表现层状态转化</strong>。是某歪果仁博士提出的一种<strong>网络应用软件架构</strong>风格。<br>根据<a href="http://www.ruanyifeng.com/blog/2011/09/restful.html" target="_blank" rel="noopener">理解RESTful架构</a>的分析，RESTful的关键因素主要有三个：资源、表现层、状态转化。<br>(1) 资源<br>表现层依赖的实体，在网络中一般使用URI指定。可以是一张图片，也可以是一段文本。<br>(2) 表现层<br>资源的表现形式，是图片还是文本还是视频，应使用HTTP协议头部的Accept和Content-Type字段指定。<br>(3) 状态转化<br>client通过HTTP协议的GET、POST、PUT、DELETE等操作获取、创建、修改、删除服务器端的资源，并反映在client的展示中。</p><h2 id="2-优势"><a href="#2-优势" class="headerlink" title="2. 优势"></a>2. 优势</h2><p>RESTful的优势主要体现在与传统C/S架构应用软件的对比上：<br>浏览器即客户端，客户端的开发难度和成本降低<br>仅在服务器端存在状态转化，有利于系统结构的拆分和扩展，有利于合理配置服务器资源<br>系统更新升级方便，向后兼容性好</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h2 id=&quot;1-RESTful&quot;&gt;&lt;a href=&quot;#1-RESTful&quot; class=&quot;headerlink&quot; title=&quot;1. RESTful&quot;&gt;&lt;/a&gt;1. RESTful&lt;/h2&gt;&lt;p&gt;RESTful，即Representational State Transfer
      
    
    </summary>
    
    
      <category term="restful" scheme="http://windpuller.github.io/blog/tags/restful/"/>
    
  </entry>
  
  <entry>
    <title>deserialize numeric string for map key in json</title>
    <link href="http://windpuller.github.io/blog/2016/02/28/deserialize-numeric-string-for-map-key-in-json/"/>
    <id>http://windpuller.github.io/blog/2016/02/28/deserialize-numeric-string-for-map-key-in-json/</id>
    <published>2016-02-28T14:21:00.000Z</published>
    <updated>2016-09-02T10:39:38.000Z</updated>
    
    <content type="html"><![CDATA[<p>最近反序列化json的时候，踩到了一个jackson转换map key的坑。踩坑时反序列化的数据格式如下:<br><figure class="highlight json"><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></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="attr">"data"</span>: &#123;</span><br><span class="line">    <span class="attr">"1"</span>: <span class="string">"观景"</span>,</span><br><span class="line">    <span class="attr">"2"</span>: <span class="string">"小资"</span>,</span><br><span class="line">    <span class="attr">"3"</span>: <span class="string">"院落"</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">"ret"</span>: <span class="literal">true</span>,</span><br><span class="line">  <span class="attr">"errcode"</span>: <span class="number">0</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>然后使用如下代码对其进行反序列化：<br><figure class="highlight lsl"><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">String retStr = <span class="string">"&#123;<span class="subst">\"</span>data<span class="subst">\"</span>:&#123;<span class="subst">\"</span>1<span class="subst">\"</span>:<span class="subst">\"</span>观景<span class="subst">\"</span>,<span class="subst">\"</span>2<span class="subst">\"</span>:<span class="subst">\"</span>小资<span class="subst">\"</span>,<span class="subst">\"</span>3<span class="subst">\"</span>:<span class="subst">\"</span>院落<span class="subst">\"</span>&#125;,<span class="subst">\"</span>ret<span class="subst">\"</span>:true,<span class="subst">\"</span>errcode<span class="subst">\"</span>:0&#125;"</span>;</span><br><span class="line">ObjectMapper objectMapper = new ObjectMapper();</span><br><span class="line">Map&lt;String, Object&gt; retMap = objectMapper.readValue(retStr, new TypeReference&lt;Map&lt;String, Object&gt;&gt;()&#123;&#125;);</span><br><span class="line">Map&lt;Integer, String&gt; dataMap = (Map&lt;Integer, String&gt;) retMap.get(<span class="string">"data"</span>);</span><br></pre></td></tr></table></figure></p><p>之后针对一些数字，需要判断dataMap中是否存在这个key，这里调用的是Map的containsKey()方法：<br><figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">boolean existing</span> = dataMap.containsKey(1);</span><br></pre></td></tr></table></figure></p><p>明明dataMap中存在key=1的键值对，但是得到的结果却是false。<br>此时debug查看dataMap的内容(如下)，发现dataMap中是存在key=1的键值对的。但是查看key的类型，并不是int而是char，而上边调用constainsKey()方法传入的参数是int，因此返回false。<br><img src="/blog/2016/02/28/deserialize-numeric-string-for-map-key-in-json/image01.png" alt="cast_numeric_string_to_Integer01.png"><br>深扒了一下jackson的底层代码，发现它在反序列化map的key的时候，如果没有明确指定key的类型，将默认按照String类型处理，最终调用的是<code>StringKD</code>的<code>_parse</code>方法，直接将json中的数字以字符串的形式返回了。<br><figure class="highlight scala"><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="keyword">final</span> static <span class="class"><span class="keyword">class</span> <span class="title">StringKD</span> <span class="keyword">extends</span> <span class="title">StdKeyDeserializer</span></span></span><br><span class="line"><span class="class"></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    public <span class="type">String</span> _parse(<span class="type">String</span> key, <span class="type">DeserializationContext</span> ctxt) <span class="keyword">throws</span> <span class="type">JsonMappingException</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> key;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>修改代码如下，显式地将key转化为Integer类型，我们得到了想要的结果。<br><figure class="highlight vbscript"><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></pre></td><td class="code"><pre><span class="line"><span class="built_in">String</span> retStr = <span class="string">"&#123;\"</span>data\<span class="string">":&#123;\"</span><span class="number">1</span>\<span class="string">":\"</span>观景\<span class="string">",\"</span><span class="number">2</span>\<span class="string">":\"</span>小资\<span class="string">",\"</span><span class="number">3</span>\<span class="string">":\"</span>院落\<span class="string">"&#125;,\"</span>ret\<span class="string">":true,\"</span>errcode\<span class="string">":0&#125;"</span>;</span><br><span class="line">ObjectMapper objectMapper = <span class="keyword">new</span> ObjectMapper();</span><br><span class="line">Map&lt;<span class="built_in">String</span>, Object&gt; retMap = objectMapper.readValue(retStr, <span class="keyword">new</span> TypeReference&lt;Map&lt;<span class="built_in">String</span>, Object&gt;&gt;()&#123;&#125;);</span><br><span class="line">Map&lt;<span class="built_in">String</span>, <span class="built_in">String</span>&gt; dataMap = (Map&lt;<span class="built_in">String</span>, <span class="built_in">String</span>&gt;) retMap.<span class="keyword">get</span>(<span class="string">"data"</span>);</span><br><span class="line">Map&lt;Integer, <span class="built_in">String</span>&gt; tempMap = Maps.newHashMapWithExpectedSize(dataMap.size());</span><br><span class="line"><span class="keyword">for</span> (Map.Entry&lt;<span class="built_in">String</span>, <span class="built_in">String</span>&gt; entry : dataMap.entrySet()) &#123;</span><br><span class="line">    tempMap.put(Integer.valueOf(entry.getKey()), entry.getValue());</span><br><span class="line">&#125;</span><br><span class="line">boolean existing = tempMap.containsKey(<span class="number">1</span>);</span><br></pre></td></tr></table></figure></p><p>当然还有另外一种解决方案，就是用明确了数据类型的类(即下面的<code>AjaxResult</code>)去接收反序列化的结果，代码如下，这个时候jackson知道了map key的类型，直接调用了<code>IntKD</code>的<code>_parse</code>，将字符串转化为Integer之后返回。<br><figure class="highlight kotlin"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AjaxResult</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> boolean ret;</span><br><span class="line">    <span class="keyword">private</span> int errcode;</span><br><span class="line">    <span class="keyword">private</span> Map&lt;Integer, String&gt; <span class="keyword">data</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> boolean isRet() &#123;</span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> AjaxResult setRet(boolean ret) &#123;</span><br><span class="line">        <span class="keyword">this</span>.ret = ret;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> int getErrcode() &#123;</span><br><span class="line">        <span class="keyword">return</span> errcode;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> AjaxResult setErrcode(int errcode) &#123;</span><br><span class="line">        <span class="keyword">this</span>.errcode = errcode;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Map&lt;Integer, String&gt; getData() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">data</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> AjaxResult setData(Map&lt;Integer, String&gt; <span class="keyword">data</span>) &#123;</span><br><span class="line">        <span class="keyword">this</span>.<span class="keyword">data</span> = <span class="keyword">data</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><figure class="highlight lasso"><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">AjaxResult ajaxResult = objectMapper.readValue(retStr, <span class="literal">new</span> TypeReference&lt;AjaxResult&gt;() &#123;&#125;);</span><br><span class="line"><span class="built_in">Map</span>&lt;<span class="built_in">Integer</span>, <span class="built_in">String</span>&gt; ajaxDataMap = ajaxResult.getData();</span><br><span class="line">dataNodeMap.containsKey(<span class="number">1</span>);</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;最近反序列化json的时候，踩到了一个jackson转换map key的坑。踩坑时反序列化的数据格式如下:&lt;br&gt;&lt;figure class=&quot;highlight json&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;l
      
    
    </summary>
    
    
      <category term="java" scheme="http://windpuller.github.io/blog/tags/java/"/>
    
      <category term="jackson" scheme="http://windpuller.github.io/blog/tags/jackson/"/>
    
      <category term="deserialization" scheme="http://windpuller.github.io/blog/tags/deserialization/"/>
    
  </entry>
  
  <entry>
    <title>mount partitions on startup in archlinux</title>
    <link href="http://windpuller.github.io/blog/2016/01/17/mount-partitions-on-startup-in-archlinux/"/>
    <id>http://windpuller.github.io/blog/2016/01/17/mount-partitions-on-startup-in-archlinux/</id>
    <published>2016-01-17T09:36:47.000Z</published>
    <updated>2016-09-02T10:39:38.000Z</updated>
    
    <content type="html"><![CDATA[<p>机器装了两个系统，一个win7备用，一个linux生产。但是最近linux的剩余磁盘空间仅10G多，眼看就要不够用了，于是想着挤挤win7，分些空间出来给linux。</p><h3 id="第一步，grub-rescue的处理"><a href="#第一步，grub-rescue的处理" class="headerlink" title="第一步，grub rescue的处理"></a>第一步，grub rescue的处理</h3><p>先在win7中压缩了20G出来，然后重启机器准备进入linux加载新分区，此时出现了问题，grub无法正常启动，进入了rescue界面。<br>解决办法是：</p><ol><li><p>列出所有分区</p><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grub <span class="keyword">rescue</span>&gt; ls</span><br></pre></td></tr></table></figure></li><li><p>依次ls每个分区直到找到不报’unknown filesystem’的分区，比如n=5</p><figure class="highlight jboss-cli"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grub rescue&gt; <span class="keyword">ls</span> <span class="params">(hd0,msdos5)</span><span class="string">/boot/grub</span></span><br></pre></td></tr></table></figure></li><li><p>依次执行以下命令，可进入正常的系统引导界面</p><figure class="highlight gams"><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">grub rescue&gt; <span class="keyword">set</span> root=(hd0,msdos5)/boot/grub</span><br><span class="line">grub <span class="comment">rescue&gt; set prefix=(hd0,msdos5)</span>/boot/<span class="comment">grub</span></span><br><span class="line">grub <span class="comment">rescue&gt; insmod normal</span></span><br><span class="line">grub <span class="comment">rescue&gt; normal</span></span><br></pre></td></tr></table></figure></li><li><p>进入linux操作系统，执行以下命令修复grub，重启后grub可恢复正常</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> sudo grub-install /dev/sda</span></span><br></pre></td></tr></table></figure></li></ol><h3 id="第二步，archlinux挂载分区"><a href="#第二步，archlinux挂载分区" class="headerlink" title="第二步，archlinux挂载分区"></a>第二步，archlinux挂载分区</h3><p>配置新分区在linux启动的时候自动挂载，并映射到某一个文件路径，比如/extend</p><ol><li><p>找到要挂载的新分区硬盘号码，比如/dev/sda5</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> sudo fdisk -l</span></span><br></pre></td></tr></table></figure></li><li><p>格式化/dev/sda5为linux系统的文件格式(也可使用其它稳定的文件格式)</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> sudo mkfs.ext4 /dev/sda5</span></span><br></pre></td></tr></table></figure></li><li><p>配置新分区在系统启动的时候挂载，并映射为/extend<br>修改<code>/etc/fstab</code>文件，在最后添加一行，注意使用对应的UUID并修改加载顺序</p><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">UUID=<span class="number">59</span>f8ba70<span class="number">-62</span>d4<span class="number">-4</span>d1d<span class="number">-982</span>e-a33166d59394  /extend  ext4  rw,relatime,data=ordered   <span class="number">0</span> <span class="number">3</span></span><br></pre></td></tr></table></figure></li></ol>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;机器装了两个系统，一个win7备用，一个linux生产。但是最近linux的剩余磁盘空间仅10G多，眼看就要不够用了，于是想着挤挤win7，分些空间出来给linux。&lt;/p&gt;
&lt;h3 id=&quot;第一步，grub-rescue的处理&quot;&gt;&lt;a href=&quot;#第一步，grub-re
      
    
    </summary>
    
    
      <category term="archlinux" scheme="http://windpuller.github.io/blog/tags/archlinux/"/>
    
      <category term="mount partitions" scheme="http://windpuller.github.io/blog/tags/mount-partitions/"/>
    
      <category term="grub rescue" scheme="http://windpuller.github.io/blog/tags/grub-rescue/"/>
    
  </entry>
  
  <entry>
    <title>csrf defense</title>
    <link href="http://windpuller.github.io/blog/2015/11/22/csrf-defense/"/>
    <id>http://windpuller.github.io/blog/2015/11/22/csrf-defense/</id>
    <published>2015-11-22T06:39:32.000Z</published>
    <updated>2016-09-02T10:39:38.000Z</updated>
    
    <content type="html"><![CDATA[<p><em>本文仅用来自己备忘，更详细内容请<a href="https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/" target="_blank" rel="noopener">阅读原文</a>。</em></p><h2 id="防止csrf攻击的常用方法"><a href="#防止csrf攻击的常用方法" class="headerlink" title="防止csrf攻击的常用方法"></a>防止csrf攻击的常用方法</h2><h3 id="1-HTTP-Reference"><a href="#1-HTTP-Reference" class="headerlink" title="1. HTTP Reference"></a>1. HTTP Reference</h3><p><strong>原理</strong>：检查HTTP Reference的地址，判定请求的来源。<br><strong>缺点</strong>：低版本浏览器（IE6等）可以篡改HTTP Reference，达不到防御效果；较新的浏览器允许用户关闭HTTP Reference的使用，致使用户的正常请求也不能通过。</p><h3 id="2-url中添加token参数"><a href="#2-url中添加token参数" class="headerlink" title="2. url中添加token参数"></a>2. url中添加token参数</h3><p><strong>原理</strong>：检查请求url中的token值是否是合法的。<br><strong>缺点</strong>：所有请求地址中添加token字段，实现起来较复杂；url中的token很容易被攻击者获取到。</p><h3 id="3-HTTP协议头部添加自定义属性"><a href="#3-HTTP协议头部添加自定义属性" class="headerlink" title="3. HTTP协议头部添加自定义属性"></a>3. HTTP协议头部添加自定义属性</h3><p><strong>原理</strong>：检查HTTP头部的csrfToken字段值是否合法。<br><strong>缺点</strong>：要使用XMLHttpRequest一次性给该类的所有请求添加csrfToken字段，而XMLHttpRequest的使用局限性很大，并非所有的请求都适合由XMLHttpRequest发起，使用XMLHttpRequest请求到的页面不能被浏览器记录，给用户带来不便。</p><h3 id="推荐的防御方式"><a href="#推荐的防御方式" class="headerlink" title="推荐的防御方式"></a>推荐的防御方式</h3><p>2+3, 对于安全性要求没那么高的请求，可以采用在url中添加token参数的方法防御csrf，对于安全性要求比较高的请求，则使用在HTTP协议头部添加csrfToken的方式。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;&lt;em&gt;本文仅用来自己备忘，更详细内容请&lt;a href=&quot;https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;阅读原文&lt;/a&gt;。&lt;/em&gt;&lt;
      
    
    </summary>
    
    
      <category term="csrf" scheme="http://windpuller.github.io/blog/tags/csrf/"/>
    
  </entry>
  
  <entry>
    <title>@transactional</title>
    <link href="http://windpuller.github.io/blog/2015/11/08/transactional/"/>
    <id>http://windpuller.github.io/blog/2015/11/08/transactional/</id>
    <published>2015-11-08T03:36:44.000Z</published>
    <updated>2016-09-02T10:39:38.000Z</updated>
    
    <content type="html"><![CDATA[<p>在<code>＠Transactional</code>注解的程序块中调用未使用<code>＠Transactional</code>注解的方法，则事务将在未被注解的方法中继续生效。在未被注解的方法中，继续使用事务中的数据库连接，该方法中的任何异常都会引起事务的回滚。<br>在<code>＠Transactional</code>注解的程序块中调用使用<code>＠Transactional</code>注解的方法，如果这两个方法属于同一个实例，那么事务在被调用的方法中不会生效；如果两个方法属于不同的实例，则事务在被调用的方法中继续生效。<br>同理，在一个实例内部，通过未被<code>＠Transactional</code>注解的方法调用被<code>＠Transactional</code>注解的方法，被调用方法的事务也不会生效。<br>之所以会出现以上现象，是受到Spring AOP机制的限制。<code>＠Transactional</code>注解使用的是Spring的AOP机制，AOP仅在外部实例调用被注解的方法时才会生效，在同一个实例中调用任何被注解的方法都只能调用到原生方法，而不是注解后生成的代理方法。<br>如果不得不在一个实例内部调用被<code>＠Transactional</code>注解的方法，需要在这个实例内部显示的注入自身类的实例，并通过这个被注入的实例调用被注解的方法，才能访问到代理方法使事务生效。示例如下：<br><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span>(<span class="string">"transactionalTestClass"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TransactionalTestClass</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Resource</span>(<span class="string">"transactionalTestClass"</span>)</span><br><span class="line">    <span class="keyword">private</span> TransactionalTestClass transactionalTestClass;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">noTransactionalMethod</span><span class="params">()</span></span>&#123;</span><br><span class="line">        transactionalTestClass.transactionalMethod();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Transactional</span>(rollbackFor = Exception.class)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">transactionalMethod</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//do somthing</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;在&lt;code&gt;＠Transactional&lt;/code&gt;注解的程序块中调用未使用&lt;code&gt;＠Transactional&lt;/code&gt;注解的方法，则事务将在未被注解的方法中继续生效。在未被注解的方法中，继续使用事务中的数据库连接，该方法中的任何异常都会引起事务的回滚。&lt;br
      
    
    </summary>
    
    
      <category term="spring" scheme="http://windpuller.github.io/blog/tags/spring/"/>
    
      <category term="java" scheme="http://windpuller.github.io/blog/tags/java/"/>
    
      <category term="transactional" scheme="http://windpuller.github.io/blog/tags/transactional/"/>
    
  </entry>
  
  <entry>
    <title>Spring circular dependency</title>
    <link href="http://windpuller.github.io/blog/2015/10/25/Spring-circular-dependency/"/>
    <id>http://windpuller.github.io/blog/2015/10/25/Spring-circular-dependency/</id>
    <published>2015-10-25T06:11:22.000Z</published>
    <updated>2016-09-02T10:39:38.000Z</updated>
    
    <content type="html"><![CDATA[<p>最近踩了一个继承加循环依赖的坑，抽象出的代码如下：<br>ChildClass:<br><figure class="highlight scala"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line">public <span class="class"><span class="keyword">class</span> <span class="title">ChildClass</span> <span class="keyword">extends</span> <span class="title">ParentClass</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> <span class="type">TestService</span> testService;</span><br><span class="line"></span><br><span class="line">    public <span class="type">String</span> play() &#123;</span><br><span class="line">        <span class="keyword">return</span> testService.getParent().play();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>ParentClass:<br><figure class="highlight cs"><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="keyword">public</span> <span class="keyword">class</span> <span class="title">ParentClass</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String <span class="keyword">value</span> = <span class="string">"I am parent class"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">play</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">value</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setValue</span>(<span class="params">String str</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.<span class="keyword">value</span> = str;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>TestService:<br><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestService</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> ParentClass parent;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostConstruct</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        parent = create();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ParentClass <span class="title">getParent</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.parent;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@SuppressWarnings</span>(&#123; <span class="string">"rawtypes"</span>, <span class="string">"unchecked"</span> &#125;)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> ParentClass <span class="title">create</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Class classDefinition = Class.forName(<span class="string">"com.springapp.mvc.inherited.ChildClass"</span>);</span><br><span class="line">            ParentClass parent = (ParentClass) classDefinition.getConstructor(<span class="keyword">new</span> Class[<span class="number">0</span>]).newInstance(<span class="keyword">new</span> Object[<span class="number">0</span>]);</span><br><span class="line">            parent.setValue(<span class="string">"I was processed by test service"</span>);</span><br><span class="line">            <span class="keyword">return</span> parent;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>ResultController:<br><figure class="highlight kotlin"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="meta">@RequestMapping(<span class="meta-string">"/inherited"</span>)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ResultController</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> ChildClass childClass;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@RequestMapping(method = RequestMethod.GET)</span></span><br><span class="line">    <span class="keyword">public</span> ModelAndView printWelcome() &#123;</span><br><span class="line">        ModelAndView modelAndView = new ModelAndView(<span class="string">"hello"</span>);</span><br><span class="line">        modelAndView.addObject(<span class="string">"message"</span>, childClass.play());</span><br><span class="line">        <span class="keyword">return</span> modelAndView;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>我们注意到，ChildClass重写了ParentClass的play方法。由于在TestService中使用反射方式生成了ChildClass的实例，并赋值给了ParentClass的实例，此时ParentClass实例并不能访问到ChildClass实例的成员变量testService，且ParentClass实例的play方法已经被ChildClass实例的play方法隐藏，也就是说<code>testService.getParent().play()</code>实际调用的是ChildClass的play()方法，显而易见，此处出现了循环调用。但是由于ParentClass的实例中<code>testService == null</code>，因此程序在进入这一层时会抛出NPE。</p><p>之后我们使用注解在TestService中实现成员变量parent的初始化，代码如下：<br>ParentClass:<br><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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TestService</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> ParentClass parent;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostConstruct</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">init</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        parent.setValue(<span class="string">"I was processed by test service"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ParentClass <span class="title">getParent</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.parent;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>此时运行程序，NPE消失了，但是出现栈溢出问题。从<code>＠Resource</code>的注解来看，注解的继承关系是向上的，所有使用注解注入的实例共用资源，即以依赖注入形式实现的ChildClass和ParentClass的实例共享资源。因此，TestService中的成员变量parent可以访问到子类ChildClass实例的成员变量testService，进而形成循环依赖并最终导致栈溢出。<br><code>＠Resource</code>部分注解：<br><figure class="highlight applescript"><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">* Even though this annotation <span class="keyword">is</span> <span class="keyword">not</span> marked Inherited, deployment</span><br><span class="line">* tools are required <span class="keyword">to</span> examine all superclasses <span class="keyword">of</span> any component</span><br><span class="line">* <span class="built_in">class</span> <span class="keyword">to</span> discover all uses <span class="keyword">of</span> this annotation <span class="keyword">in</span> all superclasses.</span><br><span class="line">* All such annotation instances specify resources <span class="keyword">that</span> are needed</span><br><span class="line">* <span class="keyword">by</span> <span class="keyword">the</span> <span class="built_in">application</span> component.  Note <span class="keyword">that</span> this annotation may</span><br><span class="line">* appear <span class="keyword">on</span> private fields <span class="keyword">and</span> methods <span class="keyword">of</span> superclasses; <span class="keyword">the</span> container</span><br><span class="line">* <span class="keyword">is</span> required <span class="keyword">to</span> perform injection <span class="keyword">in</span> these cases <span class="keyword">as</span> well.</span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;最近踩了一个继承加循环依赖的坑，抽象出的代码如下：&lt;br&gt;ChildClass:&lt;br&gt;&lt;figure class=&quot;highlight scala&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span
      
    
    </summary>
    
    
      <category term="circular dependency" scheme="http://windpuller.github.io/blog/tags/circular-dependency/"/>
    
      <category term="spring" scheme="http://windpuller.github.io/blog/tags/spring/"/>
    
      <category term="java" scheme="http://windpuller.github.io/blog/tags/java/"/>
    
      <category term="inherited" scheme="http://windpuller.github.io/blog/tags/inherited/"/>
    
  </entry>
  
  <entry>
    <title>git base commands</title>
    <link href="http://windpuller.github.io/blog/2015/09/24/git-base-commands/"/>
    <id>http://windpuller.github.io/blog/2015/09/24/git-base-commands/</id>
    <published>2015-09-24T03:52:12.000Z</published>
    <updated>2016-09-02T10:39:38.000Z</updated>
    
    <content type="html"><![CDATA[<h3 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h3><figure class="highlight shell"><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="meta">$</span><span class="bash"> mkdir <span class="built_in">test</span></span></span><br><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">cd</span> <span class="built_in">test</span></span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git init</span></span><br></pre></td></tr></table></figure><h3 id="config"><a href="#config" class="headerlink" title="config"></a>config</h3><figure class="highlight routeros"><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<span class="built_in"> config </span>--global user.name username</span><br><span class="line">$ git<span class="built_in"> config </span>--global user.email useremail.chn@gmail.com</span><br></pre></td></tr></table></figure><h3 id="文件修改-、查看状态、文件添加以及修改提交"><a href="#文件修改-、查看状态、文件添加以及修改提交" class="headerlink" title="文件修改 、查看状态、文件添加以及修改提交"></a>文件修改 、查看状态、文件添加以及修改提交</h3><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">echo</span> <span class="string">"hello world"</span>&gt;&gt;new.txt</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git status</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git add new.txt</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git status</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git commit -m <span class="string">"first"</span> //提交第一个版本</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">echo</span> <span class="string">"hello new world"</span>&gt;&gt;new.txt</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git status</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git add new.txt</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git status</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git commit -m <span class="string">"second"</span> //提交第二个版本</span></span><br></pre></td></tr></table></figure><h3 id="版本切换"><a href="#版本切换" class="headerlink" title="版本切换"></a>版本切换</h3><p>查看更新记录<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> git <span class="built_in">log</span></span></span><br></pre></td></tr></table></figure></p><p>使用能够区别版本的前几位即可<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> git checkout commit-id</span></span><br></pre></td></tr></table></figure></p><h3 id="远程提交"><a href="#远程提交" class="headerlink" title="远程提交"></a>远程提交</h3><p>添加远程仓库<br><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git remote <span class="built_in">add</span> origin http<span class="variable">s:</span>//github.<span class="keyword">com</span>/windpuller/test.git</span><br></pre></td></tr></table></figure></p><p>将修改提交到服务器端<br><figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="built_in">push</span> -u <span class="built_in">origin</span> master</span><br></pre></td></tr></table></figure></p><h3 id="检出仓库"><a href="#检出仓库" class="headerlink" title="检出仓库"></a>检出仓库</h3><p>创建本地仓库的克隆版本<br><figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="keyword">clone</span> <span class="title">/path</span>/to/repository</span><br></pre></td></tr></table></figure></p><p>创建远端服务器的克隆版本<br><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$ </span>git clone uxername<span class="variable">@host</span><span class="symbol">:/past/to/repository</span></span><br></pre></td></tr></table></figure></p><h3 id="分支"><a href="#分支" class="headerlink" title="分支"></a>分支</h3><p>创建分支<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> git branch branch1</span></span><br></pre></td></tr></table></figure></p><p>切换分支<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> git checkout branch1</span></span><br></pre></td></tr></table></figure></p><p>删除本地分支<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> git branch -d branch1</span></span><br></pre></td></tr></table></figure></p><p>删除远程分支(慎重使用)<br><figure class="highlight shell"><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="meta">$</span><span class="bash"> git branch -r -d origin/branch1</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git push origin :branch1</span></span><br></pre></td></tr></table></figure></p><p>将分支推送到远端仓库，不推送的话分支是不为他人所见的<br><figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="built_in">push</span> <span class="built_in">origin</span> branch1</span><br></pre></td></tr></table></figure></p><h3 id="更新与合并"><a href="#更新与合并" class="headerlink" title="更新与合并"></a>更新与合并</h3><p>更新本地仓库至最新改动，完成了获取fetch并合并merge改动的功能<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> git pull</span></span><br></pre></td></tr></table></figure></p><p>合并其他分支到当前分支<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> git merge branch</span></span><br></pre></td></tr></table></figure></p><p>在以上两种情况下，git都会尝试自动合并改动。但是不是每次合并都能成功，可能出现冲突。这时候就需要修改文件来手动合并这些冲突。改完文件之后，需要重新commit。<br>在合并改动之前，可以使用如下命令预览差异：<br><figure class="highlight gams"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><span class="meta-keyword">$git</span> diff source_branch target_branch</span></span><br></pre></td></tr></table></figure></p><h3 id="标签"><a href="#标签" class="headerlink" title="标签"></a>标签</h3><p>为某个版本创建标签<br><figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="keyword">tag</span> <span class="title">tag-name</span> commit-ID</span><br></pre></td></tr></table></figure></p><h3 id="替换本地改动"><a href="#替换本地改动" class="headerlink" title="替换本地改动"></a>替换本地改动</h3><p>如果操作失误，可以使用HEAD中的最新内容替换掉工作目录中的文件，已添加到缓存区的改动和新文件都不会受到影响<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> git checkout -- filename</span></span><br></pre></td></tr></table></figure></p><p>如果想要放弃本地的所有改动和提交，可以到服务器上获取最新的版本历史，并将本地主分支指向它：<br><figure class="highlight shell"><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="meta">$</span><span class="bash"> git fetch origin</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> git reset --hard origin/master</span></span><br></pre></td></tr></table></figure></p><h3 id="实用小贴士"><a href="#实用小贴士" class="headerlink" title="实用小贴士"></a>实用小贴士</h3><p>内建的图形化git<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> gitk</span></span><br></pre></td></tr></table></figure></p><p>彩色的git输出<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git<span class="built_in"> config </span>color.ui <span class="literal">true</span></span><br></pre></td></tr></table></figure></p><p>显示历史记录时，每个提交的信息只显示一行<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git<span class="built_in"> config </span>format.pretty oneline</span><br></pre></td></tr></table></figure></p><p>交互式添加文件到暂存区<br><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="keyword">add</span><span class="bash"> -i</span></span><br></pre></td></tr></table></figure></p><h3 id="参考文献："><a href="#参考文献：" class="headerlink" title="参考文献："></a>参考文献：</h3><ol><li><a href="http://rogerdudler.github.io/git-guide/index.zh.html" target="_blank" rel="noopener">http://rogerdudler.github.io/git-guide/index.zh.html</a></li></ol>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h3 id=&quot;初始化&quot;&gt;&lt;a href=&quot;#初始化&quot; class=&quot;headerlink&quot; title=&quot;初始化&quot;&gt;&lt;/a&gt;初始化&lt;/h3&gt;&lt;figure class=&quot;highlight shell&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;s
      
    
    </summary>
    
    
      <category term="git" scheme="http://windpuller.github.io/blog/tags/git/"/>
    
  </entry>
  
</feed>
