简体   繁体   English

在Spring JavaConfig中,bean返回类型应该是接口还是实现?

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

When I configure a class that implements DataSource (for example HikariCP ) via XML, it looks something like this: 当我通过XML配置实现DataSource (例如HikariCP )的类时,它看起来像这样:

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

According to the Spring Reference manual , the equivalent of this in JavaConfig is: 根据Spring Reference手册 ,JavaConfig中的相当于:

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

Why are we returning the interface type in JavaConfig, especially in this case, where DataSource doesn't have a close() method, but the implementation does (and somehow Spring does manage to find the close() method)? 为什么我们在JavaConfig中返回接口类型,特别是在这种情况下, DataSource没有close()方法,但实现确实(并且Spring确实设法找到了close()方法)?

I couldn't find any difference in the application's behavior between this configuration method to using the implementation's type: 我找不到应用程序在此配置方法与使用实现类型之间的行为方面的任何差异:

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

Even when considering autowiring this shouldn't be a problem, since both return types will work for a DataSource instance variable. 即使在考虑自动装配时,这也不应成为问题,因为两种返回类型都适用于DataSource实例变量。 So what is the correct type to return (if there is a 'correct' one), and why? 那么返回的正确类型是什么(如果有一个'正确的'),为什么?

I couldn't find any difference in the application's behavior between this configuration method to using the implementation's type 我找不到应用程序在此配置方法与使用实现类型之间的行为方面的任何差异

You have got it right, there will not be any difference because in both case finally what is returned is new HikariDataSource(); 你做对了,没有任何区别,因为在这两种情况下最终返回的是new HikariDataSource(); , ie object of HikariDataSource class. ,即HikariDataSource类的对象。

You first case is more scalable because in future you can return some other implementation of DataSource without changing the return type. 您的第一种情况更具可伸缩性,因为将来您可以在不更改返回类型的情况下返回DataSource其他实现。 Or you can update that method to implement a Factory design pattern to return hell lot of implementations of DataSource depending upon situation. 或者您可以更新该方法以实现Factory设计模式,以根据情况返回大量的DataSource实现。

So what is the correct type to return (if there is a 'correct' one), and why? 那么返回的正确类型是什么(如果有一个'正确的'),为什么?

There is really no right way, it entirely depends upon developer BUT it is always good design to "program to interface" . 实际上没有正确的方法,它完全取决于开发人员但是“编程接口”总是很好的设计。 In your case since you are returning something so it would not make much difference but still you should use public DataSource dataSource () . 在你的情况下,因为你返回的东西,所以它不会有太大的区别,但你仍然应该使用public DataSource dataSource ()

Program to interface is specially useful when you can creating a method which accept some parameter, suppose public void dataSource (DataSource ds) , in this case you can pass any implementation of DataSource , so it is a good design because it is scalable . 当你可以创建一个接受某个参数的方法时,程序到接口特别有用,假设public void dataSource (DataSource ds) ,在这种情况下你可以传递DataSource任何实现,所以它是一个很好的设计, 因为它是可扩展的

Read more about program to interface . 阅读有关程序界面的更多信息

Also, I would recommend reading about Factory design pattern , which is a good example of program to interface . 另外,我建议阅读有关工厂设计模式的内容 ,这是一个很好的接口程序示例

you should return the generic implementation. 你应该返回通用实现。

This is why: 这就是为什么:

First of, you are right. 首先,你是对的。 If you return the impl, you can still autowire the interface. 如果您返回impl,您仍然可以自动装配接口。 So you can do the above, and then: 所以你可以做到以上,然后:

@Autowire Datasource ds;

However, you can not do the reverse. 但是,你不能这样做。 You can't return Datasource and autowire HikariDataSource. 您无法返回Datasource并自动装配HikariDataSource。

Why is this important? 为什么这很重要?

You don't want your implementation to depend on specific implementations. 您不希望您的实现依赖于特定的实现。 For example: 例如:

You write your Appcode and all of your code depend on HikariDataSource. 您编写了Appcode,所有代码都依赖于HikariDataSource。 Since this is a datasource, say you have 400 daos implemented that use this and use an implementation specific detail of that class. 由于这是一个数据源,假设你有400个daos实现了使用它并使用该类的实现特定细节。 Now, if you change that impl, all your clients break. 现在,如果你改变那个impl,你所有的客户都会破产。 You will have a hell of a time making things work again. 你将有一段时间让事情再次发挥作用。 And this will repeat itself each time you need to change that (mind you, probs won't happen as often with a datasource). 每当你需要改变它时,这将重复出现(请注意,probs不会像数据源那样经常发生)。

Now returning the interface or a base class discourages your clients to depend on implementation specific details. 现在返回接口或基类会阻止客户依赖于特定于实现的详细信息。 You will have no problems switching out your datasource quickly afterwards. 之后您可以快速切换数据源。 Everything will continue to work as long as you implement the datasource interface. 只要您实现数据源接口,一切都将继续工作。

Next: Tests. 下一个:测试。 You'd want to provide a different thing for your tests (let's say datasource). 您希望为测试提供不同的东西(比方说数据源)。 Do you really want to spin up a database for your tests, while an in memory database is enough? 你真的想为你的测试启动一个数据库,而内存数据库就足够了吗? Now in your DAO test, if you depend on the IMPL, there is no way to test against a generic datasource (InMemoryDataSource). 现在在DAO测试中,如果依赖于IMPL,则无法针对通用数据源(InMemoryDataSource)进行测试。 If you return an interface, you can have a different configuration for your tests that simplifies your setup. 如果返回界面,则可以使用不同的测试配置来简化设置。

I hope this makes sense/helps. 我希望这有意义/有帮助。

Cheers, 干杯,

Artur 阿图尔

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM