Mybatis接口编程示例
(1)首先定义接口编程需要的接口及其方法
public interface IUserMapper {
public User getById(int id);//接口方法,不需要实现
}
(2)创建mybatis的mapper文件,其中namespace的值为接口的完整类名
<mapper namespace="com.tianjunwei.learn.learn2.IUserMapper">//接口完整类名
<select id="getById" parameterType="int"
resultType="com.tianjunwei.learn.learn1.entity.User">
select * from users where id=#{id}
</select>
</mapper>
(3)创建接口调用操作
public class Learn2Main {
public static void main(String [] args){
String resource = "learn/mybatis-config.xml";
InputStream is = Learn1Main.class.getClassLoader().getResourceAsStream(resource);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sessionFactory.openSession();
IUserMapper userMapper = session.getMapper(IUserMapper.class);//获取接口,已经是代理接口
userMapper.getById(1);
RowBounds rowBounds = new RowBounds(2, 4);//接口分页编程
System.out.println(userMapper.page(rowBounds).size());
}
}
Mybatis接口编程相关的类主要有MapperProxyFactory、MapperProxy、MapperMethod和MapperRegister四个类:
MapperProxyFactory:通过类名我们可以猜到这是一个MapperProxy的工厂类,用于创建MapperProxy的,通过函数newInstance(SqlSession sqlSession)来创建MapperProxy的代理类。
源码如下:
//这个类赋值创建具体mapper接口代理对象的工厂
public class MapperProxyFactory<T> {
//具体Mapper接口的class对象
private final Class<T> mapperInterface;
//该接口下面的缓存,key是方法对象,value是对接口中方法对象的封装
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
//创建一个代理类并返回
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
//在这里创建MapperProxy对象,这个类实现了JDK的动态代理接口 InvocationHandler
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
//调用上面的方法,返回一个接口的代理类
return newInstance(mapperProxy);
}
}
源码如下:
//实现了JDK动态代理的接口,InvocationHandler
//在invoke方法中实现了代理方法调用的细节
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
//sqlSession
private final SqlSession sqlSession;
//接口的类型对象
private final Class<T> mapperInterface;
//接口中方法的缓存,由MapperProxyFactory传递过来
private final Map<Method, MapperMethod> methodCache;
//构造函数
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
//接口代理对象所有的方法调用都会调用该方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//判断是不是基础方法比如toString、hashCode等,这些方法直接调用不需要处理
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
//进行缓存
final MapperMethod mapperMethod = cachedMapperMethod(method);
//调用mapperMethod.execute 核心的地方就在这个方法里,这个方法对才是真正对SqlSession进行的包装调用
return mapperMethod.execute(sqlSession, args);
}
//缓存处理
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
}