abel533 / MyBatis-Spring-Boot

Spring Boot集成MyBatis的基础项目
3.37k stars 1.59k forks source link

大神帮忙看下-----只差把这个示例代码 全部copy过去了。 #34

Open helloworldtang opened 7 years ago

helloworldtang commented 7 years ago

错误:Caused by: java.lang.InstantiationException: tk.mybatis.mapper.provider.SpecialProvider at java.lang.Class.newInstance(Class.java:427) at org.apache.ibatis.builder.annotation.ProviderSqlSource.createSqlSource(ProviderSqlSource.java:85) ... 136 common frames omitted Caused by: java.lang.NoSuchMethodException: tk.mybatis.mapper.provider.SpecialProvider.() at java.lang.Class.getConstructor0(Class.java:3082)

相关代码已上传到github:https://github.com/helloworldtang/SpringBootCookbook rest接口:/tx/post 所在class: com.tangcheng.rest.TxController

helloworldtang commented 7 years ago

重新切了个分支:v1.0.0_tx 去掉通用mapper,只使用mybatis-spring-boot-starter,就可以正常使用了

helloworldtang commented 7 years ago

重新启了一个Module,按照例子中操作了一遍。是ok的 我上面的那个项目中,那个地方的配置干扰了通用Mapper的初始呢? 奇怪

abel533 commented 7 years ago

上面错误的原因是mapper配置错误,导致通用方法没有被正确的初始化。

helloworldtang commented 7 years ago

@abel533 反复把代码与这个例子比对了一下。没有发现错。跟了下代码,发现执行过程中传的参数都对

但还是报错了:

Error invoking SqlProvider method (tk.mybatis.mapper.provider.SpecialProvider.dynamicSQL). Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.SpecialProvider

