版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。

最近在项目开发中遇到这样一个需求,由于元数据在短时间内被客户端多次读取,因此希望直接将数据存储到内存,以减少网络开销,借助guava cache于是有了下面这个类

  1. /**
  2. * Created on 2018/10/18
  3. */
  4. @Component
  5. public class CacheUtil {
  6. <span class="token annotation punctuation">@Autowired</span>
  7. CaseGraphService caseGraphService<span class="token punctuation">;</span>
  8. <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>
  9. <span class="token keyword">long</span> expireDuration<span class="token punctuation">;</span>
  10. <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
  11.             <span class="token punctuation">.</span><span class="token function">newBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  12.             <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>
  13.             <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>
  14.             <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>
  15. <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>
  16.     <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>
  17. <span class="token punctuation">}</span>
  18. <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>
  19.     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>
  20. <span class="token punctuation">}</span>
  21. <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>
  22.     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>
  23. <span class="token punctuation">}</span>
  24. }

    • 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方法,类似于这样:

  1. @Component
  2. public class TestComponent {
  3. @Autowired
  4. CacheUtil cacheUtil;
  5. <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>
  6. 	<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>
  7. <span class="token punctuation">}</span>
  8. }

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

当我们第一次调用getMetaNode时,cache使用caseGraphService获取元数据,而后将这一元数据存放的cache中,我们在CacheUtil的getMetaNode方法中添加两行代码来测试一下:

  1. public CaseGraphDTO getMetaNode(long caseId) throws ExecutionException {
  2. //metaNodeCache的get方法,如果缓存中已有数据,直接返回数据,如果没有则通过Callable方法获取存入缓存再返回数据
  3. CaseGraphDTO caseGraphDTO = metaNodeCache.get(caseId, () -> caseGraphService.getCaseGraph
  4. (caseId));
  5. //getIfPresent方法,如果存在数据即返回
  6. CaseGraphDTO caseGraphDTO1 = metaNodeCache.getIfPresent(caseId);
  7. System.out.println(caseGraphDTO1);
  8. return caseGraphDTO;
  9. }
  10.  
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

启动application, 打开断点调试:



可以看到caseGraphDTO1为null,而不是我们预想的元数据;metaNodeCache中localCache的大小为0,也就是根本没有缓存任何数据。

而后我采用另一种方式@PostConstruct的方式来初始化metaNodeCache, 代码如下:

  1. @Component
  2. public class CacheUtil {
  3. <span class="token annotation punctuation">@Autowired</span>
  4. CaseGraphService caseGraphService<span class="token punctuation">;</span>
  5. <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>
  6. <span class="token keyword">long</span> expireDuration<span class="token punctuation">;</span>
  7. <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>
  8. <span class="token annotation punctuation">@PostConstruct</span>
  9. <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>
  10.     metaNodeCache <span class="token operator">=</span> CacheBuilder
  11.             <span class="token punctuation">.</span><span class="token function">newBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  12.             <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>
  13.             <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>
  14.             <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>
  15. <span class="token punctuation">}</span>
  16. <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>
  17.     <span class="token comment">//metaNodeCache的get方法,如果缓存中已有数据,直接返回数据,如果没有则通过Callable方法获取存入缓存再返回数据</span>
  18.     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
  19.             <span class="token punctuation">(</span>caseId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  20.     <span class="token comment">//getIfPresent方法,如果存在数据即返回</span>
  21.     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>
  22.     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>
  23.     <span class="token keyword">return</span> caseGraphDTO<span class="token punctuation">;</span>
  24. <span class="token punctuation">}</span>
  25. <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>
  26.     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>
  27. <span class="token punctuation">}</span>
  28. <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>
  29.     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>
  30. <span class="token punctuation">}</span>
  31. }

    • 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注解的方法中去做

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

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

