【问题标题】:How to correctly override BasicDataSource for Spring and Hibernate如何正确覆盖 Spring 和 Hibernate 的 BasicDataSource
【发布时间】:2011-05-28 11:34:57
【问题描述】:

目前我在 Spring 中有以下基本数据源:

<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost/test?relaxAutoCommit=true" />
    ...
</bean>

现在我需要提供基于服务器环境的自定义数据源(不是配置),为此我需要根据一些条件计算driverClassNameurl字段。

我尝试覆盖 createDataSource() 方法:

public class MyDataSource extends BasicDataSource {

    @Override
    protected synchronized DataSource createDataSource() throws SQLException {
        if(condition) {
            super.setDriverClassName("com.mysql.jdbc.Driver");
            super.setUrl("jdbc:mysql://localhost/test?relaxAutoCommit=true");
        } else {
            //...
        }
        return super.createDataSource();
    }
}

这可行,但我注意到每次执行查询时都会调用createDataSource()(?),所以我宁愿将条件测试移到其他地方。

我尝试覆盖 setDriverClassName()setUrl(),它们也可以工作,并且据我所知只被调用一次,但是我需要在 Spring 配置中提供一些值以触发这些设置器,因为它们没有被调用否则:

<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="whatever" />
    <property name="url" value="whatever" />
    ...
</bean>

这可能看起来令人困惑。

有没有更好的解决方案?

【问题讨论】:

  • 你看过BasicDataSource的实现吗?
  • 我认为你应该从那里开始调查,你不觉得吗? :)

标签: java hibernate spring jdbc


【解决方案1】:

无需扩展BasicDataSource。继承是最强的耦合形式,除非您有真正的理由使用它,否则应避免使用它。

你有两个选择:

  • 创建一个包装器(使用组合而不是继承)

    public class MyDataSource implements DataSource {
        private BasicDataSource target = new BasicDataSource();
        public MyDataSource() {
            if (condition) {
                target.setDriverClassName("com.mysql.jdbc.Driver");                
                target.setUrl("jdbc:mysql://localhost/test?relaxAutoCommit=true"); 
            } else { ... }
        }
        public Connection getConnection() {
            return target.getConnection();
        }
        ... etc ...
    }
    
  • 创建一个工厂(因为你只需要自定义对象的创建阶段,你不需要控制它的整个生命周期)。

     public class MyDataSourceFactory {
        public DataSource createDataSource() {
            BasicDataSource target = new BasicDataSource();
            if (condition) {
                target.setDriverClassName("com.mysql.jdbc.Driver");                
                target.setUrl("jdbc:mysql://localhost/test?relaxAutoCommit=true"); 
            } else { ... }
            return target;
        }
    }
    

    .

    <bean id = "factory" class = "MyDataSourceFactory" />
    <bean id = "dbcpDataSource" 
         factory-bean = "factory" factory-method = "createDataSource">
         <property ... />
    </bean>
    

编辑:请注意,您仍然可以将从工厂获取的对象配置为常规 Spring bean。

此外,如果您的条件足够简单,您可以完全避免编写自己的代码,使用 Spring 提供的声明性方法,例如 Spring Expression language

【讨论】:

  • 因此,您建议不要扩展 BasicDataSource,而是创建它的副本?这似乎比需要的工作更多......我仍然需要 BasicDataSource 的默认行为(通过 spring 配置设置一些属性),只需为这两个字段设置自定义条件。
  • @serg:如果是这样,看看工厂方法 - 其他属性仍然可以配置。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-16
  • 2013-04-26
  • 1970-01-01
  • 1970-01-01
  • 2015-11-18
  • 1970-01-01
  • 2019-06-14
相关资源
最近更新 更多