最近新接手一个项目,在日常环境启动的时候报错启动不了,查看日志发现是由于@Value的值为null,导致启动报错

我们先来还原一下事故现场

自定义一个BeanDefinitionRegistryPostProcessor来模拟Mybatis的MapperScannerConfigurer

public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {private ConsoleApi consoleApi;@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {System.out.println("this is MyBeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry");System.out.println("MyBeanDefinitionRegistryPostProcessor: "+ consoleApi);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)throws BeansException {System.out.println("this is MyBeanDefinitionRegistryPostProcessor#postProcessBeanFactory");}public ConsoleApi getDivisionDO() {return consoleApi;}public void setDivisionDO(ConsoleApi consoleApi) {this.consoleApi = consoleApi;}
}

在配置类中注入这个Bean

@Configuration
public class DsConfig  {// 这里通过@Value注入配置信息@Value("spring.demo.hsf.env")private String env;@Beanpublic ConsoleApi divisionDO(){System.out.println("DsConfig env ===========>>>> " + env);if("daily".equalsIgnoreCase(env)){return new ConsoleApi();}else {throw new RuntimeException("环境不支持");}}@Beanpublic MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor(ConsoleApi ConsoleApi){MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor = new MyBeanDefinitionRegistryPostProcessor();myBeanDefinitionRegistryPostProcessor.setDivisionDO(ConsoleApi);return myBeanDefinitionRegistryPostProcessor;}
}

启动应用

可以看到启动报错,这里的env取值为null

很是疑惑,这里我明明配置了env=daily,为啥取不到值呢?

然后开始面向百度编程.......

首先我将自定义个这个BeanDefinitionRegistryPostProcessor注释掉,发现应用能够成功启动,那么问题十有八九就是这个自定义的BeanDefinitionRegistryPostProcessor导致的

BeanDefinitionRegistryPostProcessor是一个BeanFactoryPostProcessor 那么这个Bean是在什么时候被示例化的呢,咱们来debug一下

Spring容器启动

org.springframework.context.support.AbstractApplicationContext#refresh

{// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.// 这里调用Spring容器的BeanFactoryPostProcessor // 注意这里调用的时候还没有初始化自定义的BeanFactoryPostProcessor,而是创建BeanFactory的是Spring 自己New出来的三个BeanFactoryPostProcessorinvokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();
}

接着往里面跟一下代码

这里Spring会两次调用获取BeanDefinitionRegistryPostProcessor类型的Bean名称并实例化Bean

第一次调用获取到了是框架自身的ConfigurationClassPostProcessor 加载应用中所有的BeanDefinition

第二次调用是获取自定义的BeanDefinitionRegistryPostProcessor并实例化这些Bean,就会通过代理的方式处理@Bean注入的Bean,这个时候其实Spring还没有初始化其他的Bean包括DsConfig所以这个时候@Value还没有被处理,那么env的值当然为nulll了

现在问题找到了,那么该怎么去解决呢?

问题的关键是在实例化MyBeanDefinitionRegistryPostProcessor的时候,DsConfig还没有被实例化出来,那能不能在实例化MyBeanDefinitionRegistryPostProcessor之前就把DsConfig给实例化出来呢?顺着这思路我给出了下面的解决方法

@Configuration
public class DsConfig implements ApplicationContextAware, InitializingBean {// 这里通过@Value注入配置信息//@Value("${spring.demo.hsf.env}")private String env;private ApplicationContext applicationContext;@Beanpublic ConsoleApi consoleApi(DsConfig dsConfig) {System.out.println("DsConfig env ===========>>>> " + env);if ("daily".equalsIgnoreCase(env)) {return new ConsoleApi();} else {throw new RuntimeException("环境不支持");}}@Beanpublic MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor(ConsoleApi ConsoleApi){MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor = new MyBeanDefinitionRegistryPostProcessor();myBeanDefinitionRegistryPostProcessor.setDivisionDO(ConsoleApi);return myBeanDefinitionRegistryPostProcessor;}@Overridepublic void afterPropertiesSet() throws Exception {Environment environment = applicationContext.getEnvironment();String env = environment.getProperty("spring.demo.hsf.env");this.env = env;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}

咱们再来启动

这里已经能够获取到配置的变量 env=daily了,应用也成功启动了

如果你有更好的解决方法,欢迎一起探讨

参考:Spring源码之@Configuration原理 - 曹自标 - 博客园

spring @Value注解原理梳理及自定义实现@MyValue注解实例_mapeng765441650的博客-CSDN博客

@Value为null问题排查及解决方法相关推荐

