在我的代码中有一个Bean管理。Admin的一个操作是创建_Task_s和_start_ing。
任务执行的操作相当复杂。因此,它被分成几个不同的步骤类。
这就是我的代码的样子
public interface Admin{
void start();
//other methods
}
public class AdminImpl implements Admin{
private BeanA bean1;
private BeanB bean2;
//other fields
public Admin(BeanA bean1,
BeanB bean2,
BeanC bean3
//Lot more parameters
BeanO bean15
){
this.bean1 = bean1;
this.bean2 = bean2;
//and so on
}
public void start(){
return new Task(bean1, bean2, bean3,...).start()
}
//other methods
}
public class Task{
private BeanA bean1;
private BeanB bean2;
//other fields
public Task(BeanA bean1,
BeanB bean2,
BeanC bean3
//Lot more parameters
){
//bind parameters to fields
}
public void start(){
new Step1(bean1, bean2,.. other parameters).do();
new Step2(bean3, bean7,.. other parameters).do();
//more steps
}
}
@Configuration
public class MyConfiguration{
@Bean
public Admin admin(BeanA bean1, BeanB bean2....){
return new AdminImpl(bean1, bean2...);
}
}如您所见,每个步骤类都有2或3个Bean依赖项。Step类不是Spring,因此它们是从Task传递的依赖项。任务也不是Spring,因此它从Admin获得依赖项。这导致Admin有太多的依赖项(~15)。
我试过这个:https://dzone.com/articles/autowiring-spring-beans-into-classes-not-managed-by-spring。
基本上,您可以创建一个名为BeanUtil的服务Bean,即ApplicationContextAware。静态方法getBean使用ApplicationContext获取bean。
Step类现在如下所示:
class Step{
public Step(){
BeanA bean1 = BeanUtil.getBean(BeanA.class);
BeanB bean2 = BeanUtil.getBean(BeanB.class);
}
public void do(){
//do stuff
}
}这解决了最初的问题,但后来我在测试方面遇到了困难。这就是测试类现在的样子。
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class Step1Test extends AbstractTestNGSpringContextTests {
@Test
public void test(){
Step1 step = new Step().do();
}
@Configuration
static class MockConfiguration {
@Bean
public BeanA beanA() {
BeanA mockBeanA=Mockito.mock(BeanA.class);
// set behavior of mock
return mockBeanA;
}
@Bean
public BeanUtil beanUtil(){
return new BeanUtil();
}
}
}如果不创建不同的配置类,就不能更改不同测试用例的模拟行为。这就像是通过创造另一个问题来解决一个问题。
这是Spring开发人员面临的一个常见问题吗?在这个问题上,抽象级别较高的类最终具有太多的依赖关系?还是我的设计出了什么问题?什么是正确的方法来处理或避免这一点?
其他看似相似但不是的问题
编辑:我从user7得到的一个建议是,我将BeanX分组并将抽象传递给Admin。beans没有任何我可以利用的逻辑分组。此外,许多步骤都需要完全访问bean(访问接口中的所有方法)。这将导致抽象变得臃肿。
发布于 2018-03-10 10:27:21
您可以将步骤Spring作为原型bean(因为它们是有状态的,并且每次都需要不同的实例),并在任务bean中注入Provider<Step> (如果我正确理解,它可以是单例bean)。
例如:
public class Step1 {
private Bean1 bean1;
private Bean2 bean2;
private final String someValue;
private final String someOtherValue;
public Step(String someValue, String someOtherValue) {
this.someValue = someValue;
this.someOtherValue = someOtherValue;
}
@Autowired
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
@Autowired
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
do() {
// ...
}
}然后,在configuration类中,将各种步骤定义为bean,并使用需要的参数的方法:
@Bean
@Scope("prototype")
public Step1 step1(String someValue, String someOtherValue) {
return new Step(someValue, someOtherValue);
}在Task中,注入一个ObjectProvider<Step1>
private ObjectProvider<Step1> stepProvider;
public Service(ObjectProvider<Step1> step1Provider) {
this.stepProvider = stepProvider;
}
public void start() {
Step1 step1 = step1Provider.getObject("a", "b");
step1.do();
}https://stackoverflow.com/questions/49207421
复制相似问题