在org.mybatis.spring.mapper.MapperScannerConfigurer#processPropertyPlaceHolders方法中,调用了applicationContext.getBeansOfType(PropertyResourceConfigurer.class); 从而引发了后面的一些列的对象创建在PropertyResourceConfigurer之前。
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { if (this.processPropertyPlaceHolders) { // true processPropertyPlaceHolders(); } ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); scanner.setAddToConfig(this.addToConfig); scanner.setAnnotationClass(this.annotationClass); scanner.setMarkerInterface(this.markerInterface); scanner.setSqlSessionFactory(this.sqlSessionFactory); scanner.setSqlSessionTemplate(this.sqlSessionTemplate); scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName); scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName); scanner.setResourceLoader(this.applicationContext); scanner.setBeanNameGenerator(this.nameGenerator); scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass); if (StringUtils.hasText(lazyInitialization)) { scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization)); } scanner.registerFilters(); scanner.scan( StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); } private void processPropertyPlaceHolders() { // 这里调 getBeansOfType(PropertyResourceConfigurer.class) Map<string, propertyresourceconfigurer=""> prcs = applicationContext.getBeansOfType(PropertyResourceConfigurer.class); // ...此处省略若干代码... } // ...此处省略若干代码... }【applicationContext.getBeansOfType(PropertyResourceConfigurer.class);】执行过程中
Spring一路执行到org.springframework.beans.factory.support.DefaultListableBeanFactory#doGetBeanNamesForType,
并在方法内,循环所有beanDefinitionNames,逐一判断beanDefinition是不是PropertyResourceConfigurer类型的(isTypeMatch方法)
判断的时候,就需要从Spring容器中取这个bean,取着取着发现没有,就开始doCeateBean-->invokeInitMethods-->afterPropertiesSet 了。
在创建dubbo消费者的时候,消费者接口被封装成ReferenceBean,在其afterPropertiesSet方法中,依赖RegistryConfig对象,从而依赖注册中心配置的地址。
而这些,都是发生在PropertyResourceConfigurer创建之前。
此处特别说明,我项目里面使用的mybatis-spring是2.0.3版本
4、 解决方法 4.1、方法一前面分析了,MapperScannerConfigurer对象的boolean属性processPropertyPlaceHolders为true,导致执行了processPropertyPlaceHolders()方法。
那么,据此可以自定义一个MapperScannerConfigurer对象,设置processPropertyPlaceHolders为false。
// 去掉 @MapperScan 注解,通过下面的方式设置MapperScannerConfigurer @Bean public MapperScannerConfigurer dsCrmMapperScannerConfigurer() { MapperScannerConfigurer configurer = new MapperScannerConfigurer(); configurer.setProcessPropertyPlaceHolders(false); configurer.setBasePackage("com.yc.dc.mapper"); configurer.setSqlSessionFactoryBeanName("dsCrmSqlSessionFactory"); return configurer; }通过这种方式试了下,发现果然可行。
为啥可行? 究其原因如下:
MapperScannerConfigurer一般通过MapperScannerRegistrar引入进来。
mybatis-spring 是从2.0.2版本开始,引入MapperScannerConfigurer的时候,设置了processPropertyPlaceHolders值为true。