微服务架构之Spring Boot(六十九)

2022-05-23 15:43:09 浏览数 (1)

49.3条件Annotations

您几乎总是希望在自动配置类中包含一个或多个 @Conditional 注释。@ConditionalOnMissingBean 注释是一个常见示例,用于允许开发人员

在您的默认值不满意时覆盖自动配置。

Spring Boot包含许多 @Conditional 注释,您可以通过注释 @Configuration 类或单独的 @Bean 方法在您自己的代码中重用这些注释。这些注

释包括:

第49.3.1节“类别条件”

第49.3.2节,“Bean条件”

第49.3.3节,“Property条件”

第49.3.4节“资源条件”

第49.3.5节“Web应用程序条件”

第49.3.6节“SpEL表达条件”

@ConditionalOnClass 和 @ConditionalOnMissingClass 注释允许根据特定类的存在与否来包含配置。由于使用ASM解析注释元数据这一事

实,您可以使用 value 属性来引用真实类,即使该类实际上可能不会出现在正在运行的应用程序类路径中。如果您希望使用 String 值指定类

名,也可以使用 name 属性。

如果您使用 @ConditionalOnClass 或 @ConditionalOnMissingClass 作为元注释的一部分来编写自己的组合注释,则必须使

用 name 作为引用该类的情况,在这种情况下不会处理。

49.3.2 Bean条件

@ConditionalOnBean 和 @ConditionalOnMissingBean 注释允许根据特定beans的存在与否来包括bean。您可以使用 value 属性按类型指定

beans,或使用 name 按名称指定beans。search 属性允许您限制搜索beans时应考虑的 ApplicationContext 层次结构。

置于 @Bean 方法时,目标类型默认为方法的返回类型,如以下示例所示:

@Configuration

public class MyAutoConfiguration {

@Bean

@ConditionalOnMissingBean

public MyService myService() { ... }

}

在前面的示例中,如果 ApplicationContext 中未包含类型 MyService 的bean,则将创建 myService bean。

您需要非常小心添加bean定义的顺序,因为这些条件是根据到目前为止已处理的内容进行评估的。因此,我们建议仅对自动配置

类使用 @ConditionalOnBean 和 @ConditionalOnMissingBean 注释(因为这些注释保证在添加任何用户定义的bean定义后加

载)。

@ConditionalOnBean 和 @ConditionalOnMissingBean 不会阻止创建 @Configuration 类。在类级别使用这些条件和使用注释

标记每个包含 @Bean 方法的唯一区别是,如果条件不匹配,前者会阻止将 @Configuration 类注册为bean。

49.3.3 Property条件

@ConditionalOnProperty 注释允许基于Spring Environment属性包含配置。使用 prefix 和 name 属性指定应检查的属性。默认情况下,匹

配存在且不等于 false 的任何属性。您还可以使用 havingValue 和 matchIfMissing 属性创建更高级的检查。

49.3.4资源条件

@ConditionalOnResource 注释仅在存在特定资源时才允许配置。可以使用通常的Spring约定来指定资源,如以下示例所

示:file:/home/user/test.dat 。

49.3.5 Web应用程序条件

@ConditionalOnWebApplication 和 @ConditionalOnNotWebApplication 注释允许配置,具体取决于应用程序是否为“Web应用程序”。

Web应用程序是使用Spring WebApplicationContext ,定义 session 范围或具有 StandardServletEnvironment 的任何应用程序。

49.3.6 SpEL表达条件

@ConditionalOnExpression 注释允许根据SpEL表达式的结果包含配置。

49.4测试自动配置

自动配置可能受许多因素的影响:用户配置( @Bean 定义和 Environment 自定义),条件评估(存在特定库)等。具体而言,每个测试都应创

建一个定义良好的 ApplicationContext ,它代表这些自定义的组合。ApplicationContextRunner 提供了实现这一目标的好方法。

ApplicationContextRunner 通常被定义为测试类的一个字段,用于收集基本的通用配置。以下示例确保始终调

用 UserServiceAutoConfiguration :

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()

.withConfiguration(AutoConfigurations.of(UserServiceAutoConfiguration.class));

如果必须定义多个自动配置,则无需按照与运行应用程序时完全相同的顺序调用它们的声明。

每个测试都可以使用运行器来表示特定的用例。例如,下面的示例调用用户配置( UserConfiguration )并检查自动配置是否正确退回。调

用 run 提供了一个可以与 Assert4J 一起使用的回调上下文。

@Test

public void defaultServiceBacksOff() {

this.contextRunner.withUserConfiguration(UserConfiguration.class)

.run((context) -> {

assertThat(context).hasSingleBean(UserService.class);

assertThat(context.getBean(UserService.class)).isSameAs(

context.getBean(UserConfiguration.class).myUserService());

});

}

@Configuration

static class UserConfiguration {

@Bean

public UserService myUserService() {

return new UserService("mine");

}

}

也可以轻松自定义 Environment ,如以下示例所示:

@Test

public void serviceNameCanBeConfigured() {

this.contextRunner.withPropertyValues("user.name=test123").run((context) -> {

assertThat(context).hasSingleBean(UserService.class);

assertThat(context.getBean(UserService.class).getName()).isEqualTo("test123");

});

}

跑步者也可以用来显示 ConditionEvaluationReport 。该报告可以 INFO 或 DEBUG 级别打印。以下示例显示如何使

用 ConditionEvaluationReportLoggingListener 在自动配置测试中打印报表。

@Test

public void autoConfigTest {

ConditionEvaluationReportLoggingListener initializer = new ConditionEvaluationReportLoggingListener(

LogLevel.INFO);

ApplicationContextRunner contextRunner = new ApplicationContextRunner()

.withInitializer(initializer).run((context) -> {

// Do something...

});

}

49.4.1模拟Web上下文

如果需要测试仅在Servlet或Reactive Web应用程序上下文中运行的自动配置,请分别使用 WebApplicationContextRunner

或 ReactiveWebApplicationContextRunner 。

49.4.2覆盖Classpath

还可以测试在运行时不存在特定类和/或包时发生的情况。Spring Boot装有 FilteredClassLoader ,可以很容易地被跑步者使用。在以下示例

中,我们声明如果不存在 UserService ,则会正确禁用自动配置:

@Test

public void serviceIsIgnoredIfLibraryIsNotPresent() {

this.contextRunner.withClassLoader(new FilteredClassLoader(UserService.class))

.run((context) -> assertThat(context).doesNotHaveBean("userService"));

}

49.5创建自己的初学者

库的完整Spring Boot启动器可能包含以下组件:

包含自动配置代码的 autoconfigure 模块。

starter 模块,它提供对 autoconfigure 模块以及库的依赖关系以及通常有用的任何其他依赖项。简而言之,添加启动器应该提供开始使

用该库所需的一切。

如果您不需要将这两个问题分开,则可以将自动配置代码和依赖关系管理组合在一个模块中。

0 人点赞