spring中bean的構造函數,Autowired(Value)注入與@PostConstruct調用順序


版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接: https://blog.csdn.net/yyysylvia/article/details/83177345

最近在項目開發中遇到這樣一個需求,由於元數據在短時間內被客戶端多次讀取,因此希望直接將數據存儲到內存,以減少網絡開銷,借助guava cache於是有了下面這個類

/** * Created on 2018/10/18 */
@Component
public class CacheUtil {
<span class="token annotation punctuation">@Autowired</span>
CaseGraphService caseGraphService<span class="token punctuation">;</span>

<span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${cache.expire.duration}"</span><span class="token punctuation">)</span>
<span class="token keyword">long</span> expireDuration<span class="token punctuation">;</span>

<span class="token keyword">private</span> Cache<span class="token generics function"><span class="token punctuation">&lt;</span>Long<span class="token punctuation">,</span> CaseGraphDTO<span class="token punctuation">&gt;</span></span> metaNodeCache <span class="token operator">=</span> CacheBuilder
            <span class="token punctuation">.</span><span class="token function">newBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">maximumSize</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">expireAfterAccess</span><span class="token punctuation">(</span>expireDuration<span class="token punctuation">,</span> TimeUnit<span class="token punctuation">.</span>MINUTES<span class="token punctuation">)</span> <span class="token comment">//設置過期時間</span>
            <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> CaseGraphDTO <span class="token function">getMetaNode</span><span class="token punctuation">(</span><span class="token keyword">long</span> caseId<span class="token punctuation">)</span> <span class="token keyword">throws</span> ExecutionException <span class="token punctuation">{</span>
    <span class="token keyword">return</span> metaNodeCache<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>caseId<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> caseGraphService<span class="token punctuation">.</span><span class="token function">getCaseGraph</span><span class="token punctuation">(</span>caseId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">removeMetaNodeByKey</span><span class="token punctuation">(</span><span class="token keyword">long</span> caseId<span class="token punctuation">)</span><span class="token punctuation">{</span>
    metaNodeCache<span class="token punctuation">.</span><span class="token function">invalidate</span><span class="token punctuation">(</span>caseId<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">removeMetaNodeAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    metaNodeCache<span class="token punctuation">.</span><span class="token function">invalidateAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

我們在另一個類中注入CacheUtil並調用它的getMetaNode方法,類似於這樣:

@Component
public class TestComponent {
	@Autowired
	CacheUtil cacheUtil;
<span class="token keyword">public</span> CaseGraphDTO <span class="token function">getMetaData</span><span class="token punctuation">(</span><span class="token keyword">long</span> caseId<span class="token punctuation">)</span><span class="token punctuation">{</span>
	<span class="token keyword">return</span> cacheUtil<span class="token punctuation">.</span><span class="token function">getMetaNode</span><span class="token punctuation">(</span>caseId<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

當我們第一次調用getMetaNode時,cache使用caseGraphService獲取元數據,而后將這一元數據存放的cache中,我們在CacheUtil的getMetaNode方法中添加兩行代碼來測試一下:

public CaseGraphDTO getMetaNode(long caseId) throws ExecutionException {
        //metaNodeCache的get方法,如果緩存中已有數據,直接返回數據,如果沒有則通過Callable方法獲取存入緩存再返回數據
        CaseGraphDTO caseGraphDTO = metaNodeCache.get(caseId, () -> caseGraphService.getCaseGraph
                (caseId));
        //getIfPresent方法,如果存在數據即返回
        CaseGraphDTO caseGraphDTO1 = metaNodeCache.getIfPresent(caseId);
        System.out.println(caseGraphDTO1);
        return caseGraphDTO;
    }

    
    
    
            
   
   
   
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

啟動application, 打開斷點調試:
在這里插入圖片描述
可以看到caseGraphDTO1為null,而不是我們預想的元數據;metaNodeCache中localCache的大小為0,也就是根本沒有緩存任何數據。

而后我采用另一種方式@PostConstruct的方式來初始化metaNodeCache, 代碼如下:

@Component
public class CacheUtil {
<span class="token annotation punctuation">@Autowired</span>
CaseGraphService caseGraphService<span class="token punctuation">;</span>

<span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${cache.expire.duration}"</span><span class="token punctuation">)</span>
<span class="token keyword">long</span> expireDuration<span class="token punctuation">;</span>

<span class="token keyword">private</span> Cache<span class="token generics function"><span class="token punctuation">&lt;</span>Long<span class="token punctuation">,</span> CaseGraphDTO<span class="token punctuation">&gt;</span></span> metaNodeCache<span class="token punctuation">;</span>

<span class="token annotation punctuation">@PostConstruct</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    metaNodeCache <span class="token operator">=</span> CacheBuilder
            <span class="token punctuation">.</span><span class="token function">newBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">maximumSize</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">expireAfterAccess</span><span class="token punctuation">(</span>expireDuration<span class="token punctuation">,</span> TimeUnit<span class="token punctuation">.</span>MINUTES<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> CaseGraphDTO <span class="token function">getMetaNode</span><span class="token punctuation">(</span><span class="token keyword">long</span> caseId<span class="token punctuation">)</span> <span class="token keyword">throws</span> ExecutionException <span class="token punctuation">{</span>
    <span class="token comment">//metaNodeCache的get方法,如果緩存中已有數據,直接返回數據,如果沒有則通過Callable方法獲取存入緩存再返回數據</span>
    CaseGraphDTO caseGraphDTO <span class="token operator">=</span> metaNodeCache<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>caseId<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">&gt;</span> caseGraphService<span class="token punctuation">.</span>getCaseGraph
            <span class="token punctuation">(</span>caseId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//getIfPresent方法,如果存在數據即返回</span>
    CaseGraphDTO caseGraphDTO1 <span class="token operator">=</span> metaNodeCache<span class="token punctuation">.</span><span class="token function">getIfPresent</span><span class="token punctuation">(</span>caseId<span class="token punctuation">)</span><span class="token punctuation">;</span>
    System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>caseGraphDTO1<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> caseGraphDTO<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">removeMetaNodeByKey</span><span class="token punctuation">(</span><span class="token keyword">long</span> caseId<span class="token punctuation">)</span><span class="token punctuation">{</span>
    metaNodeCache<span class="token punctuation">.</span><span class="token function">invalidate</span><span class="token punctuation">(</span>caseId<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">removeMetaNodeAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    metaNodeCache<span class="token punctuation">.</span><span class="token function">invalidateAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

再進行調試:
在這里插入圖片描述
這時我們看到caseGraphDTO1中有了數據,並且metaNodeCache中localCache的大小也變成了1.

那么直接初始化成員變量和使用postConstruct來初始化二者的區別是什么呢?

要將對象p注入到對象a,那么首先就必須得生成對象p與對象a,才能執行注入。所以,如果一個類A中有個成員變量p被@Autowired注解,那么@Autowired注入是發生在A的構造方法執行完之后的。
如果想在生成對象時候完成某些初始化操作,而偏偏這些初始化操作又依賴於依賴注入,那么就無法在構造函數中實現。為此,可以使用@PostConstruct注解一個方法來完成初始化,@PostConstruct注解的方法將會在依賴注入完成后被自動調用。

事情似乎明朗起來了,雖然我們在初始化metaNodeCache時沒有使用autowired進來的caseGraphService,但我們使用了@Value來注入緩存過期時間(配置中這個值為60)。讓我們再來斷點調試一下,當使用直接初始化成員變量的方式時,@Value("${cache.expire.duration}")注入的過期時間是多少,如下:
在這里插入圖片描述
我們看到expireDuration的值為0,而不是配置中的60,對於cache的含義即為緩存中的數據被讀取后0分鍾使其失效,等同於立即失效。所以導致上文我們的緩存中始終沒有數據。

讓我們再來看看使用PostConstruct初始化時,這個過期時間的值:
在這里插入圖片描述
此時看到expireDuration的值為60.

因此我們需要記住,構造函數,Autowired(Value),PostConstruct的執行順序為:

Constructor >> Autowired >> PostConstruct
如果初始化成員變量需要使用注入進來的對象或者值,那么應該放在被PostConstruct注解的方法中去做

                                </div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-095d4a0b23.css" rel="stylesheet">

原文地址:https://blog.csdn.net/yyysylvia/article/details/83177345


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM