目前我在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>
可能看起来令人困惑。
有没有更好的解决方案?
答案 0 :(得分:4)
无需延长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)来避免编写自己的代码。