MapperScannerConfigurer与<context:property-placeholder>加载顺序导致异常解决办法

来源:互联网 发布:天刀唐门男捏脸数据 编辑:程序博客网 时间:2024/05/23 19:20

在使用Spring和MyBaits整合时,使用c3p0数据源,将数据源配置信息写在属性文件中,然后使用<context:property-placeholder>引入配置文件,但是同时使用MapperScannerConfigurer类自动配置Mapper,启动时抛出

java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41) at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:220) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean

with name 'mapperScannerConfigurer' defined in class path resource [spring.xml]:

Cannot resolve reference to bean 'sqlSessionFactory' while setting bean property 'sqlSessionFactory';

nested exception is org.springframework.beans.factory.BeanCreationException:

Error creating bean with name 'sqlSessionFactory' defined in class path resource [spring.xml]:

Cannot resolve reference to bean 'dataSource' while setting bean property 'dataSource';

nested exception is org.springframework.beans.factory.BeanCreationException:

Error creating bean with name 'dataSource' defined in class path resource [spring.xml]:

Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException:

Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'initialPoolSize';

nested exception is java.lang.NumberFormatException: For input string: "${pool.c3p0.initialPoolSize}" at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1360) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1118) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:400) at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:612) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:446) at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:103) at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1) at org.springframework.test.context.support.DelegatingSmartContextLoader.loadContext(DelegatingSmartContextLoader.java:228) at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124) at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148) ... 24 moreCaused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [spring.xml]: Cannot resolve reference to bean 'dataSource' while setting bean property 'dataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [spring.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'initialPoolSize'; nested exception is java.lang.NumberFormatException: For input string: "${pool.c3p0.initialPoolSize}" at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:106) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1360) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1118) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:322) ... 41 moreCaused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [spring.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'initialPoolSize'; nested exception is java.lang.NumberFormatException: For input string: "${pool.c3p0.initialPoolSize}" at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:322) ... 51 moreCaused by: org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'initialPoolSize'; nested exception is java.lang.NumberFormatException: For input string: "${pool.c3p0.initialPoolSize}" at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:490) at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:516) at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:510) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1406) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1365) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1118) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517) ... 57 moreCaused by: java.lang.NumberFormatException: For input string: "${pool.c3p0.initialPoolSize}" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48) at java.lang.Integer.parseInt(Integer.java:447) at java.lang.Integer.valueOf(Integer.java:553) at org.springframework.util.NumberUtils.parseNumber(NumberUtils.java:155) at org.springframework.beans.propertyeditors.CustomNumberEditor.setAsText(CustomNumberEditor.java:115) at org.springframework.beans.TypeConverterDelegate.doConvertTextValue(TypeConverterDelegate.java:431) at org.springframework.beans.TypeConverterDelegate.doConvertValue(TypeConverterDelegate.java:403) at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:163) at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:470) ... 63 more

我的配置:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd      http://www.springframework.org/schema/context      http://www.springframework.org/schema/context/spring-context-3.0.xsd      http://www.springframework.org/schema/tx      http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

 <context:component-scan base-package="com.ssi.bus" />

 <!-- 引入资源文件 --> <context:property-placeholder location="classpath:dbconfig.properties"/>

 <!-- c3p0数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  <property name="driverClass" value="${jdbc.driverClass}" />  <property name="jdbcUrl" value="${jdbc.url}" />  <property name="user" value="${jdbc.username}" />  <property name="password" value="${jdbc.password}" />  <property name="initialPoolSize" value="${pool.c3p0.initialPoolSize}" />  <property name="minPoolSize" value="${pool.c3p0.minPoolSize}" />  <property name="maxPoolSize" value="${pool.c3p0.maxPoolSize}" />  <property name="acquireIncrement" value="${pool.c3p0.acquireIncrement}" />  <property name="idleConnectionTestPeriod" value="${pool.c3p0.idleConnectionTestPeriod}" />  <property name="checkoutTimeout" value="${pool.c3p0.checkoutTimeout}" />  <property name="testConnectionOnCheckin" value="${pool.c3p0.testConnectionOnCheckin}" />  <property name="testConnectionOnCheckout" value="${pool.c3p0.testConnectionOnCheckout}" /> </bean>  <!-- c3p0数据源 --> <bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  <property name="driverClass" value="${jdbc.driverClass}" />  <property name="jdbcUrl" value="${jdbc.url}" />  <property name="user" value="${jdbc.username}" />  <property name="password" value="${jdbc.password}" />  <property name="initialPoolSize" value="${pool.c3p0.initialPoolSize}" />  <property name="minPoolSize" value="${pool.c3p0.minPoolSize}" />  <property name="maxPoolSize" value="${pool.c3p0.maxPoolSize}" />  <property name="acquireIncrement" value="${pool.c3p0.acquireIncrement}" />  <property name="idleConnectionTestPeriod" value="${pool.c3p0.idleConnectionTestPeriod}" />  <property name="checkoutTimeout" value="${pool.c3p0.checkoutTimeout}" />  <property name="testConnectionOnCheckin" value="${pool.c3p0.testConnectionOnCheckin}" />  <property name="testConnectionOnCheckout" value="${pool.c3p0.testConnectionOnCheckout}" /> </bean>  <!-- sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  <property name="dataSource" ref="dataSource" />  <property name="configLocation" value="classpath:mybatis-config.xml" />  <property name="mapperLocations" value="classpath:com/ssi/bus/mapper/**/*.xml" /> </bean>  <!-- 自动配置mapper --> <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">  <property name="basePackage" value="com.ssi.bus.dao" />  <property name="annotationClass" value="org.springframework.stereotype.Repository"></property>  <property name="sqlSessionFactory" ref="sqlSessionFactory"></property> </bean>  <!-- 事务 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  <property name="dataSource" ref="dataSource" /> </bean>  <!-- 开启注解事务 --> <tx:annotation-driven transaction-manager="transactionManager" /></beans>

 

原因是:

在spring里使用org.mybatis.spring.mapper.MapperScannerConfigurer 进行自动扫描的时候,设置了sqlSessionFactory 的话,可能会导致PropertyPlaceholderConfigurer失效,也就是用${jdbc.username}这样之类的表达式,将无法获取到properties文件里的内容。 导致这一原因是因为,MapperScannerConigurer实际是在解析加载bean定义阶段的,这个时候要是设置sqlSessionFactory的话,会导致提前初始化一些类,这个时候,PropertyPlaceholderConfigurer还没来得及替换定义中的变量,导致把表达式当作字符串复制了。 但如果不设置sqlSessionFactory 属性的话,就必须要保证sessionFactory在spring中名称一定要是sqlSessionFactory ,否则就无法自动注入。

解决办法:

<!-- 自动配置mapper --><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.ssi.bus.dao" /><property name="annotationClass" value="org.springframework.stereotype.Repository"></property><property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property></bean>

改用sqlSessionFactoryBeanName注入就没有问题(不要使用sqlSessionFactory属性注入,使用sqlSessionFactoryBeanName注入),因为这时不会立即初始化sqlSessionFactory,传入的只是名字,非bean,所以不会引发提前初始化问题。

注意:如果你只有一个DataSource,那么就没有必要去指定SqlSessionFactory或SqlSessionTemplate,因为MapperScannerConfigurer将会创建MapperFactoryBean,之后自动装配。但是,如果你使用了一个以上的DataSource(因此,也是多个的SqlSessionFactory),那么就可以使用sqlSessionFactoryBeanName去指定sqlSessionFactory,否则自动装配可能会失效。

原创粉丝点击