今天再利用spring集成mybatis并配置数据源的时候,发现使用propertyPlaceholder读取properties文件时,spring一直无法解析EL表达式。
调试源码发现,spring加载bean的内容大概为
org.springframework.beans.factory.support.DefaultListableBeanFactory@21aba986: defining beans [
goodsComparePriceController
pluginPositionController,
systemController,
exceptionHandler,
goodsComparePriceServiceImpl,
pluginPositionServiceImpl,
org.springframework.context.annotation.internalConfigurationAnnotationProcessor,
org.springframework.context.annotation.internalAutowiredAnnotationProcessor,
org.springframework.context.annotation.internalRequiredAnnotationProcessor,
org.springframework.context.annotation.internalCommonAnnotationProcessor,
org.springframework.aop.config.internalAutoProxyCreator,mvcContentNegotiationManager,
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0,
org.springframework.format.support.FormattingConversionServiceFactoryBean#0,
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0,
org.springframework.web.servlet.handler.MappedInterceptor#0,
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0,
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0,
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0,
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,
org.springframework.web.servlet.resource.ResourceHttpRequestHandler#0,
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#0,
org.springframework.web.servlet.resource.ResourceHttpRequestHandler#1,
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#1,
org.springframework.web.servlet.resource.ResourceHttpRequestHandler#2,
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#2,
org.springframework.web.servlet.view.InternalResourceViewResolver#0,
org.springframework.web.servlet.view.BeanNameViewResolver#0
,exceptionJsonView,
org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0,
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,
dataSource,
sqlSessionFactory,
mapperScannerConfigurer];
root of factory hierarchy
我们只需要关注最后4个。
</pre><pre name="code" class="html">org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,
dataSource,
sqlSessionFactory,
mapperScannerConfigurer
</pre><p></p><p>发现顺序是正常,按照顺序先加载Properties解析类,再加载mybatis相关内容。</p><p>但是调试源码发现,spring筛选出来2个类预先加载</p><p><pre name="code" class="html">org.springframework.context.annotation.internalConfigurationAnnotationProcessor,
mapperScannerConfigurer
第一个类为Spring启用注解方式。第二个及时我们的mybatis配置类。
我们来看看此时我们的配置文件
此时我们配置了PropertyPlaceholder,以及MapperScannerConfigurer。此时MapperScannerConfigurer通过ref引入了sqlSessionFactory。
前面说到spring预先加载了MapperScanner这个类,而又通过ref引入了SqlSessionFactory。造成直接加载了DataSource.而此时还未加载Properties解析类,因此spring无法解析EL表达式。
2015-05-26 00:14:26,096 [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0] WARN com.mchange.v2.c3p0.DriverManagerDataSource - Could not load driverClass ${jdbi.db.driver}
java.lang.ClassNotFoundException: ${jdbi.db.driver}
导致datasource获取就是未解析的EL表达式。
这里通过让spring不要预先注入sqlSessionFacotory来达到让其properties解析类加载完毕后使其整个mapperScannerConfigurer初始化。
更改MapperScannerConfigurer的sqlSessionFactory注入类的key,变更为sqlSessionFactoryBeanName。修改ref为value即可
此时spring再加载MapperScannerConfigurer时就不会立刻去注入sqlSessionFacotry了。
此刻datasource的EL表达式正常被spring解析。