我们以往使用ibatis或者mybatis 都是以这种方式调用XML当中定义的CRUD标签来执行SQL 比如这样

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>
SqlSession session = sqlSessionFactory.openSession();
try {
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
  session.close();
}

这种方式有很明显的缺点就是通过字符串去调用标签定义的SQL,第一容易出错,第二是当XML当中的id修改过以后你不知道在程序当中有多少个地方使用了这个ID,需要手工查找并一一修改。在Mybatis这个版本中做了一些改进,支持这种方式调用。

定义一个接口 方法名,参数需要与XML定义保持一致。(namespace要对应包名和类名,不然mybatis定位不了)

org.mybatis.example.BlogMapper.selectBlog
public interface BlogMapper {
  Blog selectBlog(int id);
}

aaarticlea/png;base64,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" alt="" />

aaarticlea/png;base64,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" alt="" />


然后这么调用,这样以来当我们修改了XML的ID以后,只需要修改接口中的方法就可以了,编译器会在其他使用该接口的地方报错,很容易进行修改。当然好处还不只这些,还可以通过与Spring进行无缝集成,动态注入 等等。后面会一一讲到。

SqlSession session = sqlSessionFactory.openSession();
try {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  Blog blog = mapper.selectBlog(101);
} finally {
  session.close();
}

