平时我们在spring中用Mybatis的时候,都是用一个Mapper接口,然后通过xml或者注解进行配置。
ServiceImpl
@Override
public List<Map<String, Object>> getSignImgs(Map<String, Object> params) {
return modulesMapper.getSignImgs(params);
}
ModulesMapper
@Select("select * from imgs")
List<Map<String, Object>> getSignImgs(Map<String, Object> params);
这是Spring中配置Mybatis之后的调用。
但是,ModulesMapper是一个接口,背后又是如何实现调用getSignImgs方法的。
我们也知道Mybatis背后偶肯定使用动态代理去实现接口的,我们剥离spring重新看Mybatis的使用方法。
SqlSessionFactory factory = ... // 获取SqlSessionFactory的方法
SqlSession session = factory.openSession(); // 创建一个session
ModulesMapper modulesMapper = session.getMapper(ModulesMapper.class); // session 通过动态代理获取modulesMapper的实现类
继续看SqlSession的源码
SqlSessionTemplate
@Override
public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);
}
Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistery
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
MapperProxyFactory
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
//这里mapperInterface就是定义的Mapper接口,methodCache就是通过注解或者xml配置获取的方法cache,这里
//不继续展开其实怎么获取的
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
整合一下,我们所知道的,对于Proxy的常用代理实现。
- 已经有类实现了某个接口,将该类实例化,通过反射获取该类的接口,在Proxy中实现其用法,可以在原有的方法上下添加操作,InvocationHandler 的实现中需要对原对象进行invoke操作。
- 只是对接口进行动态代理的实现,例如Mybatis中的实现,在Proxy中直接获取Class对象,不需要用到反射,开始并没有创建实例,InvocationHandler中不需要invoke。
列上代码,看一下区别
interface Ptest{
void test();
}
class PtestImpl implements Ptest{
@Override
public void test() {
System.out.println("原本的方法");
}
}
class ProxyTest {
public static void main(String[] args) {
Ptest ptest = new PtestImpl();
Ptest p2 = (Ptest) Proxy.newProxyInstance(ptest.getClass().getClassLoader(), ptest.getClass().getInterfaces(), (proxy, method, args1) -> {
System.out.println("动态代理");
return method.invoke(ptest, args1);
});
p2.test();
}
}
class ProxyTest2 {
public static void main(String[] args) {
Ptest p2 = (Ptest) Proxy.newProxyInstance(ProxyTest2.class.getClassLoader(), new Class[]{Ptest.class}, (proxy, method, args1) -> {
System.out.println("动态地生成对象,为接口的方法做了实现");
return proxy;
});
p2.test();
}
}