当前位置: 首页 > news >正文

南宁网站建设招聘上海seo优化公司 kinglink

南宁网站建设招聘,上海seo优化公司 kinglink,wordpress插件扫描,wordpress调用分类文章MyBatis的自定义插件 前置知识 MyBatis 可以拦截的四大组件 Executor - 执行器StatementHandler - SQL 语句构造器ParameterHandler - 参数处理器ResultSetHandler - 结果集处理器 自定义 MyBatis 插件 /*** 打印 sql 执行的时间插件*/ Intercepts(// 指定拦截器拦截的对象…

MyBatis的自定义插件

前置知识

MyBatis 可以拦截的四大组件

  • Executor - 执行器
  • StatementHandler - SQL 语句构造器
  • ParameterHandler - 参数处理器
  • ResultSetHandler - 结果集处理器

自定义 MyBatis 插件

/*** 打印 sql 执行的时间插件*/
@Intercepts(// 指定拦截器拦截的对象、方法和参数类型{@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})}
)
// 注册到 Spring 容器,不是 Spring 环境的话可以用 mybatis 的 config 配置进去
@Component
public class SqlExecuteTimePrintMybatisPlugin implements Interceptor {protected Logger logger = LoggerFactory.getLogger(SqlExecuteTimePrintMybatisPlugin.class);@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 获取代理对象StatementHandler statementHandler = (StatementHandler) invocation.getTarget();// 获取执行 sqlBoundSql boundSql = statementHandler.getBoundSql();// 此处简单处理一下,只打印参数替换前的 sql,目的是演示自定义插件String sql = boundSql.getSql();long start = System.currentTimeMillis();try {return invocation.proceed();} finally {logger.info("sql -> {}, takes time -> {}", sql, System.currentTimeMillis() - start);}}
}

效果如下

2023-10-14 17:18:39.297  INFO 25972 --- [p-nio-80-exec-1] c.y.m.c.SqlExecuteTimePrintMybatisPlugin : sql -> SELECT * FROM `INFO` WHERE `id` = ? , takes time -> 57
2023-10-14 17:18:39.324  INFO 25972 --- [p-nio-80-exec-1] c.y.m.c.SqlExecuteTimePrintMybatisPlugin : sql -> SELECT `id`, `info_id`, `extend_info` FROM `INFO_DETAIL` WHERE `info_id` = ?, takes time -> 4

源码解析

创建四大对象的代码如下

public class 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) {return newExecutor(transaction, defaultExecutorType);}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;}
}
  1. 首先在创建 Executor、StatementHandler、ParameterHandler、ResultSetHandler 四个对象时,将插件(plugins)注入

  2. 调用 InterceptorChain.pluginAll() 方法将插件增加到责任链,并返回代理后的 target 包装对象,InterceptorChain 保存了所有的拦截器(Interceptors)

  3. 最终在执行的时候调用的其实是 JDK 动态代理的对象,执行 MyBatis 中 InvocationHandler 的实现 org.apache.ibatis.plugin.Plugin 的 invoke 方法

public class InterceptorChain {private final List<Interceptor> interceptors = new ArrayList<>();public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target = interceptor.plugin(target);}return target;}
}
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}}
public class Plugin implements InvocationHandler {private final Object target;private final Interceptor interceptor;private final Map<Class<?>, Set<Method>> signatureMap;private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {this.target = target;this.interceptor = interceptor;this.signatureMap = signatureMap;}public static Object wrap(Object target, Interceptor interceptor) {Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);Class<?> type = target.getClass();Class<?>[] interfaces = getAllInterfaces(type, signatureMap);if (interfaces.length > 0) {// jdk 动态代理return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target, interceptor, signatureMap));}return target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// 获取插件中生命要增强的方法Set<Method> 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);}}...
}

备注

不明白的需要去看下 JDK 动态代理实现原理,概括的来讲就是 Proxy#newProxyInstance 时,通过字节码增强的方法,生成一个实现了跟被代理类相同接口并继承了 java.lang.reflect.Proxy 的类并返回其实例,调用这个代理类的方法时,实际上调用的是 Proxy.InvocationHandler.invoke(this, method, new Object[]{args}) 方法

http://www.hkea.cn/news/457357/

相关文章:

  • python做网站需要什么seo学习论坛
  • 用手机怎样制作网站网络seo是什么
  • 企业网站开发信息搜索大全浏览器
  • 做虚拟货币交易网站域名注册平台有哪些
  • 企业网站首页的实现专业的网页制作公司
  • 动态网站建设教程宝鸡seo排名
  • 做外贸b2b免费网站优化推广网站排名
  • 丹徒网站建设价格香港服务器
  • 宿迁哪里有做网站开发的信息流广告案例
  • 电脑网页无法访问如何解决北京seo地址
  • 直销网站系统制作价格java培训机构
  • dw软件个人简历网站怎么做百度导航下载2022最新版官网
  • 成都官方网站建设泉州seo外包
  • 矿山建设网站天津网络推广seo
  • 国内优秀的响应式网站深圳专业seo外包
  • 重庆装修价格c盘优化大师
  • 银行网站 设计方案外包优化网站
  • 做网站是学什么专业软件外包企业排名
  • wordpress商城 中文站百度站长平台网址
  • 建手机网站的软件有哪些南宁百度seo价格
  • 做网站私活长沙网络营销公司
  • 网站建设公司 广告法被处罚沧州网络推广外包公司
  • 电商网站 开发成本惠州seo外包服务
  • 佛山做网站建设价格百度网盘官方下载
  • 网上购物商城网站建设个人免费域名注册网站
  • 成都学网站建设电子营销主要做什么
  • 织梦cms通用蓝白简介大气企业网站环保科技公司源码网络推广员招聘
  • 网站后台怎么添加图片视频app推广
  • 网站秒收录怎么做的经典软文案例和扶贫农产品软文
  • 珠海疫情最新情况厦门搜索引擎优化