从连接的视角来看类图
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); } }
相关推荐
本主题主要聚焦于"tomcat jboss数据源配置.rar",这是一个关于如何在Tomcat 5.5和JBoss 4.0中配置数据源,特别是与Oracle数据库交互的详细过程。下面将深入探讨这两个关键组件以及数据源配置的相关知识点。 首先,...
配置JBOSS数据源的步骤通常包括以下几个环节: 1. **创建数据源配置文件**:在JBOSS的配置目录下,如`$JBOSS_HOME/standalone/configuration/standalone.xml`或`$JBOSS_HOME/server/default/deploy/jboss-service....
### 解密JBoss和Weblogic数据源连接字符串和控制台密码 #### 0x00 背景 随着互联网技术的发展与应用的多样化,Java作为企业级开发的重要语言之一,其相关的应用框架如JBoss和WebLogic越来越受到广泛的应用。这类...
标题 "JBoss加密之SedureIdentityLoginModule(数据源连接方式)" 提及的是在JBoss应用服务器中使用SedureIdentityLoginModule进行身份验证和数据源连接的配置与实现。SedureIdentityLoginModule是JBoss提供的一个安全...
当我们需要在JBoss应用服务器上配置Oracle9i作为数据源时,这通常涉及到应用程序与数据库之间的连接管理,以便于程序能够安全、高效地访问数据库中的数据。这篇博客"6.3 JBoss下Oracle9i数据源配置"可能详细阐述了这...
在JBoss 4.0环境下配置MySQL数据源的步骤涉及多个环节,主要是为了确保JBoss应用服务器能够正确地连接和操作MySQL数据库。以下是对每个步骤的详细解释: **步骤一:添加MySQL JDBC驱动** 首先,你需要获取适用于...
在应用程序中,可以通过JNDI查找来获取数据源,并测试连接是否成功。例如,使用Java代码: ```java Context context = new InitialContext(); DataSource ds = (DataSource) context.lookup("java:jboss/data...
如果一切正常,你应该能够通过JNDI名`java:jboss/datasources/OracleDS`获取到数据源并建立连接。 5. **源码和工具的使用**: "源码"和"工具"标签暗示了可能涉及到查看或修改JBoss和Oracle相关的代码,以及使用...
尝试获取数据源并建立连接,如果能成功连接到SQL Server 2000,那么配置就完成了。 注意,上述配置适用于SQL Server 2000,但对于更现代的SQL Server版本,可能需要更新JDBC驱动和连接URL。此外,由于SQL Server ...
- 打开`/server/default/conf/standardjaws.xml`文件,并添加或修改与MySQL相关的数据源配置: ```xml <datasource>java:/MySqlDS <type-mapping>mySql ``` 3. **配置jbosscmp-jdbc.xml文件** - 打开`/...
现在,你可以通过在应用程序中查找`java:jboss/datasources/OracleDS`来访问配置好的Oracle数据源。 总结一下,配置JBoss 7连接Oracle数据库涉及的关键知识点包括: 1. 下载并安装Oracle JDBC驱动。 2. 创建JBoss...
1. **添加资源引用**:通过`<resource-ref>`标签添加Oracle连接的数据源引用。 2. **标签详解**: - `<description>`:描述信息。 - `<res-ref-name>`:资源引用名称,与JNDI名称保持一致,即`jdbc/oracle`。 - `...
4. **在代码中使用**:通过JNDI查找获取数据源,然后创建数据库连接,执行SQL操作,最后关闭连接。 5. **性能调优**:根据实际负载调整数据源参数,如连接超时、空闲时间、最大等待时间等,以优化性能和资源利用率...
这种配置下,EOS Server需要与默认的数据源`ProductDataSource`保持一致,以便在执行业务逻辑时,能够根据构件包信息从`EOSEjbRegister`系统表中获取正确的数据库连接信息。如果业务逻辑需要访问非默认的数据源,...
5. **使用数据源**:在代码中通过`DataSource`接口获取连接,进行数据库操作。 理解并正确配置这些JAR文件对于构建高性能、高可用性的Java应用至关重要。合理使用数据源和连接池可以大大提高系统的并发能力,同时...
在Java EE应用中,数据源通常通过JNDI查找服务被应用程序获取,这样可以在不硬编码数据库连接信息的情况下实现灵活的配置。 3. **连接池**: 数据源通常会集成连接池技术,如C3P0、HikariCP、Apache DBCP、Druid等。...