C3P0 连接分析

最近在看C3P0的原理,还是将C3P0的源码导入到Ecplise中debug看得清楚多了。下面记录我debug的经历。

1.下载c3p0的jar和源码,这个百度吧。

2.导入jar和源码到java工程中,导入后,会发现有些错误的,把junit的类去掉,有的提示没有实现一些方法,就加进去,还有的提示要删除多余的实现方法,就删除掉吧,这样下来,基本上不报错了。

3.debug的过程中,有些类没有源码的,到google上去搜,会有源码的,写一个对应的java类加进工程里去就行了。

1.写一个连接池的简单的工具类

public class ConnectionPool {
	private static ComboPooledDataSource ds;
	public synchronized static final Connection getConnection() {
		try {
			if (ds != null) {
				return ds.getConnection();
			}
			else{
				ds = new ComboPooledDataSource(true);
				ds.setJdbcUrl("jdbc:mysql://192.168.1.102:3306/S10");
				try {
					ds.setDriverClass("com.mysql.jdbc.Driver");
				} catch (PropertyVetoException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				ds.setUser("root");
				ds.setPassword("123456");
				ds.setInitialPoolSize(10);
				ds.setMinPoolSize(10);
				ds.setMaxPoolSize(20);
				ds.setMaxIdleTime(30);
				
				return ds.getConnection();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
}
2. 现在需要debug的代码是
ds.getConnection()
,看看它的执行顺序吧。

首先进入的是AbstractPoolBackedDataSource中的getConnection方法

pc = getPoolManager().getPool().checkoutPooledConnection();
return pc.getConnection();

其中:getPoolManager().getPool()是获取连接池,它对应的类是C3P0PooledConnectionPoolManager,它管理着连接池的生命周期。

C3P0PooledConnectionPoolManager中有一个内部类PooledConnectionResourcePoolManager,它里面会创建BasicResourcePool,BasicResourcePool才是真正创建连接的地方。

会调用里面的私有方法。

private void _recheckResizePool()
    {
        assert Thread.holdsLock(this);

        if (! broken)
        {
            int msz = managed.size();

            int shrink_count;
            int expand_count;

            if ((shrink_count = msz - pending_removes - target_pool_size) > 0)
                shrinkPool( shrink_count );
            else if ((expand_count = target_pool_size - (msz + pending_acquires)) > 0)
                expandPool( expand_count );
        }
    }

继续跟踪expandPool()方法,这里的expand_count是初始值10.

private void expandPool(int count)
    {
        assert Thread.holdsLock(this);

        // XXX: temporary switch -- assuming no problems appear, we'll get rid of AcquireTask
        //      in favor of ScatteredAcquireTask
        if ( USE_SCATTERED_ACQUIRE_TASK )
        {
            for (int i = 0; i < count; ++i)
                taskRunner.postRunnable( new ScatteredAcquireTask() );
        }
        else
        {
            for (int i = 0; i < count; ++i)
                taskRunner.postRunnable( new AcquireTask() );
        }
    }

进入到AcquireTask()方法里看到如下的代码。

BasicResourcePool.this.doAcquire();

 Object resc = mgr.acquireResource();

acquireResource()方法会调用一个内部类PooledConnectionResourcePoolManager,它会调用下面的代码。

if ( connectionCustomizer == null)
                    {
                        out = (auth.equals( C3P0ImplUtils.NULL_AUTH ) ?
                               cpds.getPooledConnection() :
                               cpds.getPooledConnection( auth.getUser(), 
                                                         auth.getPassword() ) );
                    }

上面的代码调用下面的代码

protected PooledConnection getPooledConnection(String user, String password, ConnectionCustomizer cc, String pdsIdt)
	throws SQLException
    { 
        // 它里面包含jdbcUrl等信息
	DataSource nds = getNestedDataSource();
	if (nds == null)
	    throw new SQLException( "No standard DataSource has been set beneath this wrapper! [ nestedDataSource == null ]");
        // 这里的代码调用是在DriverManagerDataSource中实现的
	Connection conn = nds.getConnection(user, password);
	if (conn == null)
	    throw new SQLException("An (unpooled) DataSource returned null from its getConnection() method! " +
				   "DataSource: " + getNestedDataSource());
	if ( this.isUsesTraditionalReflectiveProxies() )
	    {
		//return new C3P0PooledConnection( new com.mchange.v2.c3p0.test.CloseReportingConnection( conn ), 
		return new C3P0PooledConnection( conn,
						 connectionTester,
						 this.isAutoCommitOnClose(), 
						 this.isForceIgnoreUnresolvedTransactions(),
						 cc,
						 pdsIdt);
	    }
	else
	    {
		return new NewPooledConnection( conn, 
						connectionTester,
						this.isAutoCommitOnClose(), 
						this.isForceIgnoreUnresolvedTransactions(),
						this.getPreferredTestQuery(),
						cc,
						pdsIdt); 
	    }
    }
public Connection getConnection(String username, String password) throws SQLException
    { 
        ensureDriverLoaded();
        // 这才是真实的物理连接啊
        Connection out = driver().connect( jdbcUrl, overrideProps(username, password) );  
        if (out == null)
            throw new SQLException("Apparently, jdbc URL '" + jdbcUrl + "' is not valid for the underlying " +
                            "driver [" + driver() + "].");
        return out;
    }

至此,初始化的10个连接完成了。

相关推荐