Nacos配置中心之环境准备

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

8 Nacos配置中心之环境准备

Nacos配置中心的工作流程是怎么样的呢? 首先启动SpringBoot项目,在启动项目之后,需要把远程服务器的配置文件加载到Spring容器中

@SpringBootApplication
public class SpringCloudNacosConfigApplication {

   public static void main(String[] args) {
      ConfigurableApplicationContext context=
            SpringApplication.run(SpringCloudNacosConfigApplication.class, args);
      String info=context.getEnvironment().getProperty("info");
      System.out.println(info);
   }
}
复制代码

如何从远处服务器上的配置加载到Environment?

SpringBoot启动时,SpringApplication.run()方法进行环境准备

public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   configureHeadlessProperty();
   SpringApplicationRunListeners listeners = getRunListeners(args);
   listeners.starting();
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
       //环境准备
      ConfigurableEnvironment environment = prepareEnvironment(listeners,
            applicationArguments);
      configureIgnoreBeanInfo(environment);
      Banner printedBanner = printBanner(environment);
      context = createApplicationContext();
      exceptionReporters = getSpringFactoriesInstances(
            SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      prepareContext(context, environment, listeners, applicationArguments,
            printedBanner);
      refreshContext(context);
      afterRefresh(context, applicationArguments);
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass)
               .logStarted(getApplicationLog(), stopWatch);
      }
      listeners.started(context);
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, listeners);
      throw new IllegalStateException(ex);
   }

   try {
      listeners.running(context);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, null);
      throw new IllegalStateException(ex);
   }
   return context;
}
复制代码

调用prepareEnvironment方法:

private ConfigurableEnvironment prepareEnvironment(
      SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments) {
   // Create and configure the environment
   ConfigurableEnvironment environment = getOrCreateEnvironment();
   configureEnvironment(environment, applicationArguments.getSourceArgs());
   listeners.environmentPrepared(environment);
   bindToSpringApplication(environment);
   if (!this.isCustomEnvironment) {
      environment = new EnvironmentConverter(getClassLoader())
            .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
   }
   ConfigurationPropertySources.attach(environment);
   return environment;
}
复制代码

listeners.environmentPrepared(environment);中发布一个ApplicationEnvironmentPreparedEvent事件,所有感兴趣的Listener都会监听到这个事件。

BootstrapApplicationListener就会收到该事件并进行处理

@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
   ConfigurableEnvironment environment = event.getEnvironment();
   if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,
         true)) {
      return;
   }
   // don't listen to events in a bootstrap context
   if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
      return;
   }
   ConfigurableApplicationContext context = null;
   String configName = environment
         .resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
   for (ApplicationContextInitializer<?> initializer : event.getSpringApplication()
         .getInitializers()) {
      if (initializer instanceof ParentContextApplicationContextInitializer) {
         context = findBootstrapContext(
               (ParentContextApplicationContextInitializer) initializer,
               configName);
      }
   }
   if (context == null) {
      context = bootstrapServiceContext(environment, event.getSpringApplication(),
            configName);
      event.getSpringApplication()
            .addListeners(new CloseContextOnFailureApplicationListener(context));
   }

   apply(context, event.getSpringApplication(), environment);
}
复制代码

bootstrapServiceContext方法中调用builder.sources(BootstrapImportSelectorConfiguration.class),进行自动装配

BootstrapImportSelectorConfiguration是配置类

@Configuration
@Import(BootstrapImportSelector.class)
public class BootstrapImportSelectorConfiguration {

}
复制代码

用@Import导入BootstrapImportSelector实现自动装配

扫描二维码关注公众号,回复: 13166593 查看本文章

BootstrapImportSelector的selectImports方法:

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
   ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
   // Use names and ensure unique to protect against duplicates
   List<String> names = new ArrayList<>(SpringFactoriesLoader
         .loadFactoryNames(BootstrapConfiguration.class, classLoader));
   names.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(
         this.environment.getProperty("spring.cloud.bootstrap.sources", ""))));

   List<OrderedAnnotatedElement> elements = new ArrayList<>();
   for (String name : names) {
      try {
         elements.add(
               new OrderedAnnotatedElement(this.metadataReaderFactory, name));
      }
      catch (IOException e) {
         continue;
      }
   }
   AnnotationAwareOrderComparator.sort(elements);

   String[] classNames = elements.stream().map(e -> e.name).toArray(String[]::new);

   return classNames;
}
复制代码

利用Spring的SPI机制查找META-INF/spring.factories扩展点

key是BootstrapConfiguration

在spring-cloud-context.jar中的spring.factories:PropertySourceBootstrapConfiguration

# Bootstrap components
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration,\
org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration,\
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
复制代码

在spring-cloud-context.jar中的spring.factories:

NacosConfigBootstrapConfiguration

org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.NacosConfigAutoConfiguration,\
com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer
复制代码

这就是Nacos配置中心的环境准备方面,其实nacos最重要的功能就是注册中心和配置中心,作为nacos的使用者,我们要掌握好nacos的流程和工作原理,才能定位到问题,并在合适的业务场景中进行对nacos服务的功能优化和利用好nacos,这篇文章仅仅是对nacos作为配置中心功能的环境准备方面的结束,后续还会进一步分析nacos配置文件的流程和工作原理。如果你觉得这篇文章对你有帮助的话,欢迎给我留言点赞评论转发 01DD0A40.png

猜你喜欢

转载自juejin.im/post/7017758844797321253