Spring依赖注入-私有字段-反模式?为什么它甚至起作用? [英] Spring Dependency Injection - Private fields - Anti Pattern? Why does it even work?

查看:70
本文介绍了Spring依赖注入-私有字段-反模式?为什么它甚至起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通常是c#开发人员,但是现在正在使用Java,然后我看到在 private 属性上使用Spring进行了大量的依赖注入,没有公开设置值的方法.我很惊讶这确实有效,但是我想可以通过反思吗?

I am generally a c# developer but working on Java now and then I see a lot of dependency injection using Spring on private properties, with no public way of setting the value. I was surprised this actually works, but I guess it’s possible via reflection?

这肯定是可怕的做法吗?!我看不到任何单元测试或检查类的人怎么可能知道需要从某个外部框架设置私有成员.

Surely this is terrible practice?! I can't see how anyone unit testing or inspecting the class would possibly know that a private member needs to be set from some external framework.

在进行单元测试时,您甚至将如何设置属性?还是只是单独使用课程?

How would you even set the property when you are unit testing? Or just using the class stand alone?

我想您必须在单元测试中使用spring,这似乎实在是太过分了.您肯定可以在没有IOC容器的情况下进行单元测试吗?该类完全依赖于spring ...

I guess you have to use spring in your unit tests which seems really overkill. Surely you should be able to unit test without your IOC container? The class becomes completely dependent on spring...

我在这里错过了什么吗?

Have I missed anything here?

依赖注入是否不总是涉及某种公共的setter,并且在可能的情况下最好使用构造函数?还是我想念的关于Java的东西??

Should dependency injection not always involve a public setter of some kind, and preferably use the constructor if possible? Or is there something about Java I am missing...?

谢谢

推荐答案

即使您有私有字段,也可以始终模拟注入的bean.您应该查看Spring文档中的 @MockBean .本质上,您可以执行以下操作:

You can always mock injected beans even if you have private fields. You should have a look on @MockBean from Spring documentation. Essentially, you could do the following:

@ExtendWith({SpringExtension.class})
class MyServiceTest{

    @MockBean
    private RepositoryInterface repository;

    @Autowired
    private MyService service;

}

假设 RepositoryInterface 是在 MyService 中注入的接口(而不是具体的类).发生的是,如果您是从Spring Initialzr创建pom.xml的,则JUnit5的 SpringExtension 应该已经存在于依赖项中,它将使用另一个称为Mockito的框架为该接口构建一个模拟(可能看看).然后,Spring IoC将在服务中注入创建的模拟.这适用于现场注入:

Supposing that RepositoryInterface is an interface (and not a concrete class) that is injected in MyService. What happens is that the SpringExtension for JUnit5, which should be already in your dependencies if you created your pom.xml from Spring Initialzr, will build a mock for that interface using another framework that is called Mockito (maybe have a look to it). Then Spring IoC will inject the created mock in the service. This works for field injection:

@Service
public class MyService{

    @Autowired
    private RepositoryInterface repositoryInterface
}

固定注入:

@Service
public class MyService{

    private RepositoryInterface repositoryInterface

    @Autowired
    public void setRepository(RepositoryInterface repositoryInterface){
        this.repositoryInterface = repositoryInterface;
    }
}

或构造函数注入:

@Service
public class MyService{

    private RepositoryInterface repositoryInterface

    public MyService(RepositoryInterface repositoryInterface){
        this.repositoryInterface = repositoryInterface;
    }
}

本质上,最后一个是推荐的,因为这样,您的服务的依赖关系将是显式的.更多有关代码样式的信息.不建议使用字段注入,因为它会隐藏您的类依赖项.因此,建议使用构造函数注入构建测试的方法如下:

Essentially, the last one is the recommended one because in this way your service's dependencies will be explicit. It's more on code style. Field injection is not recommended because iy hides your class dependencies. So, the recommended way of building a test using the constructor injection would be the following:

@ExtendWith({SpringExtension.class})
class MyServiceTest{

    @MockBean
    private RepositoryInterface repository;

    private MyService service;

    @BeforeEach
    void setup(){
        service = new MyService(repository);
    }
}

希望这有助于您理解.

这篇关于Spring依赖注入-私有字段-反模式?为什么它甚至起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