代理模式
定义:
- 代理对象具有和目标对象(真实业务对象)相同的方法,即实现共同的接口或继承同一个类
- 代理对象持有目标对象的引用,并由代理对象控制对目标对象的操作
代理模式属于结构型模式,它在不改变目标类代码的情况下,通过引入代理类来给目标类附加功能。
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);
}
//省略...
}