spring中bean的构造函数,Autowired(Value)注入与@PostConstruct调用顺序的更多相关文章

  1. 由一个RABBITMQ监听器死循环引出的SPRING中BEAN和MAPPER接口的注入问题

    1 @Slf4j 2 @RestController 3 @Component 4 public class VouchersReceiverController implements Message ...

  2. Spring中bean的注入方式

    首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入.依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖. Spring ...

  3. Spring官网阅读(十)Spring中Bean的生命周期(下)

    文章目录 生命周期概念补充 实例化 createBean流程分析 doCreateBean流程分析 第一步:factoryBeanInstanceCache什么时候不为空? 第二步:创建对象(crea ...

  4. Spring中Bean的实例化

                                    Spring中Bean的实例化 在介绍Bean的三种实例化的方式之前,我们首先需要介绍一下什么是Bean,以及Bean的配置方式. 如果 ...

  5. Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别

    Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...

  6. (转)Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别

    Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...

  7. Spring中Bean的命名问题及ref和idref之间的区别

    一直在用Spring,其实对其了解甚少,刚去了解了一下Spring中Bean的命名问题以及ref和idref之间的区别,略作记录,以备后查. Spring中Bean的命名 1.每个Bean可以有一个i ...

  8. Spring中Bean获取IOC容器服务的方法

    Spring 依赖注入可以让所有的Bean对其IOC容器的存在是没有意识的,甚至可以将容器换成其它的.但实际开发中如果某个Bean对象要用到Spring 容器本身的功能资源,需要意识到IOC容器的存在 ...

  9. Spring中的控制反转和依赖注入

    Spring中的控制反转和依赖注入 原文链接:https://www.cnblogs.com/xxzhuang/p/5948902.html 我们回顾一下计算机的发展史,从最初第一台计算机的占地面积达 ...

随机推荐

  1. [NOI2004]郁闷的出纳员(平衡树)

    [NOI2004]郁闷的出纳员 题目链接 题目描述 OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的 ...

  2. bzoj3123 [Sdoi2013]森林 树上主席树+启发式合并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3123 题解 如果是静态的查询操作,那么就是直接树上主席树的板子. 但是我们现在有了一个连接两棵 ...

  3. CGfsb

    这里补充一下%n是代表向参数赋值打印的字符个数 例如printf("AAAA%n",&a); 代表的是向a写入4 printf("AAAA%1n", & ...

  4. Chronograf启动(Influxdb的管理平台)

    1.创建一个bat文件,文件内容如下 @echo off:: 开启chronograf服务,服务监听端口9084echo 开启chronograf服务chronograf.exe /port 9084 ...

  5. redis学习一 String数据类型

    一:概述 字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等.在Redis中字符串类型的 ...

  6. python全栈开发,Day40(进程间通信(队列和管道),进程间的数据共享Manager,进程池Pool)

    昨日内容回顾 进程 multiprocess Process —— 进程 在python中创建一个进程的模块 start daemon 守护进程 join 等待子进程执行结束 锁 Lock acqui ...

  7. Python全栈开发,Day2

    一.Pycharm的使用 1.创建项目 2.python调整字体大小随ctrl+鼠标滚轮上下滚动 3.python新建程序自动补全编码和环境 4.设置断点(在代码前面行号后面单击鼠标左键) 5.调试断 ...

  8. 29 基于PCL的点云平面分割拟合算法技术路线(针对有噪声的点云数据)

    0 引言 最近项目中用到了基于PCL开发的基于平面的点云和CAD模型的配准算法,点云平面提取采用的算法如下. 1 基于PCL的点云平面分割拟合算法 2 参数及其意义介绍 (1)点云下采样 1. 参数: ...

  9. C#中给RICHTEXTBOX加上背景图片

    在系统自带的RichTextBox中是无法给它设置背景图片,但是我们在某些场合可能需要给RichTextBox设置背景图片.那么怎么实现这一想法呢?经过研究发现通过其它巧妙的途径可以给RichText ...

  10. (\w+)\s*, \s*(\w+)

    \s表示空格 \w表示任何字符,字母数字下划线 _就表示下划线