`
iwinit
  • 浏览: 452644 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

[Jboss数据源二]连接获取

阅读更多

从连接的视角来看类图

1.WrappedConnection直接实现了Connection接口,对外的包装类

2.BaseWrapperManagedConnection,包装了底层的物理连接,实现了连接获取,销毁等方法,psCache也是这里实现

3.BaseConnectionEventListener,和BaseWrapperManagedConnection互相引用,数据源内部实现并发控制的实体单元

4.InternalManagedConnectionPool,获取连接的并发控制地方,维护着connectionListener的列表和一个Semaphore信号量以实现最大连接数控制

 

连接获取过程

WrapperDataSource入口

public Connection getConnection() throws SQLException {
        try {
            WrappedConnection wc = (WrappedConnection) cm.allocateConnection(mcf, null);
            wc.setDataSource(this);
            wc.setZdatasource(zdatasource);
            return wc;
        } catch (ResourceException re) {
	......  
  }

 allocateConnection操作

public Object allocateConnection(ManagedConnectionFactory mcf, ConnectionRequestInfo cri)
                                                                                             throws ResourceException {
        ....

        // Pick a managed connection from the pool
        Subject subject = getSubject();
	//创建ConnectionListener
        ConnectionListener cl = getManagedConnection(subject, cri);

        // Tell each connection manager the managed connection is active
        reconnectManagedConnection(cl);

        // Ask the managed connection for a connection
        Object connection = null;
	//创建WrappedConnection
        try {
            connection = cl.getManagedConnection().getConnection(subject, cri);
        } catch (Throwable t) {
            managedConnectionDisconnected(cl);
            JBossResourceException.rethrowAsResourceException(
                "Unchecked throwable in ManagedConnection.getConnection() cl=" + cl, t);
        }

        // Associate managed connection with the connection
	//关联WrappedConnection和ConnectionListener
        registerAssociation(cl, connection);
	.....

        return connection;
   

 创建ConnectionListener过程

public ConnectionListener getConnection(Transaction trackByTransaction, Subject subject,
                                                ConnectionRequestInfo cri) throws ResourceException {
            // Determine the pool key for this request
            boolean separateNoTx = false;
            if (noTxSeparatePools)
                separateNoTx = clf.isTransactional();
            Object key = getKey(subject, cri, separateNoTx);
            SubPoolContext subPool = getSubPool(key, subject, cri, poolName);
	    //初始化连接池
            InternalManagedConnectionPool mcp = subPool.getSubPool();

            // Are we doing track by connection?
            TransactionLocal trackByTx = subPool.getTrackByTx();

            // Simple case
		//非事务,直接拿连接
            if (trackByTransaction == null || trackByTx == null) {
                ConnectionListener cl = mcp.getConnection(subject, cri);
                if (traceEnabled)
                    dump("Got connection from pool " + cl);
                return cl;
            }
		....
      }

 拿连接过程

    public ConnectionListener getConnection(Subject subject, ConnectionRequestInfo cri)
                                                                                       throws ResourceException {

        subject = (subject == null) ? defaultSubject : subject;
        cri = (cri == null) ? defaultCri : cri;
        long startWait = System.currentTimeMillis();
        try {
		//获取锁,blockingTimeout超时
            if (permits.tryAcquire(poolParams.blockingTimeout, TimeUnit.MILLISECONDS)) {
                //We have a permit to get a connection. Is there one in the pool already?
                ConnectionListener cl = null;
		//从缓存的连接中拿连接
                do {
                    synchronized (connectionListeners) {
                        if (shutdown.get()) {
                            permits.release();
                            throw new ResourceException("The pool has been shutdown");
                        }
			//如果缓存中有,则取之,并添加到checkedOut记录中,更新maxUsedConnections数
                        if (connectionListeners.size() > 0) {
                            cl = (ConnectionListener) connectionListeners
                                .remove(connectionListeners.size() - 1);
                            checkedOut.add(cl);
                            int size = (maxSize - permits.availablePermits());

                            //Update the maxUsedConnections
                            if (size > maxUsedConnections)
                                maxUsedConnections = size;
                        }
                    }
			//缓存中拿到了连接,进行校验
                    if (cl != null) {
                        //Yes, we retrieved a ManagedConnection from the pool. Does it match?
                        try {
                            Object matchedMC = mcf.matchManagedConnections(Collections.singleton(cl
                                .getManagedConnection()), subject, cri);
				//校验通过,返回连接
                            if (matchedMC != null) {
                                if (log.isDebugEnabled()) {
                                    log.debug("supplying ManagedConnection from pool: " + cl);
                                }

                                cl.grantPermit(true);
                                return cl;
                            }
				//校验不通过,销毁连接,继续找下一个连接
                            //Match did not succeed but no exception was thrown.
                            //Either we have the matching strategy wrong or the
                            //connection died while being checked.  We need to
                            //distinguish these cases, but for now we always
                            //destroy the connection.
                            log
                                .warn("Destroying connection that could not be successfully matched: "
                                      + cl);
                            synchronized (connectionListeners) {
                                checkedOut.remove(cl);
                            }
                            doDestroy(cl, "getConnection");
                            cl = null;

                        } catch (Throwable t) {
                         .....

                    }
                } while (connectionListeners.size() > 0);//end of do loop

                //OK, we couldnt find a working connection from the pool.  Make a new one.
		//从缓存中拿不到连接,则创建新的,并放入缓存
                try {
                    //No, the pool was empty, so we have to make a new one.
                    cl = createConnectionEventListener(subject, cri);
			//添加到checkOut中,returnConnection的时候再添加到connectionListeners中
                    synchronized (connectionListeners) {
                        checkedOut.add(cl);
                        int size = (maxSize - permits.availablePermits());
                        if (size > maxUsedConnections)
                            maxUsedConnections = size;
                    }

                    //lack of synch on "started" probably ok, if 2 reads occur we will just
                    //run fillPool twice, no harm done.
			//第一次启动的时候,进行最小连接数的预热
                    if (started == false) {
                        started = true;
                        if (poolParams.minSize > 0)
                            PoolFiller.fillPool(this);
                    }
                    if (log.isDebugEnabled()) {
                        log.debug("supplying new ManagedConnection: " + cl);
                    }

                    cl.grantPermit(true);
                    return cl;
                } catch (Throwable t) {
                    log.warn("Throwable while attempting to get a new connection: " + cl, t);
                    //return permit and rethrow
                    synchronized (connectionListeners) {
                        checkedOut.remove(cl);
                    }
                    permits.release();
                    JBossResourceException.rethrowAsResourceException(
                        "Unexpected throwable while trying to create a connection: " + cl, t);
                    throw new UnreachableStatementException();
                }
            } else {
		//获取连接失败,抛出异常
                if (this.maxSize == 0) {// 如果最大连接数为0,则说明db处于不可用状态
                    throw new ResourceException("当前数据库处于不可用状态,poolName = " + poolName,
                        ZConstants.ERROR_CODE_DB_NOT_AVAILABLE);
                } else if (this.maxSize == this.maxUsedConnections) {
                    throw new ResourceException("数据源最大连接数已满,并且在超时时间范围内没有新的连接释放,poolName = "
                                                + poolName + " blocking timeout="
                                                + poolParams.blockingTimeout + "(ms),now-time = "
                                                + sdf.format(new Date()),
                        ZConstants.ERROR_CODE_CONNECTION_NOT_AVAILABLE);
                } else {// 属于超时
                    throw new ResourceException(
                        "No ManagedConnections available within configured blocking timeout ( "
                                + poolParams.blockingTimeout + " [ms] ),the poolName = " + poolName,
                        ZConstants.ERROR_CODE_CONNECTION_TIMEOUT);
                }
            }

        } catch (InterruptedException ie) {
            long end = System.currentTimeMillis() - startWait;
            throw new ResourceException("Interrupted while requesting permit! Waited " + end
                                        + " ms", ie);
        }
    }

 获取物理连接过程

public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cri)
                                                                                                throws com.alipay.zdal.datasource.resource.ResourceException {
	//配置的链接参数
        Properties props = getConnectionProperties(subject, cri);
        // Some friendly drivers (Oracle, you guessed right) modify the props you supply.
        // Since we use our copy to identify compatibility in matchManagedConnection, we need
        // a pristine copy for our own use.  So give the friendly driver a copy.
        Properties copy = (Properties) props.clone();
        if (log.isDebugEnabled()) {
            // Make yet another copy to mask the password
            Properties logCopy = copy;
            if (copy.getProperty("password") != null) {
                logCopy = (Properties) props.clone();
                logCopy.setProperty("password", "--hidden--");
            }
            log.debug("Using properties: " + logCopy);
        }

        try {
		//从driver获取真实连接
            String url = getConnectionURL();
            Driver d = getDriver(url);
            Connection con = d.connect(url, copy);
            if (con == null) {
                throw new JBossResourceException("Wrong driver class for this connection URL");
            }
            String stz = copy.getProperty("sessionTimeZone");//支持oracle-driver中设置timestamp字段的属性.
            if (stz != null && stz.trim().length() > 0
                && (con instanceof oracle.jdbc.OracleConnection)) {
                ((oracle.jdbc.OracleConnection) con).setSessionTimeZone(stz);
            }

            return new LocalManagedConnection(this, con, props, transactionIsolation,
                preparedStatementCacheSize);
        } catch (Exception e) {
            throw new JBossResourceException("Could not create connection,the url = "
                                             + getConnectionURL(), e);
        }
    }

 以上就是获取连接的过程。接下来看以下,归还连接的过程

入口WrappedConnection.close方法

public void close() throws SQLException {
        closed = true;
        if (mc != null) {
            .....
		//通过ManagedConnection来关闭
            mc.closeHandle(this);
        }
	//释放引用,方便gc
        mc = null;
        dataSource = null;
    }

 BaseWrapperManagedConnection释放连接

void closeHandle(WrappedConnection handle) {
        synchronized (stateLock) {
            if (destroyed)
                return;
        }
	//把WrappedConnection引用释放
        synchronized (handles) {
            handles.remove(handle);
        }
	//发送CLOSED事件
        ConnectionEvent ce = new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED);
        ce.setConnectionHandle(handle);
        Collection copy = null;
        synchronized (cels) {
            copy = new ArrayList(cels);
        }
	//通知连接池里的onnectionEventListener进行连接释放
        for (Iterator i = copy.iterator(); i.hasNext();) {
            ConnectionEventListener cel = (ConnectionEventListener) i.next();
            cel.connectionClosed(ce);
        }
    }

 连接池内部释放连接,TxConnectionEventListener的connectionClosed方法

public void connectionClosed(ConnectionEvent ce) {

            ......

            try {
		//释放对WrappedConnection的引用
                unregisterAssociation(this, ce.getConnectionHandle());
                boolean isFree = isManagedConnectionFree();

                //no more handles
		//没有外部引用,则归还连接
                if (isFree) {
                    delist();
                    returnManagedConnection(this, false);
                }
            } catch (Throwable t) {
                log.error("Error while closing connection handle!", t);
                returnManagedConnection(this, true);
            }
        }

 InternalManagedConnectionPool归还过程

public void connectionClosed(ConnectionEvent ce) {

            ......

            try {
		//释放对WrappedConnection的引用
                unregisterAssociation(this, ce.getConnectionHandle());
                boolean isFree = isManagedConnectionFree();

                //no more handles
		//没有外部引用,则归还连接
                if (isFree) {
                    delist();
                    returnManagedConnection(this, false);
                }
            } catch (Throwable t) {
                log.error("Error while closing connection handle!", t);
                returnManagedConnection(this, true);
            }
        }
InternalManagedConnectionPool归还过程
public void returnConnection(ConnectionListener cl, boolean kill) {
	......
	//清理ManagedConnection里对外部WrappedConnection的引用
        try {
            cl.getManagedConnection().cleanup();
        } catch (ResourceException re) {
            log.warn("ResourceException cleaning up ManagedConnection: " + cl, re);
            kill = true;
        }

        // We need to destroy this one
        if (cl.getState() == ConnectionListener.DESTROY)
            kill = true;
	
        synchronized (connectionListeners) {
		//checkOut里删除
            checkedOut.remove(cl);

            // This is really an error
            if (kill == false && connectionListeners.size() >= poolParams.maxSize) {
                log.warn("Destroying returned connection, maximum pool size exceeded " + cl);
                kill = true;
            }

            // If we are destroying, check the connection is not in the pool
		//如果是销毁连接,则删除之
            if (kill) {
                // Adrian Brock: A resource adapter can asynchronously notify us that
                // a connection error occurred.
                // This could happen while the connection is not checked out.
                // e.g. JMS can do this via an ExceptionListener on the connection.
                // I have twice had to reinstate this line of code, PLEASE DO NOT REMOTE IT!
                connectionListeners.remove(cl);
            }
            // return to the pool
		//不销毁,重新添加到缓存中
            else {
                cl.used();
                connectionListeners.add(cl);
            }
		//重置状态为未使用,归还信号量
            if (cl.hasPermit()) {
                // release semaphore
                cl.grantPermit(false);
                permits.release();
            }
        }
	//销毁连接
        if (kill) {
            if (trace)
                if (log.isDebugEnabled()) {
                    log.debug("Destroying returned connection " + cl);
                }
            doDestroy(cl, "returnConnection");
        }

    }

 连接销毁

    public void destroy() throws ResourceException {
        synchronized (stateLock) {
            destroyed = true;
        }

        cleanup();
        try {
            con.close();
        } catch (SQLException ignored) {
            getLog().error("Ignored error during close: ", ignored);
        }
    }

 

  • 大小: 174.6 KB
分享到:
评论

相关推荐

    解密JBoss和Weblogic数据源连接字符串和控制台密码 _ WooYun知识库1

    0x01 JBoss解密jboss的数据库连接密码般存在<jndi-name>OracleDS</jndi-name> //jndi名字<connection-

    JAVA上百实例源码以及开源项目源代码

    Java实现的FTP连接与数据浏览程序 1个目标文件 摘要:Java源码,网络相关,FTP Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。 部分源代码摘录: ftpClient = new FtpClient(); //实例化FtpClient对象 ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part4

     19.1.3 从容器中获得数据源  19.1.4 由Java应用本身提供数据库连接  19.2 配置事务类型  19.3 把SessionFactory与JNDI绑定  19.4 配置日志  19.5 使用XML格式的配置文件  19.6 小结  19.7 思考题 第20章 ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     19.1.3 从容器中获得数据源  19.1.4 由Java应用本身提供数据库连接  19.2 配置事务类型  19.3 把SessionFactory与JNDI绑定  19.4 配置日志  19.5 使用XML格式的配置文件  19.6 小结  19.7 思考题 第20章 ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part3

     19.1.3 从容器中获得数据源  19.1.4 由Java应用本身提供数据库连接  19.2 配置事务类型  19.3 把SessionFactory与JNDI绑定  19.4 配置日志  19.5 使用XML格式的配置文件  19.6 小结  19.7 思考题 第20章 ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part1.rar

     19.1.3 从容器中获得数据源  19.1.4 由Java应用本身提供数据库连接  19.2 配置事务类型  19.3 把SessionFactory与JNDI绑定  19.4 配置日志  19.5 使用XML格式的配置文件  19.6 小结  19.7 思考题 第20章 ...

    ssh(structs,spring,hibernate)框架中的上传下载

     第3~9行定义了一个数据源,其实现类是apache的BasicDataSource,第11~25行定义了Hibernate的会话工厂,会话工厂类用Spring提供的LocalSessionFactoryBean维护,它注入了数据源和资源映射文件,此外还通过一些键值...

    java开源包4

    3、连接复用,因此在多线程获取连接时无需阻塞; 4、同步调用; 5、超时机制; 6、支持多种通信框架(Mina/Netty/Grizzly),支持多种序列化/反序列化(Java/Hessian/PB); 7、支持自定义通信协议,可完全替换...

    《MyEclipse 6 Java 开发中文教程》前10章

    1.4 JBoss 服务器的下载,安装和运行(可选) 28 1.5 MySQL 5数据库服务器下载,安装和运行(可选) 31 1.5.1 MySQL 5 官方版本的下载和安装,运行 32 1.5.2 MySQL 5绿色版的下载安装和运行 32 1.5.2.1 下载 32 1.5....

    MySQL 5.1中文手冊

    1.7. MySQL信息源 1.7.1. MySQL邮件列表 1.7.2. IRC(在线聊天系统)上的MySQL社区支持 1.7.3. MySQL论坛上的MySQL社区支持 1.8. MySQL标准的兼容性 1.8.1. MySQL遵从的标准是什么 1.8.2. 选择SQL模式 1.8.3. 在ANSI...

    MySQL5.1参考手册官方简体中文版

    1.7. MySQL信息源 1.7.1. MySQL邮件列表 1.7.2. IRC(在线聊天系统)上的MySQL社区支持 1.7.3. MySQL论坛上的MySQL社区支持 1.8. MySQL标准的兼容性 1.8.1. MySQL遵从的标准是什么 1.8.2. 选择SQL模式 1.8.3. 在ANSI...

    JAVA上百实例源码以及开源项目

    百度云盘分享 ... Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。  部分源代码摘录:  ftpClient = new FtpClient(); //实例化FtpClient对象  String serverAddr=jtfServer.getText();...

    mysql官方中文参考手册

    1.7. MySQL信息源 1.7.1. MySQL邮件列表 1.7.2. IRC(在线聊天系统)上的MySQL社区支持 1.7.3. MySQL论坛上的MySQL社区支持 1.8. MySQL标准的兼容性 1.8.1. MySQL遵从的标准是什么 1.8.2. 选择SQL模式 1.8.3. 在ANSI...

    MYSQL中文手册

    1.7. MySQL信息源 1.7.1. MySQL邮件列表 1.7.2. IRC(在线聊天系统)上的MySQL社区支持 1.7.3. MySQL论坛上的MySQL社区支持 1.8. MySQL标准的兼容性 1.8.1. MySQL遵从的标准是什么 1.8.2. 选择SQL模式 1.8.3....

    MySQL 5.1参考手册中文版

    1.7. MySQL信息源 1.7.1. MySQL邮件列表 1.7.2. IRC(在线聊天系统)上的MySQL社区支持 1.7.3. MySQL论坛上的MySQL社区支持 1.8. MySQL标准的兼容性 1.8.1. MySQL遵从的标准是什么 1.8.2. 选择SQL模式 1.8.3. ...

    MySQL 5.1参考手册

    1.7. MySQL信息源 1.7.1. MySQL邮件列表 1.7.2. IRC(在线聊天系统)上的MySQL社区支持 1.7.3. MySQL论坛上的MySQL社区支持 1.8. MySQL标准的兼容性 1.8.1. MySQL遵从的标准是什么 1.8.2. 选择SQL模式 1.8.3. 在ANSI...

Global site tag (gtag.js) - Google Analytics