敬礼,哈布罗夫斯克。 因此,专为“ Spring框架开发人员 ”课程的学生准备的文章第二部分的翻译及时出现了。 第一部分可以在这里阅读。
Spring可能是最受欢迎的Java开发平台之一。 这是一个功能强大但很难学习的工具。 它的基本概念相当容易理解和学习,但是要成为一名经验丰富的Spring开发人员需要花费时间和精力。
在本文中,我们将研究在Spring中工作时犯的一些最常见的错误,尤其是与Web应用程序的开发和Spring Boot平台的使用有关的错误。 如Spring Boot网站上所述 ,Spring Boot采用标准化的方法来创建现成的应用程序,本文将沿用这种方法。 它将提供许多建议,这些建议可以有效地用于基于Spring Boot的标准Web应用程序的开发中。
如果您对Spring Boot平台不是很熟悉,但是想尝试本文中的示例,那么我创建了一个GitHub存储库,其中包含本文的其他材料 。 如果您对本文有些困惑,我建议您为该存储库创建一个副本,并在计算机上尝试代码。
常见错误#6:不使用基于注释的数据验证
假设前面示例中的TopTalent服务需要一个端点来添加新的TopTalent数据。 此外,我们假设由于某些非常重要的原因,您添加的每个名称都必须正好包含10个字符。 例如,可以如下实现:
@RequestMapping("/put") public void addTopTalent(@RequestBody TopTalentData topTalentData) { boolean nameNonExistentOrHasInvalidLength = Optional.ofNullable(topTalentData) .map(TopTalentData::getName) .map(name -> name.length() == 10) .orElse(true); if (nameNonExistentOrInvalidLength) {
但是,以上代码不仅结构不良,而且不是真正的“干净”解决方案。 我们执行几种类型的数据验证(即,我们验证
TopTalentData
对象不为null,TopTalentData.name字段的值不为null,
TopTalentData.name
字段的长度为10个字符),并且如果数据不正确,也会引发异常。
使用Spring中的
Hibernate验证程序可以更准确地完成所有这些操作。 让我们首先重写
addTopTalent
方法,添加对数据验证的支持:
@RequestMapping("/put") public void addTopTalent(@Valid @NotNull @RequestBody TopTalentData topTalentData) { topTalentService.addTopTalent(topTalentData); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleInvalidTopTalentDataException(MethodArgumentNotValidException methodArgumentNotValidException) {
此外,我们需要在
TopTalentData
类中指示要执行的属性验证:
public class TopTalentData { @Length(min = 10, max = 10) @NotNull private String name; }
Spring现在将拦截该请求并在调用该方法之前对其进行验证,因此不需要其他手动检查。
也可以通过创建自己的注释来实现期望的目标。 在实际情况下,仅当您的需求超出
内置的Hibernate限制集的能力时才使用自己的批注通常是有意义的,但是对于此示例,让我们假设
@Length
批注不存在。 您可以通过创建两个其他类来创建一个用于检查字符串长度的数据验证器:一个用于验证,另一个用于注释属性:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint(validatedBy = { MyAnnotationValidator.class }) public @interface MyAnnotation { String message() default "String length does not match expected"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; int value(); } @Component public class MyAnnotationValidator implements ConstraintValidator<MyAnnotation, String> { private int expectedLength; @Override public void initialize(MyAnnotation myAnnotation) { this.expectedLength = myAnnotation.value(); } @Override public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { return s == null || s.length() == this.expectedLength; } }
请注意,在这些情况下,正确应用责任分离原则要求将属性标记为有效(如果其值为null
(s == null
isValid
方法中的
(s == null
)),然后再使用
@NotNull
注释(如果此属性另外需要此注释):
public class TopTalentData { @MyAnnotation(value = 10) @NotNull private String name; }
常见错误7:使用基于XML的旧配置
使用Spring的早期版本时必须使用XML,但是现在大多数配置任务都可以使用Java代码和注释来实现。 XML配置现在充当附加和可选的模板代码。
在本文(以及随附的GitHub存储库材料)中,使用批注来配置Spring,并且Spring知道需要绑定哪些JavaBean组件,因为使用@SpringBootApplication复合批注对根包进行了批注-像这样:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
这个复合注释(
有关更多信息,请参见
Spring文档 )仅告诉Spring平台要扫描哪些软件包以提取JavaBean组件。 在我们的特殊情况下,这意味着以下co.kukurin子包将用于绑定:
- 组件 (TopTalentConverter,MyAnnotationValidator)
- @RestController(TopTalentController)
- 存储库 (TopTalentRepository)
- 服务 (TopTalentService)类
如果我们还有带有
@Configuration
批注的其他类,则还将检查它们的Java配置。
常见错误#8:不使用配置文件
在开发服务器系统时,一个常见的问题是在不同的配置之间切换(通常,这些是用于操作和开发环境的配置)。 代替在测试和操作模式之间的每次转换时手动更改各种参数,使用配置配置文件更为有效。
想象一下,在本地开发环境中使用RAM中的数据库,而在应用程序实际操作的环境中使用MySQL数据库的情况。 这实质上意味着您将使用不同的URL,并且可能使用不同的凭据来访问每个数据库。 让我们看看如何使用两个配置文件来实现:
文件APPLICATION.YAML # set default profile to 'dev' spring.profiles.active: dev # production database details spring.datasource.url: 'jdbc:mysql://localhost:3306/toptal' spring.datasource.username: root spring.datasource.password:
文件APPLICATION-DEV.YAML spring.datasource.url: 'jdbc:h2:mem:' spring.datasource.platform: h2
必须假定在使用代码时,您不想对用于操作环境的数据库执行某些随机操作,因此有必要为开发环境(DEV)选择配置文件作为默认配置文件。 随后,您可以通过为JVM指定
-Dspring.profiles.active=prod
来手动覆盖服务器上的配置概要文件。 另外,可以在操作系统环境变量中指定默认配置概要文件。
常见错误编号9。无法使用依赖项注入机制
在Spring中正确使用依赖项注入机制意味着Spring可以通过扫描所有必需的配置类来绑定所有对象。 这对于放松相互依赖关系很有用,并且极大地方便了测试。 而不是紧密地链接类,而是这样的:
public class TopTalentController { private final TopTalentService topTalentService; public TopTalentController() { this.topTalentService = new TopTalentService(); } }
...我们允许Spring平台绑定:
public class TopTalentController { private final TopTalentService topTalentService; public TopTalentController(TopTalentService topTalentService) { this.topTalentService = topTalentService; } }
Mishko Hevery在Google Tech Talks频道上的演讲详细说明了为什么应该使用依赖项注入,但是在这里,我们将了解在实践中如何使用这种机制。 在职责划分(“常见错误3”)中,我们创建了服务和控制器类。 假设我们想测试一个控制器,假设
TopTalentService
类运行正常。 通过创建单独的配置类,我们可以插入模拟器对象而不是当前服务实现:
@Configuration public class SampleUnitTestConfig { @Bean public TopTalentService topTalentService() { TopTalentService topTalentService = Mockito.mock(TopTalentService.class); Mockito.when(topTalentService.getTopTalent()).thenReturn( Stream.of("Mary", "Joel").map(TopTalentData::new).collect(Collectors.toList())); return topTalentService; } }
之后,我们可以通过
SampleUnitTestConfig
Spring平台我们需要使用
SampleUnitTestConfig
作为配置源来实现模拟器对象:
@ContextConfiguration(classes = { SampleUnitTestConfig.class })
随后,这将使我们能够使用上下文配置将定制JavaBean组件嵌入单元测试中。
常见错误编号10。缺少测试或测试不正确
尽管单元测试的想法绝非新鲜事物,但似乎许多开发人员还是“忘记”了它(特别是如果
不是强制性的 ),或者为时已晚。 显然,这是错误的,因为测试不仅使您可以检查代码的正确操作,而且还可以作为说明应用程序在各种情况下的行为的文档。
在测试Web服务时,您很少运行异常的“干净”单元测试,因为对于HTTP连接,您通常需要使用Spring
DispatcherServlet
Servlet并查看收到真实的
HttpServletRequest
请求时会发生什么(也就是说,结果证明是使用验证,序列化等)。 一个经过验证的优雅解决方案是使用
REST Assured (一种Java库),通过MockMVC方便地测试REST服务。 考虑以下带有依赖项注入的代码片段:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { Application.class, SampleUnitTestConfig.class }) public class RestAssuredTestDemonstration { @Autowired private TopTalentController topTalentController; @Test public void shouldGetMaryAndJoel() throws Exception {
SampleUnitTestConfig
将
TopTalentService
类的代理实现绑定到
TopTalentController
,所有其他类都使用通过扫描基于Application类的包的包而获得的标准配置来绑定。
RestAssuredMockMvc
仅用于设置轻量级环境,并将
GET
请求发送到
/toptal/get
。
专业使用Spring
Spring是一个功能强大的平台,易于入门,但是要完全掌握它需要时间和精力。 如果您花时间熟悉该平台,那么最终无疑会提高您的工作效率,帮助您创建更简洁的代码并提高开发人员的资格。
我建议您注意
Spring In Action-这是一本面向应用程序的好书,它讨论了许多与Spring平台相关的重要主题。
至此,本文的翻译结束了。
阅读第一部分 。