@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公司开发,目前已经 ...
最新文章
- Python源码怎么读,听听顶级爬虫工程师的建议
- Visual C#创建Windows服务程序
- Microsoft SQL Server 2000清理LDF日志
- 图像文字识别(三):Tesseract4.0训练字库,提高正确识别率
- [VBA] 设置行高和列宽,以及全选单元格
- jenkins vue 打包特别慢_从零开始 使用VUE开发桌面客户端
- 小米11 Pro最新渲染图曝光:后置体积巨大的矩阵四摄
- 计算机技能测试题6,2016年10月自考计算机网络技术练习题及答案(6)
- HTML5七夕情人节表白网页制作【我喜欢你H5】HTML+CSS+JavaScript
- 研究称纯电动汽车起火几率更低,但更难被扑灭
- 成功将qt程序移植到arm板上
- eclipse 启动失败,出现hs_err_pid972.log类文件,文件中含JavaThread Bundle File Closer daemon类内容
- canvas实现电子签名
- 深度学习中降维和升维
- Java整合Jsonpath解析Json字符串
- 【带着canvas去流浪(12)】用Three.js制作简易的MARVEL片头动画(上)
- yarn WEB UI及reserved memory、spark WEB UI
- Docker——安装和启动
- 手工搭建多层(多隐藏层)BP神经网络
- Python习题答案