栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

代理模式在Jeesuite框架中的使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

代理模式在Jeesuite框架中的使用

上一篇解析Jeesuite框架中mybatis拦截器的使用讲到拦截器添加到了sqlSessionFactory的配置类sqlSessionFactory.getConfiguration().addInterceptor(interceptor)

那么拦截器是何时执行以及如何生效的呢?

这个实际上是添加到配置类Configuration的interceptorChain属性了

interceptorChain.addInterceptor(interceptor);

我们先来看这个拦截器接口

public interface Interceptor {

  Object intercept(Invocation invocation) throws Throwable;

  Object plugin(Object target);

  void setProperties(Properties properties);

}

关键的是这个intercept()方法,就是执行拦截逻辑的.它的的实现类里做了三件事情.

1.循环执行拦截器的处理类,调用拦截器onInterceptor()

2.执行原有方法逻辑

3.执行拦截器处理类的结束方法

@Override
public Object intercept(Invocation invocation) throws Throwable {
		
		Object result = null;
		boolean proceed = false;
		for (InterceptorHandler handler : interceptorHandlers) {
			result = handler.onInterceptor(invocation);
			if(result != null)break;
		}
		
		if(result == null){
			result = invocation.proceed();
			proceed = true;
		}
		
		for (InterceptorHandler handler : interceptorHandlers) {
			handler.onFinished(invocation,proceed ? result : null);
		}
		
		return result;
	}

我们在看看它在哪被调用的它在Plugin的invoke()方法中被调用

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      Set methods = signatureMap.get(method.getDeclaringClass());
      if (methods != null && methods.contains(method)) {
        return interceptor.intercept(new Invocation(target, method, args));
      }
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }
这个Plugin实现了 InvocationHandler.

当执行一个sql的时候,例如

thirdpayChannelacctMapper.selectByPrimaryKey(channelId)

debug的时候thirdpayChannelacctMapper就是MapperProxy代理类了

此时是由MapperProxy类来代理的,调用org.apache.ibatis.binding.MapperProxy#invoke方法来处理.我们看其构造方法的参数,sqlSession,mapper接口,以及方法.

MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache)

然后调用了org.apache.ibatis.binding.MapperMethod#execute(),在这里看到了我们熟悉的sqlSession.selectOne()方法

result = sqlSession.selectOne(command.getName(), param);

然后往下看,并不是直接使用,还是用代理sqlSessionProxy处理,

this.sqlSessionProxy. selectOne(statement, parameter);

然后执行拦截器SqlSessionInterceptor方法

org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke

然后执行方法,返回结果.

Object result = method.invoke(sqlSession, args);

最后是Executor执行的结果.Executor分baseExecutor和CachingExecutor.

像简单sql就是通过baseExecutor的子类SimpleExecutor来执行,这里调用了prepareStatement()方法,获取了Statement用于后续执行sql.
stmt = prepareStatement(handler, ms.getStatementLog());
  @Override
  public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
然后baseStatementHandler的子类PreparedStatementHandler处理
@Override
public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
  PreparedStatement ps = (PreparedStatement) statement;
  ps.execute();
  return resultSetHandler. handleResultSets(ps);
}

早前,我们使用jdbc也是使用PreparedStatement来执行sql的

Connection connection = DriverManager.getConnection(url, username, password);
String sql = "update user set username='admin' where id = 1";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
int result = preparedStatement.executeUpdate();

上面提到了prepareStatement()方法,也是获取connection,初始化statement.

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection, transaction.getTimeout());
    handler.parameterize(stmt);
    return stmt;
  }

handler.parameterize(stmt)是用于设置sql参数,替换掉参数的占位符.DefaultParameterHandler是ParameterHandler接口的默认实现.

查询到结果后就是结果的处理

resultSetHandler. handleResultSets(ps);

需要用到另一种handler是ResultSetHandler,只有一个默认实现DefaultResultSetHandler

 实现ResultSetHandler这个接口也可以自定义结果处理类.至此,流程结束.

总结一下:

MapperProxy#invoke

MapperMethod#execute()

sqlSession.selectList()

SqlSessionTemplate#selectList(java.lang.String, java.lang.Object)

this.sqlSessionProxy. selectList(statement, parameter)

DefaultSqlSession#selectList(java.lang.String, java.lang.Object)

CachingExecutor#query()开启缓存就会先调这个,如果缓存为空就调SimpleExecutor

SimpleExecutor#doQuery

RoutingStatementHandler#query 

PreparedStatementHandler#query

PreparedStatement.execute()

RoutingStatementHandler这里做了个路由

switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}

那怎么知道是什么类型呢?DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds) 这个方法里自动创建了

MappedStatement ms = configuration.getMappedStatement(statement);

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/329143.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号