Серия приложений Springboot — рекомендации @ConfigurationProperties для внешней конфигурации

Spring Boot

I. Предыстория

  предыдущий поствведена система@ValueЛучшие практики, в этой статье будет документирован еще один главный герой конфигурации экстернализации Springboot.@ConfigurationProperties.

2. Лучшие практики для @ConfigurationProperties

  Многие компоненты Springboot можно использовать «из коробки» без настройки. например, введениеspring-boot-redis-starter, вы можете использовать локальный Redis. Причина, по которой может быть достигнута возможность нулевой конфигурации, заключается в том, что она зависит от@ConfigurationPropertiesСпособность.

2.1 Основное использование

   @ConfigurationProperties может сделать нашу конфигурацию модульной. Таким образом удобно централизованно управлять при использовании и обслуживании, а конфигурация каждого модуля не будет влиять друг на друга. Мы также можем использовать @Value, Environment, параметры запуска и т. д., чтобы добиться этого. Но это явно неприменимо в сценарии модульной функции.

Основное использование   @ConfigurationProperties заключается в следующем:

класс пользовательской конфигурации
/**
 * @author sunliming11
 * @date created in 2021/2/17
 */
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "my.plugin")
public class MyPluginProperties {
    /**
     * 是否开启
     */
    private Boolean enabled;
    /**
     * 插件名称
     */
    private String name;
    /**
     * 别名
     */
    private List<String> alias;
    /**
     * map属性
     */
    private Map<String, String> map;
    /**
     * obj
     */
    private Security security;

    @Data
    @ToString
    public static class Security {
        /**
         * 用户名
         */
        private String username;
        /**
         * 密码
         */
        private String password;
        /**
         * 角色列表
         */
        private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
    }
}
импортный пакет jar

нужно представитьspring-boot-configuration-processorпакет, основная возможность пакета состоит в том, чтобы обеспечитьConfigurationMetadataAnnotationProcessorЭтот постпроцессор, его роль заключается в@ConfigurationPropertiesСоздайте файл [метаданные].

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
настроить

Перед настройкой давайте сначала соберем проект. Если это IDEA, нажмите 🔨 в правом верхнем углу:

После этого вы можете увидеть в каталоге компиляции:

На данный момент мы можем видеть соответствующие подсказки при настройке в файле конфигурации yml:

Полная конфигурация YAML выглядит следующим образом:

my:
    plugin:
        name: 插件名称
        enabled: true
        alias:
            - 别名1
            - 别名2
            - 别名3
        map:
            "[key1]": value1
            "[key2]": value2
            "/key3": value3
        security:
            password: 12345
            username: 用户名
            roles:
                - USER
                - ADMIN

Если вы используете конфигурацию свойств, полная конфигурация выглядит следующим образом:

my.plugin.name=插件名称
my.plugin.enabled=true
my.plugin.alias[0]=别名1
my.plugin.alias[1]=别名2
my.plugin.alias[2]=别名3
my.plugin.map[key1]=value1
my.plugin.map[key2]=value2
my.plugin.map[key3]=value3
my.plugin.security.username=用户名
my.plugin.security.password=12345
my.plugin.security.roles[0]=ADMIN
my.plugin.security.roles[1]=USER

   В приведенном выше примере показано, как передать@ConfigurationPropertiesдля настройки POJO, который может легко внедрять сложные типы свойств. но@ValueЭто требует использования трюков и приемов для реализации внедрения сложных типов.

2.2 relaxed binding

  поддержка SpringBoot@ConfigurationPropertiesсвободные правила связывания. Напримерacme.myProject.person.firstNameКонфигурация этого свойства имеет тот же эффект, что и следующий.

acme.my-project.person.first-name=LEON
acme.my_project.person.first_name=LEON
ACME_MYPROJECT_PERSON_FIRSTNAME=LEON
...

   Основываясь на принципе свободного связывания, вышеприведенная нотация в конечном итоге может быть проанализирована. То есть для того же слова просто удалите驼峰式、下划线(\_)、短横线(-)Простые буквы после правила в конечном итоге одинаковы (без учета регистра) и могут быть проанализированы.

2.3 Лучший способ активации

использовать@ConfigurationPropertiesАннотацию нельзя использовать напрямую, нам также необходимо активировать этот класс конфигурации. Если этот класс конфигурации не активирован, проект Springboot все еще можно запустить в обычном режиме, но класс конфигурации использовать нельзя.
активация@ConfigurationPropertiesЕсть много способов, в принципе класс конфигурации можно внедрить в контейнер, даже если он активирован. Исходя из этого принципа, существуют следующие способы активации:

2.3.1 @Component
@Component // 通过@Component并被容器scan到,可以注入到容器中。
@ConfigurationProperties(prefix = "my.plugin")
public class MyPluginProperties {
……
}
2.3.2 @Configuration
@Configuration
@ConfigurationProperties(prefix = "my.plugin")
public class MyPluginProperties {
……
}
2.3.3 @Bean
@Configuration
public class MyConfiguration {

	@Bean
    public MyPluginProperties myPluginProperties() {
    	return new MyPluginProperties();
    }
}
2.3.4 @EnableConfigurationProperties
@Configuration
@EnableConfigurationProperties(MyPluginProperties.class)
public class MyConfiguration {
}

   В комментариях к исходному коду@EnableConfigurationPropertiesфункция состоит в том, чтобы обеспечить@ConfigurationPropertiesслужба поддержки. Как это поддерживается? Определение класса в исходном коде имеет:@Import(EnableConfigurationPropertiesRegistrar.class), то есть говорят, что он поддерживается благодаря возможности @Import.EnableConfigurationPropertiesRegistrarДостигнутоImportBeanDefinitionRegistrar, так что вы можете вводить пользовательскиеBeanDefinition, исходный класс пользовательского bd здесь@EnableConfigurationPropertiesЗначение, указанное в аннотации. BD может быть сгенерирован BD естественным путем.

   С таким количеством способов его использования, какой из них лучше? На самом деле нет ни хорошего, ни плохого. Но все же рекомендуется использовать@EnableConfigurationProperties, Особые люди делают особые вещи.

