一次Spring Bean初始化顺序问题排查记录

最近在使用Springboot的时候需要通过静态的方法获取到Spring容器托管的bean对象,参照一些博文里写的,新建了个类,并实现ApplicationContextAware接口。代码大致如下:

@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringUtils.applicationContext == null) {
            SpringUtils.applicationContext = applicationContext;
        }
    }
   public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }
}

然后另外一个bean需要依赖这个静态获取bean的方法,代码大致如下:

@Component
public class TestBean{

   private Object dependencyBean = SpringUtils.getBean(OtherBean.class);  

}

(注: 忽略代码逻辑是否合理~~ 这些代码是为演示所用简化的逻辑,肯定有同学会说:既然都是bean了为什么不注入,而是要用静态的获取呢?这个暂时不考虑,暂认为就必须要这样搞)

这两个类的层次结构和包名大致如下: 

utils

> notice

  > TestBean

> SpringUtils


就是TestBean在SpringUtils的下一级,TestBean所在包名为notice(这这个名字很重要! 直接影响到这两个bean的加载顺序,具体原理往下看)

代码就这么多,从以上代码来静态分析看,确实有些漏洞,因为没有考虑到Spring bean的加载顺序,可能导致的SpringUtils报空指针异常(在TestBean先于SpringUtils初始化的场景下),不管怎么样先执行一下看下效果,效果如下:

macOS操作系统下代码正常

windows平台下代码空指针异常

为什么这还跟平台有关了呢?难道Spring bean的初始化顺序还跟平台有关?事实证明这个猜想是正确的。下面从Spring源代码里找原因。

普通的(什么样的bean算是普通?这里暂定用@Component注解的bean)Spring bean的加载包括两个部分,第一部分是加载bean的定义,第二部分是实例化bean。这个可以在AbstractApplicationContext.refresh方法里找到对应:

原文地址:https://www.cnblogs.com/caiyao/p/10096263.html

时间: 2024-08-04 03:50:43

一次Spring Bean初始化顺序问题排查记录的相关文章

storm初始化Bolt实例,spring bean绑定失败原因排查

public static final String METRICS_AGGREGATE_PERIOD_MILLISECONDS = "metrics.storm.aggregate.period.milliseconds"; @Value("${" + METRICS_AGGREGATE_PERIOD_MILLISECONDS + "}") private long metricsAggregateIntervalMilliSeconds; 上

spring bean初始化和销毁

当实例化一个bean时,可能需要执行一些初始化操作来确保该bean处于可用状态.当不在需要bean的时候,将其从容器中移除时候,我们可能会执行一些清理的工作. 1.spring提供了:InitializingBean和DisposableBean接口 Spring容器以特殊的方式对待实现这两个接口的bean,容许他们进入bean的生命周期. 看下例子: public class TestSpring implements InitializingBean,DisposableBean { //初

spring初始化bean的顺序

不是说单个bean的初始化顺序.这个顺序大体上是构造方法-set方法-init方法,详细的可以百度. 这里说的是在spring容器中互不相关的两个bean的初始化顺序.例如: <bean id="a" class="A"/> <bean id="b" class="B"/> 经过昨天遇到的问题,现在知道了这两个bean的顺序是以xml文件中的顺序为准的.例如a配置在b的前面,那么spring就先装配实例

Spring 容器里的bean初始化回调方法研究(一)

@Author xiejun @Since 2015/10/24 感慨一下,曾经某内的讲师说spring bean的创建讲三天三夜也说不完,这种空话听的耳朵 起茧了,却还是不停地被人repeat,究其原因,o(︶︿︶)o 唉确实有的研究. **** 米字符号中是业务剥离 业务介绍: 系统a需要从另一个系统b批量获取到单号,然后存入数据库,当到使用时,a系统将单号与绑定信息回传给b系统. 在这个业务中可以把获取和存入数据库做成一个单独的服务,在后台线程中自动运行.介绍一下实现: 在容器初始化级别的

spring加载bean实例化顺序

转载:http://blog.sina.com.cn/s/blog_525960510100ipwj.html http://blog.sina.com.cn/s/blog_6940cab30102uwma.html 问题来源: 有一个bean为 A,一个bean为B.想要A在容器实例化的时候的一个属性name赋值为B的一个方法funB的返回值. 如果只是在A里单纯的写着: private B b;private String name = b.funb(); 会报错说nullpointExce

在Spring Bean的生命周期中各方法的执行顺序

Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,常用的设定方式有以下十种: 通过实现 InitializingBean 接口来定制初始化之后的操作方法: 通过实现DisposableBean 接口来定制销毁之前的操作方法: 通过元素的 init-method属性指定初始化之后调用的操作方法: 通过元素的 destroy-method属性指定销毁之前调用的操作方法: 在指定方法上加上 @PostConstruct

Spring实现初始化和销毁bean之前进行的操作,三种方式

关于在spring  容器初始化 bean 和销毁前所做的操作定义方式有三种: 第一种:通过@PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作 第二种是:通过 在xml中定义init-method 和  destory-method方法 第三种是:通过bean实现InitializingBean和 DisposableBean接口 下面演示通过  @PostConstruct 和 @PreDestory 1:定义相关的实现类: [java] v

spring bean的初始化和销毁

spring bean的初始化和销毁有3种形式: 1.通过注解@PostConstruct 和 @PreDestroy 方法实现初始化和销毁bean之前的操作. 2.通过xml配置init-method="" 和destory-method="" 3.通过实现InitializingBean和 DisposableBean接口

Spring中Bean初始化和销毁方法的几种配置方式

在Bean的生命周期中,Spring可以设置在Bean初始化之后以及在销毁之前要执行的方法. 主要设置方式有以下几种: 通过实现InitializingBean/DisposableBean 接口并重写afterPropertiesSet()/destroy()方法: 通过<bean> 标签的 init-method/destroy-method属性指定: 通过在指定方法上加@PostConstruct或@PreDestroy注解来指定: 通过<beans>标签的 default-