用了很久mybatis,一直猜想mybatis是使用动态代理的方式实现mapper接口的,通过实践探索之后,果然如此,但是还是遇到了不少问题,在此粘出来供初学者参考。
首先我将案例代码粘出来,这段代码简单实现了从service层开始调用mapper接口的过程。
package com.star.ott.common.office;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TestClass {
public static void main(String[] args) {
new UserService().updateUserByUserName();
new UserService().findUser("");
}
}
/**
* 我们需要操作的user实体
*/
class User {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
/**
* 这里是我们的mapper接口
*/
interface UserMapper {
User findUserByUserName(String userName);
void updateUserByUserName(User user);
}
/**
* 此处是service层的业务类
*/
class UserService {
//在实际开发中,此处的UserMapper是通过注解加载进来的,而其真正的
//实现就类似于下面的实现方式,通过动态带来的方式创建实例
UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{UserMapper.class}, new MybatisProxy());
public User findUser(String userName) {
return userMapper.findUserByUserName(userName);
}
public void updateUserByUserName() {
userMapper.updateUserByUserName(new User());
}
}
/**
* 这里就是具体的代理类,在代理类中,通过数据库驱动与数据库获取
* 连接,然后读取相关mapper.xml执行sql,最后获得操作结果,具体
* 连接数据库,读取mapper.xml文件的方式就不再累赘
*/
class MybatisProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("遍历参数" + method.getParameters()[0]);
System.out.println("通过method的名字去mapper.xml文件中找到sql: " + method.getName());
System.out.println("执行数据库操作,若果有异常等,直接在此处抛出,没有则拿到返回值");
if(method.getReturnType().toString().equals("void")){
System.out.println("无返回值的情况");
return method.getGenericReturnType();
}else {
Object result = method.getReturnType().getDeclaredConstructor().newInstance();
System.out.println("将得到的返回值赋值给result,然后返回" + method.getReturnType());
return result;
}
}
}
需要注意的是,通过Proxy.newProxyInstance方式生成代理对象时,一般除了需要接口类的类类型之外,还需要实现类的实例作为代理类的参数,这样,我们就可以在代理对象中,也就是MybatisProxy中直接执行实现类实例的方法,然后返回。但是我们此处代理对象的特殊之处,就是代理了接口,实现逻辑完全写在代理类中,所以遇到没有返回值的方法时,需要做逻辑判断,返回一个method.getGenericReturnType(),否则这里会报错。
好了,这就是mybatis通过动态代理的方式实现mapper接口的大致方式,可以参考一下。