本 文的重点不是去讲解如何使用MyBatis(关于如何使用Mybatis可以参考官方API http://mybatis.github.io/mybatis-3/zh/getting-started.html),而是讲解MyBatis是 如何通过接口对SqlSession进行动态封装的。

在上面的例子当中呢,BlogMapper是一个接口 它并没有实现类,为什么接口可以直接使用呢? 

那是因为MyBbatis使用了JDK动态代理机制动态生成了代理类,那么代理类又是如何多SqlSession进行封装的呢?

带着这些疑问,让我们通过分析源代码的方式来解释这些问题。

Mybatis关于包装Mapper的代码都在org.apache.ibatis.binding 这个包下面。

其中有4个类。

上面的4个类封装了Mapper接口动态生成代理类的全部细节

MapperRegistry 类是注册Mapper接口与获取代理类实例的工具类

package org.apache.ibatis.binding;
import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder;
import org.apache.ibatis.io.ResolverUtil;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
//这个类通过名字就可以看出 是用来注册Mapper接口与获取生成代理类实例的工具类 
public class MapperRegistry {
  //全局配置文件对象
  private Configuration config;
  //一个HashMap Key是mapper的类型对象, Value是MapperProxyFactory对象
  //这个MapperProxyFactory是创建Mapper代理对象的工厂 我们一会在分析
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
  public MapperRegistry(Configuration config) {
    this.config = config;
  }
  //获取生成的代理对象
  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //通过Mapper的接口类型 去Map当中查找 如果为空就抛异常
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null)
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    try {
      //否则创建一个当前接口的代理对象 并且传入sqlSession
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
  
  public <T> boolean hasMapper(Class<T> type) {
    return knownMappers.containsKey(type);
  }
  //注册Mapper接口
  public <T> void addMapper(Class<T> 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<T>(type));
        // It's important that the type is added before the parser is run
        // otherwise the binding may automatically be attempted by the
        // mapper parser. If the type is already known, it won't try.
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
        parser.parse();
        loadCompleted = true;
      } finally {
        if (!loadCompleted) {
          knownMappers.remove(type);
        }
      }
    }
  }
  public Collection<Class<?>> getMappers() {
    return Collections.unmodifiableCollection(knownMappers.keySet());
  }
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
    for (Class<?> mapperClass : mapperSet) {
      addMapper(mapperClass);
    }
  }
  //通过包名扫描下面所有接口
  public void addMappers(String packageName) {
    addMappers(packageName, Object.class);
  }
  
}
MapperRegistry
package org.apache.ibatis.binding;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.ibatis.session.SqlSession;
//这个类负责创建具体Mapper接口代理对象的工厂类
public class MapperProxyFactory<T> {
  //具体Mapper接口的Class对象
  private final Class<T> mapperInterface;
  //该接口下面方法的缓存 key是方法对象 value是对接口中方法对象的封装
  private Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
  //构造参数没啥好说的
  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }
  public Class<T> getMapperInterface() {
    return mapperInterface;
  }
  public Map<Method, MapperMethod> getMethodCache() {
    return methodCache;
  }
  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    //创建了一个代理类并返回
    //关于Proxy的API 可以查看java官方的API
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }
  //在这里传入sqlSession 创建一个Mapper接口的代理类
  public T newInstance(SqlSession sqlSession) {
    //在这里创建了MapperProxy对象 这个类实现了JDK的动态代理接口 InvocationHandler
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    //调用上面的方法 返回一个接口的代理类
    return newInstance(mapperProxy);
  }
}
MapperProxyFactory
package org.apache.ibatis.binding;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
//实现了JDK动态代理的接口 InvocationHandler
//在invoke方法中实现了代理方法调用的细节
public class MapperProxy<T> implements InvocationHandler, Serializable {
  private static final long serialVersionUID = -6424540398559729838L;
  //SqlSession
  private final SqlSession sqlSession;
  //接口的类型对象
  private final Class<T> mapperInterface;
  //接口中方法的缓存 有MapperProxyFactory传递过来的。
  private final Map<Method, MapperMethod> methodCache;
  //构造参数
  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }
  //接口代理对象所有的方法调用 都会调用该方法
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //判断是不是基础方法 比如toString() hashCode()等,这些方法直接调用不需要处理
    if (Object.class.equals(method.getDeclaringClass())) {
      return method.invoke(this, args);
    }
    //这里进行缓存
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //调用mapperMethod.execute 核心的地方就在这个方法里,这个方法对才是真正对SqlSession进行的包装调用
    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;
  }
}
MapperProxy
package org.apache.ibatis.binding;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.*;
//这个类是整个代理机制的核心类,对Sqlsession当中的操作进行了封装
public class MapperMethod {
  //一个内部封 封装了SQL标签的类型 insert update delete select
  private final SqlCommand command;
  //一个内部类 封装了方法的参数信息 返回类型信息等
  private final MethodSignature method;
  //构造参数
  public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
    this.command = new SqlCommand(config, mapperInterface, method);
    this.method = new MethodSignature(config, method);
  }
  //这个方法是对SqlSession的包装调用
  public Object execute(SqlSession sqlSession, Object[] args) {
    //定义返回结果
    Object result;
    //如果是INSERT操作
    if (SqlCommandType.INSERT == command.getType()) {
      //处理参数
      Object param = method.convertArgsToSqlCommandParam(args);
      //调用sqlSession的insert方法
      result = rowCountResult(sqlSession.insert(command.getName(), param));
      //如果是UPDATE操作 同上
    } else if (SqlCommandType.UPDATE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.update(command.getName(), param));
      //如果是DELETE操作 同上
    } else if (SqlCommandType.DELETE == command.getType()) {
      Object param = method.convertArgsToSqlCommandParam(args);
      result = rowCountResult(sqlSession.delete(command.getName(), param));
      //如果是SELECT操作 那么情况会多一些 但是也都和sqlSession的查询方法一一对应
    } else if (SqlCommandType.SELECT == command.getType()) {
      //如果返回void 并且参数有resultHandler
      //则调用 void select(String statement, Object parameter, ResultHandler handler);方法
      if (method.returnsVoid() && method.hasResultHandler()) {
        executeWithResultHandler(sqlSession, args);
        result = null;
      //如果返回多行结果这调用 <E> List<E> selectList(String statement, Object parameter);
      //executeForMany这个方法调用的
      } else if (method.returnsMany()) {
        result = executeForMany(sqlSession, args);
      //如果返回类型是MAP 则调用executeForMap方法
      } else if (method.returnsMap()) {
        result = executeForMap(sqlSession, args);
      } else {
        //否则就是查询单个对象
        Object param = method.convertArgsToSqlCommandParam(args);
        result = sqlSession.selectOne(command.getName(), param);
      }
    } else {
      //如果全都不匹配 说明mapper中定义的方法不对
      throw new BindingException("Unknown execution method for: " + command.getName());
    }
    //如果返回值为空 并且方法返回值类型是基础类型 并且不是VOID 则抛出异常
    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;
  }
  private Object rowCountResult(int rowCount) {
    final Object result;
    if (method.returnsVoid()) {
      result = null;
    } else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
      result = rowCount;
    } else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
      result = (long) rowCount;
    } else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
      result = (rowCount > 0);
    } else {
      throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
    }
    return result;
  }
  private void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
    MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
    if (void.class.equals(ms.getResultMaps().get(0).getType())) {
      throw new BindingException("method " + command.getName() 
          + " needs either a @ResultMap annotation, a @ResultType annotation," 
          + " or a resultType attribute in XML so a ResultHandler can be used as a parameter.");
    }
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
    } else {
      sqlSession.select(command.getName(), param, method.extractResultHandler(args));
    }
  }
  //返回多行结果 调用sqlSession.selectList方法
  private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    List<E> result;
    Object param = method.convertArgsToSqlCommandParam(args);
    //如果参数含有rowBounds则调用分页的查询
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.<E>selectList(command.getName(), param, rowBounds);
    } else {
      //没有分页则调用普通查询
      result = sqlSession.<E>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;
  }
  private <E> Object convertToDeclaredCollection(Configuration config, List<E> list) {
    Object collection = config.getObjectFactory().create(method.getReturnType());
    MetaObject metaObject = config.newMetaObject(collection);
    metaObject.addAll(list);
    return collection;
  }
  @SuppressWarnings("unchecked")
  private <E> E[] convertToArray(List<E> list) {
    E[] array = (E[]) Array.newInstance(method.getReturnType().getComponentType(), list.size());
    array = list.toArray(array);
    return array;
  }
  private <K, V> Map<K, V> executeForMap(SqlSession sqlSession, Object[] args) {
    Map<K, V> result;
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.<K, V>selectMap(command.getName(), param, method.getMapKey(), rowBounds);
    } else {
      result = sqlSession.<K, V>selectMap(command.getName(), param, method.getMapKey());
    }
    return result;
  }
  public static class ParamMap<V> extends HashMap<String, V> {
    private static final long serialVersionUID = -2212268410512043556L;
    @Override
    public V get(Object key) {
      if (!super.containsKey(key)) {
        throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + keySet());
      }
      return super.get(key);
    }
  }
//一个内部类 封装了具体执行的动作
  public static class SqlCommand {
    //xml标签的id
    private final String name;
    //insert update delete select的具体类型
    private final SqlCommandType type;
    public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) throws BindingException {
      //拿到全名 比如 org.mybatis.example.BlogMapper.selectBlog
      String statementName = mapperInterface.getName() + "." + method.getName();
      MappedStatement ms = null;
      //获取MappedStatement对象 这个对象封装了XML当中一个标签的所有信息 比如下面
      //<select id="selectBlog" resultType="Blog">
      //select * from Blog where id = #{id}
      //</select>
      if (configuration.hasStatement(statementName)) {
        ms = configuration.getMappedStatement(statementName);
      } else if (!mapperInterface.equals(method.getDeclaringClass().getName())) { // 这里是一个BUG
        String parentStatementName = method.getDeclaringClass().getName() + "." + method.getName();
        if (configuration.hasStatement(parentStatementName)) {
          ms = configuration.getMappedStatement(parentStatementName);
        }
      }
      //为空抛出异常
      if (ms == null) {
        throw new BindingException("Invalid bound statement (not found): " + statementName);
      }
      name = ms.getId();
      type = ms.getSqlCommandType();
      //判断SQL标签类型 未知就抛异常
      if (type == SqlCommandType.UNKNOWN) {
        throw new BindingException("Unknown execution method for: " + name);
      }
    }
    public String getName() {
      return name;
    }
    public SqlCommandType getType() {
      return type;
    }
  }
  //内部类 封装了接口当中方法的 参数类型 返回值类型 等信息
  public static class MethodSignature {
    //是否返回多调结果
    private final boolean returnsMany;
    //返回值是否是MAP
    private final boolean returnsMap;
    //返回值是否是VOID
    private final boolean returnsVoid;
    //返回值类型
    private final Class<?> returnType;
    //mapKey
    private final String mapKey;
    //resultHandler类型参数的位置
    private final Integer resultHandlerIndex;
    //rowBound类型参数的位置
    private final Integer rowBoundsIndex;
    //用来存放参数信息
    private final SortedMap<Integer, String> params;
    //是否存在命名参数
    private final boolean hasNamedParameters;
    //在这里对上面的属性进行初始化 就不一一详细说明了 具体实现细节可以看下面的代码。
    public MethodSignature(Configuration configuration, Method method) throws BindingException {
      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);
      this.hasNamedParameters = hasNamedParams(method);
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      this.params = Collections.unmodifiableSortedMap(getParams(method, this.hasNamedParameters));
    }
    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<String, Object> param = new ParamMap<Object>();
        int i = 0;
        for (Map.Entry<Integer, String> entry : params.entrySet()) {
          param.put(entry.getValue(), args[entry.getKey()]);
          // 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;
      }
    }
    public boolean hasRowBounds() {
      return (rowBoundsIndex != null);
    }
    public RowBounds extractRowBounds(Object[] args) {
      return (hasRowBounds() ? (RowBounds) args[rowBoundsIndex] : null);
    }
    public boolean hasResultHandler() {
      return (resultHandlerIndex != null);
    }
    public ResultHandler extractResultHandler(Object[] args) {
      return (hasResultHandler() ? (ResultHandler) args[resultHandlerIndex] : null);
    }
    public String getMapKey() {
      return mapKey;
    }
    public Class<?> getReturnType() {
      return returnType;
    }
    public boolean returnsMany() {
      return returnsMany;
    }
    public boolean returnsMap() {
      return returnsMap;
    }
    public boolean returnsVoid() {
      return returnsVoid;
    }
    private Integer getUniqueParamIndex(Method method, Class<?> paramType) {
      Integer index = null;
      final Class<?>[] argTypes = method.getParameterTypes();
      for (int i = 0; i < argTypes.length; i++) {
        if (paramType.isAssignableFrom(argTypes[i])) {
          if (index == null) {
            index = i;
          } else {
            throw new BindingException(method.getName() + " cannot have multiple " + paramType.getSimpleName() + " parameters");
          }
        }
      }
      return index;
    }
    private String getMapKey(Method method) {
      String mapKey = null;
      if (Map.class.isAssignableFrom(method.getReturnType())) {
        final MapKey mapKeyAnnotation = method.getAnnotation(MapKey.class);
        if (mapKeyAnnotation != null) {
          mapKey = mapKeyAnnotation.value();
        }
      }
      return mapKey;
    }
    private SortedMap<Integer, String> getParams(Method method, boolean hasNamedParameters) {
      final SortedMap<Integer, String> params = new TreeMap<Integer, String>();
      final Class<?>[] argTypes = method.getParameterTypes();
      for (int i = 0; i < argTypes.length; i++) {
        if (!RowBounds.class.isAssignableFrom(argTypes[i]) && !ResultHandler.class.isAssignableFrom(argTypes[i])) {
          String paramName = String.valueOf(params.size());
          if (hasNamedParameters) {
            paramName = getParamNameFromAnnotation(method, i, paramName);
          }
          params.put(i, paramName);
        }
      }
      return params;
    }
    private String getParamNameFromAnnotation(Method method, int i, String paramName) {
      final Object[] paramAnnos = method.getParameterAnnotations()[i];
      for (Object paramAnno : paramAnnos) {
        if (paramAnno instanceof Param) {
          paramName = ((Param) paramAnno).value();
        }
      }
      return paramName;
    }
    private boolean hasNamedParams(Method method) {
      boolean hasNamedParams = false;
      final Object[][] paramAnnos = method.getParameterAnnotations();
      for (Object[] paramAnno : paramAnnos) {
        for (Object aParamAnno : paramAnno) {
          if (aParamAnno instanceof Param) {
            hasNamedParams = true;
            break;
          }
        }
      }
      return hasNamedParams;
    }
  }
}
MapperMethod

