在使用MyBatis
时,有时候会想,为什么只写一个接口没有编写任何的实现类,但是就能返回接口的实例,并且调用接口的方法返回数据库中的数据?此时脑海中浮现了写动态代理时候的记忆,记得动态代理也是接管了接口,不需要实际的代理角色。然后经过源码的Debug发现果然是运用了动态代理的技术。如果对于动态代理技术不熟悉的同学可以看
Mybatis自动映射器Mapper的源码分析
首先我们想Debug源码就得写一个测试类如下:
@Autowiredprivate SqlSessionFactory sqlSessionFactory;@Testpublic void testMybatis(){ SqlSession sqlSession = sqlSessionFactory.openSession(); TBapCheckPtsTranscdMapper mapper = sqlSession.getMapper(TBapCheckPtsTranscdMapper.class); TAmsAcPmtDtlPo tAmsAcPmtDtlPo= new TAmsAcPmtDtlPo(); mapper.queryTransCdByType(tAmsAcPmtDtlPo);}复制代码
Mapper
是这样的
public interface TBapCheckPtsTranscdMapper { List
首先先弄明白如何得到的接口的实际对象,由此Debug进去。
TBapCheckPtsTranscdMapper mapper = sqlSession.getMapper(TBapCheckPtsTranscdMapper.class);复制代码
然后进行Debug源码,发现在MapperProxyFactory
中,返回了代理对象。
protected T newInstance(MapperProxymapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }复制代码
然后发现在执行接口的方法的时候进入到了代理MapperProxy
@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try { //诸如hashCode()、toString()、equals()等方法,将target指向当前对象this if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else if (isDefaultMethod(method)) { return invokeDefaultMethod(proxy, method, args); }} catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t);}final MapperMethod mapperMethod = cachedMapperMethod(method);return mapperMethod.execute(sqlSession, args);}复制代码
自己写一个小例子
首先自己定义个实体类
public class User { private Integer id; private String name; private String age; -----get,set方法}复制代码
然后Mapper接口如下
public interface UserMapper { public User findUserById(Integer id);}复制代码
代理类如下
public class MapperProxy implements InvocationHandler { @SuppressWarnings("unchecked") publicT newInstance(Class clz) { return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] { clz }, this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())) { try { // 诸如hashCode()、toString()、equals()等方法,将target指向当前对象this return method.invoke(this, args); } catch (Throwable t) { } } //后面的xml解析之类的就先不模拟,在这直接返回数据 return new User((Integer) args[0], "zhangsan", "18"); }}复制代码
测试如下
public static void main(String[] args) { ClassLoader classLoader = UserMapper.class.getClassLoader(); MapperProxy mapperProxy = new MapperProxy(); //通过代理生成接口的实例对象 UserMapper mapper = (UserMapper) Proxy.newProxyInstance(classLoader, new Class[]{UserMapper.class},mapperProxy); User user = mapper.findUserById(10000); System.out.println("ID:" + user.getId()); System.out.println("Name:" + user.getName()); System.out.println("Age:" + user.getAge());}复制代码
打印如下
ID:10000Name:zhangsanAge:18Practice.Day09.MapperProxy@24d46ca6复制代码