zoukankan      html  css  js  c++  java
  • mybatis 启动流程源码分析(一)

    Mybatis 启动流程

    @Before
        public void init() throws IOException {
            String resouce = "mybatis-config.xml";
            /**
             * 读取 mybatis文件,返回的是 InputStream流
             */
            InputStream inputStream = Resources.getResourceAsStream(resouce);
            /**
             * 使用 SqlSessionFactoryBuilder 来构建出一个 SqlSessionFactory来.
             */
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            session = sqlSessionFactory.openSession();
    
        }
    
    1. 通过Resouces提供的getResourceAsStream,加载mybatis-config.xml 文件,从下面的源码中可以看到,不仅可以读取转为InputStream,还可以返回Reader,Properties
    /**
     * A class to simplify access to resources through the classloader.
     *
     * @author Clinton Begin
     */
    public class Resources {
    
        private static ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();
    
      /*
       * Returns a resource on the classpath as a Stream object
       *
       * @param resource The resource to find
       * @return The resource
       * @throws java.io.IOException If the resource cannot be found or read
       */
      public static InputStream getResourceAsStream(String resource) throws IOException {
        return getResourceAsStream(null, resource);
      }
    
      /*
       * Returns a resource on the classpath as a Stream object
       *
       * @param loader   The classloader used to fetch the resource
       * @param resource The resource to find
       * @return The resource
       * @throws java.io.IOException If the resource cannot be found or read
       */
      public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
        InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
        if (in == null) {
          throw new IOException("Could not find resource " + resource);
        }
        return in;
      }
    
      /*
       * Returns a resource on the classpath as a Properties object
       *
       * @param resource The resource to find
       * @return The resource
       * @throws java.io.IOException If the resource cannot be found or read
       */
      public static Properties getResourceAsProperties(String resource) throws IOException {
        Properties props = new Properties();
        InputStream in = getResourceAsStream(resource);
        props.load(in);
        in.close();
        return props;
      }
    
      /*
       * Returns a resource on the classpath as a Properties object
       *
       * @param loader   The classloader used to fetch the resource
       * @param resource The resource to find
       * @return The resource
       * @throws java.io.IOException If the resource cannot be found or read
       */
      public static Properties getResourceAsProperties(ClassLoader loader, String resource) throws IOException {
        Properties props = new Properties();
        InputStream in = getResourceAsStream(loader, resource);
        props.load(in);
        in.close();
        return props;
      }
    
      /*
       * Returns a resource on the classpath as a Reader object
       *
       * @param resource The resource to find
       * @return The resource
       * @throws java.io.IOException If the resource cannot be found or read
       */
      public static Reader getResourceAsReader(String resource) throws IOException {
        Reader reader;
        if (charset == null) {
          reader = new InputStreamReader(getResourceAsStream(resource));
        } else {
          reader = new InputStreamReader(getResourceAsStream(resource), charset);
        }
        return reader;
      }
    
      /*
       * Returns a resource on the classpath as a Reader object
       *
       * @param loader   The classloader used to fetch the resource
       * @param resource The resource to find
       * @return The resource
       * @throws java.io.IOException If the resource cannot be found or read
       */
      public static Reader getResourceAsReader(ClassLoader loader, String resource) throws IOException {
        Reader reader;
        if (charset == null) {
          reader = new InputStreamReader(getResourceAsStream(loader, resource));
        } else {
          reader = new InputStreamReader(getResourceAsStream(loader, resource), charset);
        }
        return reader;
      }
    
    }
    
    1. new SqlSessionFactoryBuilder().build() 读取文件流,并解析,其中提供了包含Reader和InputStream的重载方法,于Resources中提供的方法相对应。
     public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
        try {
          XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
          return build(parser.parse());
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error building SqlSession.", e);
        } finally {
          ErrorContext.instance().reset();
          try {
            reader.close();
          } catch (IOException e) {
            // Intentionally ignore. Prefer previous error.
          }
        }
      }
    // 这次我使用的是该方法,传入的是inputStream.
    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        try {
          //new XMLConfigBuilder()构造方法,
          XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
          // 重点:使用XMLConfigBuilder的parse方法,去解析xml配置文件
          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.
          }
        }
      }
    
      public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
      }
    
    1. 使用XMLConfigBuilder构造方法构建对象,
     public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
        //XMLMapperEntityResolver mybatis的实体解析器
        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;
      }
    // 解析xml 配置文件,返回一个configuration对象,从这儿可以看出,加载的配置内容都是存放在Configuration对象中。
     public Configuration parse() {
        if (parsed) {
          throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        }
        parsed = true;
        // parser.evalNode("/configuration")
        parseConfiguration(parser.evalNode("/configuration"));
        return configuration;
      }
    // 这部分是解析xml文件中的每个节点配置,之后单独再分析
    private void parseConfiguration(XNode root) {
        try {
          //issue #117 read properties first
          propertiesElement(root.evalNode("properties"));
          Properties settings = settingsAsProperties(root.evalNode("settings"));
          loadCustomVfs(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);
        }
      }
    
    

    4.创建XPathParser解析器来解析Xml文件。

    public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
        commonConstructor(validation, variables, entityResolver);
        this.document = createDocument(new InputSource(inputStream));
      }
    
    // 给属性赋值,获取xpath对象
      private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
        this.validation = validation;
        this.entityResolver = entityResolver;
        this.variables = variables;
        // 获取XpathFactory 类实例
        XPathFactory factory = XPathFactory.newInstance();
        // 使用factory创建XPathImpl对象
        this.xpath = factory.newXPath();
      }
    
    //使用Document解析器,返回Document对象
    private Document createDocument(InputSource inputSource) {
        // important: this must only be called AFTER common constructor
        try {
          // 创建DocumentBuilderFactoryImpl 实例
          DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
          factory.setValidating(validation);
    
          factory.setNamespaceAware(false);
          factory.setIgnoringComments(true);
          factory.setIgnoringElementContentWhitespace(false);
          factory.setCoalescing(false);
          factory.setExpandEntityReferences(true);
          // 使用工厂创建DocumentBuilder,再使用build去解析xml文件流
          DocumentBuilder builder = factory.newDocumentBuilder();
          builder.setEntityResolver(entityResolver);
          builder.setErrorHandler(new ErrorHandler() {
            @Override
            public void error(SAXParseException exception) throws SAXException {
              throw exception;
            }
    
            @Override
            public void fatalError(SAXParseException exception) throws SAXException {
              throw exception;
            }
    
            @Override
            public void warning(SAXParseException exception) throws SAXException {
            }
          });
          return builder.parse(inputSource);
        } catch (Exception e) {
          throw new BuilderException("Error creating document instance.  Cause: " + e, e);
        }
      }
    

    通过实现类DocumentBuilderImpl 解析文件流

    public Document parse(InputSource is) throws SAXException, IOException {
            if (is == null) {
                throw new IllegalArgumentException(
                    DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
                    "jaxp-null-input-source", null));
            }
            if (fSchemaValidator != null) {
                if (fSchemaValidationManager != null) {
                    fSchemaValidationManager.reset();
                    fUnparsedEntityHandler.reset();
                }
                resetSchemaValidator();
            }
            // 采用DomParser 解析器解析xml文件
            domParser.parse(is);
            Document doc = domParser.getDocument();
            domParser.dropDocumentReferences();
            return doc;
    
  • 相关阅读:
    Java面向对象设计——购物车·
    查找

    栈和队列
    指针
    数组
    第四次博客——函数
    第三次博客作业
    第二次博客作业
    Java购物车大作业01
  • 原文地址:https://www.cnblogs.com/wanthune/p/13672360.html
Copyright © 2011-2022 走看看