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}直接替换成文件中的参数,引入改成手写,启动项目,竟然发现启动成功!,这让我百思不得其解,于是开始漫长的百度,找不到我想要的答案,便再看一遍日志,发现是因为配置sqlSessionFactorybean时,dataSource出错找不到JDBC驱动,既然JDBC驱动没有毛病,sqlSessionFactory也不可能出毛病,于是我就将目光锁定到了mapperScannerConfigurerbean,因为他注入了没有毛病的SQL Session Factory,然后就是开始百度,果然,找对了错误答案一下就出来了。
原来的mapperScannerConfigurerbean:

<!-- 扫描Mapper文件 -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactory" ref="sessionFactory"/>
        <property name="basePackage" value="com.lyl.mapper"/>
    </bean>

修改后的mapperScannerConfigurerbean:

  <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属性,如果使用的是占位符去配置dataSourcebean,那么可能会造成sqlSessionFactory构建先于jdbc.properties文件的加载。

目前还没有找到用sqlSessionFactory来注入成功的解决方法(除非直接写jdbc的值不用占位符形式),既然都过时了那就不用了吧。

posted @ 2021-05-27 09:55  CN_DADA  阅读(1346)  评论(0编辑  收藏  举报