mybaits源码分析(一) 核心执行流程

本文主要介绍mybaits的核心执行过程的源码分析,我们按照xml配置的方式,建立一个查询的demo,测试代码如下

@Test
	public void test2() throws Exception {
		InputStream in = Resources.getResourceAsStream("custom/sqlMapConfig2.xml");
		SqlSessionFactory factory2 =  new SqlSessionFactoryBuilder().build(in);
		SqlSession openSession = factory2.openSession();
		UserMapper mapper = openSession.getMapper(UserMapper.class);
		User user = mapper.findUserById(1);
		// User user = openSession.selectOne("com.wj.source_two.demo.mapper.UserMapper.findUserById", 1);
		System.out.println(user);
		openSession.close();
	}

    按照上面的代码执行过程,我们把执行过程分为下面几个部分分析: 配置加载,创建mapper代理,SqlSession执行

一、配置加载

1、相关的类
            SqlSessionFactoryBuilder : 负责创建SqlSessionFactory对象,并且传入了从配置文件解析的Configuration。
            XMLConfigBuilder: 核心解析类及其父类BaseBuilder的子类,负责解析xml各种配置到Configuration对象。
            XPathParser:xpath解析
            XNode:node的包装

2、流程分析
  1) SqlSessionFactoryBuilder调用XMLConfigBuilder解析输入流解析到Configuration 

 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
                try {
                  XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
                  return build(parser.parse());

 2) parse方法是对sqlMapConfig.xml的解析,XPathParser和XNode用法后期补充。

public Configuration parse() {
                    parseConfiguration(parser.evalNode("/configuration"));
                    return 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);
                }
              }

 3) 截取部分构建过程
      加载配置键值对到configuration

  private void propertiesElement(XNode context) throws Exception {
                if (context != null) {
                  Properties defaults = context.getChildrenAsProperties(); // 得到子节点加载Properties
                  String resource = context.getStringAttribute("resource"); // 得到resource属性
                  String url = context.getStringAttribute("url"); // 得到url属性
                  // ....
                  if (resource != null) { // 从资源文件加载Properties
                    defaults.putAll(Resources.getResourceAsProperties(resource));
                  } else if (url != null) { // 从url属性加载Properties
                    defaults.putAll(Resources.getUrlAsProperties(url));
                  }
                  Properties vars = configuration.getVariables();
                  if (vars != null) {
                    defaults.putAll(vars);
                  }
                  parser.setVariables(defaults);
                  configuration.setVariables(defaults); // 设置到configuration
                }
              }

       加载拦截器,解析plugin,并且根据interceptor的类名,进行实例化,而且加载了子元素的配置

     private void pluginElement(XNode parent) throws Exception {
         if (parent != null) {
                  for (XNode child : parent.getChildren()) {
                    String interceptor = child.getStringAttribute("interceptor");
                    Properties properties = child.getChildrenAsProperties();
                    Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
                    interceptorInstance.setProperties(properties);
                    configuration.addInterceptor(interceptorInstance);
                  }
               }
          }

二、创建mapper代理

    1、主要工作类:
             MapperRegistry:configuration的属性(1对1),用于管理已经创建的MapperProxyFactory
             MapperProxyFactory:代理创建的工厂类,代理实现类是MapperProxy、代理方法实际调用类是MapperMethod。
             MapperProxy:实现InvocationHandler的增强,并且缓存了MapperMethod
             MapperMethod:包装原接口方法,配置,session等参数,实现通用excute方法执行,给MapperProxy使用。

   2、执行流程分析

 1) 找Mapper,UserMapper mapper = openSession.getMapper(UserMapper.class), 实际上是MapperRegistry中Map<Class<?>, MapperProxyFactory<?>> knownMappers查找。

      public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
                 final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
                 // 上面那个方法只是找到已经创建了Mapper接口并缓存到MapperRegistry,没找到报错
                 return mapperProxyFactory.newInstance(sqlSession); // 此方法才是Mapper动态代理的核心
             }

2) newInstance方法是创建了一个mapperProxy,这个mapperProxy实现了InvocationHandler

		     public T newInstance(SqlSession sqlSession) {
			    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
			    return newInstance(mapperProxy);
			 }
	    	 protected T newInstance(MapperProxy<T> mapperProxy) {
			    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
			 }	

