欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识

例子1:Mybatis 的 MapperScannerConfigurer引起的占位符没有 劳务派遣管理系统 处理 例

点击: 次  来源:宝鼎软件 时间:2017-12-31

原文出处: hengyunabc

Spring里的占位符

spring里的占位符凡是表示的形式是:

<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="url" value="${jdbc.url}"/>
</bean>

可能

@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig {
    @Value("${jdbc.url}")
    private String url;
}

Spring应用在有时会呈现占位符设置没有注入,原因大概是多样的。

本文先容两种较量巨大的环境。

占位符是在Spring生命周期的什么时候处理惩罚的

Spirng在生命周期里关于Bean的处理惩罚或许可以分为下面几步:

  1. 加载Bean界说(从xml可能从@Import等)
  2. 处理惩罚BeanFactoryPostProcessor
  3. 实例化Bean
  4. 处理惩罚Bean的property注入
  5. 处理惩罚BeanPostProcessor

虽然这只是较量抱负的状态,实际上因为Spring Context在结构时,也需要建设许多内部的Bean,应用在接话柄现里也会做本身的各类逻辑,整个流程会很是巨大。

那么占位符(${}表达式)是在什么时候被处理惩罚的?

  • 实际上是在org.springframework.context.support.PropertySourcesPlaceholderConfigurer里处理惩罚的,它会会见了每一个bean的BeanDefinition,然后做占位符的处理惩罚
  • PropertySourcesPlaceholderConfigurer实现了BeanFactoryPostProcessor接口
  • PropertySourcesPlaceholderConfigurer的 order是Ordered.LOWEST_PRECEDENCE,也就是最低优先级的
  • 团结上面的Spring的生命周期,昆山软件公司,假如Bean的建设和利用在PropertySourcesPlaceholderConfigurer之前,那么就有大概呈现占位符没有被处理惩罚的环境。

    例子1:Mybatis 的 MapperScannerConfigurer引起的占位符没有处理惩罚

    例子代码:mybatis-demo.zip

  • 首先应用本身在代码里建设了一个DataSource,个中${db.user}是但愿从application.properties里注入的。代码在运行时会打印出user的实际值。
  • @Configuration
    public class MyDataSourceConfig {
        @Bean(name = "dataSource1")
        public DataSource dataSource1(@Value("${db.user}") String user) {
            System.err.println("user: " + user);
            JdbcDataSource ds = new JdbcDataSource();
            ds.setURL("jdbc:p:˜/test");
            ds.setUser(user);
            return ds;
        }
    }
  • 然后应用用代码的方法来初始化mybatis相关的设置,依赖上面建设的DataSource工具
  • @Configuration
    public class MybatisConfig1 {
    
        @Bean(name = "sqlSessionFactory1")
        public SqlSessionFactory sqlSessionFactory1(DataSource dataSource1) throws Exception {
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            org.apache.ibatis.session.Configuration ibatisConfiguration = new org.apache.ibatis.session.Configuration();
            sqlSessionFactoryBean.setConfiguration(ibatisConfiguration);
    
            sqlSessionFactoryBean.setDataSource(dataSource1);
            sqlSessionFactoryBean.setTypeAliasesPackage("sample.mybatis.domain");
            return sqlSessionFactoryBean.getObject();
        }
    
        @Bean
        MapperScannerConfigurer mapperScannerConfigurer(SqlSessionFactory sqlSessionFactory1) {
            MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
            mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory1");
            mapperScannerConfigurer.setBasePackage("sample.mybatis.mapper");
            return mapperScannerConfigurer;
        }
    }

    今世码运行时,输出功效是:

    user: ${db.user}

    为什么会user这个变量没有被注入?

    阐明下Bean界说,可以发明MapperScannerConfigurer它实现了BeanDefinitionRegistryPostProcessor。这个接口在是Spring扫描Bean界说时会回调的,远早于BeanFactoryPostProcessor。

    所以原因是:

  • MapperScannerConfigurer它实现了BeanDefinitionRegistryPostProcessor,所以它会Spring的早期会被建设
  • 从bean的依赖干系来看,mapperScannerConfigurer依赖了sqlSessionFactory1,sqlSessionFactory1依赖了dataSource1
  • MyDataSourceConfig里的dataSource1被提前初始化,没有颠末PropertySourcesPlaceholderConfigurer的处理惩罚,所以@Value(“${db.user}”) String user 里的占位符没有被处理惩罚
  • 要办理这个问题,可以在代码里,显式来处理惩罚占位符:

    environment.resolvePlaceholders("${db.user}")

    例子2:Spring boot自身实现问题,导致Bean被提前初始化

    例子代码:demo.zip

    Spring Boot里提供了@ConditionalOnBean,这个利便用户在差异条件下来建设bean。内里提供了判定是否存在bean上有某个注解的成果。

    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional(OnBeanCondition.class)
    public @interface ConditionalOnBean {
        /**
         * The annotation type decorating a bean that should be checked. The condition matches
         * when any of the annotations specified is defined on a bean in the
         * {@link ApplicationContext}.
         * @return the class-level annotation types to check
         */
        Class<? extends Annotation>[] annotation() default {};

    好比用户本身界说了一个Annotation:

    @Target({ ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {
    }