简体   繁体   中英

How to extend c3p0 ComboPooledDataSource

Ok I have a resource in Tomcat 5.5 in server.xml for database connection like this:

<Resource name="jdbc/MyApp" auth="Container" type="com.mchange.v2.c3p0.ComboPooledDataSource" driverClass="com.microsoft.sqlserver.jdbc.SQLServerDriver"  maxPoolSize="100"  minPoolSize="5"   
acquireIncrement="5"    
 user="username" 
password="password"
factory="org.apache.naming.factory.BeanFactory"  
jdbcUrl="jdbc:sqlserver://localhost:1433;databaseName=myDatabase;autoReconnect=true" />

Has anyone tried to extend the above ComboPooledDataSource? Problem is that database password is in clear text. Idea is to first encrypt the password and place the encrypted key in the server.xml. I have a decrypting utility so I can decrypt the key before trying to connect to database.

I found an example solution for my problem for org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory, but I'm not using this connection pool. I'm using C3P0. Anyone tried this before with C3P0?

Yes, you can't extend com.mchange.v2.c3p0.ComboPooledDataSource because it is public. Here is the workaround by which I have achieved this.

I have extended org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy and passed the com.mchange.v2.c3p0.ComboPooledDataSource datasource as a constructor argument.

Here is my hibernate.cfg.xml configuration of above datasource:

<bean id="dataSource" class="MyDataSource"> 
        <constructor-arg ref="c3p0DataSource" />
    </bean>

    <bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <property name="driverClass" value="${jdbc.driver.className}" />
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="user" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="acquireIncrement" value="${dataSource.acquireIncrement}" />
        <property name="acquireRetryAttempts" value="${dataSource.acquireRetryAttempts}" />
        <property name="acquireRetryDelay" value="${dataSource.acquireRetryDelay}" />
        <property name="autoCommitOnClose" value="${dataSource.autoCommitOnClose}" />
        <property name="breakAfterAcquireFailure" value="${dataSource.breakAfterAcquireFailure}" />
        <property name="checkoutTimeout" value="${dataSource.checkoutTimeout}" />
        <property name="debugUnreturnedConnectionStackTraces"
            value="${dataSource.debugUnreturnedConnectionStackTraces}" />
        <property name="forceIgnoreUnresolvedTransactions"
            value="${dataSource.forceIgnoreUnresolvedTransactions}" />
        <property name="idleConnectionTestPeriod" value="${dataSource.idleConnectionTestPeriod}" />
        <property name="initialPoolSize" value="${dataSource.initialPoolSize}" />
        <property name="maxAdministrativeTaskTime" value="${dataSource.maxAdministrativeTaskTime}" />
        <property name="maxConnectionAge" value="${dataSource.maxConnectionAge}" />
        <property name="maxIdleTime" value="${dataSource.maxIdleTime}" />
        <property name="maxIdleTimeExcessConnections" value="${dataSource.maxIdleTimeExcessConnections}" />
        <property name="maxPoolSize" value="${dataSource.maxPoolSize}" />
        <property name="maxStatements" value="${dataSource.maxStatements}" />
        <property name="maxStatementsPerConnection" value="${dataSource.maxStatementsPerConnection}" />
        <property name="minPoolSize" value="${dataSource.minPoolSize}" />
        <property name="numHelperThreads" value="${dataSource.numHelperThreads}" />
        <property name="propertyCycle" value="${dataSource.propertyCycle}" />
        <property name="testConnectionOnCheckin" value="${dataSource.testConnectionOnCheckin}" />
        <property name="testConnectionOnCheckout" value="${dataSource.testConnectionOnCheckout}" />
        <property name="unreturnedConnectionTimeout" value="${dataSource.unreturnedConnectionTimeout}" />
    </bean>

Mine jdbc.properties file:


jdbc.driver.className=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc.url=xxxxx
jdbc.username=xxx
jdbc.password=xxxxxxxxx #Encrytped password here
jdbc.hibernate.dialect=org.hibernate.dialect.SQLServerDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=update

dataSource.acquireIncrement=3
dataSource.acquireRetryAttempts=30
dataSource.acquireRetryDelay=60000
dataSource.autoCommitOnClose=false
dataSource.breakAfterAcquireFailure=false
dataSource.checkoutTimeout=0
dataSource.debugUnreturnedConnectionStackTraces=false
dataSource.forceIgnoreUnresolvedTransactions=false
dataSource.idleConnectionTestPeriod=0
dataSource.initialPoolSize=10
dataSource.maxAdministrativeTaskTime=0
dataSource.maxConnectionAge=0
dataSource.maxIdleTime=0
dataSource.maxIdleTimeExcessConnections=0
dataSource.maxPoolSize=10
dataSource.maxStatements=0
dataSource.maxStatementsPerConnection=0
dataSource.minPoolSize=10
dataSource.numHelperThreads=3
dataSource.propertyCycle=0
dataSource.testConnectionOnCheckin=false
dataSource.testConnectionOnCheckout=false
dataSource.unreturnedConnectionTimeout=0


Mine extended class where I decrypt the password before passing the datasource to transaction Proxy wrapper.

import javax.sql.DataSource;

import org.jasypt.util.text.BasicTextEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;

import com.csc.emms.common.EMMSConstraints;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class MyDataSource extends TransactionAwareDataSourceProxy
{
    private static char[] appName =
    {
            'B', 'I', 'N', 'G', 'O', 'D', 'I', 'N', 'G', 'O'
    };

    @Autowired
    // Inject your class by constructor
    MyDataSource(ComboPooledDataSource dataSource)
    {
        super.setTargetDataSource(decryptPassword(dataSource));
    }

    private DataSource decryptPassword(ComboPooledDataSource dataSource)
    {
        dataSource.setPassword(decode(dataSource.getPassword()));
        return dataSource;
    }

    private String decode(String encodedPassword)
    {
        BasicTextEncryptor decoder = new BasicTextEncryptor();
        decoder.setPasswordCharArray(appName);
        return decoder.decrypt(encodedPassword);
    }

    private String encode(String password)
    {
        BasicTextEncryptor encoder = new BasicTextEncryptor();
        encoder.setPasswordCharArray(appName);
        return encoder.encrypt(password);
    }
}
Hope this resolved your issue.

由于com.mchange.v2.c3p0.ComboPooledDataSource是公共最终类,因此无法扩展它。

You can't extend ComboPooledDataSource , but you can basically duplicate it by extending its parent class, AbstractComboPooledDataSource . You can really, really get close to duplicating it by either getting the source from Github , or by decompiling the class file. The result will look something like this:

import com.mchange.v2.c3p0.AbstractComboPooledDataSource;

public final class YourC3p0DataSource extends AbstractComboPooledDataSource
        implements Serializable, Referenceable {

    public void setPassword(String encryptedPassword) {
        try {
            String decryptedPassword
                    = yourDecryption(encryptedPassword);
            super.setPassword(decryptedPassword);
        } catch (Exception e) { /* ... */ }
    }
    /* Increment a few other methods found in ComboPooledDataSource. */
}

you can using jasypt to encrypt properties file and then used encrypted properties in datasource bean.

jasypt also support spring and it is very easy to use. read this for more details.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM