spring单元测试无法注入bean_Spring容器启动@Value属性无法注入?
本文来源:http://yeming.me/2017/04/16/springValueAnnotation/
问题
一个同事基于Annotation配置了一段代码,结果有一个Configuration类的两个@Value标注的属性值没有注入进来,代码如下:
@Configuration@PropertySource("mysql.properties")public class GroupDataSourceAnatationSample { @Value("${zebra.jdbcref}") private String jdbcRef;
@Value("${zebra.pooltype}") private String poolType;
@Bean(destroyMethod = "close") public DataSource dataSource() { 。。。。。。 }
@Bean public ZebraMapperScannerConfigurer mapperScannerConfigurer() { ZebraMapperScannerConfigurer mapperScannerConfigurer = new ZebraMapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.sankuai.flight.flagship.mapper"); return mapperScannerConfigurer; }
@Bean public SqlSessionFactory sqlSessionFactoryBean() throws Exception { 。。。。。。 }}
原因
上面这段代码是基于java Annotation注解配置的zebra-dao的demo,上述存在一个问题,就是Value注解标注的两个属性jdbcType和poolType的值不能被注入进来。这个原因有点复杂,需要对spring容器的加载比较熟悉,之前我有两篇博客已经分析了spring容器加载的源码,有兴趣可以看一下Spring IOC流程清楚不? 聊聊看聊聊Spring Bean实例化。这里稍微提一下。
上面这个图是spring容器的加载顺序。ZebraMapperScannerConfigurer这个类实现了BeanDefinitionRegistryPostProcessor,这是一个BeanFactoryPostProcessor可以看到若实现了这个processor,那么会在第5步调用的时候触发这个processor,所以ZebraMapperScannerConfigurer这个类会先初始化。(本来初始化是第完成第6个步骤向spring容器注册了若干个BeanPostProcessor)
注意第5个BeanPostProcessor,有了这个processor,才会在bean被实例化的时候调用这个processor来完成对@Value标注属性值的注入)。正因为现在在完成spring容器初始化第5个步骤的时候,由于实现了BeanDefinitionRegistryPostProcessor这个接口,会提前触发对ZebraMapperScannerConfigurer的实例化,可以把ZebraMapperScannerConfigurer看做GroupDataSourceAnatationSample的一个成员属性,所以也会提前触发GroupDataSourceAnatationSample的实例化,因为没有注册上述红框圈出的第5个BeanPostProcessor所以jdbcRef和poorType不会被注入。
这个图是在ZebraMapperScannerConfigurer(singletonObject的第5个属性)初始化过程中debug出来的数据,证明了上述分析。所以总结原因,就是因为ZebraMapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor这个接口造成后续spring容器的执行的一些顺序问题,引起了上述@Value属性不能注入
解决问题
那么我们该怎么解决,我提供以下3种解决方案,下述三种方法都可以解决问题,大家有兴趣可以去尝试一下。
嵌套Configuration
@Configuration@PropertySource("annotation/mysql.properties")public class GroupDataSourceAnnotationSample {
@Configuration static class DataSourceConfig{ @Value("${zebra.jdbcref}") //@Value("flagshipbiz_flagship_test") private String jdbcRef;
@Value("${zebra.pooltype}") //@Value("tomcat-jdbc") private String poolType;
@Bean(destroyMethod = "close") public DataSource dataSource() { 。。。。。。 }
@Bean public SqlSessionFactory sqlSessionFactoryBean() throws Exception { 。。。。。。 } }
@Bean public ZebraMapperScannerConfigurer mapperScannerConfigurer() { ZebraMapperScannerConfigurer mapperScannerConfigurer = new ZebraMapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.dianping.zebra.sample.dao"); return mapperScannerConfigurer; }}
非单例(多例模式)
第二种方法@Scope(“protoType”)多例模式(这只是一个纯粹解决问题的方法,线上不推荐这里使用多例,还请注意)
@Configuration@Scope("protoType")@PropertySource("mysql.properties")public class GroupDataSourceAnatationSample { @Value("${zebra.jdbcref}") private String jdbcRef;
@Value("${zebra.pooltype}") private String poolType;
@Bean(destroyMethod = "close") public DataSource dataSource() { 。。。。。。 }
@Bean public ZebraMapperScannerConfigurer mapperScannerConfigurer() { ZebraMapperScannerConfigurer mapperScannerConfigurer = new ZebraMapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.sankuai.flight.flagship.mapper"); return mapperScannerConfigurer; }
@Bean public SqlSessionFactory sqlSessionFactoryBean() throws Exception { 。。。。。。 }}
拆分配置类
把ZebraMapperScannerConfigurer这个bean的配置从上述DataSource中抽出来,单独放到另外一个独立的@Configuration类里面。
参考
SpringIOC源码分析
SpringIOC源码分析二(Bean实例化)
http://yeming.me/2016/04/16/spring/
http://yeming.me/2016/04/26/spring2/
● 聊聊Spring Bean实例化
● Spring IOC流程清楚不?聊聊看
● 面试官:ScheduleThreadPoolExecutor了解不?
● 配置中心只有Apollo么?看看点评的Lion
● 面试官说从源码角度说说Java线程池
● JedisPool连接池相关配置
● Hystrix初探
● 别再关注删库跑路了,谈谈数据库架构
● 那些年非常火的MyCAT是什么?
● Java14带来了许多新功能
● 关于烂代码的那些事(上)
● 关于整洁代码的那些事(中)
● 关于整洁代码的那些事(下)
● 面试官说Spring AOP 实现原理给我说说
● 深入理解JVM - 方法调用
● Spring Boot神操作-多个数据源Service层封装
● Lombok经常用,但是你知道它的原理是什么吗?
spring单元测试无法注入bean_Spring容器启动@Value属性无法注入?相关推荐
- Spring源码分析2 — 容器启动流程
1 主要类 部署web应用时,web容器(比如Tomcat)会读取配置在web.xml中的监听器,从而启动spring容器.有了spring容器之后,我们才能使用spring的IOC AOP等特性.弄 ...
- spring系统学习:day4--Spring配置: 集合类型属性的注入
请参考相关视频. 转载于:https://www.cnblogs.com/JAVA-STUDYER/p/9146446.html
- Spring Boot学习总结(26)—— Spring Boot 容器启动详解
一.容器启动 spring boot 一般是指定容器启动 main 方法,然后以命令行方式启动Jar包,如: @SpringBootApplication public class Applicati ...
- bean注入属性_摆脱困境:将属性值注入配置Bean
bean注入属性 Spring Framework对将从属性文件中找到的属性值注入到bean或@Configuration类中提供了很好的支持. 但是,如果将单个属性值注入这些类中,则会遇到一些问题. ...
- 摆脱困境:将属性值注入配置Bean
Spring Framework对将从属性文件中找到的属性值注入到bean或@Configuration类中提供了很好的支持. 但是,如果将单个属性值注入这些类中,则会遇到一些问题. 这篇博客文章指出 ...
- spring单元测试无法注入bean_2019年,最新的Spring 面试108题 “ 系列 ”,附带答案.........
选择使用Spring框架的原因? 使用Spring: 第一是使用它的IOC功能,在解耦上达到了配置级别. 第二是使用它对数据库访问事务相关的封装. 第三就是各种其他组件与Spring的融合,在Spri ...
- spring源码阅读(3)-- 容器启动之BeanFactoryPostProcessor
接着上文<spring源码阅读(2)-- 容器启动之加载BeanDefinition>,当spring加载完所有BeanDefinition时,并不会马上去创建bean,而是先配置bean ...
- spring中容器启动过程中初始化资源使用方法
一.定义 在业务场景中,有时需要我们在容器启动过程中加载资源,完成数据的初始化或者配置,需要在调用前加载进spring容器过程中去,有以下一些方法来实现 1.定义静态常量,随着类的生命周期加载而提前加 ...
- quartz工程容器启动与 Service注入
容器启动 因为任务没有定义在 ApplicationContext.xml中,而是放到了数据库中,SpringBoot启动时,怎么读取任务信息? 或者,怎么在 Spring启动完成的时候做一些事情? ...
最新文章
- 专访小书作者刘传君:练太极的“读书机器”
- ngx_http_lua_inject_socket_tcp_api函数代码注释
- HTML经典模板总结(地址)
- 微型计算机最早出现在第三代计算机中,微型计算机最早出现在第三代计算机中。...
- Vue项目实战06:nprogress页面加载进度条
- java内存泄露有什么后果,Java内存泄露问题是什么?
- java开发安装程序_创建java开发环境安装包
- JZOJ 3426. 封印一击
- mac android studio sdk配置,macOS安装Android Studio及配置环境变量
- 好用的项目工时管理系统有哪些
- 最新复刻李峋爱心表白HTML源代码+超唯美
- MotionLayout MotionScene 动画从未如此简单!
- 使用STM32CubeMX新建小熊派的STM32L431RCT6工程实现LED灯闪烁
- linux删除slave网卡,Linux bonding网卡与其slave共同使用
- mac怎么做一段卡点音乐
- 进制转换器的c代码实现
- 管理是个难题,向你讲述小企业经验
- 大数据时代,香港成为IDC发展新战略区域
- 厉害了!印度老头:从雅虎挖来陆奇,All in云业务,带领微软重生!
- SCM系统之 SVN VS CVS
热门文章
- java语句while主意点
- 这么说吧,NIO很简单,其实就是个牛逼IO
- Hibernate学习(四)
- myeclipse 8.6安装freemarker插件
- railscasts #1 Caching with Instance Variables
- 【祈福】一句话让你的网页为灾区祈福(让网页变灰色)
- XBug:一个强大的JavaScript调试器
- 惠普服务器ssa找不到控制卡,DL380 Gen10服务器Vmware ESXi 6.0 系统SSACLI工具
- mysql中表结构语句_mysql中表数据与表结构复制语句
- 运维安全加固规范_DBA如何巧用“三十六计”保障数据库安全?