3) 上面就是创建代理类过程,我们重点看看MapperProxy的invoke实现

			  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			    if (Object.class.equals(method.getDeclaringClass())) { 
			      try { // Object方法直接放行。
			        return method.invoke(this, args);
			      } catch (Throwable t) {
			      }
			    } // 创建MapperMethod并且缓存(缓存到MapperProxy对象中)
			    final MapperMethod mapperMethod = cachedMapperMethod(method);
			    return mapperMethod.execute(sqlSession, args);
			  }

4)     MapperMethod的分析

 4.1) execute方法一览
			  public Object execute(SqlSession sqlSession, Object[] args) {
			    Object result;
			    if (SqlCommandType.INSERT == command.getType()) {
			      Object param = method.convertArgsToSqlCommandParam(args);
			      result = rowCountResult(sqlSession.insert(command.getName(), param));
			    } else if (SqlCommandType.UPDATE == command.getType()) {
			      Object param = method.convertArgsToSqlCommandParam(args);
			      result = rowCountResult(sqlSession.update(command.getName(), param));
			    } else if (SqlCommandType.DELETE == command.getType()) {
			      Object param = method.convertArgsToSqlCommandParam(args);
			      result = rowCountResult(sqlSession.delete(command.getName(), param));
			    } else if (SqlCommandType.SELECT == command.getType()) {
			      if (method.returnsVoid() && method.hasResultHandler()) {
			      } else if (method.returnsMany()) {
			        result = executeForMany(sqlSession, args); // 查询方法
			      } else if (method.returnsMap()) {
			      } else {
			      }
			    } else {
			      throw new BindingException("Unknown execution method for: " + command.getName());
			    }
			    return result;
			  }		
			 4.2) 我们从 execute方法看到	insert方法是调用session.insert(command.getName,param),这个name是什么?
			  public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
			 	 String statementName = mapperInterface.getName() + "." + method.getName(); //就是接口名+方法名
			 4.3)  在看看查询的方法 result = executeForMany(sqlSession, args); 
			   private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
			    List<E> result;
			    // 转换参数
			    Object param = method.convertArgsToSqlCommandParam(args);
			    // 执行查询
			    result = sqlSession.<E>selectList(command.getName(), param);
			    // .....
			    return result;
			  }

5、总结:
                mybaits动态代理mapper就是根据自己设定的mapper接口,给每个类型创建一个动态代理类,这个代理类实际上调用的方法是sqlsession调用interface+method的id进行操作,其中结合了一些缓存,参数处理 等等其他操作。

 三、SqlSession执行过程

1、主要工作类

            DefaultSqlSession: 包装Executor
            Executor: 包装Transaction, 核心调用类,增删改查等操作都是由此类调用的。
            MappedStatement :包装sql,sql类型,返回值类型,参数映射 (对应配置文件一个select等标签)。
            BoundSql : 包装sql和参数映射和参数值。(由不同的SqlSource生成同一类型BoundSql)。
            StatementHandler : 参数处理和执行,内含参数处理、sql执行、返回值处理。
                ParameterHandler: 参数处理
                ResultSetHandler: 结果处理
            TypeHandler: 类型转换

2、执行过程

1) selectOne实际上调用selectList,参数id可以从Configuration中找到MappedStatement。

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
			  // 找mapperStatement
		      MappedStatement ms = configuration.getMappedStatement(statement); 
		      // 调用executor执行查询方法query。
		      List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
		      return result;
			}

2) 缓存层的几个调用忽略,实际上调用的是queryFromDatabase

			  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
			    List<E> list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
			    return list;
			  }

3) doQuery 方法是创建StatementHandler,然后执行参数预解析,执行sql,并且最后的返回值处理

			 public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
			    Statement stmt = null;
			    try {
			      Configuration configuration = ms.getConfiguration();
			      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
			      stmt = prepareStatement(handler, ms.getStatementLog());
			      return handler.<E>query(stmt, resultHandler);
			    } finally {
			      closeStatement(stmt);
			    }
			  }

4) 参数解析和返回值处理实际上是StatementHandler的    ParameterHandler和ResultSetHandler的作用,其中涉及到参数处理,用到了TypeHandler。过程省略

网上盗图一张,这张图对执行流程展示是非常直观的。

end!

猜你喜欢

转载自blog.csdn.net/shuixiou1/article/details/113531162