myBatis源码解析

// 对外提供的数据源工厂接口

public interface DataSourceFactory {

  // 设置配置信息

  void setProperties(Properties props);

// 获取数据源

  DataSource getDataSource();

}

复制代码

复制代码

// 非池化的数据源工厂类

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; // 数据源   

  public UnpooledDataSourceFactory() {

    this.dataSource = new UnpooledDataSource(); // 构造一个非池化的数据源(下文分析数据源详细代码)

  }

  public void setProperties(Properties properties) { // 对数据源进行配置,此处设计反射包的知识(本章重点不在这,可忽略)

    Properties driverProperties = new Properties();

    MetaObject metaDataSource = SystemMetaObject.forObject(dataSource); // 将dataSource类转为metaObject类

    for (Object key : properties.keySet()) {

      String propertyName = (String) key;

      if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) { // 若是数据库驱动配置

        String value = properties.getProperty(propertyName);

        driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value); // driverProperties存储数据库驱动参数

      } else if (metaDataSource.hasSetter(propertyName)) { // 如果有set方法

        String value = (String) properties.get(propertyName);

        // 根据属性类型进行类型的转换,主要是 Integer, Long, Boolean 三种类型的转换

        Object convertedValue = convertValue(metaDataSource, propertyName, value);

        // 设置DataSource 的相关属性值

        metaDataSource.setValue(propertyName, convertedValue);

      } else {

        throw new DataSourceException("Unknown DataSource property: " + propertyName);

      }

    }

    // 设置 DataSource.driverProerties 属性值

    if (driverProperties.size() > 0) {

      metaDataSource.setValue("driverProperties", driverProperties);

    }

  }

  // 获取数据源

  public DataSource getDataSource() {

    return dataSource;

  }

// 对Integer, Long, Boolean 三种类型的转换

  private Object convertValue(MetaObject metaDataSource, String propertyName, String value) {

    Object convertedValue = value;

    Class<?> targetType = metaDataSource.getSetterType(propertyName);

    if (targetType == Integer.class || targetType == int.class) {

      convertedValue = Integer.valueOf(value);

    } else if (targetType == Long.class || targetType == long.class) {

      convertedValue = Long.valueOf(value);

    } else if (targetType == Boolean.class || targetType == boolean.class) {

      convertedValue = Boolean.valueOf(value);

    }

    return convertedValue;

  }

}

复制代码

复制代码

public class PooledDataSourceFactory extends UnpooledDataSourceFactory {

  public PooledDataSourceFactory() {

    // dataSource实现类变为PooledDataSource

    this.dataSource = new PooledDataSource();

  }

}

复制代码

unPooledDataSourceFactory主要工作是对数据源进行参数配置,并提供获取数据源方法。分析PooledDataSourceFactory源码,只是继承unPooledDataSourceFactory,将DataSource实现类改变为PooledDataSource。

unPooledDataSource源码分析:基本的数据源实现都实现了DataSource接口,重写获取数据库连接的方法。unPooledDataSource从类名可知,不支持数据库连接的池化。也就是说,每来一个获取连接请求,就新建一个数据库连接。让我们看源码验证下。

复制代码

public class UnpooledDataSource implements DataSource {


  private ClassLoader driverClassLoader; // 数据库驱动类加载器

  private Properties driverProperties; // 有关数据库驱动的参数

  private static Map<String, Driver> registeredDrivers = new ConcurrentHashMap<String, Driver>(); // 缓存已注册过的数据库驱动

  private String driver; // 数据库驱动

  private String url; // 数据库名

  private String username; // 连接用户名

  private String password; // 密码

  private Boolean autoCommit; // 是否自动提交

  private Integer defaultTransactionIsolationLevel; // 事物隔离级别

  static { // 初始化

    Enumeration<Driver> drivers = DriverManager.getDrivers();  // DriverManager中已存在的数据库驱动加载到数据库驱动缓存

    while (drivers.hasMoreElements()) {

      Driver driver = drivers.nextElement();

      registeredDrivers.put(driver.getClass().getName(), driver);

    }

  }

  .....



  public Connection getConnection() throws SQLException {

    return doGetConnection(username, password);

  }


  // 获取数据库连接

  private Connection doGetConnection(Properties properties) throws SQLException {

    initializeDriver(); // 初始化数据库驱动

    Connection connection = DriverManager.getConnection(url, properties); // 此处每次获取连接,就新建一个数据库连接

    configureConnection(connection); // 设置数据库是否自动提交,设置数据库事物隔离级别

    return connection;

  }

  private synchronized void initializeDriver() throws SQLException {

    // 若此驱动还没初始化,则进行初始化

    if (!registeredDrivers.containsKey(driver)) {

      Class<?> driverType;

      try {

        if (driverClassLoader != null) {

          driverType = Class.forName(driver, true, driverClassLoader);

        } else {

          driverType = Resources.classForName(driver);

        }

        // DriverManager requires the driver to be loaded via the system ClassLoader.

        // http://www.kfu.com/~nsayer/Java/dyn-jdbc.html

        Driver driverInstance = (Driver)driverType.newInstance();

        DriverManager.registerDriver(new DriverProxy(driverInstance));

        registeredDrivers.put(driver, driverInstance);

      } catch (Exception e) {

        throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);

      }

    }

  }

  private void configureConnection(Connection conn) throws SQLException {

    if (autoCommit != null && autoCommit != conn.getAutoCommit()) {

      conn.setAutoCommit(autoCommit);

    }

    if (defaultTransactionIsolationLevel != null) {

      conn.setTransactionIsolation(defaultTransactionIsolationLevel);

    }

  }

  ....

}

