MyBatis源码分析

  • Post author:
  • Post category:其他

1.使用步骤

        //加载核心配置文件
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        //解析配置文件得到SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

        //得到sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //获取Mapper接口对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //测试
        int res = mapper.insertUser();
        System.out.println(res);

2.加载核心配置文件

 InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

Resources类提供了多种获取资源文件的方法:

 

我们选择了其中一种方法: getResourceAsStream(String resource)

跟踪该方法发现其间接调用了以下方法:

//Resources类中的方法
public static InputStream getResourceAsStream(String resource) throws IOException {
    //直接调用重载方法
    return getResourceAsStream(null, resource);
  }
 
 public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
    //classLoaderWrapper是Resources类的一个成员属性
    InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
    if (in == null) {
      throw new IOException("Could not find resource " + resource);
    }
    return in;
  }

//classLoaderWrapper类中的方法
  public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
    //直接调用重载方法
    return getResourceAsStream(resource, getClassLoaders(classLoader));
  }

//返回一个类加载器数组
  ClassLoader[] getClassLoaders(ClassLoader classLoader) {
    return new ClassLoader[]{
        classLoader,//参数传入的加载器
        defaultClassLoader,//当前类的成员属性加载器
        Thread.currentThread().getContextClassLoader(),
        getClass().getClassLoader(),//加载当前类的类加载器
        systemClassLoader};//当前类的成员属性加载器,构造方法时初始化为systemClassLoader
  }

   //遍历该加载器数组,通过类加载器的getResourceAsStream方法得到InputStream对象
  InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
    for (ClassLoader cl : classLoader) {
      if (null != cl) { //遍历该 加载器类数组,找到第一个不为空的加载器对象,调用它的getResourceAsStream方法得到InputStream对象

        // try to find the resource as passed
        InputStream returnValue = cl.getResourceAsStream(resource);

        // now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
        if (null == returnValue) {
          returnValue = cl.getResourceAsStream("/" + resource);
        }

        if (null != returnValue) {
          return returnValue;
        }
      }
    }
    return null;
  }

总结 :  InputStream is = Resources.getResourceAsStream(“mybatis-config.xml”);该代码底层通过调用类加载器的getResourceAsStream方法获取到InputStream对象并返回。

2. 解析配置文件得到SqlSessionFactory对象

 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

类SqlSessionFactoryBuilder:

该类中的所有方法都是build方法的重载,主要对字符流,字节流,Configuration进行处理。

跟进我们使用的这个方法:

public SqlSessionFactory build(InputStream inputStream)

间接调用了如下方法 : 

SqlSessionFactoryBuilder 的部分源码


public SqlSessionFactory build(InputStream inputStream) {
//直接调用重载方法
    return build(inputStream, null, null);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
    //创建一个XMLConfigBuilder对象
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
    //调用处理Configuration的build方法,parser.parse()方法返回一个Configuration对象
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

XMLConfigBuilder的部分源码 

XMLConfigBuilder继承自BaseBuilder,BaseBuilder类有许多以Builder结尾的子类,这里使用了建造者模式。

public class XMLConfigBuilder extends BaseBuilder

XMLConfigBuilder部分源码: 

  private boolean parsed;
  private final XPathParser parser;
  private String environment;

  public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
    //调用下面的重载构造方法
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
  }

  private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration()); //初始化父类
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    //初始化当前类的三个属性
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }

  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

//该方法为Configuration设置属性值,通过调用不同的方法读取xml配置来设置对应的属性
//Configuration存放着Mybatis的所有配置信息
 private void parseConfiguration(XNode root) {
    try {
      // issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      loadCustomLogImpl(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

XPathParser 类的部分源码:

  private final Document document;
  private boolean validation;
  private EntityResolver entityResolver;
  private Properties variables;
  private XPath xpath;
 
 public XNode evalNode(String expression) {
    return evalNode(document, expression);
  }

  public XNode evalNode(Object root, String expression) {
    Node node = (Node) evaluate(expression, root, XPathConstants.NODE);
    if (node == null) {
      return null;
    }
    return new XNode(this, node, variables);
  }


 

 


 

 

 


版权声明:本文为weixin_52907605原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。