ApplicationContext可以同时获取多个Bean吗?
在实际场景中提供了N个接口给第三方,常规情况下是不会同时调用的,如果N个接口同时调用,随着接口的数量和业务场景逻辑增加,将会给服务带来很不好的体验,但恰恰业务就是如此,面对同一类型的业务查询场景,我将策略模式应用到此接口上来应对。关于实际设计的demo可参考往期文章炫技?No.
这个对外接口与以往不同的是,接口调用通过openFeign方式调用,针对此类调用也提醒了注意事项CompletableFuture调用OpenFegin,谁用谁傻,除了业务需求的更改,已经是上线逻辑了,但偶发的出现了返回数据为null的情况,针对业务已经对Integer做了处理,正常的应该是返回0的,且出现null的情况也未能复现,针对代码做出排查。
ApplicationContext可以同时获取多个Bean吗?
其实这个问题不应该这么问,多线程调用的默认Springboot的无状态Bean是线程安全的,一般情况下是不会对Bean的成员变量进行修改的,这个跟修改注解的方法值那个问题是两个问题,context无非是一个map,当在外部进行调用的前提,我所需要的我bean是一定已经初始化完成的,我们看下context的内部存储数据:
在这里可以看到已经初始化的bean,或者在beanDefinitionMap中也能看到,只不过在其实现中是有区别的,比如在SimpleJndiBeanFactory中其getBean方法是一个HashMap,而在DefaultListableBeanFactory中则是ConcurrentHashMap,所以不管是哪种类型,在map中同时获取bean是没有问题的,即便是在多线程场景下。
考虑到版本和镜像初始化问题,如果需要可以在bean初始化完成之后进行指定bean的初始化。
1.实现ApplicationListener接口
Bean在初始化完成后会执行onApplicationEvent方法
@Componentpublic class LazyApplicationListener implements ApplicationListener<ContextRefreshedEvent> { public LazyApplicationListener() { System.out.println("LazyApplicationListener init"); }
@Override public void onApplicationEvent(ContextRefreshedEvent event) { if (event.getApplicationContext().getParent() == null) { System.out.println("LazyApplicationListener onApplicationEvent"); } }}
2.实现InitializingBean接口
Bean在初始化完成后会执行afterPropertiesSet()
@Componentpublic class LazyInitializingBean implements InitializingBean { public LazyInitializingBean() { System.out.println("LazyInitializingBean init"); }
@Override public void afterPropertiesSet() throws Exception { System.out.println("LazyInitializingBean afterPropertiesSet"); }}
3.使用@PostConstruct注解
@Componentpublic class LazyPostConstructAnnotation { public LazyPostConstructAnnotation() { System.out.println("LazyPostConstructAnnotation constructor"); }
@PostConstruct public void init(){ System.out.println("LazyPostConstructAnnotation init"); }}2023-01-09 17:29:55.588 INFO 5884 --- [main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2489 ms
那么为何为null?
SQL语句不能保证100%为null,原sql如下
<select id="task" resultType="java.lang.Integer"> select count(*) from (select id from xxx tri where xxx xxx xxx GROUP BY xxx) a </select>
count(字段名):返回select语句检索的行中字段名的值不为null的数量,结果是BIGINT值;
count(*):统计结果中会包含值为null的行数;
count(常量):count(*)、count(常量):表示的是直接查询符合条件的数据库表的行数。而count(列名)表示的是查询符合条件的列的值不为null的行数;
原因猜测
如果确实为null可手动处理Integer值。但其实并没有再次复现此问题,我其实怀疑是因为在这个期间我某个SQL当时写错了,构建完没改的情况导致在一个接口同时调用时报错,从而返回了null。
- 点赞
- 收藏
- 关注作者
评论(0)