`
iwinit
  • 浏览: 454788 次
  • 性别: 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
分享到:
评论

相关推荐

    tomcat jboss数据源配置.rar

    本主题主要聚焦于"tomcat jboss数据源配置.rar",这是一个关于如何在Tomcat 5.5和JBoss 4.0中配置数据源,特别是与Oracle数据库交互的详细过程。下面将深入探讨这两个关键组件以及数据源配置的相关知识点。 首先,...

    配置jboss数据源

    配置JBOSS数据源的步骤通常包括以下几个环节: 1. **创建数据源配置文件**:在JBOSS的配置目录下,如`$JBOSS_HOME/standalone/configuration/standalone.xml`或`$JBOSS_HOME/server/default/deploy/jboss-service....

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

    ### 解密JBoss和Weblogic数据源连接字符串和控制台密码 #### 0x00 背景 随着互联网技术的发展与应用的多样化,Java作为企业级开发的重要语言之一,其相关的应用框架如JBoss和WebLogic越来越受到广泛的应用。这类...

    JBoss加密之SedureIdentityLoginModule(数据源连接方式)

    标题 "JBoss加密之SedureIdentityLoginModule(数据源连接方式)" 提及的是在JBoss应用服务器中使用SedureIdentityLoginModule进行身份验证和数据源连接的配置与实现。SedureIdentityLoginModule是JBoss提供的一个安全...

    6.3 JBoss下Oracle9i数据源配置

    当我们需要在JBoss应用服务器上配置Oracle9i作为数据源时,这通常涉及到应用程序与数据库之间的连接管理,以便于程序能够安全、高效地访问数据库中的数据。这篇博客"6.3 JBoss下Oracle9i数据源配置"可能详细阐述了这...

    在Jboss4.0下对MySql数据源的设置方法

    在JBoss 4.0环境下配置MySQL数据源的步骤涉及多个环节,主要是为了确保JBoss应用服务器能够正确地连接和操作MySQL数据库。以下是对每个步骤的详细解释: **步骤一:添加MySQL JDBC驱动** 首先,你需要获取适用于...

    jboss配置数据源(oracle)

    在应用程序中,可以通过JNDI查找来获取数据源,并测试连接是否成功。例如,使用Java代码: ```java Context context = new InitialContext(); DataSource ds = (DataSource) context.lookup("java:jboss/data...

    在jboss连接oracle

    如果一切正常,你应该能够通过JNDI名`java:jboss/datasources/OracleDS`获取到数据源并建立连接。 5. **源码和工具的使用**: "源码"和"工具"标签暗示了可能涉及到查看或修改JBoss和Oracle相关的代码,以及使用...

    jboss6 sqlserver 2000 数据库连接配置

    尝试获取数据源并建立连接,如果能成功连接到SQL Server 2000,那么配置就完成了。 注意,上述配置适用于SQL Server 2000,但对于更现代的SQL Server版本,可能需要更新JDBC驱动和连接URL。此外,由于SQL Server ...

    jboss配置 mysql数据库连接池

    - 打开`/server/default/conf/standardjaws.xml`文件,并添加或修改与MySQL相关的数据源配置: ```xml <datasource>java:/MySqlDS <type-mapping>mySql ``` 3. **配置jbosscmp-jdbc.xml文件** - 打开`/...

    jboss7连接oracle驱动及配置

    现在,你可以通过在应用程序中查找`java:jboss/datasources/OracleDS`来访问配置好的Oracle数据源。 总结一下,配置JBoss 7连接Oracle数据库涉及的关键知识点包括: 1. 下载并安装Oracle JDBC驱动。 2. 创建JBoss...

    jboss配置Oracle连接池.doc

    1. **添加资源引用**:通过`<resource-ref>`标签添加Oracle连接的数据源引用。 2. **标签详解**: - `<description>`:描述信息。 - `<res-ref-name>`:资源引用名称,与JNDI名称保持一致,即`jdbc/oracle`。 - `...

    mysql数据源设置

    4. **在代码中使用**:通过JNDI查找获取数据源,然后创建数据库连接,执行SQL操作,最后关闭连接。 5. **性能调优**:根据实际负载调整数据源参数,如连接超时、空闲时间、最大等待时间等,以优化性能和资源利用率...

    EOS配置多数据源

    这种配置下,EOS Server需要与默认的数据源`ProductDataSource`保持一致,以便在执行业务逻辑时,能够根据构件包信息从`EOSEjbRegister`系统表中获取正确的数据库连接信息。如果业务逻辑需要访问非默认的数据源,...

    数据源配置所用的JAR

    5. **使用数据源**:在代码中通过`DataSource`接口获取连接,进行数据库操作。 理解并正确配置这些JAR文件对于构建高性能、高可用性的Java应用至关重要。合理使用数据源和连接池可以大大提高系统的并发能力,同时...

    数据源所需jar.rar

    在Java EE应用中,数据源通常通过JNDI查找服务被应用程序获取,这样可以在不硬编码数据库连接信息的情况下实现灵活的配置。 3. **连接池**: 数据源通常会集成连接池技术,如C3P0、HikariCP、Apache DBCP、Druid等。...

Global site tag (gtag.js) - Google Analytics