2.4 Что делать, если атрибут или значение атрибута не могут быть сопоставлены

Если настроены избыточные атрибуты, такие как еще одна конфигурация в приведенном выше примереmy.plugin.name1

my:
    plugin:
        name: 插件名称
        name1: 多余的配置

По умолчанию проект запускается нормально. Если вы хотите, чтобы проект не запускался, вы можете настроитьignoreUnknownFields = false:

@ConfigurationProperties(prefix = "my.plugin", ignoreUnknownFields = false)

Если типы атрибутов не совпадают, запуск по умолчанию завершится ошибкой.Если вы не хотите ошибаться, вы можете настроитьignoreInvalidFields = true:

@ConfigurationProperties(prefix = "my.plugin", ignoreInvalidFields = true)

2.5 Проверка

Механизм проверки Spring основан на JSR303, и Spring также поддерживает@ConfigurationPropertiesСвойства класса конфигурации основаны на проверке JSR303. Способ его использования очень прост, а именно:

@Data
@ToString
@Component
@ConfigurationProperties(prefix = "my.plugin", ignoreUnknownFields = false, ignoreInvalidFields = true)
@Validated //开启校验
public class MyPluginProperties {
    /**
     * 是否开启
     */
    private Boolean enabled;
    /**
     * 插件名称
     */
    @NotNull
    @Size(min = 12, max = 16)
    private String name;
    /**
     * 别名
     */
    @NotNull
    private List<String> alias;
    /**
     * map属性
     */
    private Map<String, String> map;
    /**
     * obj
     */
    private Security security;

открыть в классе@ValidatedВот и все. Затем используйте аннотации проверки, поддерживаемые обычным JSR303.

2.6 Принцип «нулевой конфигурации»

   В springboot, как добиться конфигурации 0? такие как импортspring-boot-redis-starter, вы можете запустить проект без какой-либо настройки, подключиться к локальной базе данных Redis и использовать ее.
существует@ConfigurationPropertiesОн также опирается на аннотацию на основе:@EnableAutoConfiguration. Эта аннотация по-прежнему основана на@ImportСпособность можно увидеть в исходном коде:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class) //委托给AutoConfigurationImportSelector
public @interface EnableAutoConfiguration {
    ……
}

Его полная ссылка выглядит следующим образом:
@EnableAutoConfiguration➡️
@Import➡️
@AutoConfigurationImportSelector➡️
AutoConfigurationImportSelector➡️
выполнитьselectImports()➡️
Внутренний вызовgetAutoConfigurationEntry()➡️
Внутренний вызовgetCandidateConfigurations➡️
org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames➡️
Внутренний вызовloadSpringFactories()
В этом методе мы видим:

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    Map<String, List<String>> result = cache.get(classLoader);
    if (result != null) {
        return result;
    }

    result = new HashMap<>();
    try {
        Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
    }
    ......

В исходном коде вы можете увидетьFACTORIES_RESOURCE_LOCATIONПостоянное значение:

То есть, если вы используете@EnableAutoConfigurationAnnotation, то Springboot просканирует все пути к пакетам в процессе запуска.META-INF/spring.factories, все классы в этом файле будут внедрены сканированием Spring.

настроить

Основываясь на вышеуказанных знаниях, запустите новый модуль для настройки конфигурации. Структура каталогов следующая:

@Data
@ConfigurationProperties(prefix = "my.plugin")
public class MyPluginProperties {
    /**
     * 插件名称
     */
    private String name = "我的自定义插件";
    /**
     * 是否开启
     */
    private Boolean enabled;
}

//****************************************

@EnableConfigurationProperties(MyPluginProperties.class)
public class MyPluginAutoConfiguration {
}

Файл spring.factories выглядит следующим образом:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.leon.myplugin.MyPluginAutoConfiguration

Затем используйте пакет maven и внедрите его в проект Springboot:

<dependency>
    <groupId>com.leon</groupId>
    <artifactId>spring-boot-starter-myplugin</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

После повторного импорта вы можете использовать его в файле yml:

4. Недостатки @ConfigurationProperties

  @ConfigurationPropertiesОчень мощный, но есть одно место, где его нельзя сравнить@Value, то есть выражения SpringEL не поддерживаются. Об этом прямо сказано на официальном сайте. Но это не мешает@ConfigurationPropertiesСтаньте одной из самых важных базовых возможностей Springboot.

  @ValueПринцип таков: перед инициализацией bean-компонента сначала выполняется внедрение зависимостей, в основном делегированноеAutowiredAnnotationBeanPostProcessorзавершается постпроцессором;

  @ConfigurationPropertiesПринцип такой: на основе@Importспособность пройтиEnableConfigurationPropertiesRegistrarЧтобы добиться внедрения BeanDefinition класса конфигурации, а затем внедрения атрибутов.

   Принципы реализации этих двух совершенно разные.

V. Резюме

  Эта статья в основном о@ConfigurationPropertiesВ процессе также демонстрируются использование и принцип работы «Springboot», а также вариант использования и принцип работы нулевой конфигурации «Springboot». Наконец-то сравнил@ConfigurationPropertiesа также@Valueпринципиальная разница.