문제

I am designing a distributed data warehouse that supports sharding and replication. Now let's suppose I have a manager application that maintains a "list" of all the database instances that belong to the data warehouse somewhere in a database table (in some "master" database) together with their type, e.g., Oracle, MySql, etc., and credentials, e.g., server name, user name, password, database name, etc. (note that this could also be a distributed configuration service like Zookeeper). Let's also suppose that given one row x from this table, I want to be able to create a native DataSource object for x at runtime, i.e., as the manager application needs it. What I need to do is reading the row for database x from the master database, get the type of the database, its credentials and create an instance of the DataSource implementation provided by the vendor (I don't want to use wrappers such as DriverManagerDataSource and the likes). I'd like to be able to add new JDBC drivers from configuration only, without recompiling.

Now here's my implementation idea. Given a list of N JDBC drivers, I could create N Spring prototype beans, one per DataSource and then when my application needs an instance for database x, create a new instance from one of the N prototypes and then set the right credentials for x.

This is the tricky part: I don't want to have to write code to do the above for each different driver. I'd like somehow to put placeholders in my Spring prototype and then fill them at runtime with a map from the database fields to the native DataSource setters for those. For example, I could have two prototypes such as:

<bean id="postgresDatasourcePrototype" scope="prototype"
    class="org.postgresql.jdbc2.optional.SimpleDataSource">
    <property name="serverName" value="${db.host}"/>
    <property name="databaseName" value="${db.name}"/>
    <property name="portNumber" value="${db.port}"/>
    <property name="user" value="${db.user}"/>
    <property name="password" value="${db.pwd}"/>
</bean>
<bean id="ingresDatasourcePrototype" scope="prototype"
    class="com.ingres.jdbc.IngresDataSource">
    <property name="serverName" value="${db.host}"/>
    <property name="databaseName" value="${db.name}"/>
    <property name="portName" value="${db.port}"/>
    <property name="user" value="${db.user}"/>
    <property name="password" value="${db.pwd}"/>
</bean>

and I would want to bind the placeholders with parameters from the row for x.

Notice that although the properties for most JDBC drivers are similar, (1) there is no common interface and (2) there can be variation, e.g., portNumber vs portName above. If there's no out-of-the-box way to do so using Spring, the only thing I could think of is to provide a map from the fields of x to the properties of the JDBC datasource for each driver (at configuration time) and then use reflection to actually set those properties, which is basically what Spring does under the cover.

EDIT: Just to make it clear, there can be N different JDBC drivers, and I might need to create M distinct instances of the data source for that driver, each with different credentials read from a different row x.

Note that I want a general solution, i.e., it should work for JMS ConnectionFactorys as well.

Is there a way to do this using Spring? I was looking at PropertyPlaceholderConfigurer but it doesn't look like it fits my use case.

Thanks!

Giovanni

도움이 되었습니까?

해결책

Just my 2 cents:
You can use an holder bean for every RDBMS config in this way and bind values with spEL:

class RDBMSConfigBean {
  String host;
  String name;
  String port;
  String user;
  String pwd;

  /* All accessors  */
}
class RDBMSConfigBeanHolder {
  RDBMSConfigBean pgConfig;
  RDBMSConfigBean ingresConfig;

  /* All accessors */
}
<bean id="rdbmsConfigHolder" class="RDBMSConfigBeanHolder" />
<bean id="ingresDatasourcePrototype" scope="prototype" class="com.ingres.jdbc.IngresDataSource">
  <property name="serverName" value="#{rdbmsConfigHolder.ingresConfig.host}"/>
  <!-- other props --> 
</bean>

In your application code you can @Autowire rdbmsConfigHolder and fill right properties from every database row.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top