通过上面的分析就很容易弄清楚Mybatis是如何利用JDK动态代理的机制生成代理类来对各种Mapper接口进行封装的了。

MyBatis Mapper 接口如何通过JDK动态代理来包装SqlSession 源码分析的更多相关文章

  1. java动态代理基本原理及proxy源码分析一

    本系列文章主要是博主在学习spring aop的过程中了解到其使用了java动态代理,本着究根问底的态度,于是对java动态代理的本质原理做了一些研究,于是便有了这个系列的文章 为了尽快进入正题,这里 ...

  2. Spring Cloud Nacos实现动态配置加载的源码分析

    理解了上述Environment的基本原理后,如何从远程服务器上加载配置到Spring的Environment中. NacosPropertySourceLocator 顺着前面的分析思路,我们很自然 ...

  3. JDK(五)JDK1.8源码分析【集合】HashMap

    本文转载自无始无终,原文连接 HashMap 在 JDK 1.8 后新增的红黑树结构 传统 HashMap 的缺点 JDK 1.8 以前 HashMap 的实现是 数组+链表,即使哈希函数取得再好,也 ...

  4. JDK(七)JDK1.8源码分析【集合】TreeMap

    本文转载自joemsu,原文链接 [JDK1.8]JDK1.8集合源码阅读——TreeMap(二) TreeMap是JDK中一种排序的数据结构.在这一篇里,我们将分析TreeMap的数据结构,深入理解 ...

  5. JDK(二)JDK1.8源码分析【排序】timsort

    如无特殊说明,文中的代码均是JDK 1.8版本. 在JDK集合框架中描述过,JDK存储一组Object的集合框架是Collection.而针对Collection框架的一组操作集合体是Collecti ...

  6. Mybatis【2.2】-- Mybatis关于创建SqlSession源码分析的几点疑问?

    代码直接放在Github仓库[https://github.com/Damaer/Mybatis-Learning ],可直接运行,就不占篇幅了. 目录 1.为什么我们使用SQLSessionFact ...

  7. JDK动态代理Demo代码,进一步学习分析

    import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflec ...

  8. Future模式的学习以及JDK内置Future模式的源码分析

    并发程序设计之Future模式 一).使用Future模式的原因 当某一段程序提交了一个请求,期待得到一个答复,但服务程序对这个请求的处理可能很慢,在单线程的环境中,调用函数是同步的,必须等到服务程序 ...

  9. JDK(三)JDK1.8源码分析【排序】mergeSort

    归并排序是JDK对象数组的排序算法之一,接下来开始分析JDK的归并排序算法. /** * 将指定范围的对象数组按自然顺序升序排序 * * Src is the source array that st ...

随机推荐

  1. OpenStack collectd的从零安装客户端

    1.查看是否需要增加yum 源 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [root@node-12 ~]# yum search collectd Loaded plugin ...

  2. JVM复习笔记

    1. JVM是什么? JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来 ...

  3. 160901、在大型项目中组织CSS

    编写CSS容易. 编写可维护的CSS难. 这句话你之前可能听过100次了. 原因是CSS中的一切都默认为全局的.如果你是一个C程序员你就知道全局变量不好.如果你是任何一种程序员,你都知道隔离和可组合的 ...

  4. php CodeIgniter处理多环境错误级别配置

    php CodeIgniter处理多环境错误级别配置 开发者常常希望当系统运行在开发环境或生产环境中时能有不同的行为, 例如,在开发环境如果程序能输出详细的错误信息将非常有用,但是在 生产环境这将造成 ...

  5. JSP直接连接sql2008数据库并显示

    <%@ page contentType="text/html; charset=utf-8" language="java" errorPage=&qu ...

  6. Bootstrap:弹出框和提示框效果以及代码展示

    前言:对于Web开发人员,弹出框和提示框的使用肯定不会陌生,比如常见的表格新增和编辑功能,一般常见的主要有两种处理方式:行内编辑和弹出框编辑.在增加用户体验方面,弹出框和提示框起着重要的作用,如果你的 ...

  7. html5 教程网站

    html5 MDN Canvas tutorial Canvas教程 canvas: 阮一峰 在那山的那边海的那边有一群程序猿 使用 HTML5 canvas 绘制精美的图形 HTML5定稿了,为什么 ...

  8. C#小知识点

    1.显示|隐示转换: public static explicit operator ImplicitClass(ExplicitClass explicitClass) //implicit { I ...

  9. ftp -i -n -v <<! 其中 -n禁止自动登录到初始连接

    <<!说明是输入.如是结束了需要再输入 !例如:ftp  -i -n -v  <<! 这里的叹号代表是ftp 命令的开始get  文件exit  !      代表ftp的命令 ...

  10. ACM题目————一笔画问题

    描述 zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,判断一个图是否能够用一笔画下来. 规定,所有的边都只能画一次,不能重复画. 输入 第一行只有一个正整数N(N< ...