在SpringJavaConfig中,beanreturn类型应该是接口还是实现?

In Spring JavaConfig, should the bean return type be the interface or implementation?

当我配置通过 XML 实现 DataSource(例如 HikariCP)的 class 时,它看起来像这样:

<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"/>

根据 Spring Reference manual,JavaConfig 中的等效项是:

@Bean (destroyMethod = "close")
public DataSource dataSource () {
    return new HikariDataSource();
}

为什么我们 return 在 JavaConfig 中设置接口类型,特别是在这种情况下,DataSource 没有 close() 方法,但是实现有(并且以某种方式Spring 确实找到了 close() 方法)?

我找不到此配置方法与使用实现类型之间应用程序行为的任何区别:

@Bean (destroyMethod = "close")
public HikariDataSource dataSource () {
    return new HikariDataSource();
}

即使考虑自动装配,这也不应该成为问题,因为两种 return 类型都适用于 DataSource 实例变量。 那么 return 的正确类型是什么(如果有 'correct' ),为什么?

I couldn't find any difference in the application's behavior between this configuration method to using the implementation's type

你说得对,不会有任何区别,因为在这两种情况下,最终 returned 的是 new HikariDataSource();,即 HikariDataSource class 的对象.

您的第一个案例 更具可扩展性 因为将来您可以 return DataSource 的一些其他实现而不更改 return 类型。或者您可以更新该方法以实现工厂设计模式 return DataSource 的大量实现,具体取决于情况。

So what is the correct type to return (if there is a 'correct' one), and why?

确实没有正确的方法,这完全取决于开发人员,但 "program to interface" 总是好的设计。在你的情况下,因为你正在 returning 东西所以它不会有太大的区别,但你仍然应该使用 public DataSource dataSource ().

当你可以创建一个接受一些参数的方法时,程序接口特别有用,假设public void dataSource (DataSource ds),在这种情况下你可以传递DataSource的任何实现,所以这是一个很好的设计因为它是可扩展的

Read more about program to interface.

此外,我建议阅读有关 Factory design pattern 的内容,这是一个 程序接口的好例子

您应该 return 通用实现。

这就是为什么:

首先,你是对的。如果你 return impl,你仍然可以自动装配接口。所以你可以做上面的,然后:

@Autowire Datasource ds;

但是,你不能反过来。您不能 return 数据源和自动装配 HikariDataSource。

为什么这很重要?

您不希望您的实现依赖于特定的实现。例如:

您编写了您的 Appcode,并且您的所有代码都依赖于 HikariDataSource。由于这是一个数据源,假设您实现了 400 个使用它的 daos 并使用了那个 class 的实现特定细节。现在,如果你改变那个 impl,你所有的客户都会崩溃。让事情重新运转起来你会很痛苦。每次您需要更改它时,这都会重复(请注意,数据源不会经常发生这种情况)。

现在 return 接口或基础 class 不鼓励您的客户依赖实现的具体细节。之后您将可以毫无问题地快速切换数据源。只要您实现数据源接口,一切都会继续工作。

下一步:测试。 您希望为您的测试提供不同的东西(比如说数据源)。你真的想为你的测试启动一个数据库,而内存数据库就足够了吗? 现在在您的 DAO 测试中,如果您依赖 IMPL,则无法针对通用数据源 (InMemoryDataSource) 进行测试。如果你 return 一个接口,你可以为你的测试使用不同的配置来简化你的设置。

我希望这能让 sense/helps。

干杯,

亚瑟