范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

mybatis源码注解sql

  Demo
  主启动类
  java public class MybatisHelloWorld {     public static void main(String[] args) throws Exception {         String resource = "org/mybatis/config.xml";         InputStream inputStream = Resources.getResourceAsStream(resource);         SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);         SqlSession session = sqlSessionFactory.openSession();         UserMapper mapper = session.getMapper(UserMapper.class);         List users = mapper.getUsers(1);         session.close();     } }
  userMapper.class
  java public interface UserMapper {     @Select({"select * from user where age=#{age}"})     List getUsers(int age); }
  config.xml
  xml <?xml version="1.0" encoding="UTF-8"?>                 //控制台输出sql                                                                                                                                                                               
  Mybatis通过session来进行数据库的操作,sqlSessionFactory封装了session的创建,而SqlSessionFactoryBuilder又封装了sqlSessionFactory的创建
  从上面代码来看总共做了两件事 读取配置文件,通过SqlSessionFactoryBuilder创建sqlSessionFactory继而创建session 获取mapper进行读取数据库
  先来看如何将xml配置文件封装为对象的 解析配置文件
  java new SqlSessionFactoryBuilder().build(inputStream);
  这里使用构造者模式来创建一个sqlSessionFactory,里面使用重载
  java public SqlSessionFactory build(InputStream inputStream) {     return build(inputStream, null, null); }
  最终调用
  SqlSessionFactoryBuilder.java
  java public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {     try {         //创建一个xml解析类         XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);         //解析xml中配置,转换为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.         }     } }
  mybatis是把一些配置类以及它自己需要使用的各种类封装成一个大的config对象
  org.apache.ibatis.session.Configuration 里面有很多环境,mapper等等的信息,内容太多就不粘贴了
  XMLConfigBuilder.java
  java 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) {     //创建了一个Configuration 对象     super(new Configuration());     ErrorContext.instance().resource("SQL Mapper Configuration");     this.configuration.setVariables(props);     this.parsed = false;     //这一行设置环境id     this.environment = environment;     this.parser = parser; }
  XMlConfigBuilder类关系图
  BaseBuilder.java
  java  public BaseBuilder(Configuration configuration) {     this.configuration = configuration;     this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();     this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();   }
  解析主配置文件.xml
  SqlSessionFactoryBuilder.java
  java public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {     //....     return build(parser.parse());     //.... }  public Configuration parse() {     if (parsed) {         throw new BuilderException("Each XMLConfigBuilder can only be used once.");     }     parsed = true;     //读取configuration节点下的node传入     parseConfiguration(parser.evalNode("/configuration"));     return configuration; }   private void parseConfiguration(XNode root) {     try {         //issue #117 read properties first         //读取properties         propertiesElement(root.evalNode("properties"));         //读取一些setting设置         Properties settings = settingsAsProperties(root.evalNode("settings"));         loadCustomVfs(settings);         //注册别名         typeAliasesElement(root.evalNode("typeAliases"));         //插件,进行增强-先略过         pluginElement(root.evalNode("plugins"));         //对象工厂,自定义实例化方法--略过         objectFactoryElement(root.evalNode("objectFactory"));         objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));         reflectionFactoryElement(root.evalNode("reflectionFactory"));         settingsElement(settings);         // read it after objectFactory and objectWrapperFactory issue #631         //配置环境         environmentsElement(root.evalNode("environments"));         //数据厂商表示--略过         databaseIdProviderElement(root.evalNode("databaseIdProvider"));         typeHandlerElement(root.evalNode("typeHandlers"));         //配置mapper         mapperElement(root.evalNode("mappers"));     } catch (Exception e) {         throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);     } }
  解析的东西很多,我们只先看environments和mapper environmentsElement
  XMLConfigBuilder.java
  java private void environmentsElement(XNode context) throws Exception {     if (context != null) {         if (environment == null) {             environment = context.getStringAttribute("default");         }         for (XNode child : context.getChildren()) {             String id = child.getStringAttribute("id");             //可以配置多个环境,判断是不是指定的环境             if (isSpecifiedEnvironment(id)) {                 //获取事物管理器,创建事物管理器工厂                 TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));                 //获取datasource工厂-UnpooledDataSourceFactory默认                 DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));                 DataSource dataSource = dsFactory.getDataSource();                 Environment.Builder environmentBuilder = new Environment.Builder(id)                     .transactionFactory(txFactory)                     .dataSource(dataSource);                 configuration.setEnvironment(environmentBuilder.build());             }         }     } }
  进入发现第一件是就是判断环境,没有指定就使用   中default的环境id,在上面的XMLConfigBuilder的有参构造中this.environment = environment;  将环境配置设置给了XMLConfigBuilder的environment 点我跳转到XMLConfigBuilder-有参构造
  我们在使用时可以这样,在配置文件xml中,声明多个环境
  xml                                                                                                                                                                                                                                                                             
  主启动类中,手动指明一个配置环境
  java public static void main(String[] args) throws Exception {     //....     SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"myTest");     //.... }
  回到代码第一步就是判断用户选择的那个id的环境,之后创建事务管理器
  XMLConfigBuilder.java
  java private void environmentsElement(XNode context) throws Exception {     //..     TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));     //.. } private TransactionFactory transactionManagerElement(XNode context) throws Exception {     if (context != null) {         //获取我们在xml中声明的事务管理类型,当前是JDBC         String type = context.getStringAttribute("type");         //获取节点下的子节点,当前案例没有子节点         Properties props = context.getChildrenAsProperties();         //这里只是创建工厂类         TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();         factory.setProperties(props);         return factory;     }     throw new BuilderException("Environment declaration requires a TransactionFactory."); }
  这里调用 resolveClass()  方法是父类BaseBuilder的方法
  一直点进去最后如下
  TypeAliasRegistry.java
  java public class TypeAliasRegistry { 	 private final Map> TYPE_ALIASES = new HashMap>();     //.....     public  Class resolveAlias(String string) {         try {             if (string == null) {                 return null;             }             // issue #748             String key = string.toLowerCase(Locale.ENGLISH);             Class value;             if (TYPE_ALIASES.containsKey(key)) {                 value = (Class) TYPE_ALIASES.get(key);             } else {                 value = (Class) Resources.classForName(string);             }             return value;         } catch (ClassNotFoundException e) {             throw new TypeException("Could not resolve type alias "" + string + "".  Cause: " + e, e);         }     } }
  判断这个TYPE_ALIASES map中是否存在JDBC这个key,如果不存在,则去加载
  按理来说这里应该是不存在的,因为你在TypeAliasRegistry中找不到任何一个地方对TYPE_ALIASES添加一个JDBC的key
  但是实际它却存在这个key,在Configuration类的无参构造时,对这个TypeAliasRegistry进行的添加
  Configuration.java
  java  public Configuration() {     typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);      //...     typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);     languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class); 	//......   }
  这个过程如下图
  回到代码因为我们这次案例的配置为   所以不会存在子节点context.getChildrenAsProperties();  返回的结果0个配置项,transactionManagerElement  方法结束
  之后去解析数据库配置文件
  XMLConfigBulider.java
  java private void environmentsElement(XNode context) throws Exception {     //...     //获取datasource工厂-UnpooledDataSourceFactory默认     DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));     DataSource dataSource = dsFactory.getDataSource();     //... }
  和解析环境基本一样的代码,不过解析dataSource的时候,子节点就不为空了
  会有四个属性
  xml                      
  java   private DataSourceFactory dataSourceElement(XNode context) throws Exception {     if (context != null) {       String type = context.getStringAttribute("type");       Properties props = context.getChildrenAsProperties();        //type为POOLED的默认实现是PooledDataSourceFactory       DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();       factory.setProperties(props);       return factory;     }     throw new BuilderException("Environment declaration requires a DataSourceFactory.");   }
  进入 factory.setProperties(props);
  java public class UnpooledDataSourceFactory implements DataSourceFactory {      private static final String DRIVER_PROPERTY_PREFIX = "driver.";     private static final int DRIVER_PROPERTY_PREFIX_LENGTH = DRIVER_PROPERTY_PREFIX.length();      protected DataSource dataSource; 	//无参默认将dataSource设置为UnpooledDataSource     public UnpooledDataSourceFactory() {         this.dataSource = new UnpooledDataSource();     }      @Override     public void setProperties(Properties properties) {         Properties driverProperties = new Properties();         //将工厂对象进行包装         MetaObject metaDataSource = SystemMetaObject.forObject(dataSource);         for (Object key : properties.keySet()) {             String propertyName = (String) key;             //如果存在driver             if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) {                 String value = properties.getProperty(propertyName);                 driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value);             //如果当前属性在类中有对应的可以写入的属性             } else if (metaDataSource.hasSetter(propertyName)) {                 String value = (String) properties.get(propertyName);                 Object convertedValue = convertValue(metaDataSource, propertyName, value);                 metaDataSource.setValue(propertyName, convertedValue);             } else {                 throw new DataSourceException("Unknown DataSource property: " + propertyName);             }         }         //如果属性不为空,则设置给meatDataSource         if (driverProperties.size() > 0) {             metaDataSource.setValue("driverProperties", driverProperties);         }     } 	//...... }
  一顿设置后回到XMLConfigurationBuilder中的environmentsElement方法
  最后将读取出的配置封装为Environment,赋值给BaseBuilder中的environment
  java private void environmentsElement(XNode context) throws Exception { 	//.....     DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));     DataSource dataSource = dsFactory.getDataSource();     Environment.Builder environmentBuilder = new Environment.Builder(id)         .transactionFactory(txFactory)         .dataSource(dataSource);     configuration.setEnvironment(environmentBuilder.build()); 	//..... } mapperElement
  回到XMLConfigBuilder中的parseConfiguration
  java private void parseConfiguration(XNode root) {     //.....     //配置mapper     mapperElement(root.evalNode("mappers"));  }
  我们只看根据包扫描的,给Configuration中添加了mapper包名
  java private void mapperElement(XNode parent) throws Exception {     if (parent != null) {         for (XNode child : parent.getChildren()) {             //使用包,默认查找指定包下位置             if ("package".equals(child.getName())) {                 String mapperPackage = child.getStringAttribute("name");                 configuration.addMappers(mapperPackage);             }              //.....         }     } }
  Configuration.java
  java public void addMappers(String packageName) {     mapperRegistry.addMappers(packageName); }
  MapperRegistry.java
  java public void addMappers(String packageName) {     addMappers(packageName, Object.class); } //根据包名去查询该包下的类 public void addMappers(String packageName, Class<?> superType) {     ResolverUtil> resolverUtil = new ResolverUtil>();     resolverUtil.find(new ResolverUtil.IsA(superType), packageName);     Set>> mapperSet = resolverUtil.getClasses();     for (Class<?> mapperClass : mapperSet) {         addMapper(mapperClass);     } }
  之后就是动态代理对应的mapper
  MapperRegistry.java
  java public  void addMapper(Class type) {     if (type.isInterface()) {         //判断是否已经存在         if (hasMapper(type)) {             throw new BindingException("Type " + type + " is already known to the MapperRegistry.");         }         boolean loadCompleted = false;         try {             knownMappers.put(type, new MapperProxyFactory(type));             MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);             parser.parse();             loadCompleted = true;         } finally {             if (!loadCompleted) {                 knownMappers.remove(type);             }         }     } }
  java public class MapperProxyFactory {      private final Class mapperInterface;     private final Map methodCache = new ConcurrentHashMap();      public MapperProxyFactory(Class mapperInterface) {         this.mapperInterface = mapperInterface;     }      public Class getMapperInterface() {         return mapperInterface;     }      public Map getMethodCache() {         return methodCache;     }      @SuppressWarnings("unchecked")     protected T newInstance(MapperProxy mapperProxy) {         return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);     }      public T newInstance(SqlSession sqlSession) {         final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);         return newInstance(mapperProxy);     }  }
  主要来看这段
  java MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse();
  MapperAnnotationBuilder.java
  java public class MapperAnnotationBuilder {     private final Set> sqlAnnotationTypes = new HashSet>();     private final Set> sqlProviderAnnotationTypes = new HashSet>();     //....     /**     * 在构造时添加mybatis的注解     */     public MapperAnnotationBuilder(Configuration configuration, Class<?> type) {         String resource = type.getName().replace(".", "/") + ".java (best guess)";         this.assistant = new MapperBuilderAssistant(configuration, resource);         this.configuration = configuration;         this.type = type;          sqlAnnotationTypes.add(Select.class);         sqlAnnotationTypes.add(Insert.class);         sqlAnnotationTypes.add(Update.class);         sqlAnnotationTypes.add(Delete.class);          sqlProviderAnnotationTypes.add(SelectProvider.class);         sqlProviderAnnotationTypes.add(InsertProvider.class);         sqlProviderAnnotationTypes.add(UpdateProvider.class);         sqlProviderAnnotationTypes.add(DeleteProvider.class);     }       public void parse() {         String resource = type.toString();         if (!configuration.isResourceLoaded(resource)) {             loadXmlResource();             configuration.addLoadedResource(resource);             assistant.setCurrentNamespace(type.getName());             parseCache();             parseCacheRef();             Method[] methods = type.getMethods();             for (Method method : methods) {                 try {                     // issue #237                     if (!method.isBridge()) {                         parseStatement(method);                     }                 } catch (IncompleteElementException e) {                     configuration.addIncompleteMethod(new MethodResolver(this, method));                 }             }         }         parsePendingMethods();     } }
  java void parseStatement(Method method) {     Class<?> parameterTypeClass = getParameterType(method);     LanguageDriver languageDriver = getLanguageDriver(method);     SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);    //... }
  首先第一步是获取参数类型-代码如下,如果mapper的入参数量大于1,则返回的就是ParamMap.class
  java private Class<?> getParameterType(Method method) {     Class<?> parameterType = null;     Class<?>[] parameterTypes = method.getParameterTypes();     for (int i = 0; i < parameterTypes.length; i++) {         if (!RowBounds.class.isAssignableFrom(parameterTypes[i]) && !ResultHandler.class.isAssignableFrom(parameterTypes[i])) {             if (parameterType == null) {                 parameterType = parameterTypes[i];             } else {                 // issue #135                 parameterType = ParamMap.class;             }         }     }     return parameterType; }
  之后获取语言解析,没有指定就去找默认-默认的是XMLLanguageDriver.class 还是在Configuration类无参构造时添加进去的点我跳转到Configuration-无参构造
  java private LanguageDriver getLanguageDriver(Method method) {     Lang lang = method.getAnnotation(Lang.class);     Class<?> langClass = null;     if (lang != null) {         langClass = lang.value();     }     return assistant.getLanguageDriver(langClass); }
  获取注解上的内容,以及封装sql就在这个方法
  java private SqlSource getSqlSourceFromAnnotations(Method method, Class<?> parameterType, LanguageDriver languageDriver) {     try {         //获取是否存在@Select,@Insert....         Class<? extends Annotation> sqlAnnotationType = getSqlAnnotationType(method);         //获取是否存在@SelectProvider,@InsertProvider...         Class<? extends Annotation> sqlProviderAnnotationType = getSqlProviderAnnotationType(method);         if (sqlAnnotationType != null) {             if (sqlProviderAnnotationType != null) {                 throw new BindingException("You cannot supply both a static SQL and SqlProvider to method named " + method.getName());             }             Annotation sqlAnnotation = method.getAnnotation(sqlAnnotationType);             //获取注解上的值             final String[] strings = (String[]) sqlAnnotation.getClass().getMethod("value").invoke(sqlAnnotation);             //返回sqlSource              //这个时候还没有进行填充值              return buildSqlSourceFromStrings(strings, parameterType, languageDriver);         } else if (sqlProviderAnnotationType != null) {             Annotation sqlProviderAnnotation = method.getAnnotation(sqlProviderAnnotationType);             return new ProviderSqlSource(assistant.getConfiguration(), sqlProviderAnnotation);         }         return null;     } catch (Exception e) {         throw new BuilderException("Could not find value method on SQL annotation.  Cause: " + e, e);     } }
  此时的 strings  值还是 select * from user where age = #{age} 需要给替换为 select * from user where age =?
  java   private SqlSource buildSqlSourceFromStrings(String[] strings, Class<?> parameterTypeClass, LanguageDriver languageDriver) {     final StringBuilder sql = new StringBuilder();     for (String fragment : strings) {       sql.append(fragment);       sql.append(" ");     }     return languageDriver.createSqlSource(configuration, sql.toString().trim(), parameterTypeClass);   }
  默认的语言驱动是XMLLanguageDriver
  XMLLanguageDriver.java
  首先判断注解上的内容是否存在脚本,在mybatis官网,动态SQL下的script有使用案例,使得在注解中可以像在xml中使用 parameterType) {     // issue #3     if (script.startsWith("<script>")) {         XPathParser parser = new XPathParser(script, false, configuration.getVariables(), new XMLMapperEntityResolver());         return createSqlSource(configuration, parser.evalNode("/script"), parameterType);     } else {         // issue #127         script = PropertyParser.parse(script, configuration.getVariables());         TextSqlNode textSqlNode = new TextSqlNode(script);         //判断是否为动态的sql就取决于使用的是${} 还是#{}  当使用${}时就是动态sql         if (textSqlNode.isDynamic()) {             return new DynamicSqlSource(configuration, textSqlNode);         } else {             return new RawSqlSource(configuration, script, parameterType);         }     } }
  之后在RewSqlSource中对sql进行解析
  RewSqlSource.java
  java public RawSqlSource(Configuration configuration, String sql, Class<?> parameterType) {     SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);     Class<?> clazz = parameterType == null ? Object.class : parameterType;     sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap()); }
  解析完最终结果如下
  回到上个方法
  java   void parseStatement(Method method) {     Class<?> parameterTypeClass = getParameterType(method);     LanguageDriver languageDriver = getLanguageDriver(method);     SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);     //从这里继续     if (sqlSource != null) {       Options options = method.getAnnotation(Options.class);       //mappedStatementId=类全限定+方法名       final String mappedStatementId = type.getName() + "." + method.getName();       //设置获取数据的大小       Integer fetchSize = null;       //设置此次查询超时时间         Integer timeout = null;       //https://blog.csdn.net/king101125s/article/details/104167493       StatementType statementType = StatementType.PREPARED;       //resultSet结果类型   FORWARD_ONLY 光标只能向前移动       ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;       //设置sql类型,当前案例是SELECT       SqlCommandType sqlCommandType = getSqlCommandType(method);       boolean isSelect = sqlCommandType == SqlCommandType.SELECT;       boolean flushCache = !isSelect;       boolean useCache = isSelect;        KeyGenerator keyGenerator;       String keyProperty = "id";       String keyColumn = null;       if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {         // first check for SelectKey annotation - that overrides everything else         SelectKey selectKey = method.getAnnotation(SelectKey.class);         if (selectKey != null) {           keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver);           keyProperty = selectKey.keyProperty();         } else if (options == null) {           keyGenerator = configuration.isUseGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();         } else {           keyGenerator = options.useGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();           keyProperty = options.keyProperty();           keyColumn = options.keyColumn();         }       } else {         keyGenerator = new NoKeyGenerator();       }        if (options != null) {         flushCache = options.flushCache();         useCache = options.useCache();         fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348         timeout = options.timeout() > -1 ? options.timeout() : null;         statementType = options.statementType();         resultSetType = options.resultSetType();       }        String resultMapId = null;       ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class);       if (resultMapAnnotation != null) {         String[] resultMaps = resultMapAnnotation.value();         StringBuilder sb = new StringBuilder();         for (String resultMap : resultMaps) {           if (sb.length() > 0) {             sb.append(",");           }           sb.append(resultMap);         }         resultMapId = sb.toString();       } else if (isSelect) {         resultMapId = parseResultMap(method);       } 	//将参数传给小助手       assistant.addMappedStatement(           mappedStatementId,           sqlSource,           statementType,           sqlCommandType,           fetchSize,           timeout,           // ParameterMapID           null,           parameterTypeClass,           resultMapId,           getReturnType(method),           resultSetType,           flushCache,           useCache,           // TODO issue #577           false,           keyGenerator,           keyProperty,           keyColumn,           // DatabaseID           null,           languageDriver,           // ResultSets           null);     }   }
  添加mappedStatement
  java public MappedStatement addMappedStatement(     String id,     SqlSource sqlSource,     StatementType statementType,     SqlCommandType sqlCommandType,     Integer fetchSize,     Integer timeout,     String parameterMap,     Class<?> parameterType,     String resultMap,     Class<?> resultType,     ResultSetType resultSetType,     boolean flushCache,     boolean useCache,     boolean resultOrdered,     KeyGenerator keyGenerator,     String keyProperty,     String keyColumn,     String databaseId,     LanguageDriver lang,     String resultSets) {      if (unresolvedCacheRef) {         throw new IncompleteElementException("Cache-ref not yet resolved");     }      id = applyCurrentNamespace(id, false);     boolean isSelect = sqlCommandType == SqlCommandType.SELECT;      MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)         .resource(resource)         .fetchSize(fetchSize)         .timeout(timeout)         .statementType(statementType)         .keyGenerator(keyGenerator)         .keyProperty(keyProperty)         .keyColumn(keyColumn)         .databaseId(databaseId)         .lang(lang)         .resultOrdered(resultOrdered)         .resulSets(resultSets)         .resultMaps(getStatementResultMaps(resultMap, resultType, id))         .resultSetType(resultSetType)         .flushCacheRequired(valueOrDefault(flushCache, !isSelect))         .useCache(valueOrDefault(useCache, isSelect))         .cache(currentCache);      ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);     if (statementParameterMap != null) {         statementBuilder.parameterMap(statementParameterMap);     }      MappedStatement statement = statementBuilder.build();     //这里将这个MappedStatement放入configuration     configuration.addMappedStatement(statement);     return statement; }
  将各种参数最后封装为一个MappedStatement,放入configuration中,这样一个addMapper的方法就结束了
  之后回到SqlSessionFactory的build中,执行重载的build
  java public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {     XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);     //回到这里     return build(parser.parse());  } //默认为DefaultSqlSessionFactory public SqlSessionFactory build(Configuration config) {     return new DefaultSqlSessionFactory(config); }
  DefaultSqlSessionFactory.java
  java public class DefaultSqlSessionFactory implements SqlSessionFactory {      private final Configuration configuration;      public DefaultSqlSessionFactory(Configuration configuration) {         this.configuration = configuration;     }     //..... }
  至此 new SqlSessionFactoryBuilder().build(inputStream)  这段代码的解析环境和加载mapper就分析完了sqlSessionFactory
  回到主代码
  java public static void main(String[] args) throws Exception {     String resource = "org/mybatis/config.xml";     InputStream inputStream = Resources.getResourceAsStream(resource);     SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);     SqlSession session = sqlSessionFactory.openSession();     //.. }
  开始分析sqlSessionFactory.openSession();
  点进入发现有两个实现类,在上面的build中已经明确了创建的就是DefaultSqlSessionFactory
  DefaultSqlSessionFactory.java
  java @Override public SqlSession openSession() {     //参数:执行器,默认为simple,每次关闭statement SimpleExecutor     return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); }
  configuration.getDefaultExecutorType()  在Configuration类中获取的是本身的一个属性,类型是一个ExecutorType的枚举,默认为SIMPE
  java private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {     Transaction tx = null;     try {         //获取配置类中的事务,datasource封装类         final Environment environment = configuration.getEnvironment();         //通过配置的环境中获取事务工厂         final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);         //创建对象/datasource/隔离等级/是否自动提交         tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);         final Executor executor = configuration.newExecutor(tx, execType);         return new DefaultSqlSession(configuration, executor, autoCommit);     } catch (Exception e) {         closeTransaction(tx); // may have fetched a connection so lets call close()         throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);     } finally {         ErrorContext.instance().reset();     } }
  获取configuration中的事务工厂之后创建一个执行器
  Configuration.java
  java public Executor newExecutor(Transaction transaction, ExecutorType executorType) {     executorType = executorType == null ? defaultExecutorType : executorType;     executorType = executorType == null ? ExecutorType.SIMPLE : executorType;     Executor executor;     if (ExecutorType.BATCH == executorType) {         executor = new BatchExecutor(this, transaction);     } else if (ExecutorType.REUSE == executorType) {         executor = new ReuseExecutor(this, transaction);     } else {         executor = new SimpleExecutor(this, transaction);     }     if (cacheEnabled) {         executor = new CachingExecutor(executor);     }     executor = (Executor) interceptorChain.pluginAll(executor);     return executor; }
  这里缓存是默认开启的,所以最后返回的是一个 CachingExecutor   包含着一个SimpleExecutor
  最后返回一个默认的 DefaultSqlSession
  DefaultSqlSession.java
  java     public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {         this.configuration = configuration;         this.executor = executor;         this.dirty = false;         this.autoCommit = autoCommit;     }
  到这里session也创建完成了之后就是获取mapper执行查询了 session.getMapper
  DefaultSqlSession.java
  java @Override public  T getMapper(Class type) {     return configuration.getMapper(type, this); }
  Configuration.java
  java public  T getMapper(Class type, SqlSession sqlSession) {     return mapperRegistry.getMapper(type, sqlSession); }
  MapperRegistry.java
  java public  T getMapper(Class type, SqlSession sqlSession) {     final MapperProxyFactory mapperProxyFactory = (MapperProxyFactory) 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);     } }
  MapperProxyFactory.java
  java protected T newInstance(MapperProxy mapperProxy) {     return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }  public T newInstance(SqlSession sqlSession) {     final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);     return newInstance(mapperProxy); }
  MapperProxy.java
  动态代理来实现mapper的方法调用
  java public class MapperProxy implements InvocationHandler, Serializable {      private static final long serialVersionUID = -6424540398559729838L;     private final SqlSession sqlSession;     private final Class mapperInterface;     private final Map methodCache;      public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache) {         this.sqlSession = sqlSession;         this.mapperInterface = mapperInterface;         this.methodCache = methodCache;     }      @Override     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {         if (Object.class.equals(method.getDeclaringClass())) {             try {                 return method.invoke(this, args);             } catch (Throwable t) {                 throw ExceptionUtil.unwrapThrowable(t);             }         }         final MapperMethod mapperMethod = cachedMapperMethod(method);         return mapperMethod.execute(sqlSession, args);     }      private MapperMethod cachedMapperMethod(Method method) {         MapperMethod mapperMethod = methodCache.get(method);         if (mapperMethod == null) {             mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());             methodCache.put(method, mapperMethod);         }         return mapperMethod;     }  }
  当我们执行userMapper.getUsers()的时候,通过动态代理进入invoke方法,之后获取缓存的方法,进入 cachedMapperMethod
  先找是否已经创建过这个方法的封装类了,如果没有则去创建
  MapperMethod.java
  java  public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {     this.command = new SqlCommand(config, mapperInterface, method);     this.method = new MethodSignature(config, method);   }
  MapperMethod.java-SqlCommand.java 静态内部类
  java public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {     String statementName = mapperInterface.getName() + "." + method.getName();     MappedStatement ms = null;     //当程序走到这里的时候就会为true     if (configuration.hasStatement(statementName)) {         ms = configuration.getMappedStatement(statementName);     }      ///......     if (ms == null) {     //.....     } else {         name = ms.getId();         type = ms.getSqlCommandType();         if (type == SqlCommandType.UNKNOWN) {             throw new BindingException("Unknown execution method for: " + name);         }     } }
  Configuration.java
  java public boolean hasStatement(String statementName) {     return hasStatement(statementName, true); }  public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {     if (validateIncompleteStatements) {         buildAllStatements();     }     //主要这行     return mappedStatements.containsKey(statementName); }
  可能忘了它什么时候添加进去的了,在那个小助手中的addMappedStatement方法,最后的时候进行的添加点我跳转到addMappedStatement
  那么这里就直接走到最后的if了,将name和type赋值给SqlCommand,方法结束
  之后还有创建MethodSignature
  MapperMethod.java-MethodSignature.java 静态内部类
  java public MethodSignature(Configuration configuration, Method method) {     this.returnType = method.getReturnType();     this.returnsVoid = void.class.equals(this.returnType);     this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());     this.mapKey = getMapKey(method);     this.returnsMap = (this.mapKey != null);     //是否存在@Param注解     this.hasNamedParameters = hasNamedParams(method);     this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);     this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);     this.params = Collections.unmodifiableSortedMap(getParams(method, this.hasNamedParameters)); }
  走完这一系列后回到MapperProxy.java中的invoke方法,最后执行 mapperMethod.execute(sqlSession, args)
  MapperMethod.java
  java public Object execute(SqlSession sqlSession, Object[] args) {     Object result;     if(){         //.......     } else if (SqlCommandType.SELECT == command.getType()) {         if (method.returnsVoid() && method.hasResultHandler()) {             executeWithResultHandler(sqlSession, args);             result = null;         } else if (method.returnsMany()) {             result = executeForMany(sqlSession, args);         } else if (method.returnsMap()) {             result = executeForMap(sqlSession, args);         } else {             Object param = method.convertArgsToSqlCommandParam(args);             result = sqlSession.selectOne(command.getName(), param);         }     } else if (SqlCommandType.FLUSH == command.getType()) {         result = sqlSession.flushStatements();     } else {         throw new BindingException("Unknown execution method for: " + command.getName());     }     if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {         throw new BindingException("Mapper method "" + command.getName()                                     + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");     }     return result; }
  根据command的类型,当前这个案例是SELECT,进入后判断返回类型,当前是返回一个集合,returnsMany属性为ture,进入到 result = executeForMany(sqlSession, args);
  java private  Object executeForMany(SqlSession sqlSession, Object[] args) {     List result;     //封装入参     Object param = method.convertArgsToSqlCommandParam(args);  	//这个为false,没有设置过逻辑分页     if (method.hasRowBounds()) {         RowBounds rowBounds = method.extractRowBounds(args);         result = sqlSession.selectList(command.getName(), param, rowBounds);     } else {         result = sqlSession.selectList(command.getName(), param);     }     // issue #510 Collections & arrays support     if (!method.getReturnType().isAssignableFrom(result.getClass())) {         if (method.getReturnType().isArray()) {             return convertToArray(result);         } else {             return convertToDeclaredCollection(sqlSession.getConfiguration(), result);         }     }     return result; }
  java public Object convertArgsToSqlCommandParam(Object[] args) {     final int paramCount = params.size();     if (args == null || paramCount == 0) {         return null;     } else if (!hasNamedParameters && paramCount == 1) {         return args[params.keySet().iterator().next()];     } else {         final Map param = new ParamMap();         int i = 0;         for (Map.Entry entry : params.entrySet()) {             param.put(entry.getValue(), args[entry.getKey().intValue()]);             // issue #71, add param names as param1, param2...but ensure backward compatibility             final String genericParamName = "param" + String.valueOf(i + 1);             if (!param.containsKey(genericParamName)) {                 param.put(genericParamName, args[entry.getKey()]);             }             i++;         }         return param;     } }
  封装mapper入参,没有入参返回null,一个入参返回数组,多个入参返回ParamMap
  最终执行到 result = sqlSession.selectList(command.getName(), param);
  DefaultSqlSession.java
  java public  List selectList(String statement, Object parameter) {     return this.selectList(statement, parameter, RowBounds.DEFAULT); }  @Override public  List selectList(String statement, Object parameter, RowBounds rowBounds) {     try {         MappedStatement ms = configuration.getMappedStatement(statement);         return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);     } catch (Exception e) {         throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);     } finally {         ErrorContext.instance().reset();     } }
  warpCollection方法对入参同一封装了一遍
  DefaultSqlSession.java
  java private Object wrapCollection(final Object object) {     //如果是集合     if (object instanceof Collection) {         StrictMap map = new StrictMap();         map.put("collection", object);         if (object instanceof List) {             map.put("list", object);         }         return map;     //如果是数组     } else if (object != null && object.getClass().isArray()) {         StrictMap map = new StrictMap();         map.put("array", object);         return map;     }     return object; }
  之后进入executor.query()
  java   @Override   public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {     BoundSql boundSql = ms.getBoundSql(parameter);     CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);     return query(ms, parameter, rowBounds, resultHandler, key, boundSql);  }
  第一步先获取该方法对应的sql,入参类型,入参参数
  ms.getBoundSql(parameter);
  之后是创建缓存key
  java @Override public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {     if (closed) {         throw new ExecutorException("Executor was closed.");     }     CacheKey cacheKey = new CacheKey();     cacheKey.update(ms.getId());     cacheKey.update(Integer.valueOf(rowBounds.getOffset()));     cacheKey.update(Integer.valueOf(rowBounds.getLimit()));     cacheKey.update(boundSql.getSql());     List parameterMappings = boundSql.getParameterMappings();     TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();     // mimic DefaultParameterHandler logic     for (int i = 0; i < parameterMappings.size(); i++) {         ParameterMapping parameterMapping = parameterMappings.get(i);         if (parameterMapping.getMode() != ParameterMode.OUT) {             Object value;             String propertyName = parameterMapping.getProperty();             if (boundSql.hasAdditionalParameter(propertyName)) {                 value = boundSql.getAdditionalParameter(propertyName);             } else if (parameterObject == null) {                 value = null;             } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {                 value = parameterObject;             } else {                 MetaObject metaObject = configuration.newMetaObject(parameterObject);                 value = metaObject.getValue(propertyName);             }             cacheKey.update(value);         }     }     if (configuration.getEnvironment() != null) {         // issue #176         cacheKey.update(configuration.getEnvironment().getId());     }     return cacheKey; }
  创建CacheKey作为缓存key的封装类,根据以下参数进行生成key MappedStatement的id rowBounds.getOffset() 跳过条数 rowBounds.getLimit() 限制条数 boundSql.getSql() 要执行的sql语句
  之后遍历
  如果是数组就将每个元素取出然后执行doUpdate,否则直接执行
  CacheKey.java
  java private void doUpdate(Object object) {     int baseHashCode = object == null ? 1 : object.hashCode();      count++;     checksum += baseHashCode;     baseHashCode *= count;      hashcode = multiplier * hashcode + baseHashCode;      updateList.add(object); }
  最后走到 query
  CachingExecutor.java
  java @Override public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)     throws SQLException {     Cache cache = ms.getCache();     if (cache != null) {         flushCacheIfRequired(ms);         if (ms.isUseCache() && resultHandler == null) {             ensureNoOutParams(ms, parameterObject, boundSql);             @SuppressWarnings("unchecked")             List list = (List) tcm.getObject(cache, key);             if (list == null) {                 list = delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);                 tcm.putObject(cache, key, list); // issue #578 and #116             }             return list;         }     }     return delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
  因为是首次进入,没有缓存,直接到BaseExecutor.query方法
  BaseExecutor.java
  java @Override public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {     ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());     if (closed) {         throw new ExecutorException("Executor was closed.");     }     if (queryStack == 0 && ms.isFlushCacheRequired()) {         clearLocalCache();     }     List list;     try {         queryStack++;         list = resultHandler == null ? (List) localCache.getObject(key) : null;         if (list != null) {             handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);         } else {             list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);         }     } finally {         queryStack--;     }     if (queryStack == 0) {         for (DeferredLoad deferredLoad : deferredLoads) {             deferredLoad.load();         }         // issue #601         deferredLoads.clear();         if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {             // issue #482             clearLocalCache();         }     }     return list; }
  进入后判断如果queryStack==0并且当前MappedStatement声明了需要清除缓存,则去清除缓存
  java @Options(flushCache= Options.FlushCachePolicy.TRUE)
  xml