纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

mybatis扩展实现 mybatis中的扩展实现源码解析

此生重演   2021-03-30 我要评论

前言

最近项目中需要用到mybatis的扩展就深入看了下mybatis的实现对其灵活性和扩展性的设计思想还是非常佩服的

首先说一下mybatis的拦截器使用方法:继承其Intercepter接口实现org.apache.ibatis.plugin.Interceptor#intercept方法在其中或者对其要执行的方法进行拦截或者对返回值进行解析

同时基于org.apache.ibatis.plugin.Interceptsorg.apache.ibatis.plugin.Signature这两个注解来决定对哪些执行器的哪些方法进行拦截

先看下拦截器的核心接口

public interface Interceptor {
 
 Object intercept(Invocation invocation) throws Throwable;
 
 Object plugin(Object target);
 
 void setProperties(Properties properties);
 
}

其中intercept方法是核心方法拦截器的实现plugin方法是用于配置哪些对哪些执行器进行拦截

继续看源码可以看到mybatis的拦截是使用了jdk的动态代理实现的本质上是一种代理机制

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) {
  return Proxy.newProxyInstance(
   type.getClassLoader(),
   interfaces,
   new Plugin(target, interceptor, signatureMap));
 }
 return target;
 }
 
 @Override
 public 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);
 }
 }
 
 ......
}

mybatis的这个Plugin就是代理类这个代理类是在org.apache.ibatis.plugin.Interceptor#plugin方法中初始化的(调用org.apache.ibatis.plugin.Plugin#wrap)一个Plugin包含一个Intercepter以及该Intercepter相关的注解配置信息当对拦截对象的对应方法进行执行的时候都会根据这些注解配置来判断是否需要执行该代理拦截(org.apache.ibatis.plugin.Plugin#invoke

再看下plugin是如何被加载的:

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);
 }
 
}

org.apache.ibatis.plugin.Interceptor#plugin是在org.apache.ibatis.plugin.InterceptorChain#pluginAll方法中调用的我们可以看到如果一个应用中注册了多个拦截器那么实际上是会进行一个for循环的加载由于上面说到了加载一次本质上是对mybatis的执行期进行一次代理包装那么加载多次的话就会代理包装多次实际上就是一种多重代理了这样就保证了每次调用都会按照代理顺序进行调用和返回的处理

可以看到在做这些mybatis执行器初始化的时候都会进行拦截器链的加载

至此mybatis基于jdk动态代理的扩展实现方法就了解清楚了其灵活性在于它抽象了执行器的概念并且拦截器的拦截方法也是固定的我们可以对不同执行器的不同方法进行拦截而对这些扩展点进行扩展却不用写多个方法实现多个方法只需要实现一个接口就可以搞定了!

总结

以上就是这篇文章的全部内容了希望本文的内容对大家的学习或者工作具有一定的参考学习价值如果有疑问大家可以留言交流谢谢大家对的支持。


相关文章

猜您喜欢

网友评论

Copyright 2020 www.Shellfishsoft.com 【贝软下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式