Проект Spring Cloud SpringApplication Run выполняет расшифровку дважды

Java

Введение в ApplicationContextInitializer

роль вConfigurableApplicationContextТипApplicationContext.refreshПеред операцией позвольте намConfiurableApplicationContextРасширения для улучшения обработки.

Деловая сцена

В реальном процессе разработки контекст приложения необходимо программно инициализировать в веб-приложении. Например, регистрация источника свойства(bootstrap/application properties sources); Кодированные динамические активации отличаютсяprofileвести перепискуenvironment

Еще один недавний проект, в соответствии с различными средамиLinux/Windowsдля загрузки различных параметров SDK.

настроитьConditionвыполнить

Из-за чрезвычайно большого количества элементов конфигурации, путем измененияConfigurationPropertiesНастроить на Bean@Conditional

public class LinuxCondition  implements Condition{
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String property = context.getEnvironment().getProperty("os.name");
            ...
        return  property.contains("linux");
    }
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({LinuxCondition.class})
public @interface ConditionOnLinux {}

Поскольку классы конфигурации, разработанные SDK, извлекаются слишком часто, а разделение нецелесообразно, от этого метода отказались, не уничтожив культурные реликвии.

Пользовательская реализация ApplicationContextInitializer

Загружайте по контекстуresourceКаталоги, файлы конфигурации для разных сред

public class SelectApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        ConfigurableEnvironment env = context.getEnvironment();
        MutablePropertySources mps = env.getPropertySources();

        String property = env.getProperty("os.name");

        if (property.contains("Mac OS X")) {
            mps.addLast(new ResourcePropertySource(new ClassPathResource("linux.properties")));
        } else {
            mps.addLast(new ResourcePropertySource(new ClassPathResource("window.properties")));
        }

    }
}

Проблема: инициализация выполняется дважды

Извлеките соответствующие функции вstarter, работает на синглтонеSpring Bootпроект, если добавленSpring Cloud Contextвыполнит приведенный выше код дважды


SpringApplication.run

  • Чтобы выяснить настоящего виновника, под методом запуска SpringApplication была поставлена ​​точка останова.

BootstrapApplicationListener

следовал всю дорогуBootstrapApplicationListener.bootstrapServiceContextметод.

Давайте посмотримbootstrapServiceContextметод,

SpringApplicationBuilder builder = (new SpringApplicationBuilder(new Class[0])).profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF).environment(bootstrapEnvironment).registerShutdownHook(false).logStartupInfo(false).web(WebApplicationType.NONE);
SpringApplication builderApplication = builder.application();
if (builderApplication.getMainApplicationClass() == null) {
    builder.main(application.getMainApplicationClass());
}

if (environment.getPropertySources().contains("refreshArgs")) {
    builderApplication.setListeners(this.filterListeners(builderApplication.getListeners()));
}

builder.sources(new Class[]{BootstrapImportSelectorConfiguration.class});
ConfigurableApplicationContext context = builder.run(new String[0]);
context.setId("bootstrap");

предупреждение правды

BootstrapApplicationListenerв использованииSpringApplicationBuilderсделал перезагрузку, хотя это былоRunДважды но в первый раз не запускал контейнер и т.д., так и появилосьBeanзагрузить дважды или запустить контейнерTomcatИ другие конфликты портов.

image