MyBatis源码学习(代理模式)

代理模式

定义:

  • 代理对象具有和目标对象(真实业务对象)相同的方法,即实现共同的接口或继承同一个类
  • 代理对象持有目标对象的引用,并由代理对象控制对目标对象的操作

代理模式属于结构型模式,它在不改变目标类代码的情况下,通过引入代理类来给目标类附加功能。

Mybatis框架中,SqlSession类就用到了代理模式,SqlSession是操作数据库一个会话对象,我们用户一般通过SqlSession做增删改查,但是如果每次做增删改都开启事务,关闭事务,显然很麻烦,所以就可以交给代理类来完成这个工作,如果没有开启事务,由代理类自动开启事务

Mybatis使用的JDK动态代理,SqlSession接口定义如下。

public interface SqlSession extends Closeable {
    
    <T> T selectOne(String statement);

    <E> List<E> selectList(String statement);

    <E> List<E> selectList(String statement, Object parameter);

    <K, V> Map<K, V> selectMap(String statement, String mapKey);

    <T> Cursor<T> selectCursor(String statement);

    void select(String statement, Object parameter, ResultHandler handler);

    int insert(String statement);

    int update(String statement);

    int delete(String statement);

    void commit();

    void rollback();
    //省略...
}

动态代理的关键在于以下两点

  • 代理类对象的创建
  • InvocationHandler实现类: 持有真实目标对象,将方法调用请求分派 给真实目标对象执行

我们知道动态代理需要一个实现InvocationHandler接口的类,用于自定义代理增强处理逻辑,这个类在SqlSessionManager里,是一个内部类,叫做SqlSessionInterceptor,在这个类里做相关的处理。

private class SqlSessionInterceptor implements InvocationHandler {
    public SqlSessionInterceptor() {
        // Prevent Synthetic Access
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //获取 真实目标SqlSession对象,localSqlSession是一个ThreadLocal,所以是每个线程有自己的sqlSession
        final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
        
        if (sqlSession != null) {
            try {
                //执行方法,返回结果  
                return method.invoke(sqlSession, args);
            } catch (Throwable t) {
                throw ExceptionUtil.unwrapThrowable(t);
            }
            //如果sqlsession为null
        } else {
            //打开session  
            final SqlSession autoSqlSession = openSession();
            try {
                //执行Sqlsession的方法,获得结果  
                final Object result = method.invoke(autoSqlSession, args);
                //commit提交事务
                autoSqlSession.commit();
                //返回结果
                return result;
            } catch (Throwable t) {
                //rollback回滚事务
                autoSqlSession.rollback();
                //抛出异常
                throw ExceptionUtil.unwrapThrowable(t);
            } finally {
                //关闭sqlsession
                autoSqlSession.close();
            }
        }
    }
}

在SqlSessionManager 中,创建了代理类sqlSessionProxy对象,重写了SqlSession接口的所有方法,统一调用代理类去执行;

//实现了SqlSessionFactory,SqlSession接口
public class SqlSessionManager  implements SqlSessionFactory, SqlSession {

    private final SqlSessionFactory sqlSessionFactory;
    //代理类sqlSessionProxy
    private final SqlSession sqlSessionProxy;

    private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
        // 创建代理类对象
        this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
            SqlSessionFactory.class.getClassLoader(),
            new Class[]{SqlSession.class},
            new SqlSessionInterceptor());
    }
    //提供静态方法给外部获取SqlSessionManager实例
    public static SqlSessionManager newInstance(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionManager(sqlSessionFactory);
    }
    
    //重写selectOne方法,使用代理类去执行
    @Override
    public <T> T selectOne(String statement) {
        return sqlSessionProxy.<T> selectOne(statement);
    }
    
    //重写insert方法,使用代理类去执行
    @Override
    public int insert(String statement) {
        return sqlSessionProxy.insert(statement);
    }
    //省略...
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值