点击上方☝SpringForAll社区 轻松关注!及时获取有趣有料的技术文章

本文来源: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容器初始化

上面这个图是spring容器的加载顺序。ZebraMapperScannerConfigurer这个类实现了BeanDefinitionRegistryPostProcessor,这是一个BeanFactoryPostProcessor可以看到若实现了这个processor,那么会在第5步调用的时候触发这个processor,所以ZebraMapperScannerConfigurer这个类会先初始化。(本来初始化是第完成第6个步骤向spring容器注册了若干个BeanPostProcessor)

注册BeanPostProcessor

注意第5个BeanPostProcessor,有了这个processor,才会在bean被实例化的时候调用这个processor来完成对@Value标注属性值的注入)。正因为现在在完成spring容器初始化第5个步骤的时候,由于实现了BeanDefinitionRegistryPostProcessor这个接口,会提前触发对ZebraMapperScannerConfigurer的实例化,可以把ZebraMapperScannerConfigurer看做GroupDataSourceAnatationSample的一个成员属性,所以也会提前触发GroupDataSourceAnatationSample的实例化,因为没有注册上述红框圈出的第5个BeanPostProcessor所以jdbcRef和poorType不会被注入。

img

这个图是在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属性无法注入?相关推荐

  1. Spring源码分析2 — 容器启动流程

    1 主要类 部署web应用时,web容器(比如Tomcat)会读取配置在web.xml中的监听器,从而启动spring容器.有了spring容器之后,我们才能使用spring的IOC AOP等特性.弄 ...

  2. spring系统学习:day4--Spring配置: 集合类型属性的注入

    请参考相关视频. 转载于:https://www.cnblogs.com/JAVA-STUDYER/p/9146446.html

  3. Spring Boot学习总结(26)—— Spring Boot 容器启动详解

    一.容器启动 spring boot 一般是指定容器启动 main 方法,然后以命令行方式启动Jar包,如: @SpringBootApplication public class Applicati ...

  4. bean注入属性_摆脱困境:将属性值注入配置Bean

    bean注入属性 Spring Framework对将从属性文件中找到的属性值注入到bean或@Configuration类中提供了很好的支持. 但是,如果将单个属性值注入这些类中,则会遇到一些问题. ...

  5. 摆脱困境:将属性值注入配置Bean

    Spring Framework对将从属性文件中找到的属性值注入到bean或@Configuration类中提供了很好的支持. 但是,如果将单个属性值注入这些类中,则会遇到一些问题. 这篇博客文章指出 ...

  6. spring单元测试无法注入bean_2019年,最新的Spring 面试108题 “ 系列 ”,附带答案.........

    选择使用Spring框架的原因? 使用Spring: 第一是使用它的IOC功能,在解耦上达到了配置级别. 第二是使用它对数据库访问事务相关的封装. 第三就是各种其他组件与Spring的融合,在Spri ...

  7. spring源码阅读(3)-- 容器启动之BeanFactoryPostProcessor

    接着上文<spring源码阅读(2)-- 容器启动之加载BeanDefinition>,当spring加载完所有BeanDefinition时,并不会马上去创建bean,而是先配置bean ...

  8. spring中容器启动过程中初始化资源使用方法

    一.定义 在业务场景中,有时需要我们在容器启动过程中加载资源,完成数据的初始化或者配置,需要在调用前加载进spring容器过程中去,有以下一些方法来实现 1.定义静态常量,随着类的生命周期加载而提前加 ...

  9. quartz工程容器启动与 Service注入

    容器启动 因为任务没有定义在 ApplicationContext.xml中,而是放到了数据库中,SpringBoot启动时,怎么读取任务信息? 或者,怎么在 Spring启动完成的时候做一些事情? ...

最新文章

  1. 专访小书作者刘传君:练太极的“读书机器”
  2. ngx_http_lua_inject_socket_tcp_api函数代码注释
  3. HTML经典模板总结(地址)
  4. 微型计算机最早出现在第三代计算机中,微型计算机最早出现在第三代计算机中。...
  5. Vue项目实战06:nprogress页面加载进度条
  6. java内存泄露有什么后果,Java内存泄露问题是什么?
  7. java开发安装程序_创建java开发环境安装包
  8. JZOJ 3426. 封印一击
  9. mac android studio sdk配置,macOS安装Android Studio及配置环境变量
  10. 好用的项目工时管理系统有哪些
  11. 最新复刻李峋爱心表白HTML源代码+超唯美
  12. MotionLayout MotionScene 动画从未如此简单!
  13. 使用STM32CubeMX新建小熊派的STM32L431RCT6工程实现LED灯闪烁
  14. linux删除slave网卡,Linux bonding网卡与其slave共同使用
  15. mac怎么做一段卡点音乐
  16. 进制转换器的c代码实现
  17. 管理是个难题,向你讲述小企业经验
  18. 大数据时代,香港成为IDC发展新战略区域
  19. 厉害了!印度老头:从雅虎挖来陆奇,All in云业务,带领微软重生!
  20. SCM系统之 SVN VS CVS

热门文章

  1. java语句while主意点
  2. 这么说吧,NIO很简单,其实就是个牛逼IO
  3. Hibernate学习(四)
  4. myeclipse 8.6安装freemarker插件
  5. railscasts #1 Caching with Instance Variables
  6. 【祈福】一句话让你的网页为灾区祈福(让网页变灰色)
  7. XBug:一个强大的JavaScript调试器
  8. 惠普服务器ssa找不到控制卡,DL380 Gen10服务器Vmware ESXi 6.0 系统SSACLI工具
  9. mysql中表结构语句_mysql中表数据与表结构复制语句
  10. 运维安全加固规范_DBA如何巧用“三十六计”保障数据库安全?