不要滥用反射获取/设置的私有字段
在这里的几个答案中使用反射是我们可以避免的。
它在这里带来的价值很小,但它呈现出多个缺点:
we detect reflection issues only at runtime (ex: fields not existing any longer)
We want encapsulation but not a opaque class that hides dependencies that should be visible and make the class more opaque and less testable.
it encourages bad design. Today you declare a @Value String field. Tomorrow you can declare 5 or 10 of them in that class and you may not even be straight aware that you decrease the design of the class. With a more visible approach to set these fields (such as constructor) , you will think twice before adding all these fields and you will probably encapsulate them into another class and use @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,并通过构造函数为属性注入任何值:
public class FooTest{
Foo foo = new Foo("dummyValue");
@Test
public void doThat(){
...
}
}
集成测试示例
多亏了@SpringBootTest的properties属性,你可以用这种简单的方式在SpringBoot的上下文中注入属性:
@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,所以我不喜欢说愚蠢的事情。
旁注:如果要设置许多@Value字段,将它们提取到带有@ConfigurationProperties注释的类中更相关,因为我们不希望构造函数带有太多参数。