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

第四篇:Configuration对象构建-2

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

第四篇:Configuration对象构建-2

上一篇主要讲了properties、settings、typeAliases三个节点的解析,其实还是比较容易的

这一篇主要讲下这个几个 plugins、factory相关的、environments

话不多说,还是接着看源码

plugins
首先还是先看下使用,具体可以参考官网地址

https://mybatis.org/mybatis-3/zh/configuration.html#plugins


1. 先定义实现了Interceptor接口的实现类

@Intercepts({@Signature(
  type= Executor.class,
  method = "update",
  args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
  private Properties properties = new Properties();

  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    // implement pre processing if need
    Object returnObject = invocation.proceed();
    // implement post processing if need
    return returnObject;
  }

  @Override
  public void setProperties(Properties properties) {
    this.properties = properties;
  }
}


2. 在mybatis-config.xml文件中进行配置


  
    
  


其中properties 到时mybatis会拿到你的配置设置进去



这个主要是mybatis提供给我们进行方法拦截的功能,分页自动拦截就发生在这些插件中




接着看下源码的解析


  private void pluginElement(XNode parent) throws Exception {
    if (parent != null) {
      //循环插件列表
      for (XNode child : parent.getChildren()) {
        //获取拦截器全类名
        String interceptor = child.getStringAttribute("interceptor");
        //获取你配置的属性值,到时会调用Interceptor接口的setProperties传给你定义的拦截器
        Properties properties = child.getChildrenAsProperties();
        //解析拦截器,这里别名就发挥作用了,你可以定义一些简短的名字,在引用的时候就比较方便了
        Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
        interceptorInstance.setProperties(properties);
        //添加到配置类中进行统一管理
        configuration.addInterceptor(interceptorInstance);
      }
    }
  }



仍然是一目了然,其实还是挺简单的,别名注册测就发挥了作用,可以看看resolveClass方法做了什么


  protected Class resolveClass(String alias) {
    if (alias == null) {
      return null;
    }
    try {
      //从别名注册里面解析一个类出来
      return resolveAlias(alias);
    } catch (Exception e) {
      throw new BuilderException("Error resolving class. Cause: " + e, e);
    }
  }


再到具体的解析方法

  protected Class resolveAlias(String alias) {
    //其实就是调用前面的注册map进行获取了
    return typeAliasRegistry.resolveAlias(alias);
  }



再稍微看下configuration里面的Interceptor是如何管理的,后面会再说到这个东西,因为这个是sql运行过程中一个比较核心的拦截点


configuration使用了InterceptorChain对象同时使用了组合模式来统一管理所有的拦截器,如下



public class InterceptorChain {

  
  private final List 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 List getInterceptors() {
    return Collections.unmodifiableList(interceptors);
  }

}



一般进行代理都是使用 Plugin.wrap(target, this);即可,这是mybatis提供的插件代理生成,可以大概看看里面做了什么


  public static Object wrap(Object target, Interceptor interceptor) {
    //获取前面接口
    Map, Set> signatureMap = getSignatureMap(interceptor);
    //获取代理类,通过责任链传输过来的,一层层进行包装
    Class type = target.getClass();
    //获取所有的接口
    Class[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
      //使用jdk进行动态代理,InvocationHandler为Plugin当前这个类
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }


比如上面的 ExamplePlugin 就是一个例子了,这个代理逻辑等后面sql执行的时候再具体分析,当然有兴趣的可以自行分析
factory相关的

这个我们一般不会用,所以只会讲两个比较简单的,如下

官网参考地址:https://mybatis.org/mybatis-3/zh/configuration.html#objectFactory

objectFactory:这个接口是mybatis用来创建对象时候使用的,他提供了一个默认实现DefaultObjectFactory,我们一般不会定义,当然了你也可以进行定义


1,先提供一个实现类

public class ExampleObjectFactory extends DefaultObjectFactory {
  @Override
  public  T create(Class type) {
    return super.create(type);
  }

  @Override
  public  T create(Class type, List> constructorArgTypes, List constructorArgs) {
    return super.create(type, constructorArgTypes, constructorArgs);
  }

  @Override
  public void setProperties(Properties properties) {
    super.setProperties(properties);
  }

  @Override
  public  boolean isCollection(Class type) {
    return Collection.class.isAssignableFrom(type);
  }}


2. 在mybatis-config.xml进行注册


  




这样写后mybatis就会用你的对象工厂来生成对象了,但是我们一般不会自己去定义,当然了如果你有需要也是可以提供的



再来看下源码的解析


  if (context != null) {
      //获取类型
      String type = context.getStringAttribute("type");
      //获取properties
      Properties properties = context.getChildrenAsProperties();
      //依然使用了别名处理器进行解析
      ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
      factory.setProperties(properties);
      //设置给configuration对象
      configuration.setObjectFactory(factory);
    }
  }


就这样,一目了然,没有太多可以说的



至于objectWrapperFactory reflectorFactory这里就不说了,原理都是一样的,我们一般不会去自己设置,有兴趣的话可以自己参考下官网和解析 
environments 

这是环境相关的一个类,主要就是数据源和事务工厂了,不得不说mybatis的抽象还是比我们普通人要好的

官网配置地址:https://mybatis.org/mybatis-3/zh/configuration.html#environments


  
    
      
    
    
      
      
      
      
    
  




这里主要是讲几个比较核心的接口

DataSourceFactory:数据源工厂,用来获取数据源的,想必大家对这个还是比较熟悉的,没错,mybatis自己提供了数据库连接池的实现,接口就这样



public interface DataSourceFactory {

  
  void setProperties(Properties props);

  
  DataSource getDataSource();

}



TransactionFactory:事务工厂,主要是用来获取Transaction事务对象的,看看接口的样子



public interface TransactionFactory {

  
  void setProperties(Properties props);

  
  Transaction newTransaction(Connection conn);
  
  
  Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);

}



Transaction:事务管理对象,用来处理一次事务过程中所需要的属性和对象已经操作的,看到接口的定义你就明白了


public interface Transaction {

  
  Connection getConnection() throws SQLException;

  
  void commit() throws SQLException;

  
  void rollback() throws SQLException;

  
  void close() throws SQLException;

  
  Integer getTimeout() throws SQLException;
  
}


这些方法是不是都很熟悉,就是在一次事务过程中会进行的一些提交....




最后一个对象是 Environment : 也就是环境对象,对于mybatis来说,环境对象就是数据源和事务处理等,如下



public final class Environment {
  private final String id;
  private final TransactionFactory transactionFactory;
  private final DataSource dataSource;

  public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) {
    if (id == null) {
      throw new IllegalArgumentException("Parameter 'id' must not be null");
    }
    if (transactionFactory == null) {
        throw new IllegalArgumentException("Parameter 'transactionFactory' must not be null");
    }
    this.id = id;
    if (dataSource == null) {
      throw new IllegalArgumentException("Parameter 'dataSource' must not be null");
    }
    this.transactionFactory = transactionFactory;
    this.dataSource = dataSource;
  }



上面mybatis就用了很多设计模式:比如抽象工厂、建造者模式等




最后再简单看下源码解析,其实源码解析一直都不难


  private void environmentsElement(XNode context) throws Exception {
    if (context != null) {
      //当前环境没配置的时候拿默认的
      if (environment == null) {
        environment = context.getStringAttribute("default");
      }
      for (XNode child : context.getChildren()) {
        //循环环境,每个环境都有一个id,必须保证不一样即可
        String id = child.getStringAttribute("id");
        //如果是不指定就是上面默认的
        if (isSpecifiedEnvironment(id)) {
          //解析事务工厂
          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
          //解析数据源工厂
          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
          //从数据源工厂获取数据源
          DataSource dataSource = dsFactory.getDataSource();
          //使用建造者模式构建环境对象
          Environment.Builder environmentBuilder = new Environment.Builder(id)
              .transactionFactory(txFactory)
              .dataSource(dataSource);
          //放到configuration进行管理
          configuration.setEnvironment(environmentBuilder.build());
        }
      }
    }
  }



下面的子标签就不看了,都是比较简单的,这里主要是学习隔离的设计,mybatis抽象出了数据源工厂,事务工厂,事务对象等等

好了这一篇就到这里,内容看起来挺多,但是源码看懂并不复杂,复杂的是对mybatis的抽象进行理解,程序的美妙之处是在设计上面,而不是单纯的实现

好的设计可以提供更多的扩展性给其他开发者,而且维护起来也会更方便,基本都是在跟接口打交道进行维护的

这才是我们学习的重点

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

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

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