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

热门文章

  1. RTX3060Ti和RTX2060 SUPER,RTX2080 SUPER、RTX3070显卡参数参数对比哪个好 差距大不大
  2. 给小程序再减重 30% 的秘密​
  3. 地图学相关知识(一)
  4. upc组队赛16 GCDLCM 【Pollard_Rho大数质因数分解】
  5. 人人商城-数据选择器
  6. P1134 高精度阶乘
  7. SQLMAP-POST注入
  8. 怎样让您的电脑待机耗电等于零?
  9. msib450i gaming plus ac 开机vga长亮
  10. 钉钉小程序获取用户信息