  1. 关于出现org.hibernate.TransientObjectException: The given object has a null identifier: 错误的解决方法

    关于出现org.hibernate.TransientObjectException: The given object has a null identifier: 错误的解决方法 参考文章: (1 ...

  2. Json返回结果为null属性不显示解决方法

    Json返回结果为null属性不显示解决方法 参考文章: (1)Json返回结果为null属性不显示解决方法 (2)https://www.cnblogs.com/baizhanshi/p/10097 ...

  3. WORD Application.Documents.Open函数返回null的一种解决方法

    WORD Application.Documents.Open函数返回null的一种解决方法 参考文章: (1)WORD Application.Documents.Open函数返回null的一种解决 ...

  4. 异步 HttpContext.Current 为空null 另一种解决方法

    异步 HttpContext.Current 为空null 另一种解决方法 参考文章: (1)异步 HttpContext.Current 为空null 另一种解决方法 (2)https://www. ...

  5. Sping Environment为Null的原因和解决方法

    Sping Environment为Null的原因和解决方法 参考文章: (1)Sping Environment为Null的原因和解决方法 (2)https://www.cnblogs.com/hy ...

  6. ORA-12805: parallel query server died unexpectedly ORA-04030 (sort subheap,sort key) 原因排查与解决方法

    ORA-12805: parallel query server died unexpectedly ORA-04030 (sort subheap,sort key) 原因排查与解决方法 参考文章: ...

  7. 【阿里云】阿里云磁盘异常爆满的原因排查及解决方法,df和du命令查看磁盘时结果不一致

    [阿里云]阿里云磁盘异常爆满的原因排查及解决方法,df和du命令查看磁盘时结果不一致,虽然磁盘显示满了,但是通过du查询磁盘空间实际上空间并没有满 文章目录 一.阿里云磁盘空间满了如何查看 二.使用d ...

  8. vscode win10笔记本 蓝屏_教你win10电脑蓝屏原因排查及解决方法大全

    相信每个人用过电脑的人都遇到过windows10蓝屏的时候,对于很多小白来说,只能按电源键重起,祈祷电脑能自己修复,不过今天,看过这篇后,希望大家对windows10蓝屏自主排查及解决有帮助,让我们开 ...

  9. NFS服务常见故障排查和解决方法

    NFS,全名叫Network File System,中文叫网络文件系统,是Linux.UNIX系统的分布式文件系统的一个组成部分,可实现在不同网络上共享远程文件系统.NFS由Sun公司开发,目前已经 ...

最新文章

  1. button按钮无法提交表单问题发现与解决
  2. matlab绘制8条曲线,科学网—【Matlab】如何用plotyy对应坐标绘制多条曲线 - 叶瑞杰的博文...
  3. mysql的查询结果ResultSet处理
  4. android学习笔记---48_实现软件国际化,实现文字国际化,和图片国际化
  5. AI 开发者如何摆脱只有“人工”没有“智能?
  6. mysql的多媒体类型_多媒体数据库技术及其发展方向
  7. 晚间看图片就高亮,这体验太差
  8. matlab求积分 没有解,MATLAB 求积分时无法输出数值解,一直是积分表达式
  9. 搭载rtmp直播服务器
  10. 基于php的微信公众号开发,基于ThinkPHP框架快速构建微信公众号开发框架
  11. 软件测试工程师调研报告,软件测试工程师竞聘报告范文.docx
  12. 数据资产治理:元数据采集那点事
  13. opencv 拍摄并保存照片
  14. 小程序时间段选择 选取某天的某时间段 基于vantweapp的时间段选择器 日期选择器
  15. 百度网盘准备好,测绘相关资料
  16. Environment.SpecialFolder的值的含义(本地打印)
  17. AD学习笔记(四)PCB布局分析
  18. SRI-Subresource Integrity
  19. Alevin——虚拟网络仿真平台
  20. dillo支持html5吗,流动聚焦及射流不稳定性

热门文章

  1. NEX让人们对vivo刮目相看,这个互联网巨头出了一份力
  2. 如何分辨真假LV包包
  3. DS18B20温度采集报警系统,原理及汇编、C语言实现
  4. 南宁装修工长带队,价格公道不乱增加项目
  5. sqlmap介绍和用法
  6. 服务器网站需要多大硬盘,做网站服务器硬盘多大
  7. Python有参函数和无参函数实例
  8. 搜索引擎如何判定站群是否作弊?
  9. Android下最好用的免费在线影视应用是哪个?
  10. SSM框架的基本概念(什么是ssm框架?)