[英]@Autowired or constructor inject non-managed classes into Spring context @Service for better testing
In a Spring Boot project, we access our non managed DAO classes through a static method:在 Spring 引导项目中,我们通过 static 方法访问我们的非托管 DAO 类:
MyDao myDao = DaoProvider.getMyDao();
We use this in Spring managed @Service
classes:我们在 Spring 托管
@Service
类中使用它:
@Service
public class MyService {
public void foo() {
MyDao myDao = DaoProvider.getMyDao();
myDao.bar();
....
}
}
This makes it hard to write unit tests.这使得编写单元测试变得困难。 Static mocks are no option, because they are slowing down our build pipeline.
Static 模拟是没有选择的,因为它们会减慢我们的构建管道。
We would rather have a solution with @Autowired
or constructor dependency and some kind of configuration, that decides which class to inject:我们宁愿有一个具有
@Autowired
或构造函数依赖和某种配置的解决方案,它决定注入哪个 class:
@Service
public class MyService {
@Autowired
MyDao myDao;
public void foo() {
myDao.bar();
....
}
}
Obviously, someone has to tell Spring what class to inject, is there a way to do so?:显然,必须有人告诉 Spring 什么 class 注入,有没有办法这样做?:
public class NonManagedSpringInjectionConfiguration {
@Bean
MyDao getMyDao() {
return DaoProvider.getMyDao();
}
}
You just have to specify the profil for example:您只需指定配置文件,例如:
@Configuration
public class NonManagedSpringInjectionConfiguration {
@Bean
@Profile("dev")
MyDao getMyDao() {
return DaoProvider.getMyDao();
}
}
If you don't want to turn your MyDao
into a Spring-managed Bean, your simpler and probably best option is to instead create the MyService
Spring-managed Bean programmatically instead of relying on @Service
annotation.如果您不想将
MyDao
变成 Spring 管理的 Bean,则更简单且可能是最好的选择是以编程方式创建MyService
Spring 管理的 Bean,而不是依赖@Service
注释。 First, just remove @Service
from MyService
and adjust its constructor to accept MyDao
:首先,只需从
MyService
中删除@Service
并调整其构造函数以接受MyDao
:
public class MyService {
MyDao myDao;
public MyService(MyDao myDao) {
this.myDao = myDao;
}
public void foo() {
myDao.bar();
....
}
}
And now you just need to register a MyService
bean using @Bean
in a Configuration class as follows:现在您只需要在配置 class 中使用
@Bean
注册一个MyService
bean,如下所示:
@Configuration
public class WhateverConfiguration {
@Bean
MyService myService() {
return new MyService(DaoProvider.getMyDao());
}
}
If instead there is a possibility to make MyDao
a Spring-managed Bean, then just keep your NonManagedSpringInjectionConfiguration
as is:相反,如果有可能使
MyDao
成为 Spring 管理的 Bean,那么只需保持NonManagedSpringInjectionConfiguration
:
@Configuration
public class NonManagedSpringInjectionConfiguration {
@Bean
MyDao getMyDao() {
return DaoProvider.getMyDao();
}
}
But then rely on constructor injection instead of on @Autowired
.但是然后依靠构造函数注入而不是
@Autowired
。 It makes MyService
easier to unit test and also explicitly defines that MyDao
is mandatory for MyService
to work properly.它使
MyService
更容易进行单元测试,并明确定义MyDao
是MyService
正常工作所必需的。 In this case you would keep @Service
and rely on Spring to instantiate it:在这种情况下,您将保留
@Service
并依靠 Spring 来实例化它:
@Service
public class MyService {
MyDao myDao;
public MyService(MyDao myDao) {
this.myDao = myDao;
}
public void foo() {
myDao.bar();
....
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.