不要通过反射滥用私有字段获取/设置
在这里的几个答案中使用反射是我们可以避免的。
它在这里带来了很小的价值,同时也带来了多个缺点:
- 我们仅在运行时检测反射问题(例如:不再存在的字段)
- 我们想要封装,而不是一个不透明的类,它隐藏了应该可见的依赖项,并使类更不透明且更难测试。
- 它鼓励糟糕的设计。今天你声明一个
@Value String field
. 明天你可以在那个类中声明它们,你5
甚至10
可能不会直接意识到你减少了类的设计。使用更直观的方法来设置这些字段(例如构造函数),您在添加所有这些字段之前会三思而后行,您可能会将它们封装到另一个类中并使用@ConfigurationProperties
.
使您的课程在统一和集成方面都可测试
为了能够为您的 Spring 组件类编写简单的单元测试(即没有运行的 spring 容器)和集成测试,您必须使这个类在有或没有 Spring 的情况下都可用。
在不需要时在单元测试中运行容器是一种不好的做法,会减慢本地构建速度:您不希望这样。
我添加了这个答案,因为这里没有答案似乎显示了这种区别,因此它们系统地依赖于正在运行的容器。
所以我认为你应该移动这个定义为类内部的属性:
@Component
public class Foo{
@Value("${property.value}") private String property;
//...
}
到将由 Spring 注入的构造函数参数中:
@Component
public class Foo{
private String property;
public Foo(@Value("${property.value}") String property){
this.property = property;
}
//...
}
单元测试示例
由于构造函数,您可以在没有 Spring 的情况下实例化Foo
并注入任何值:property
public class FooTest{
Foo foo = new Foo("dummyValue");
@Test
public void doThat(){
...
}
}
集成测试示例
由于以下属性,您可以使用 Spring Boot 以这种简单的方式在上下文中注入properties
属性@SpringBootTest
:
@SpringBootTest(properties="property.value=dummyValue")
public class FooTest{
@Autowired
Foo foo;
@Test
public void doThat(){
...
}
}
您可以使用作为替代方案 @TestPropertySource
,但它添加了一个额外的注释:
@SpringBootTest
@TestPropertySource(properties="property.value=dummyValue")
public class FooTest{ ...}
使用 Spring(没有 Spring Boot),它应该会稍微复杂一些,但是由于我很长一段时间都没有使用没有 Spring Boot 的 Spring,所以我不喜欢说一句愚蠢的话。
附带说明:如果您@Value
要设置许多字段,则将它们提取到带有注释的类@ConfigurationProperties
中更为相关,因为我们不希望构造函数具有太多参数。