标签:
mybatis支持插件来插入自定制的处理过程,所有的plugin都需实现Interceptor接口,自定制的处理过程可以在Executor,ParameterHandler,ResultSetHandler,StatementHandler四个处理过程中插入,原理是在使用这四中类型处理数据的时候使用的都是经过plugin处理过的代理对象。同一个处理过程支持配置多个plugin,则plugin的执行顺序是根据包装的顺序,从最外部向内部执行,直到执行到目标对象的调用方法。包装的顺序是根据配置顺序,也就是说配置越靠前,包装的越深,越后执行
interceptor源码:
1 public interface Interceptor { 2 3 Object intercept(Invocation invocation) throws Throwable; //代理对象中调用的插件的自定制代码 4 5 Object plugin(Object target); //生成插件处理过的代理对象 6 7 void setProperties(Properties properties); 8 9 }
得到Executor对象的源码:
SqlSessionFactory#openSqlSession:得到SqlSession
1 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { 2 Transaction tx = null; 3 try { 4 final Environment environment = configuration.getEnvironment(); 5 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); 6 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); 7 final Executor executor = configuration.newExecutor(tx, execType); 8 return new DefaultSqlSession(configuration, executor, autoCommit); 9 } catch (Exception e) { 10 closeTransaction(tx); // may have fetched a connection so lets call close() 11 throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); 12 } finally { 13 ErrorContext.instance().reset(); 14 } 15 }
得到StatementHandler对象的源码:
Executor:
1 public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { 2 Configuration configuration = ms.getConfiguration(); 3 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); 4 Statement stmt = prepareStatement(handler, ms.getStatementLog()); 5 return handler.<E>query(stmt, resultHandler); 6 }
得到ParameterHandler和ResultSetHandler对象的源码:
BaseStatementHandler:
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { this.configuration = mappedStatement.getConfiguration(); this.executor = executor; this.mappedStatement = mappedStatement; this.rowBounds = rowBounds; this.typeHandlerRegistry = configuration.getTypeHandlerRegistry(); this.objectFactory = configuration.getObjectFactory(); if (boundSql == null) { // issue #435, get the key before calculating the statement generateKeys(parameterObject); boundSql = mappedStatement.getBoundSql(parameterObject); } this.boundSql = boundSql; this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql); this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql); }
可以看到,都使用的Configuration对象创建这四中对象实例
Configuration:
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) { ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql); parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler); return parameterHandler; } public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) { ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds); resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler); return resultSetHandler; } public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; } public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
可以看到使用的是interceptorChain来处理创建的对象
InterceptorChain:
public class InterceptorChain { private final List<Interceptor> interceptors = new ArrayList<Interceptor>(); public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target; } public void addInterceptor(Interceptor interceptor) { interceptors.add(interceptor); } public List<Interceptor> getInterceptors() { return Collections.unmodifiableList(interceptors); } }
可以看到调用的是interceptor接口子类对象的plugin方法来处理目标对象,interceptor接口子类对象是在XMLConfigBuilder解析mybatis-config.xml配置文件时添加的,源码:
XMLConfigBuilder:
1 private void pluginElement(XNode parent) throws Exception { 2 if (parent != null) { 3 for (XNode child : parent.getChildren()) { 4 String interceptor = child.getStringAttribute("interceptor"); 5 Properties properties = child.getChildrenAsProperties(); 6 Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance(); 7 interceptorInstance.setProperties(properties); 8 configuration.addInterceptor(interceptorInstance); 9 } 10 } 11 }
Configuration:
1 public void addInterceptor(Interceptor interceptor) { 2 interceptorChain.addInterceptor(interceptor); //protected final InterceptorChain interceptorChain = new InterceptorChain() 3 }
时序图:
插件实例(tracer系统中打印sql执行过程日志):
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class}), @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }) }) public class MybatisLogPlugin implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { LogFoot logFoot = new LogFoot(); doBeforeInvocation(logFoot); Object result =""; try{ result = invocation.proceed(); doAfterInvocation(logFoot,invocation,true,result); }catch(Exception e){ doAfterInvocation(logFoot,invocation,false,e); throw e; } return result; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); //mybatis提供的包装工具类 } @Override public void setProperties(Properties properties) { } private void doBeforeInvocation(LogFoot logFoot){ //注意这里的逻辑:这个拦截入口是HTTP或者RPC,把之前的Threadlocal中context清空 //fix me:非常小心 theadlocal和线程池同时使用时会有问题,线程会重复利用导致context会重复利用 if(LogContext.get()==null){ LogContext.set(new LogContext()); } Long startTimeMillis = System.currentTimeMillis(); // 记录方法开始执行的时间 logFoot.setId(LogContext.get().getRequestId()); logFoot.setStartTimeMillis(startTimeMillis); String optTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTimeMillis); logFoot.setOptTime(optTime); //step 递增 int seqID= LogContext.get().addSequence(); logFoot.setSequence(seqID); } private void doAfterInvocation(LogFoot logFoot,Invocation invocation,Boolean succ,Object result){ logFoot.setType(LogTypeEnum.RESOURCE_MYSQL.getValue()); Object[] arguments = invocation.getArgs(); String sql =getSqlStatement(arguments); logFoot.setArguments(new Object[]{sql}); //调用的方法名 String method=invocation.getMethod().toString(); logFoot.setMethod(method); String JVM =JVMUtil.getJVMName(); logFoot.setJvmname(JVM); String local_ip =IPAddrUtil.localAddress(); logFoot.setLocal_ip(local_ip); Long thread = Thread.currentThread().getId(); logFoot.setThread(thread.toString()); logFoot.setSucc(succ); //logFoot.doPrint(); // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行 Map<String, Object> outputParamMap = new HashMap<String, Object>(); outputParamMap.put("result", result); logFoot.setOutputParamMap(outputParamMap); Long endTimeMillis = System.currentTimeMillis(); // 记录方法执行完成的时间 logFoot.setEndTimeMillis(endTimeMillis); logFoot.doPrint(); } private String getSqlStatement(Object[] arguments){ MappedStatement mappedStatement = (MappedStatement) arguments[0]; Object parameter = null; if (arguments.length > 1) { parameter = arguments[1]; } String sqlId = mappedStatement.getId(); BoundSql boundSql = mappedStatement.getBoundSql(parameter); Configuration configuration = mappedStatement.getConfiguration(); String sql = showSql(configuration, boundSql); StringBuilder str = new StringBuilder(100); str.append(sqlId); str.append(":"); str.append(sql); str.append(":"); return str.toString(); } public String showSql(Configuration configuration, BoundSql boundSql) { Object parameterObject = boundSql.getParameterObject(); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); String sql = boundSql.getSql().replaceAll("[\\s]+", " "); if (parameterMappings.size() > 0 && parameterObject != null) { TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { sql = sql.replaceFirst("\\?", getParameterValue(parameterObject)); } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); for (ParameterMapping parameterMapping : parameterMappings) { String propertyName = parameterMapping.getProperty(); if (metaObject.hasGetter(propertyName)) { Object obj = metaObject.getValue(propertyName); sql = sql.replaceFirst("\\?", getParameterValue(obj)); } else if (boundSql.hasAdditionalParameter(propertyName)) { Object obj = boundSql.getAdditionalParameter(propertyName); sql = sql.replaceFirst("\\?", getParameterValue(obj)); } } } } return sql; } private static String getParameterValue(Object obj) { String value = null; if (obj instanceof String) { value = "‘" + obj.toString() + "‘"; } else if (obj instanceof Date) { DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA); value = "‘" + formatter.format(new Date()) + "‘"; } else { if (obj != null) { value = obj.toString(); } else { value = ""; } } return value; } }
mybatis的Plugin源码:
1 public class Plugin implements InvocationHandler { 2 3 private Object target; 4 private Interceptor interceptor; 5 private Map<Class<?>, Set<Method>> signatureMap; 6 7 private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) { 8 this.target = target; 9 this.interceptor = interceptor; 10 this.signatureMap = signatureMap; 11 } 12 13 public static Object wrap(Object target, Interceptor interceptor) { 14 Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor); 15 Class<?> type = target.getClass(); 16 Class<?>[] interfaces = getAllInterfaces(type, signatureMap); 17 if (interfaces.length > 0) { 18 return Proxy.newProxyInstance( 19 type.getClassLoader(), 20 interfaces, 21 new Plugin(target, interceptor, signatureMap)); 22 } 23 return target; 24 } 25 26 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 27 try { 28 Set<Method> methods = signatureMap.get(method.getDeclaringClass()); 29 if (methods != null && methods.contains(method)) { //先执行plugin中的方法,最后再执行目标对象调用的方法 30 return interceptor.intercept(new Invocation(target, method, args)); 31 } 32 return method.invoke(target, args); 33 } catch (Exception e) { 34 throw ExceptionUtil.unwrapThrowable(e); 35 } 36 } 37 38 private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) { 39 Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class); 40 if (interceptsAnnotation == null) { // issue #251 41 throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName()); 42 } 43 Signature[] sigs = interceptsAnnotation.value(); 44 Map<Class<?>, Set<Method>> signatureMap = new HashMap<Class<?>, Set<Method>>(); 45 for (Signature sig : sigs) { 46 Set<Method> methods = signatureMap.get(sig.type()); 47 if (methods == null) { 48 methods = new HashSet<Method>(); 49 signatureMap.put(sig.type(), methods); 50 } 51 try { 52 Method method = sig.type().getMethod(sig.method(), sig.args()); 53 methods.add(method); 54 } catch (NoSuchMethodException e) { 55 throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e); 56 } 57 } 58 return signatureMap; 59 } 60 61 private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) { 62 Set<Class<?>> interfaces = new HashSet<Class<?>>(); 63 while (type != null) { 64 for (Class<?> c : type.getInterfaces()) { 65 if (signatureMap.containsKey(c)) { 66 interfaces.add(c); 67 } 68 } 69 type = type.getSuperclass(); 70 } 71 return interfaces.toArray(new Class<?>[interfaces.size()]); 72 } 73 74 }
标签:
原文地址:http://www.cnblogs.com/stefanking/p/5114175.html