问题描述
有一组数据我需要每次定时任务执行的时候都查一遍数据库拿最新的数据来使用,为了代码的整洁和方便这组数据的参数传递,我将这项数据封装进一个单独的对象中,这组数据的初始化还需要用到mapper
,那么这个对象就还得在让Spring来管理,所以我给这个对象加上了@Component注解
,这个对象每次任务开始都需要被刷新数据,所以我加上了@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
开启他的多实例,因为Spring默认是单例的
。
为什么我需要开启多实例呢,如上图,因为我要给属性赋值都是要查询数据库的,并且可能会重复查询多次,所以我的方法会先行判空,只有为空才会查询赋值,所以我为了避免多次重复的查询,来这样设计这个对象。
public void ifSetVillageGuardRuleList(Set<String> carrierNoSet) {
if (this.villageGuardRuleList == null) {
this.villageGuardRuleList = tmsVillageGuardRuleMapper.selectListByCarrierCodes(carrierNoSet);
//分组
Optional.ofNullable(villageGuardRuleList).ifPresent(b -> {
this.villageGuardRuleListMap = b.stream().collect(Collectors.groupingBy(TmsVillageGuardRule::getCarrierCode));
});
}
}
测试阶段:
这里填写问题的分析: 以上我开启了我对象的多实例,然后接下来进行测试
@Resource
private PaymentRules paymentRules1;
@Resource
private PaymentRules paymentRules2;
@Test
public void demo1() {
System.out.println(System.identityHashCode(paymentRules1));
System.out.println(System.identityHashCode(paymentRules2));
}
一个很简单的测试,我将对象注入两次,然后打印他们的hashCode码
,发现确实开启了多实例,以下是输出内容:
使用阶段:
接下来在定时任务中是这样使用的
@Resource
private PaymentRules paymentRules;
@Scheduled(cron = "0/3 * * * * ? ") //每隔三秒执行
public void test() {
System.out.println(System.identityHashCode(paymentRules));
}
但是输出结果却是有问题的~~
发现输出结果一样,然后才发现,Springboot只在启动的时候注入了一次,后续用到的对象都是一个,/(ㄒoㄒ)/~~,那我搞这个单例不是白瞎嘛!
解决方案:
这里填写该问题的具体解决方案:解决方法很简单,通过
Springboot上下文程序
,来获取Bean即可,代码如下:
@Resource
@Resource
private ApplicationContext context;
@Scheduled(cron = "0/3 * * * * ? ") //每隔三秒执行
public void test() {
PaymentRules bean = context.getBean(PaymentRules.class);
System.out.println(System.identityHashCode(bean));
}
输出结果如下:
如上图所示,每次的对象hash都不一样了,至此完美解决多实例的问题。