@Value为null问题排查及解决方法
最近新接手一个项目,在日常环境启动的时候报错启动不了,查看日志发现是由于@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问题排查及解决方法相关推荐
- 关于出现org.hibernate.TransientObjectException: The given object has a null identifier: 错误的解决方法
关于出现org.hibernate.TransientObjectException: The given object has a null identifier: 错误的解决方法 参考文章: (1 ...
- Json返回结果为null属性不显示解决方法
Json返回结果为null属性不显示解决方法 参考文章: (1)Json返回结果为null属性不显示解决方法 (2)https://www.cnblogs.com/baizhanshi/p/10097 ...
- WORD Application.Documents.Open函数返回null的一种解决方法
WORD Application.Documents.Open函数返回null的一种解决方法 参考文章: (1)WORD Application.Documents.Open函数返回null的一种解决 ...
- 异步 HttpContext.Current 为空null 另一种解决方法
异步 HttpContext.Current 为空null 另一种解决方法 参考文章: (1)异步 HttpContext.Current 为空null 另一种解决方法 (2)https://www. ...
- Sping Environment为Null的原因和解决方法
Sping Environment为Null的原因和解决方法 参考文章: (1)Sping Environment为Null的原因和解决方法 (2)https://www.cnblogs.com/hy ...
- 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) 原因排查与解决方法 参考文章: ...
- 【阿里云】阿里云磁盘异常爆满的原因排查及解决方法,df和du命令查看磁盘时结果不一致
[阿里云]阿里云磁盘异常爆满的原因排查及解决方法,df和du命令查看磁盘时结果不一致,虽然磁盘显示满了,但是通过du查询磁盘空间实际上空间并没有满 文章目录 一.阿里云磁盘空间满了如何查看 二.使用d ...
- vscode win10笔记本 蓝屏_教你win10电脑蓝屏原因排查及解决方法大全
相信每个人用过电脑的人都遇到过windows10蓝屏的时候,对于很多小白来说,只能按电源键重起,祈祷电脑能自己修复,不过今天,看过这篇后,希望大家对windows10蓝屏自主排查及解决有帮助,让我们开 ...
- NFS服务常见故障排查和解决方法
NFS,全名叫Network File System,中文叫网络文件系统,是Linux.UNIX系统的分布式文件系统的一个组成部分,可实现在不同网络上共享远程文件系统.NFS由Sun公司开发,目前已经 ...
最新文章
- button按钮无法提交表单问题发现与解决
- matlab绘制8条曲线,科学网—【Matlab】如何用plotyy对应坐标绘制多条曲线 - 叶瑞杰的博文...
- mysql的查询结果ResultSet处理
- android学习笔记---48_实现软件国际化,实现文字国际化,和图片国际化
- AI 开发者如何摆脱只有“人工”没有“智能?
- mysql的多媒体类型_多媒体数据库技术及其发展方向
- 晚间看图片就高亮,这体验太差
- matlab求积分 没有解,MATLAB 求积分时无法输出数值解,一直是积分表达式
- 搭载rtmp直播服务器
- 基于php的微信公众号开发,基于ThinkPHP框架快速构建微信公众号开发框架
- 软件测试工程师调研报告,软件测试工程师竞聘报告范文.docx
- 数据资产治理:元数据采集那点事
- opencv 拍摄并保存照片
- 小程序时间段选择 选取某天的某时间段 基于vantweapp的时间段选择器 日期选择器
- 百度网盘准备好,测绘相关资料
- Environment.SpecialFolder的值的含义(本地打印)
- AD学习笔记(四)PCB布局分析
- SRI-Subresource Integrity
- Alevin——虚拟网络仿真平台
- dillo支持html5吗,流动聚焦及射流不稳定性