当我配置一个通过XML实现DataSource
(例如HikariCP)的类时,它看起来像这样:
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"/>
根据Spring Reference manual,JavaConfig中的相当于:
@Bean (destroyMethod = "close")
public DataSource dataSource () {
return new HikariDataSource();
}
为什么我们在JavaConfig中返回接口类型,特别是在这种情况下,DataSource
没有close()
方法,但实现确实(并且以某种方式Spring确实设法找到close()
方法)?
我找不到应用程序在此配置方法与使用实现类型之间的行为方面的任何差异:
@Bean (destroyMethod = "close")
public HikariDataSource dataSource () {
return new HikariDataSource();
}
即使在考虑自动装配时,这也不应成为问题,因为两种返回类型都适用于DataSource
实例变量。那么返回的正确类型是什么(如果有一个'正确的'),为什么?
我找不到应用程序在此配置方法与使用实现类型之间的行为方面的任何差异
你做对了,没有任何区别,因为在这两种情况下最终返回的是new HikariDataSource();
,即HikariDataSource
类的对象。
您的第一种情况更具可扩展性,因为将来您可以在不更改返回类型的情况下返回DataSource
的其他一些实现。或者您可以更新该方法以实现工厂设计模式,以根据情况返回很多DataSource
的实现。
那么返回的正确类型是什么(如果有一个'正确的'),为什么?
实际上没有正确的方法,它完全取决于开发人员但是“编程接口”总是很好的设计。在你的情况下,因为你返回的东西,所以它不会有太大的区别,但你仍然应该使用public DataSource dataSource ()
。
当你可以创建一个接受某个参数的方法时,接口程序特别有用,假设public void dataSource (DataSource ds)
,在这种情况下你可以传递任何DataSource
的实现,所以它是一个很好的设计,因为它是可扩展的。
Read more about program to interface。
另外,我建议阅读有关Factory design pattern的内容,这是一个很好的接口程序示例。
你应该返回通用实现。
这就是为什么:
首先,你是对的。如果您返回impl,您仍然可以自动装配接口。所以你可以做到以上,然后:
@Autowire Datasource ds;
但是,你不能这样做。您无法返回Datasource并自动装配HikariDataSource。
为什么这很重要?
您不希望您的实现依赖于特定的实现。例如:
您编写了Appcode,所有代码都依赖于HikariDataSource。由于这是一个数据源,假设你有400个daos实现了使用它并使用该类的实现特定细节。现在,如果你改变那个impl,你所有的客户都会破产。你将有一段时间让事情再次发挥作用。每当你需要改变它时,这将重复出现(请注意,probs不会像数据源那样经常发生)。
现在返回接口或基类会阻止客户依赖于特定于实现的详细信息。之后您可以快速切换数据源。只要您实现数据源接口,一切都将继续工作。
下一个:测试。您希望为测试提供不同的东西(比方说数据源)。你真的想为你的测试启动一个数据库,而内存数据库就足够了吗?现在在DAO测试中,如果依赖于IMPL,则无法针对通用数据源(InMemoryDataSource)进行测试。如果返回界面,则可以使用不同的测试配置来简化设置。
我希望这有意义/有帮助。
干杯,
阿图尔