mybatis源码总结--快速入门(1)

首先在此声明,本人是通过学习 湖畔微风《深入浅出mybatis》基础之上对代码进行总结。

《深入浅出mybatis》 http://blog.csdn.net/hupanfeng/article/details/9068003

 一、mybatis解析配置文件

SqlSessionFactoryBuilder类是mybatis的入口,在创建SqlSeesionFactory时会解析配置文件,将文件中的信息保存在Configuration对象中。

其中的类XmlConfigureBulider类其中,调用XPathParser类的parse方法,获取configuration根节点并调用parseConfiguration方法,XPathParser为解析xml的核心类

 public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
parseConfiguration方法相当于一个中转站,它获取configuration下不同的子节点,并调用相应的方法去解析

 private void parseConfiguration(XNode root) {
    try {
      propertiesElement(root.evalNode("properties")); //issue #117 read properties first
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      settingsElement(root.evalNode("settings"));
      environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
      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);
    }
  }
上述两个方法中都用到了evalNode方法返回Xnode类,其中evaluate方法获取目标结节点,并创建XNode 类

  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);
  }
Xnode中的构造方法,解析了节点属性和所有子节点
构造方法:
 public XNode(XPathParser xpathParser, Node node, Properties variables) {
    this.xpathParser = xpathParser;
    this.node = node;
    this.name = node.getNodeName();
    this.variables = variables;
    this.attributes = parseAttributes(node);
    this.body = parseBody(node);
  }

解析属性:

扫描二维码关注公众号,回复: 10711852 查看本文章

private Properties parseAttributes(Node n) {
    Properties attributes = new Properties();
    NamedNodeMap attributeNodes = n.getAttributes();
    if (attributeNodes != null) {
      for (int i = 0; i < attributeNodes.getLength(); i++) {
        Node attribute = attributeNodes.item(i);
        String value = PropertyParser.parse(attribute.getNodeValue(), variables);
        attributes.put(attribute.getNodeName(), value);
      }
    }
    return attributes;
  }
获取所有子节点:

 private String parseBody(Node node) {
    String data = getBodyData(node);
    if (data == null) {
      NodeList children = node.getChildNodes();
      for (int i = 0; i < children.getLength(); i++) {
        Node child = children.item(i);
        data = getBodyData(child);
        if (data != null) break;
      }
    }
    return data;
  }

总结:(1)通过学习源代码了解解析流程

            (2)学习一下解析XML程序设计的思路。mybatis设计解析xml符合开闭原则,如果以后配置文件要在configuration节点下增加新的子节点,只需增加相应的解析方法,其它地方基本不用修改。如果已存在的子节点中内容有修改,只需修改不同子节点相应的方法,不会对其它解析节点方法产生影响。

二、SqlSession对数据库的操作

在《mybatis深入浅出》中所说SqlSession对数据库的操作如下:

    SqlSession session= sqlSessionFactory.openSession();
    UserDao userDao = session.getMapper(UserDao.class);
    UserDto user = new UserDto();
    user.setUsername("iMybatis");
    List<UserDto> users = userDao.queryUsers(user);
其中session.getMapper(UserDao.class)获取的是UserDao的代理对象

先获取创建代理对象的工厂类

 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null)
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
在工厂类中,创建代理对象

  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
代理类中,执行完目标方法后,会将method存入cacheMapperMethod供以后调用。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
      return method.invoke(this, args);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }
总结:(1)熟悉流程

           (2)代码其实不难,主要是通过学习源码复习一下jdk动态代理、反射等相关基础知识。

   (3)创建代理对象中一个参数methodCache是ConcurrentHashMap的实例化对象ConcurrentHashMap是线程安全的而且支持锁分离。具体对此类的分析网上有详细解释。


发布了17 篇原创文章 · 获赞 7 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/xiangwangye66/article/details/41719047
今日推荐