Catalog
1 Initialize DruidXADataSource
2 Initialize Atomikos DataSourceBean
1 Initialize DruidXADataSource
Initializing DruidXADataSource is done by the application developer as follows:
/** * jdbc.ds1 Get configuration information, initialize druidDataSource1 * @return */ @Bean(name="druidDataSource1") @ConfigurationProperties(prefix = "jdbc.ds1") public DruidXADataSource dataSource0(){ DruidXADataSource dataSource = new DruidXADataSource(); return dataSource; }
Click on the DruidXADataSource source code to find that the DruidDataSource inherits, so according to @ConfigurationProperties(prefix = "jdbc.ds1"), the configuration information at the beginning of jdbc.ds1 under the application.properties configuration file will be read and the connection configuration of DruidDataSource will be initialized, with the following inheritance relationships:
public class DruidXADataSource extends DruidDataSource implements XADataSource { }
The debug observations are as follows:
2 Initialize Atomikos DataSourceBean
This is explained here using the X/Open DTP model. The model mentioned above includes four parts: application (AP), transaction manager (TM), resource manager (RM), and communication resource manager (CRM).
- Application (AP) is our client program
- The Transaction Manager (TM) is the role of the Tomikos tool that we introduced to help us coordinate the submission and rollback of RM's distributed transactions to ensure the consistency of distributed database data.
- Resource Manager (RM) is equivalent to the management of each local dataSource, and Druid is mainly supported by this block
- Communications Resource Manager (CRM) I understand that this is not covered here and do not explain
Next, let's go through the initialization code, take a new AtomikosDataSourceBean instance, and initialize DruidXADataSource to manage as a member object.
/** * Instantiate AtomikosDataSourceBean and set Druid initialized RuidXADataSource * @param druidDataSource1 * @return */ @Primary @Bean(name = "dataSource1") public AtomikosDataSourceBean dataSource(@Qualifier("druidDataSource1") DruidXADataSource druidDataSource1){ AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); try { druidDataSource1.setFilters("stat"); xaDataSource.setXaDataSource(druidDataSource1); xaDataSource.setMaxPoolSize(10); xaDataSource.setMinPoolSize(5); xaDataSource.setUniqueResourceName("dataSource1"); } catch (SQLException e) { System.out.println("dataSource1 init error!"+e); } return xaDataSource; }
Looking at the AtomikosDataSourceBean source code, AtomikosDataSourceBean implements the InitializingBean interface, which initiates a call to the afterPropertiesSet() method:
public class AtomikosDataSourceBean extends com.atomikos.jdbc.AtomikosDataSourceBean implements BeanNameAware, InitializingBean, DisposableBean { private String beanName; public AtomikosDataSourceBean() { } public void setBeanName(String name) { this.beanName = name; } // This method is called after the InitializingBean interface is implemented and the object is initialized public void afterPropertiesSet() throws Exception { if (!StringUtils.hasLength(this.getUniqueResourceName())) { this.setUniqueResourceName(this.beanName); } // Initialization method invoked this.init(); } public void destroy() throws Exception { this.close(); } }
Look at the core code in this.init() method as follows, and continue looking inside the new ConnectionPoolWithSynchronizedValidation(cf, this):
ConnectionFactory cf = this.doInit(); if (this.enableConcurrentConnectionValidation) { this.connectionPool = new ConnectionPoolWithConcurrentValidation(cf, this); } else { if (this.getTestQuery() != null) { LOGGER.logWarning(this + ": testQuery set - pool may be slower / you might want to consider setting maxLifetime instead..."); } // Initialize Connection this.connectionPool = new ConnectionPoolWithSynchronizedValidation(cf, this); } this.getReference();
Looking at the call stack, ConnectionPool calls an init() method again, and continues to look inside
public ConnectionPoolWithConcurrentValidation(ConnectionFactory connectionFactory, ConnectionPoolProperties properties) throws ConnectionPoolException { super(connectionFactory, properties); }
public ConnectionPool(ConnectionFactory connectionFactory, ConnectionPoolProperties properties) throws ConnectionPoolException { this.connectionFactory = connectionFactory; this.properties = properties; this.destroyed = false; this.name = properties.getUniqueResourceName(); this.init(); }
You can see from this method that the connection pool initialization starts with the following source code:
private void init() throws ConnectionPoolException { if (LOGGER.isTraceEnabled()) { LOGGER.logTrace(this + ": initializing..."); } // Start Initializing Connection Pool this.addConnectionsIfMinPoolSizeNotReached(); this.launchMaintenanceTimer(); }
Source code analysis and review as follows:
private synchronized void addConnectionsIfMinPoolSizeNotReached() { int connectionsToAdd = this.properties.getMinPoolSize() - this.totalSize(); for(int i = 0; i < connectionsToAdd; ++i) { try { // Create XPooledConnection connection XPooledConnection xpc = this.createPooledConnection(); // Join the connection pool this.connections.add(xpc); xpc.registerXPooledConnectionEventListener(this); } catch (Exception var4) { if (LOGGER.isTraceEnabled()) { LOGGER.logTrace(this + ": could not establish initial connection", var4); } } } }
Continue tracking as follows:
private XPooledConnection createPooledConnection() throws CreateConnectionException { XPooledConnection xpc = this.connectionFactory.createPooledConnection(); EventPublisher.publish(new PooledConnectionCreatedEvent(this.properties.getUniqueResourceName(), xpc)); return xpc; }
Discover the New World, find the call to this.xaDataSource.getXAConnection(), is xaDataSource not the data source for our initialized Ruid?
public XPooledConnection createPooledConnection() throws CreateConnectionException { try { // Start calling the getXAConnection method of xaDataSource XAConnection xaConnection = this.xaDataSource.getXAConnection(); return new AtomikosXAPooledConnection(xaConnection, this.jdbcTransactionalResource, this.props); } catch (SQLException var3) { String msg = "XAConnectionFactory: failed to create pooled connection - DBMS down or unreachable?"; LOGGER.logWarning(msg, var3); throw new CreateConnectionException(msg, var3); } }
Analyzing Druid's getXAConnection is as follows:
@Override public XAConnection getXAConnection() throws SQLException { // Get DruidPooledConnection, which is the connection object exposed to the client after analysis of the previous article DruidPooledConnection conn = this.getConnection(); // Unencapsulating Get Real Database Connection Objects Connection physicalConn = conn.unwrap(Connection.class); // Get XAConnection from physicalConn XAConnection rawXAConnection = createPhysicalXAConnection(physicalConn); // Encapsulate a DruidPooledXAConnection return return new DruidPooledXAConnection(conn, rawXAConnection); }
Look at the createPhysicalXAConnection(physicalConn) to get the core code logic for the XAConnection as follows:
if (utilClass == null && !utilClassError) { try { utilClass = Class.forName("com.mysql.jdbc.Util"); Method method = utilClass.getMethod("isJdbc4"); utilClass_isJdbc4 = (Boolean) method.invoke(null); // Get Connections class_5_connection = Class.forName("com.mysql.jdbc.Connection"); method_5_getPinGlobalTxToPhysicalConnection = class_5_connection.getMethod("getPinGlobalTxToPhysicalConnection"); class_5_suspendableXAConnection = Class.forName("com.mysql.jdbc.jdbc2.optional.SuspendableXAConnection"); constructor_5_suspendableXAConnection = class_5_suspendableXAConnection.getConstructor(class_5_connection); class_5_JDBC4SuspendableXAConnection = Class.forName("com.mysql.jdbc.jdbc2.optional.JDBC4SuspendableXAConnection"); constructor_5_JDBC4SuspendableXAConnection = class_5_JDBC4SuspendableXAConnection.getConstructor(class_5_connection); // Create XA Connection Object class_5_MysqlXAConnection = Class.forName("com.mysql.jdbc.jdbc2.optional.MysqlXAConnection"); constructor_5_MysqlXAConnection = class_5_MysqlXAConnection.getConstructor(class_5_connection, boolean.class); } catch (Exception ex) { ex.printStackTrace(); utilClassError = true; } }
DruidPooledXAConnection is the encapsulation of DruidPooledConnection objects and XAConnection objects.
public DruidPooledXAConnection(DruidPooledConnection pooledConnection, XAConnection xaConnection){ this.pooledConnection = pooledConnection; this.xaConnection = xaConnection; }
Continue tracking createPooledConnection analysis as follows:
public XPooledConnection createPooledConnection() throws CreateConnectionException { try { // Get XAConnection XAConnection xaConnection = this.xaDataSource.getXAConnection(); // Atomiikos self-encapsulates atomikos XAPooledConnection returns return new AtomikosXAPooledConnection(xaConnection, this.jdbcTransactionalResource, this.props); } catch (SQLException var3) { String msg = "XAConnectionFactory: failed to create pooled connection - DBMS down or unreachable?"; LOGGER.logWarning(msg, var3); throw new CreateConnectionException(msg, var3); } }
Depending on the call stack, you will find that the DruidPooledXAConnection.getXAResource() method that calls Druid is as follows:
@Override public XAResource getXAResource() throws SQLException { return xaConnection.getXAResource(); }
The debug screenshot below shows Druid calling MysqlXAConnection
Looking at this class as an implementation of Mysql's support for the Xa protocol, the object relationships are as follows:
public class MysqlXAConnection extends MysqlPooledConnection implements XAConnection, XAResource {}
Initialization of the entire transaction manager and XA objects is complete here, and will be iterated based on the number of connections configured
List <XPooledConnection> Connections connection pool out.
The next article will analyze how client s perform work after they have initialized such a connection pool for multiple databases.