Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”
This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.
8 Nacos Configuration center environment preparation
What is the workflow of the Nacos configuration center? Start the SpringBoot project, and after starting the project, load the configuration file for the remote server into the Spring container
@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); }}Copy the code
How do I load a configuration from a remote server into the Environment?
When SpringBoot starts, the springApplication.run () method prepares the environment
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);
// Environment preparation
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;
}
Copy the code
Call the prepareEnvironment method:
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;
}
Copy the code
listeners.environmentPrepared(environment); Post a ApplicationEnvironmentPreparedEvent event, all interested Listener will listen to this event.
BootstrapApplicationListener will receive the event and for processing
@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 instanceofParentContextApplicationContextInitializer) { 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);
}
Copy the code
BootstrapServiceContext method call builder. Sources (BootstrapImportSelectorConfiguration. Class), automatic assembly
BootstrapImportSelectorConfiguration is configuration class
@Configuration
@Import(BootstrapImportSelector.class)
public class BootstrapImportSelectorConfiguration {}Copy the code
Import BootstrapImportSelector with @import for auto-assembly
SelectImports method for BootstrapImportSelector:
@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;
}
Copy the code
Use Spring’s SPI mechanism to find meta-INF/Spring.Factories extension points
The key is BootstrapConfiguration
In the spring — cloud – context. The spring jar. 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
Copy the code
Spring. factories in spring-cloud-context.jar:
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
Copy the code
This is the environment preparation of Nacos configuration center, in fact, the most important function of Nacos is the registry and configuration center, as users of Nacos, we should master the process and working principle of Nacos, in order to locate the problem, and in the appropriate business scenarios for Nacos service function optimization and make good use of Nacos. This article only concludes the preparation of the environment for NACOS as a configuration hub, with further analysis of the flow and how the NACOS configuration file works. If you find this article helpful, feel free to leave a comment and like it