spring中bean的构造函数,Autowired(Value)注入与@PostConstruct调用顺序
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。
最近在项目开发中遇到这样一个需求,由于元数据在短时间内被客户端多次读取,因此希望直接将数据存储到内存,以减少网络开销,借助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"><</span>Long<span class="token punctuation">,</span> CaseGraphDTO<span class="token punctuation">></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">></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"><</span>Long<span class="token punctuation">,</span> CaseGraphDTO<span class="token punctuation">></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">></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
spring中bean的构造函数,Autowired(Value)注入与@PostConstruct调用顺序的更多相关文章
- 由一个RABBITMQ监听器死循环引出的SPRING中BEAN和MAPPER接口的注入问题
1 @Slf4j 2 @RestController 3 @Component 4 public class VouchersReceiverController implements Message ...
- Spring中bean的注入方式
首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入.依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖. Spring ...
- Spring官网阅读(十)Spring中Bean的生命周期(下)
文章目录 生命周期概念补充 实例化 createBean流程分析 doCreateBean流程分析 第一步:factoryBeanInstanceCache什么时候不为空? 第二步:创建对象(crea ...
- Spring中Bean的实例化
Spring中Bean的实例化 在介绍Bean的三种实例化的方式之前,我们首先需要介绍一下什么是Bean,以及Bean的配置方式. 如果 ...
- Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别
Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...
- (转)Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别
Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...
- Spring中Bean的命名问题及ref和idref之间的区别
一直在用Spring,其实对其了解甚少,刚去了解了一下Spring中Bean的命名问题以及ref和idref之间的区别,略作记录,以备后查. Spring中Bean的命名 1.每个Bean可以有一个i ...
- Spring中Bean获取IOC容器服务的方法
Spring 依赖注入可以让所有的Bean对其IOC容器的存在是没有意识的,甚至可以将容器换成其它的.但实际开发中如果某个Bean对象要用到Spring 容器本身的功能资源,需要意识到IOC容器的存在 ...
- Spring中的控制反转和依赖注入
Spring中的控制反转和依赖注入 原文链接:https://www.cnblogs.com/xxzhuang/p/5948902.html 我们回顾一下计算机的发展史,从最初第一台计算机的占地面积达 ...
随机推荐
- Reference与ReferenceQueue
Reference源码分析 首先我们先看一下Reference类的注释: /** * Abstract base class for reference objects. This class def ...
- 使用Github 当作自己个人博客的图床
使用Github 当作自己个人博客的图床 前提 本文前提: 我个人博客的草稿是存放在 github上的一个仓库 diarynote 截图存放的图片或者需要放在文章中图片,会固定存放在对应的文件夹中,我 ...
- python开发之virtualenv与virtualenvwrapper
在使用 Python 开发的过程中,工程一多,难免会碰到不同的工程依赖不同版本的库的问题: 亦或者是在开发过程中不想让物理环境里充斥各种各样的库,引发未来的依赖灾难. 此时,我们需要对于不同的工程使用 ...
- pandas.Series函数用法
class pandas.Series(data=None, index=None, dtype=None, name=None, copy=False, fastpath=False) e.g., ...
- Redis-缓存击穿/穿透/雪崩
缓存击穿/穿透/雪崩 Intro 使用缓存需要了解几个缓存问题,缓存击穿.缓存穿透以及缓存雪崩,需要了解它们产生的原因以及怎么避免,尤其是当你打算设计自己的缓存框架的时候需要考虑如何处理这些问题. 缓 ...
- OC + RAC (八) 查看信号状态和跳过信号
-(void)_test9{ /// RACCommand又叫命令 是用来收发数据的 监听按钮点击,网络请求.... RACCommand * command = [[RACCommand alloc ...
- OC + RAC (四) combineLatest和merg
-(void)_test4{ ///RAC combineLatest和merge // combineLatest只有当两个信号都发送了 订阅者才能收到信息 结果一次收到 结果是数组 // merg ...
- [14th CSMO Day 1 <平面几何>]
关于LowBee苦思冥想的结果(仅供参考):
- 20180822-Java接口
Java 接口 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承接口的抽象方法. 接口并 ...
- hadoop平台搭建
前言 这是小的第一次搭建hadoop平台,写下这篇博客有以下几个目的(ps:本博只记录在linux系统下搭建hadoop的步骤,如果需要了解在其他平台上搭建hadoop的步骤,还请移步): 1.希望大 ...