【问题标题】:Tomcat Multiple Datasources with decrypt password logic具有解密密码逻辑的Tomcat多个数据源
【发布时间】:2026-02-18 10:30:02
【问题描述】:

我在 Tomcat 环境中处理多个数据源时遇到了一些问题。请在下面找到详细信息。 我的 tomcat/conf/server.xml 文件中有以下 2 个数据源

数据源1:

<Resource name="myds1" 
          global="myds1"
          auth="Container"
          type="javax.sql.DataSource"
          factory="com.tomcat.datasorceEncrypt.EncryptedDataSourceFactory"
          driverClassName="oracle.jdbc.driver.OracleDriver"
          singleton = "false"/>

数据来源2:

<Resource name="myds2" 
          global="myds2"
          auth="Container"
          type="javax.sql.DataSource"
          factory="com.tomcat.datasorceEncrypt.EncryptedDataSourceFactory"
          driverClassName="com.ibm.db2.jcc.DB2Driver"
          singleton = "false"/>

这是我的EncryptedDataSourceFactory 文件,它扩展了DataSourceFactory

package com.tomcat.datasorceEncrypt;

import java.io.InputStream;
import java.util.Hashtable;
import java.util.Properties;
import java.util.stream.Stream;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.sql.DataSource;

import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.jdbc.pool.DataSourceFactory;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.apache.tomcat.jdbc.pool.XADataSource;

public class EncryptedDataSourceFactory extends DataSourceFactory {

    private static final Log log = LogFactory.getLog(EncryptedDataSourceFactory.class);

    private static final String PROP_DIALECT = "dialect";
    private static final String[] CUSTOM_PROPERTIES = new String[]{PROP_DIALECT};
    private static final String[] PROPERTIES = Stream.of(ALL_PROPERTIES, CUSTOM_PROPERTIES).flatMap(Stream::of).toArray(String[]::new);


    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment)
            throws Exception {
         if (obj != null && obj instanceof Reference) {
             Reference ref = (Reference) obj;
             Properties properties = new Properties();

             for (int i = 0; i < PROPERTIES.length; ++i) {
                 String propertyName = PROPERTIES[i];
                 RefAddr ra = ref.get(propertyName);
                 if (ra != null) {
                     String propertyValue = ra.getContent().toString();
                     properties.setProperty(propertyName, propertyValue);
                 }
             }

             return this.createDataSource(properties, nameCtx,false);
         } else {
             return null;
         }
    }

    @Override
    public DataSource createDataSource(Properties properties, Context context, boolean XA) throws Exception {
        // Here we decrypt our password.
        PoolConfiguration poolProperties = parsePoolProperties(properties);
        Properties dbProperties = loadProperties();
        poolProperties.setPassword(CryptoUtility.decryptDBPass(dbProperties.getProperty("DB_key"), dbProperties.getProperty("DB_password")));
        poolProperties.setUsername(dbProperties.getProperty("DB_username"));
        poolProperties.setUrl(dbProperties.getProperty("DB_url"));
        System.out.println(poolProperties.getPoolName() + "****-------*****" + poolProperties.getName() );
        System.out.println(poolProperties.getDataSourceJNDI() + "****------***" + poolProperties.getDataSource());
        // The rest of the code is copied from Tomcat's DataSourceFactory.
        if (poolProperties.getDataSourceJNDI() != null && poolProperties.getDataSource() == null) {
            performJNDILookup(context, poolProperties);
        }
        org.apache.tomcat.jdbc.pool.DataSource dataSource = XA ? new XADataSource(poolProperties)
                : new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
        dataSource.createPool();

        return dataSource;
    }

    private Properties loadProperties() {
        Properties prop = new Properties();

        try {
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("DBPassword.properties");
            prop.load(inputStream);
        }catch (Exception e) {
            log.fatal("Error Loading the properties.", e);
            throw new RuntimeException(e);
        }
        return prop;
    }

}

我试图从 poolProperties.getDataSourceJNDI() 中识别数据源 JNDI 名称,以便我可以通过我的属性应用正确的凭据,但我收到的 poolProperties.getDataSourceJNDI() 为 null。

我在创建数据源时是否遗漏了资源中的任何属性?

注意:在使用资源时,我可以设置用户名和密码,尽管 poolProperties.getDataSourceJNDI() 为空。

【问题讨论】:

  • 使用单一数据源对你有用吗?
  • 是的,它有效,但我确实看到 getDataSourceJNDI() 值为 null

标签: java datasource tomcat8.5


【解决方案1】:

对于 timebeeing,我通过为第二个数据源扩展 DatasourceFactory 创建了另一个类,它正在工作,但我认为这不是一个空闲的解决方案。

【讨论】:

    【解决方案2】:

    在例程 getObjectInstance 中,参数名称可以用于此。 根据名称,可以为不同的数据源调用解密方法。 我定义了 8 个数据源。我使用了这种方法,因此我只使用了一个 DataSourcefactory 类。

    【讨论】: