Mybatis中Mapper 接口的工作原理:JDK 动态代理具体实现

当我们在使用 MyBatis 的时候,通常会先定义一个包含 SQL 语句的 XML 文件(也可以使用注解方式实现),这个文件中包含了 select、update、delete、insert 等与数据库操作相关的语句。

MyBatis 通过读取这个 XML 文件,将其中定义的 SQL 语句解析成对应的 MappedStatement 对象,并存储在 Configuration 对象中。

在使用 MyBatis 进行数据库操作时,会先通过 SqlSession 对象获取到对应的 Mapper 接口,然后通过该接口上的方法调用执行相应的 SQL 语句。但实际上这些方法定义时是一个个接口方法,并没有实现,因此在执行这些方法时,需要使用动态代理来实现这些接口方法的执行。

MyBatis 通过 Java 的 Proxy 类动态生成 Mapper 接口的代理对象,并将该代理对象返回给客户端使用。Mapper 接口的代理对象会拦截所有对接口方法的调用,并把这些调用转发给 MyBatis 的 SqlSession,SqlSession 会负责执行与调用相关的一些 SQL 语句,并返回结果给代理对象,最终返回给客户端。因此,从客户端来看,就好像是直接调用了接口方法一样,这就是动态代理的魔力所在。

具体来说,当 MyBatis 调用 Mapper 接口方法时,会将对应的 MapperMethod 对象封装成对应的 Invocation 对象传递给代理对象的 invoke 方法,从而通过代理对象回调 MapperProxy 的 invoke 方法。MapperProxy 的 invoke 方法会获取 SqlSession 并根据调用 Mapper 接口方法的相关信息获取对应的 MappedStatement,然后再通过 Executor 和 StatementHandler 将 MappedStatement 中封装的 SQL 语句交给 JDBC 执行,最后将 JDBC 执行结果转化为 Mapper 接口方法执行结果并返回。

代理类 MapperProxy 实现了 InvocationHandler 接口,该接口有一个 invoke() 方法,代理对象在调用某个方法时,都会通过 invoke() 方法回调到具体的处理类中进行处理,从而实现动态代理。具体的 MapperProxy 代码,示例如下:

public class MapperProxy implements InvocationHandler {
    private final SqlSession sqlSession;
    private final Class mapperInterface;

    public MapperProxy(SqlSession sqlSession, Class mapperInterface) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 获取 MapperMethod
        MapperMethod mapperMethod = sqlSession.getMapperMethod(mapperInterface, method);

        // 执行 SQL 并返回结果
        return mapperMethod.execute(sqlSession, args);
    }
}

最终,MyBatis 会动态生成一个实现了 Mapper 接口的代理对象,并将该代理对象返回给调用方使用。这就是 Mapper 接口的工作原理。

你可能感兴趣的:(mybatis,java,代理模式,数据库)