设为首页 收藏本站
查看: 1901|回复: 0

[经验分享] 基于Spring,MyBatis的Interface及Class混用

[复制链接]

尚未签到

发表于 2016-11-27 08:35:40 | 显示全部楼层 |阅读模式
  这篇是在玩Spring-MyBatis时遇到的问题,比较闹心,还算有趣,记下经历,以备他日不时之需。
  问题是这样:想做个共通的机制来处理大量重复的“基本的增删改查”。
  网上做了些调查,通常都是需要准备一个Class,在里面用反射来拼SQL文,然后再调用MyBatis的底层Class的SqlRunner来执行。这种方案本身倒也没什么问题,但是MyBatis现在是纯Interface的风格。所以会导致MyBatis的Dao/Mapper既有Interface又有Class同时存在。于是事情变得麻烦些。
  
  最初打算简单些,只写一个类,不再搞接口什么的。代码如下:

public class CommonDao extends SqlSessionDaoSupport {
public int insert(Object object) {
...
}
...
}

  
  由于使用了Spring-MyBatis的自动配置——所有Dao/Mapper的Interface会被自动注册,于是首当其冲的问题就是该类无法自动注册。这时有两个选择,一是手动注册,二是加Interface。
  
  手动注册最简单,于是先尝试了这个方案。添加的配置如下:

<bean id="commonDao" class="mypackage.common.dao.CommonDao">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

  启动时直接抛了异常,如下

org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'commonDao' must be of type [mypackage.common.dao.CommonDao], but was actually of type [com.sun.proxy.$Proxy22]
  一通折腾后找到了原因。由于我对所有Dao都有加了拦截器,又没有提供CGLIB,于是Spring自顾自的上了JDK的代理。可是我不明白的是,Spring你明知道那玩意儿不好用,还折腾个啥。
  加上CGLIB包,并强制Spring使用它,配置如下。

<aop:aspectj-autoproxy proxy-target-class="true">
<aop:include name="daoInterceptor" />
</aop:aspectj-autoproxy>

  启动时仍然报错,这回是其他的Dao/Mapper类。报错如下:

java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy20
  查下来,似乎问题出在MyBatis上。MyBatis里面写死固定使用JDK代理,导致CGLIB再企图继承JDK代理时抛的异常。参考MyBatis 3.2.2代码如下

package org.apache.ibatis.binding;
...
public class MapperProxyFactory {
...
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}

  网上搜索了下,找到这个Issue,已经被关闭,且回答是“MyBatis使用CGLIB”!啥?是我哪里理解错了吗?!
  
  到这里,虽然咱又是加CGLIB,又是改配置,还是死胡同一条啊!
  
  于是改走Interface路线。顺便改了名字CommonDao -> UtilDao。代码如下:

// 接口
public interface UtilDao {
...
public int insert(Object object);
..
}
// 实现类
public class UtilDaoImpl extends SqlSessionDaoSupport implements UtilDao {
...
public int insert(Object object) {
...
}
...
}

  
  CGLIB也暂时去掉,手动注册和aop:aspectj的proxy-target-class也去掉。
  
  再启动,这回不报错了。耶~!试着执行下,直接抛了异常。!艹!(我TYYD是在拯救世界还是什么?!不就写个共通,至于吗?!)异常如下:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): mypackage.common.dao.UtilDao.insert
  
  查下来,是被Spring-MyBatis注册在前,看来前面的手动注册还得加上去才行。配置如下:

<bean id="utilDao" class="mypackage.common.dao.db.UtilDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

  
  这样就彻底OK了。基于MyBatis的Dao/Mapper,以Interface和class的混合方式一同工作。

  结论是即需要加Interface又需要手动注册。
  
  累稀忒了...
  以下内容已经属于完善加强的部分,开始偏离主题了。哈。

  还没完,查看启动时日志,注意下面这句有些碍眼。

2013-06-16 16:11:38,744 WARN  ClassPathMapperScanner - Skipping MapperFactoryBean with name 'utilDao' and 'mypackage.common.dao.UtilDao' mapperInterface. Bean already defined with the same name! checkCandidate

  
  这个应该是Spring在调用MyBatis的注册时,发现已经有相同的bean时发出的警告。对这种细节稍稍比较在意,于是开始琢磨怎么完善它。
  
  简单说就是屏蔽掉MyBatis的注册。调查后发现Spring-MyBatis提供的MapperScannerConfigurer不提供excludeFilters!可是Spring类似的东东都是有excludeFilters和includeFilters的,您这只有个支持通配符——还不是正则表达式——的basePackage哪里够用啊?!于是自己基于MapperScannerConfigurer做个自己的DaoScanner,最终配置如下:

<bean class="mypackage.common.dao.DaoScanner">
<property name="basePackage" value="mypackage.*.dao" />
<property name="excludeFilters">
<list>
<value><![CDATA[.*(?<!Dao)$]]></value>
<value><![CDATA[.*UtilDao$]]></value>
</list>
</property>
</bean>
<bean id="utilDao" class="mypackage.common.dao.db.UtilDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

  
  关于MapperScannerConfigurer的excludeFilters,我有去mybatis-user提过建议,得到的回答是“有些过度设计”!唔......也罢。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-305982-1-1.html 上篇帖子: MyBatis的关于批量数据操作的测试 下篇帖子: MyBatis学习之简单增删改查操作、MyBatis存储过程、MyBatis分页、MyBatis一对一、MyBatis一对多
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表