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

[经验分享] mybatis中动态加载的应用(4)

[复制链接]

尚未签到

发表于 2016-11-27 08:38:47 | 显示全部楼层 |阅读模式
  之前,对于数据映射器的理解不是很懂(即 在mybatis中,通过sqlSession可以直接操作xml中sql语句,也可以新建MAPInterface来操作sql),这几天仔细看了一下,由于基础方面的原因,并不能把全部的设计写出来,只能说个大概,有时间会在看看。
  涉及数据映射器(这个名字好像只有在与spring整合才有这个说话,但是感觉这个名字比较形象哈)的几个主要类有SqlSession,DefaultSqlsession,Configuration,MapperProxy,MapperRegistry,需要的知识主要是动态代理。之前我困惑主要是在框架中,全部只有接口和sql配置文件,但是却能够操作数据库,有点不像hibernate,在DAO里面是有session这样涉及事务管理的,mybatis DAO没有,只能操作设定的方法,不能获取事务的。(动态代理可以理解为动态加载+代理模式,如果不懂的话,请参考http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html,这篇博客,下附我自己随便写的简单代码)
  ( 回到正题,这个东西只能说个大概,请谅解,大神就留下您的理解,方便大家一起提高)
  根据源代码,可以知道是以动态加载的形式获取代理对象的(在MapperProxy里面),并且是在此类里面获取代理对象

MapperProxy.java
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (!OBJECT_METHODS.contains(method.getName())) {
final Class<?> declaringInterface = findDeclaringInterface(proxy, method);//获取所有需要处理sql的接
final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession);//构造注入
final Object result = mapperMethod.execute(args);//具体返回代理对象
if (result == null && method.getReturnType().isPrimitive() && !method.getReturnType().equals(Void.TYPE)) {
throw new BindingException("Mapper method '" + method.getName() + "' (" + method.getDeclaringClass() + ") attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
return null;
}
private Class<?> findDeclaringInterface(Object proxy, Method method) {
Class<?> declaringInterface = null;
for (Class<?> iface : proxy.getClass().getInterfaces()) {
try {
Method m = iface.getMethod(method.getName(), method.getParameterTypes());
if (declaringInterface != null) {
throw new BindingException("Ambiguous method mapping.  Two mapper interfaces contain the identical method signature for " + method);
} else if (m != null) {
declaringInterface = iface;
}
} catch (Exception e) {
// Intentionally ignore.
// This is using exceptions for flow control,
// but it's definitely faster.
}
}
if (declaringInterface == null) {
throw new BindingException("Could not find interface with the given method " + method);
}
return declaringInterface;
}
@SuppressWarnings("unchecked")
//mapperInterface为接口,sqlsession为包含配置xml的
public static <T> T newMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) {
ClassLoader classLoader = mapperInterface.getClassLoader();
Class<?>[] interfaces = new Class[]{mapperInterface};
MapperProxy proxy = new MapperProxy(sqlSession);
return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy);//获取代理对象
}
  调用的MapperMethod,具体相当于注入代理对象的方法实现

//c初始化
public MapperMethod(Class<?> declaringInterface, Method method, SqlSession sqlSession) {
paramNames = new ArrayList<String>();
paramPositions = new ArrayList<Integer>();
this.sqlSession = sqlSession;
this.method = method;
this.config = sqlSession.getConfiguration();
this.hasNamedParameters = false;
this.declaringInterface = declaringInterface;
setupFields();
setupMethodSignature();
setupCommandType();
validateStatement();
}
//具体执行,返回获取能够执行sql的代理对象
public Object execute(Object[] args) {
Object result = null;
if (SqlCommandType.INSERT == type) {
Object param = getParam(args);
result = sqlSession.insert(commandName, param);
} else if (SqlCommandType.UPDATE == type) {
Object param = getParam(args);
result = sqlSession.update(commandName, param);
} else if (SqlCommandType.DELETE == type) {
Object param = getParam(args);
result = sqlSession.delete(commandName, param);
} else if (SqlCommandType.SELECT == type) {
if (returnsVoid && resultHandlerIndex != null) {
executeWithResultHandler(args);
} else if (returnsList) {
result = executeForList(args);
} else if (returnsMap) {
result = executeForMap(args);
} else {
Object param = getParam(args);
result = sqlSession.selectOne(commandName, param);
}
} else {
throw new BindingException("Unknown execution method for: " + commandName);
}
return result;
}
  期间MapperMethod进行匹配(即接口与xml namespace下指定操作),但是为什么可以获取xml文件的配置呢?这时候Configuration这个类就出现了,是可以解析配置文件的内容的,所以可以注入相关的指令和sql语句,在封装好下的底层进行实现,我感觉这就是为什么sqlsession是可以完全控制配置文件里面的所有sql操作的原因,而且这一步是在sqlsssionFactory完成的,但是为什么由sqlsession.getMapper(xxx.class)获取的DAO操作类却只能操作接口定义的类?第一,最简单顾名思义,DAO操作类实现接口而已,而我们自己写的代码确实没有对其进行扩充,其实扩充了,但是没有写在配置文件,还是一回事;第二,在getMapper()里面,我们是以某个接口作为参数的,参考

DefaultSqlSession.class
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
if (!knownMappers.contains(type))
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
try {
return MapperProxy.newMapperProxy(type, sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
  从上面的代码,我感觉是你单个接口,对吧,首先已经有sqlsession代理对象了,已经能够进行所有操作了,现在是通过getMapper方法获取一个DAO对象,其实还是动态代理的DAO,只不过这次是单个接口,而接口里并没有定义sql操作其他的方法,对吧,所以代理的对象只能进行这些操作了,走的class流程还是跟sqlsession代理对象产生时差不多,或许说在sqlsession里面已经有了所有xml的代理对象,但是我估计底层实现不可行的,因为,得时刻保存在内存里面,还不如构造一个通用的sqlsession,需要去的时候临时把对应的操作方法集合构造代理对象,这样比较科学。这一块我没怎么看明白哈!
  以上就是我对mybatis获取SqlSession和DAO操作具体实现的一些简单认识,并且我回继续往下看!
  此博客主要用于记录个人学习内容和梳理整体知识,若有许多不明和错误的地方,还请指出 DSC0000.gif ,若是其他方面,概不欢迎 DSC0001.gif
  动态代理演示代码

1接口
public interface Name {
public void sayHello(String nusername);
}
2实现接口类
public class Proxyclass implements Name{
public void sayHello(String username) {
// TODO Auto-generated method stub
System.out.println(username);
}
}
3.实现动态代理
public class ProxyName implements InvocationHandler{
private Object proxied;
ProxyName(Object proxied){
this.proxied=proxied;
}
public Object invoke(Object proxy, Method method, Object[] params)
throws Throwable {
// TODO Auto-generated method stub
System.out.println(proxy.getClass().getName()+":"+method+":"+params[0]);
System.out.println(method.getName());
return(method.invoke(proxied, params));
}
}
4.测试
public class DynamicProxyDemo {
public static void main(String args[]) {
Proxyclass pro = new Proxyclass();
pro.sayHello("yaoge22");
Name name = (Name) Proxy.newProxyInstance(Name.class.getClassLoader(),
new Class[] { Name.class }, new ProxyName(pro));
name.sayHello("hello");
}
}

运维网声明 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-305985-1-1.html 上篇帖子: mybatis日期配置DATE,jstl用fmt:formatDate出现的日期格式问题 下篇帖子: Hibernate VS MyBatis 区别 Hibernate3和MyBatis(iBatis)的执行效率比较
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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