8Nacos配置中心之环境准备
【摘要】 8 Nacos配置中心之环境准备 prepareEnvironment()方法 BootstrapApplicationListener类 BootstrapImportSelectorConfiguration类 BootstrapImportSelector的selectImports()方法: 总结 8 Nacos配置中心之环境准备Nacos配置中心的工作流程是怎么样的呢?首先启动S...
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的获取,那么如何从远处服务器上的配置加载到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;
}
- 获取监听并启动监听
- 根据传入的参数创建applicationArguments对象
- 调用prepareEnvironment方法,进行环境准备
- 打印banner,准备上下文,刷新上下文,然后执行刷新之后操作等等
- 租后返回context上下文
我们看看prepareEnvironment方法做了什么
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就会收到该事件并进行处理
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这个类做了什么
BootstrapImportSelectorConfiguration类
BootstrapImportSelectorConfiguration是配置类
@Configuration
@Import(BootstrapImportSelector.class)
public class BootstrapImportSelectorConfiguration {
}
用@Import导入BootstrapImportSelector实现自动装配
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
水落石出了,这里自动装配了NacosConfigBootstrapConfiguration配置类
总结
这就是Nacos配置中心的环境准备方面,从SpringBoot项目启动类的环境准备的方法入手,通过BootstrapApplicationListener类的监听方法,调用了builder.sources(BootstrapImportSelectorConfiguration.class)加载了BootstrapImportSelectorConfiguration类,它的selectImports()方法中利用Spring的SPI扩展机制记载了key为BootstrapConfiguration定义的一些nacos中类,从而对nacos的启动环境做了准备。其实nacos最重要的功能就是注册中心和配置中心,作为nacos的使用者,我们要掌握好nacos的流程和工作原理,才能定位到问题,并在合适的业务场景中进行对nacos服务的功能优化和利用好nacos,这篇文章仅仅是对nacos作为配置中心功能的环境准备方面的结束,后续还会进一步分析nacos配置文件的流程和工作原理。如果你觉得这篇文章对你有帮助的话,欢迎给我留言点赞评论转发!
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)