报错位置: [ providermethod-dyn

有时间给看看呗,没有找到门道啊 示例代码在项目中的位置: package-mybati-spring

helloworldtang commented 7 years ago

@abel533 原来是SpecialProvider.class.newInstance();报错了:

nosuchmethod-2 nosuchmethod-specialprovider

为什么呢?

helloworldtang commented 7 years ago

今天在对比代码时发现一个: 上面报错项目中MappedStatement.java中sqlSource是tk.mybatis.mapper.provider.SpecialProvider 你给出的例子中却是org.apache.ibatis.scripting.xmltags.DynamicSqlSource

哪个地方的配置决定实例化哪个SqlSource呢? 有错的: providersqlsource-mybatis

正常的: dynamicsqlsource-mybatis

helloworldtang commented 7 years ago

@abel533 Mapper哪个地方配错了呢。和这个例子中除了class名字外,都是一样的呢?

abel533 commented 7 years ago

ProviderSqlSource 初始化时不会调用 newInstance 方法。当 Mapper 处理所有的通用方法后,都已经不是 ProviderSqlSource 了,永远都没机会调用 newInstance 了。唯一会导致这个错误的原因就是配置错误导致通用方法没被处理。

你接口都集成的 MyMapper,你按文档配置 mappers 属性试试。

helloworldtang commented 7 years ago

@abel533 看看错哪了呢? 又比对了一遍了。都有配置的: mappers: mybatis-config

basepackages

pom-dependency

helloworldtang commented 7 years ago

发现一个有意思地方: 我这边 通用mapper自动配置没有生效:

上面例子中spring 容器中有这些bean,我写的那个demo就没有

beans-abel

helloworldtang commented 7 years ago

@abel533 感觉这是一个bug,看看是那个方面的原因导致的呢?

问题原因应该是:com.github.pagehelper.autoconfigure.MapperAutoConfiguration和 com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration 没有自动配置。

以MapperAutoConfiguration为例,Spring容器中是有SqlSessionFactory这个实例的,从下面的代码看,MapperAutoConfiguration 是应该会被自动配置,但实际情况是 ----- 没有实例化: @Configuration @ConditionalOnBean({SqlSessionFactory.class}) @EnableConfigurationProperties({MapperProperties.class}) @AutoConfigureAfter({MybatisAutoConfiguration.class}) public class MapperAutoConfiguration {

abel533 commented 7 years ago

加个 @MapperScan

helloworldtang commented 7 years ago

@abel533 感觉问题出在MapperAutoConfiguration.java的Condition条件上了 看看是不是应该把MapperAutoConfiguration.java上的注解 @ConditionalOnBean({SqlSessionFactory.class}) 改成 @ConditionalOnClass({SqlSessionFactory.class})

MapperScan已经加过了。 @MapperScan放在启动的那个class CookbookApplication.java上了

helloworldtang commented 7 years ago

@abel533 这个bug不想跟了。回退到使用java config来配置PageInterceptor和通用Mapper. 现在已经Ok。

tips: 经过这个bug搞的,感觉现在离能写mybatis plugin只差一点点了 ☺^_^

helloworldtang commented 7 years ago

@abel533

建议将MapperAutoConfiguration和PageHelperAutoConfiguration的实例化条件改为ConditionalOnClass

应该是spring boot中加载MapperAutoConfiguration和PageHelperAutoConfiguration的时机有差异

spring boot actuator中提供的信息显示,在加载通用Mapper和PageHelper的autoconfig时,SqlSessionFactory.class并没有实例化完成。

conditiononbeansqlfactory

abel533 commented 7 years ago

我这里的启动日志中:

   MapperAutoConfiguration matched:
      - @ConditionalOnBean (types: org.apache.ibatis.session.SqlSessionFactory; SearchStrategy: all) found bean 'sqlSessionFactory' (OnBeanCondition)

   PageHelperAutoConfiguration matched:
      - @ConditionalOnBean (types: org.apache.ibatis.session.SqlSessionFactory; SearchStrategy: all) found bean 'sqlSessionFactory' (OnBeanCondition)
abel533 commented 7 years ago

你使用的 spring boot,以及 pagehelper 和 mapper 的 starter 版本是多少?

helloworldtang commented 7 years ago

@abel533 都是从https://github.com/abel533/MyBatis-Spring-Boot.git copy过去的

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.1.RELEASE</version>
    <relativePath/>
    <!-- lookup parent from repository -->
</parent>

    <!--mapper-->
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper-spring-boot-starter</artifactId>
        <version>1.1.0</version>
    </dependency>
    <!--pagehelper-->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>1.1.0</version>
    </dependency>
helloworldtang commented 7 years ago

@abel533 如果单独写一个项目,里面只有https://github.com/abel533/MyBatis-Spring-Boot.git 里面的业务逻辑,也是可以的。

但在https://github.com/helloworldtang/spring-boot-cookbook.git 这个学习用的小项目中,就会not Matched

hellokaton commented 7 years ago

@helloworldtang 遇到同样的问题,你解决了吗?

helloworldtang commented 7 years ago

现在是能用了,具体什么原因也不清楚。 把相关配置都放在application,properties中就可以。

zollty commented 7 years ago

遇到这个问题了, Caused by: org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.base.BaseSelectProvider.dynamicSQL).
Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.base.BaseSelectProvider

我的分析如下: spring boot项目中用的是mybatis的: @MapperScan(basePackages = { "com.xxx.mapper"}) 而传统spring mvc项目中用的是tk.mybatis的: <bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.xxx.mapper" /> </bean>

spring-boot那种mapper扫描方式,少了一些 tk.mybatis.spring.mapper.MapperScannerConfigurer 中的操作。所以我猜想可能是这个原因导致。

看了很多spring-boot源码和文档,但是后面总结了一下,其实spring-boot并没有像官方说的那样简便易用,特别是涉及一些复杂配置,spring-boot管理起来很乱。所以,我接下来准备尝试把xml和spring mvc的注释方式结合起来使用,不知道效果会怎样。

abel533 commented 7 years ago

@zollty 这个错误只有配置错的时候才会出现,就是没有处理通用接口方法导致的。

zollty commented 7 years ago

@abel533 据我深入分析,这不是配置错误,而是代码问题。@MapperScan注解并不能代替tk.mybatis.spring.mapper.MapperScannerConfigurer,如果用@MapperScan则少了对GenericBeanDefinition的改造、少了加入mapperHelper

为了验证这个说法,我将@MapperScan换成了自己写的@MyMapperScan,扫描注解时加上mapperHelper并对BeanDefinitionRegistry registry进行了处理,自然就解决了这个问题。

建议你提供一个tk.MapperScan,替换Mybatis自带那个。

abel533 commented 7 years ago

@zollty 你用mapper-starter了吗?这个项目会自动处理通用接口。

fengcbo commented 7 years ago

大神们,有什么解决方案吗?我也遇到了类似的错误,所有的配置都对比了一遍,应该没什么错误,但是BaseSelectProvider初始化就是报错。

abel533 commented 7 years ago

@fengcbo 你用的1.1.1版本的starter?

fengcbo commented 7 years ago

恩,用的是1.1.1版本的。只是在@Configuration中引用Mapper会报错,项目启动完成后就可以正常调用了

abel533 commented 7 years ago

@fengcbo 这种情况会在初始化完成前调用,所以会出错。

fengcbo commented 7 years ago

哪有什么方法可以解决这个问题吗?

abel533 commented 7 years ago

参考:Spring Boot - 配置排序依赖技巧 让你的配置类在 MapperAutoConfiguration 配置类后面执行。

fengcbo commented 7 years ago

按照您文章中说的配置了org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration,\ com.xxxx.ShiroConfiguration

ShiroConfiguration 没有让spring boot扫描到,但是错误依旧存在。 在网上搜索了好多关于这个错误的问答,感觉都是没有什么结果,希望您能在常见问题中提供一下解决方案,或者能够提供一个相关的项目示例。

abel533 commented 7 years ago

MapperAutoConfiguration 和 你的配置类中断点看看那个先执行。

fengcbo commented 7 years ago

上面的配置写错了,第一个应该是com.github.pagehelper.autoconfigure.MapperAutoConfiguration。 不过debug看了后,在META-INF/spring.factories 中加入上面的配置后依然是我的ShiroConfiguration先执行。

abel533 commented 7 years ago

ShiroConfiguration 注解怎么配置的?

fengcbo commented 7 years ago

只有一个Configuration注解

fengcbo commented 7 years ago

今天大概读了一下spring boot 关于spring.factories解析的过程,spring boot在解析完org.springframework.boot.autoconfigure.EnableAutoConfiguration后的配置后会对结果进行再一次的排序,所以这个配置的顺序不能保证spring boot的解析顺序。您提供的那个方法好像并不可行。

ginhom commented 7 years ago

同样的问题,@Configuration类内面用到Mapper,结果出现这个错误了。。。 image

fengcbo commented 7 years ago

Configuration的加载是在Auto Configuration之前的,有几种方式可以让Auto Configuration以前加载,作者的实现没有考虑到Configuration中使用Mapper的情况,要解决目前只能自己重写starter(没找到其他方式)。

2017-08-14 7 50 31

https://github.com/chanjarster/spring-boot-all-callbacks

abel533 commented 7 years ago

这里确实有问题。加载太早以至于没有初始化。

zuisong commented 7 years ago

我也遇到这个问题了,只能Java代码配置,没法用starter

fengcbo commented 7 years ago

仿照作者的starter重写了一个,解决了这个问题 https://github.com/fengcbo/mapper-spring-boot

zuisong commented 7 years ago

应该不需要你重写一个starter吧,可以在你使用mapper的configuration上加上 @AutoConfigureAfter(MapperAutoConfiguration.class) 的注解手动控制顺序就好了啊

fengcbo commented 7 years ago

AutoConfigureAfter不能控制Configuration和Auo-Configuration的加载顺序,我测试的是加上AutoConfigureAfter依然不能解决问题,你的应该是没在Configuration使用通用Mapper吧

abel533 commented 7 years ago

@ZuiSong @fengcbo 看这里:http://blog.csdn.net/isea533/article/details/53975720

cgnq commented 6 years ago

最终解决方案是什么呢?

abel533 commented 6 years ago

@cgnq 使用提供的mapper-starter就行。

cgnq commented 6 years ago

嗯,还有一个问题,假如A用到B,不管怎么配置,B一定会先加载。我用shiro的ShiroFilterFactoryBean在配置的时候用通用mapper加入数据库数据,用了spring.factories也没用,最终的解决方案是让ShiroFilterFactoryBean先加载,在写一个 image

760374564 commented 6 years ago

异常信息: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.base.BaseInsertProvider.dynamicSQL). Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.base.BaseInsertProvider at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77) .........................................此处省略很多无用信息....................................... Caused by: org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.base.BaseInsertProvider.dynamicSQL). Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.base.BaseInsertProvider at org.apache.ibatis.builder.annotation.ProviderSqlSource.createSqlSource(ProviderSqlSource.java:135) .........................................此处省略很多无用信息....................................... Caused by: java.lang.InstantiationException: tk.mybatis.mapper.provider.base.BaseInsertProvider at java.lang.Class.newInstance(Class.java:427) at org.apache.ibatis.builder.annotation.ProviderSqlSource.createSqlSource(ProviderSqlSource.java:117) ... 147 common frames omitted Caused by: java.lang.NoSuchMethodException: tk.mybatis.mapper.provider.base.BaseInsertProvider.() at java.lang.Class.getConstructor0(Class.java:3082) at java.lang.Class.newInstance(Class.java:412) ... 148 common frames omitted

解决方案: 使用MapperScan注解时使用 tk.mybatis.spring.annotation.MapperScan 替换 org.mybatis.spring.annotation.MapperScan,搞定问题,不知道与上面的仁兄是不是同样的问题,这算不算一种解决方案呢?另外如果这里能避免注解的再定义,只使用org.mybatis.spring.annotation.MapperScan 注解就完美了^o^!

abel533 commented 6 years ago

@760374564 你可以看看文档中配置 Configuration 的用法,用这种方式都不需要 starter,只依赖 mapper 就行了。