MapperScannerConfigurer之sqlSessionFactoryBeanName注入方式
Spring整合Mybatis时,项目启动时报错:(MapperScannerConfigurer之sqlSessionFactoryBeanName注入方式)
pringframework.beans.factory.BeanCreationException: Error creating bean with name 'mapperScannerConfigurer'defined in class path resource [applicationContext.xml]:
Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sqlSessionFactory';
nested exception is org.springframework.beans.factory BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext.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 [applicationContext.xml]: Error setting property values;
nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are: PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'driverClassName' threw exception;
nested exception is java.lang.IllegalStateException: Could not load JDBC driver class [${driver}]
可以看到报的大大小小错误共有5个错误:
pringframework.beans.factory.BeanCreationException:创建名为“mapperScannerConfigurer”的bean时出错,该bean在类路径资源[applicationContext.xml]中定义:
设置bean属性“sqlSessionFactory”时无法解析对bean“sessionFactory”的引用;
嵌套异常为org.springframework.beans.factory BeanCreationException:创建名为“sessionFactory”的bean时出错,该bean在类路径资源[applicationContext.xml]中定义:
无法解析对bean的引用
设置bean属性“dataSource”时使用“dataSource”;
嵌套异常为org.springframework.beans.factory.BeanCreationException:创建名为“dataSource”的bean时出错,该bean在类路径资源[applicationContext.xml]中定义:设置属性值时出错;
嵌套的异常是org.springframework.beans.PropertyBatchUpdateException;嵌套的PropertyAccessException(1)是:PropertyAccessException 1:org.springframework.beans.MethodInvocationException:Property'driverClassName'抛出异常;
嵌套异常为java.lang.IllegalStateException:无法加载JDBC驱动程序类[${driver}]
ok,那么下面是我的Spring配置文件的源代码
<context:property-placeholder location="classpath:/jdbc.properties"/>
<!-- 配置数据源bean -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="password" value="${password}"/>
<property name="username" value="${user}"/>
</bean>
<!-- SqlSessionFactory的bean -->
<bean name="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 扫描Mapper文件 -->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactory" ref="sessionFactory"/>
<property name="basePackage" value="com.lyl.mapper"/>
</bean>
通过分析日志提供的报错信息,发现跟本的原因时因为程序没有加载JDBC的驱动,也就是数据源bean中的driverClassName
没有加载成功,因为我这里采用的是jdbc.properties
的方式来加载数据源参数信息,所有我一开是怀疑的是文件的驱动路径写错了或者jdbc的包没有导入环境中,但是折腾后面发现一切正常,于是索性的将${driver}
直接替换成文件中的参数,引入改成手写,启动项目,竟然发现启动成功!,这让我百思不得其解,于是开始漫长的百度,找不到我想要的答案,便再看一遍日志,发现是因为配置sqlSessionFactory
bean时,dataSource
出错找不到JDBC驱动,既然JDBC驱动没有毛病,sqlSessionFactory
也不可能出毛病,于是我就将目光锁定到了mapperScannerConfigurer
bean,因为他注入了没有毛病的SQL Session Factory
,然后就是开始百度,果然,找对了错误答案一下就出来了。
原来的mapperScannerConfigurer
bean:
<!-- 扫描Mapper文件 -->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactory" ref="sessionFactory"/>
<property name="basePackage" value="com.lyl.mapper"/>
</bean>
修改后的mapperScannerConfigurer
bean:
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
<!-- <property name="sqlSessionFactory" ref="sessionFactory"/>-->
<property name="basePackage" value="com.lyl.mapper"/>
</bean>
可以发现,不再注入sqlSessionFactory
的属性,取而代之的是sqlSessionFactoryBeanName
属性,并且用的是value来赋值,程序能够正常run。
那么问题是解决了,原理是什么呢?我又百度了sqlSessionFactoryBeanName
这的个属性。
发现在MapperScannerConfigurer
中有4种注入方式,而sqlSessionFactory
的注入方式已经过时了,而造成本次报错的根本原因出现在MapperScannerConfigurer
上:
在mybatis-spring1.1.0之前,是经过
将SqlSessionFactory对象注入到sqlSessionFactory,这样作可能会有一个问题,就是在初始化MyBatis时,jdbc.properties文件还没被加载进来,dataSource的属性值没有被替换,就开始构造sqlSessionFactory类,属性值就会加载失败。在1.1.0之后,MapperScannerConfigure提供了String类型的sqlSessionFactoryBeanName,这样将bean name注入到sqlSessionFactoryBeanName,这样就会等到spring初始化完成后,再构建sqlSessionFactory。
终于找到了错误本质了,折腾了大半天!发现原来是jdbc.properties
文件和SqlSessionFactory
出现了冲突,在MapperScannerConfigurer
中直接注入sqlSessionFactory
属性,如果使用的是占位符去配置dataSource
bean,那么可能会造成sqlSessionFactory
构建先于jdbc.properties
文件的加载。
目前还没有找到用sqlSessionFactory
来注入成功的解决方法(除非直接写jdbc的值不用占位符形式),既然都过时了那就不用了吧。