网站建设的用户体验,建设网站以什么为导向,北京最大的火车站,帮人做彩票网站插件使用
动手实现plugin
首先我们需要实现一下这个Interceptor#xff0c;其中plugin和setProperties方法可以不实现#xff0c;plugin是因为已经有了完善的逻辑#xff0c;而setProperties#xff0c;如果不需要在intercept()中使用属性#xff0c;也可以不设置。然后…插件使用
动手实现plugin
首先我们需要实现一下这个Interceptor其中plugin和setProperties方法可以不实现plugin是因为已经有了完善的逻辑而setProperties如果不需要在intercept()中使用属性也可以不设置。然后在实现类中完成注解配置
public interface Interceptor {Object intercept(Invocation invocation) throws Throwable;default Object plugin(Object target) {return Plugin.wrap(target, this);}default void setProperties(Properties properties) {// NOP}}
以下是一个实现demo
Intercepts({Signature(type StatementHandler.class,method prepare,args {Connection.class, Integer.class}
), 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}
), Signature(type Executor.class,method query,args {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
)})
public class testMybatisInterceptor implements Interceptor {private Properties properties;Overridepublic Object intercept(Invocation invocation) throws Throwable {return invocation.proceed();}Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}Overridepublic void setProperties(Properties properties) {this.properties properties;}public Properties getProperties() {return properties;}}向容器注入该interceptor
可以通过两种方式 一种是Bean注入
Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {return new testMybatisInterceptor();
}另一种是xml注入目前比较少用了
pluginsplugin interceptorcom.testMybatisInterceptor/plugin
/plugins拦截器原理
public class InterceptorChain {private final ListInterceptor interceptors new ArrayList();public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target interceptor.plugin(target);}return target;}public void addInterceptor(Interceptor interceptor) {interceptors.add(interceptor);}public ListInterceptor getInterceptors() {return Collections.unmodifiableList(interceptors);}}拦截器的添加
初始化的添加
Configuration是mybatis的核心初始化数据承装容器在一开始它就会创建一个InterceptorChain后期所有添加和过滤都是在这个InterceptorChain上操作的。
public class InterceptorChain {private final ListInterceptor interceptors new ArrayList();public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target interceptor.plugin(target);}return target;}public void addInterceptor(Interceptor interceptor) {interceptors.add(interceptor);}public ListInterceptor getInterceptors() {return Collections.unmodifiableList(interceptors);}}Bean
Bean只是本人的猜测mybatis应该会添加一个beanPostProcessor对于当前bean是否拥有interceptors注解进行扫描如果有就会把这个bean放入Configuration
XML
在解析XML的时候就会把拦截器添加进configuration private void pluginElement(XNode parent) throws Exception {if (parent ! null) {for (XNode child : parent.getChildren()) {String interceptor child.getStringAttribute(interceptor);Properties properties child.getChildrenAsProperties();Interceptor interceptorInstance (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();interceptorInstance.setProperties(properties);configuration.addInterceptor(interceptorInstance);}}}初始化Handler时的设置
在完成newParameter的时候就会对Handler进行拦截器封装。封装的过程就是使用代理模式invokeHandler就是 public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject,BoundSql boundSql) {ParameterHandler parameterHandler mappedStatement.getLang().createParameterHandler(mappedStatement,parameterObject, boundSql);return (ParameterHandler) interceptorChain.pluginAll(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);return (ResultSetHandler) interceptorChain.pluginAll(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);return (StatementHandler) interceptorChain.pluginAll(statementHandler);}public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType executorType null ? defaultExecutorType : 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);}return (Executor) interceptorChain.pluginAll(executor);}在pluginAll中会对每一个Interceptor进行接口拦截 public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target interceptor.plugin(target);}return target;}target就是以上某种Handler或者Executorinterceptor就是当前遍历的执行器 public static Object wrap(Object target, Interceptor interceptor) {MapClass?, SetMethod signatureMap getSignatureMap(interceptor);Class? type target.getClass();Class?[] interfaces getAllInterfaces(type, signatureMap);if (interfaces.length 0) {return Proxy.newProxyInstance(type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap));}return target;}其中getSignatureMap就是把注解转化为map供以后调用使用里面的key就是type而value就是prepare(Connection,Integer)这个方法。
Intercepts({Signature(type StatementHandler.class,method prepare,args {Connection.class, Integer.class}
)})在invoke方法中会先检查这个方法是否通过注解注册过如果是注册的方法就会调用intercept方法并且把当前handler当前方法和方法参数返回给interceptor完成后续业务操作。 Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {SetMethod 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);}}处理拦截器
对应Handler在调用方法时会调用intercept()如果通过会调用method.invoke()进行真正的代码执行如果在拦截器模式下由于是代理模式套代理模式层层循环所以实际上是调用了第二个代理器的intercept()直到完全调用完才会进入最内层的被代理对象的源方法。
Override
public Object intercept(Invocation invocation) throws Throwable {return invocation.proceed();
}public Object proceed() throws InvocationTargetException, IllegalAccessException {return method.invoke(target, args);
}