PoolConnection是一个connection代理类,里面封装了真实的连接与代理连接,现在我们先来分析PoolConnection的源码。

复制代码

class PooledConnection implements InvocationHandler {  // 连接代理类

  private static final String CLOSE = "close";

  private static final Class<?>[] IFACES = new Class<?>[] { Connection.class };

  private int hashCode = 0;

  private PooledDataSource dataSource; // 数据源

  private Connection realConnection; // 被代理的真实连接

  private Connection proxyConnection; // 代理连接

  private long checkoutTimestamp; // 从连接池中取出连接的时间

  private long createdTimestamp; // 连接建立的时间

  private long lastUsedTimestamp; // 连接上次使用的时间

  private int connectionTypeCode; // 用于标注该连接所在的连接池

  private boolean valid; // 连接有效的标志

复制代码

PooledConnection实现了InvocationHandler接口,则可见是一个代理对象。查看属性可知,内部有真实连接与代理连接,并附带连接的一些记录信息。查看该类的构造方法。

复制代码

public PooledConnection(Connection connection, PooledDataSource dataSource) {

    this.hashCode = connection.hashCode();

    this.realConnection = connection;

    this.dataSource = dataSource;

    this.createdTimestamp = System.currentTimeMillis();

    this.lastUsedTimestamp = System.currentTimeMillis();

    this.valid = true; // 该链接是否有效

    this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);  // 使用动态代理生成连接的代理类

  }

  /*

  * Invalidates the connection

  */

  // 将该链接置为无效   

  public void invalidate() {

    valid = false;

  }

复制代码

查看构造方法可知,内部除了初始化一些属性外,还将连接的代理类也进行初始化了。那代理类究竟做了什么,查看重写的invoke方法源码。

复制代码

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  // 代理方法

    String methodName = method.getName(); // 获取方法名

    if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) { // 若是close方法,则将该连接放入数据源中

      dataSource.pushConnection(this);

      return null;

    } else {

      try {

        if (!Object.class.equals(method.getDeclaringClass())) {  // 若要执行的方法不是object方法,则检查连接的有效性

          // issue #579 toString() should never fail

          // throw an SQLException instead of a Runtime

          checkConnection();

        }

        return method.invoke(realConnection, args);  //执行真实的方法

      } catch (Throwable t) {

        throw ExceptionUtil.unwrapThrowable(t);

      }

    }

  }

  private void checkConnection() throws SQLException {

    if (!valid) {

      throw new SQLException("Error accessing PooledConnection. Connection is invalid.");

    }

  }

复制代码

由源码可知,代理连接在执行方法时,会先检查此连接的有效性,然后执行真实的方法。分析完PoolConnection后,对PoolState进行源码解析。

复制代码

public class PoolState {  // 连接池状态信息

  protected PooledDataSource dataSource; // 此状态信息关联的数据源

  protected final List<PooledConnection> idleConnections = new ArrayList<PooledConnection>(); // 空闲连接列表

  protected final List<PooledConnection> activeConnections = new ArrayList<PooledConnection>(); // 活跃连接列表

  protected long requestCount = 0; // 请求数

  protected long accumulatedRequestTime = 0; // 累加请求所用时间

  protected long accumulatedCheckoutTime = 0; // 累加占用连接所用时间

  protected long claimedOverdueConnectionCount = 0;  // 连接超时的数量

  protected long accumulatedCheckoutTimeOfOverdueConnections = 0; // 累加超时的连接超时的时间

  protected long accumulatedWaitTime = 0; // 累加等待获取连接所用时间

  protected long hadToWaitCount = 0; // 等待获取连接的线程数

  protected long badConnectionCount = 0; // 失效的连接数

复制代码

PoolState是对DataSource的状态管理类,主要包括如累计连接超时时间,失效连接的获取等一些状态信息的管理。除了包括一些数据库连接的记录信息外,内部还维护了两个数据库连接的列表idleConnections,activeConnections.。分别用来存放空闲的数据库连接列表,活跃的数据库连接列表,针对此两个列表的操作,下文在分析PooledDataSource时会进行详细介绍。

对PoolConnection和PoolState分析结束后,具体分析PoolDataSource源码。

复制代码

public class PooledDataSource implements DataSource {

  private static final Log log = LogFactory.getLog(PooledDataSource.class);

  private final PoolState state = new PoolState(this); // 维护数据源的状态

  private final UnpooledDataSource dataSource; // 使用UnpooledDataSource来建立真正的连接

  // OPTIONAL CONFIGURATION FIELDS

  protected int poolMaximumActiveConnections = 10; // 最大活跃的连接数

  protected int poolMaximumIdleConnections = 5;  // 最大空闲的连接数

  protected int poolMaximumCheckoutTime = 20000; // 最大checkout时间(checkOutTime指的是从数据源中获取连接到归还连接的时间)

  protected int poolTimeToWait = 20000; // 最大等待时间

  protected String poolPingQuery = "NO PING QUERY SET"; // 使用该语句来验证该连接是否有效

  protected boolean poolPingEnabled = false;

  protected int poolPingConnectionsNotUsedFor = 0;

  private int expectedConnectionTypeCode; // hashcode

深圳网站建设www.sz886.com

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。