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的处理惩罚或许可以分为下面几步:
虽然这只是较量抱负的状态,实际上因为Spring Context在结构时,也需要建设许多内部的Bean,应用在接话柄现里也会做本身的各类逻辑,整个流程会很是巨大。
那么占位符(${}表达式)是在什么时候被处理惩罚的?
团结上面的Spring的生命周期,昆山软件公司,假如Bean的建设和利用在PropertySourcesPlaceholderConfigurer之前,那么就有大概呈现占位符没有被处理惩罚的环境。
例子1:Mybatis 的 MapperScannerConfigurer引起的占位符没有处理惩罚
例子代码:mybatis-demo.zip
@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; } }
@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。
所以原因是:
要办理这个问题,可以在代码里,显式来处理惩罚占位符:
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 { }