ApplicationContext可以同时获取多个Bean吗?

举报
赵KK日常技术记录 发表于 2023/06/30 16:16:44 2023/06/30
【摘要】   在实际场景中提供了N个接口给第三方,常规情况下是不会同时调用的,如果N个接口同时调用,随着接口的数量和业务场景逻辑增加,将会给服务带来很不好的体验,但恰恰业务就是如此,面对同一类型的业务查询场景,我将策略模式应用到此接口上来应对。关于实际设计的demo可参考往期文章炫技?No.    这个对外接口与以往不同的是,接口调用通过openFeign方式调用,针对此类调用也提醒了注意事项Comp...

  在实际场景中提供了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。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。