目前我在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>
现在我需要根据服务器环境(不是配置)提供自定义数据源,为此我需要根据某些条件计算 driverClassName
和 url
字段。
我尝试覆盖 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 配置中以触发这些 setter ,因为它们不会以其他方式调用:
<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="whatever" />
<property name="url" value="whatever" />
...
</bean>
这可能看起来令人困惑。
有没有更好的解决方案?
最佳答案
无需扩展 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 .
关于java - 如何正确覆盖 Spring 和 Hibernate 的 BasicDataSource,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4493743/