Java 数据源 DataSource 架构分析 (jdk7/tomcat7)

Java 数据源类图

简单说明

CommonDataSource:是对数据源概念的顶层抽象,约束了数据源必需实现的方法。
从架构图中可以看出数据源有三种类型,即CommonDataSource抽象有三种实现方式,分别是:
DataSource、XADataSource、ConnectionPoolDataSource,三种类型数据源说明如下:
DataSource:基础实现,数据库物理连接的工厂,用于创建标准的数据库物理连接Connection,JDBC 2.0中诞生,与早先的DriverManager用途一样,新版本JDBC编程已推荐使用DataSource;
XADataSource:分布式事务实现,为支持分布式事务而诞生,此数据源直接生产出的不是数据库物理连接Connection,而是一个支持XA的XAConnection对象,
XAConnection对象可以直接生产数据库物理连接Connection,同时生产XAResource用于支持XA事务,通常XAConnection对象生产出的数据库物理连接Connection需要和该XAConnection生产出的XAResource对象配合使用以完成XA事务处理(请参考 XA 和 JTA 规范);
ConnectionPoolDataSource:连接池实现,此数据源实现并不直接创建数据库物理连接,而是一个逻辑实现,它的作用在于池化数据库物理连接,由于数据库物理连接是一个重量级的对象,频繁的创建销毁很影响性能,将物理连接池化后可降低创建和销毁的频率,复用连接以充分利用连接资源,此数据源通常不为用户应用所知,通常是由中间件服务方来调度,中间件服务方通过它获取一个池化对象PooledConnection,再通过该PooledConnection间接获取到物理连接,获取方式即是调用其getConnection()方法,
然后创建出一个规范定义的Connection接口句柄提供给应用使用,应用通过该句柄间接使用物理连接,在应用调用句柄的close方法时,中间件服务方的实现并没有真正调用物理连接的关闭,而是将其归还到连接池中

另外,从类结构上可以看到XAConnection继承自PooledConnection,本身即是一个受管连接,可能设计之初也是考虑XA连接的池化机制了吧,也许是想管理普通Connection的池化对象PooledConnection可以兼容管理XAConnection(继承关系嘛),值得一提的是,在tomcat7的jdbc连接池的设计中,java自己的ConnectionPoolDataSource和PooledConnection机制已经被忽略掉了,tomcat7的jdbc连接池对外开发的连接句柄表象见如下代码片段:

org.apache.tomcat.jdbc.pool.ConnectionPool

Class<?> proxyClass = xa ?
                Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class,javax.sql.PooledConnection.class, javax.sql.XAConnection.class}) :
                Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class,javax.sql.PooledConnection.class});
            proxyClassConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
Connection connection = null;
            if (getPoolProperties().getUseDisposableConnectionFacade() ) {
                connection = (Connection)proxyClassConstructor.newInstance(new Object[] { new DisposableConnectionFacade(handler) });
            } else {
                connection = (Connection)proxyClassConstructor.newInstance(new Object[] {handler});
            }
            //return the connection
            return connection;
上文中动态生成的类定义是兼容PooledConnection的,但是在其代理的实现上却被无视了,代理是实现就是那个 handler,是一个InvocationHandler(实现类org.apache.tomcat.jdbc.pool.ProxyConnection),其invoke方法内容为:

@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (compare(ISCLOSED_VAL,method)) {
            return Boolean.valueOf(isClosed());
        }
        if (compare(CLOSE_VAL,method)) {
            if (connection==null) return null; //noop for already closed.
            PooledConnection poolc = this.connection;
            this.connection = null;
            pool.returnConnection(poolc);
            return null;
        } else if (compare(TOSTRING_VAL,method)) {
            return this.toString();
        } else if (compare(GETCONNECTION_VAL,method) && connection!=null) {
            return connection.getConnection();
        } else if (method.getDeclaringClass().equals(XAConnection.class)) {
            try {
                return method.invoke(connection.getXAConnection(),args);
            }catch (Throwable t) {
                if (t instanceof InvocationTargetException) {
                    throw t.getCause() != null ? t.getCause() : t;
                } else {
                    throw t;
                }
            }
        }
        if (isClosed()) throw new SQLException("Connection has already been closed.");
        if (compare(UNWRAP_VAL,method)) {
            return unwrap((Class<?>)args[0]);
        } else if (compare(ISWRAPPERFOR_VAL,method)) {
            return Boolean.valueOf(this.isWrapperFor((Class<?>)args[0]));
        }
        try {
            PooledConnection poolc = connection;
            if (poolc!=null) {
                return method.invoke(poolc.getConnection(),args);
            } else {
                throw new SQLException("Connection has already been closed.");
            }
        }catch (Throwable t) {
            if (t instanceof InvocationTargetException) {
                throw t.getCause() != null ? t.getCause() : t;
            } else {
                throw t;
            }
        }
    }
阅读可知,此invoke方法,只是将调用对象当作了Connection或XAConnection来处理,而并未考虑PooledConnection,所以如果应用将拿到的Connection句柄强制转换(动态定义时他确实是PooledConnection的实现,所以可强转)为PooledConnection时,调用PooledConnection特定的方法(如addConnectionEventListener/removeConnectionEventListener)就会出错,不过通常来讲应用也不会关心这些方法,应用也就只关心Connection和XAConnection。


tomcat连接池的实现在源码中是模块jdbc-pool,最后打包为 tomcat -jdbc.jar,有兴趣的可以研究下。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值