In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >
Share
Shulou(Shulou.com)05/31 Report--
Today, I will talk to you about how to carry out a simple analysis of the SpringCloud configuration refresh mechanism, which may not be well understood by many people. in order to make you understand better, the editor has summarized the following contents for you. I hope you can get something according to this article.
SpringCloud Nacos
Mainly divided into the design ideas of SpringCloud Nacos
Briefly analyze the process that happened after the refresh event was triggered and some experience of stepping on the pit.
Org.springframework.cloud.bootstrap.config.PropertySourceLocator
This is an initiator load configuration class provided by SpringCloud, which implements locate and can be injected into the context to discover the configuration.
/ * *
* @ param environment The current Environment.
* @ return A PropertySource, or null if there is none.
* @ throws IllegalStateException if there is a fail-fast condition.
, /
PropertySource locate (Environment environment)
Com.alibaba.cloud.nacos.client.NacosPropertySourceLocator
This class is a configuration discovery class implemented by nacos
Org.springframework.core.env.PropertySource
Change the class to the class abstracted by springcloud to express the attribute source.
Com.alibaba.cloud.nacos.client.NacosPropertySource / nacos implements this class and assigns other properties
/ * *
* Nacos Group.
, /
Private final String group
/ * *
* Nacos dataID.
, /
Private final String dataId
/ * *
* timestamp the property get.
, /
Private final Date timestamp
/ * *
* Whether to support dynamic refresh for this Property Source.
, /
Private final boolean isRefreshable
Give an overview of com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#locate
Source code parsing
@ Override
Public PropertySource locate (Environment env) {
NacosConfigProperties.setEnvironment (env)
/ / get the service class of nacos configuration, http protocol, and access the api API of nacos to obtain configuration
ConfigService configService = nacosConfigManager.getConfigService ()
If (null = = configService) {
Log.warn ("no instance of config service found, can't load config from nacos")
Return null
}
Long timeout = nacosConfigProperties.getTimeout ()
/ / build a builder
NacosPropertySourceBuilder = new NacosPropertySourceBuilder (configService
Timeout)
String name = nacosConfigProperties.getName ()
String dataIdPrefix = nacosConfigProperties.getPrefix ()
If (StringUtils.isEmpty (dataIdPrefix)) {
DataIdPrefix = name
}
If (StringUtils.isEmpty (dataIdPrefix)) {
DataIdPrefix = env.getProperty ("spring.application.name")
}
/ / build a composite data source
CompositePropertySource composite = new CompositePropertySource (
NACOS_PROPERTY_SOURCE_NAME)
/ / load shared configuration
LoadSharedConfiguration (composite)
/ / load extension configuration
LoadExtConfiguration (composite)
/ / load the application configuration, and the priority of the application configuration is the highest, so we will do it at the back here because the place where the configuration is added is addFirst, so the priority is the first and the last.
LoadApplicationConfiguration (composite, dataIdPrefix, nacosConfigProperties, env)
Return composite
}
Every time nacos checks for a configuration update, it triggers a context configuration refresh and calls the locate method.
Org.springframework.cloud.endpoint.event.RefreshEvent
This event is an event built into spring cloud and is used to refresh the configuration
Com.alibaba.cloud.nacos.refresh.NacosRefreshHistory
This class is used to store the refresh history of nacos, to save the MD5 value of the configuration pulled each time, and to compare whether the configuration needs to be refreshed.
Com.alibaba.cloud.nacos.refresh.NacosContextRefresher
This class is used by Nacos to manage some internal listeners, mainly to start a callback when the configuration is refreshed, and to issue configuration refresh events in the spring cloud context
Com.alibaba.cloud.nacos.NacosPropertySourceRepository
This class is used by nacos to hold the pulled data
Process:
Refresher checks configuration updates and saves to NacosPropertySourceRepository
Initiate a refresh event
Locate execution, read NacosPropertySourceRepository directly
Com.alibaba.nacos.client.config.NacosConfigService
This class is the main refresh configuration service class for nacos
Com.alibaba.nacos.client.config.impl.ClientWorker
This class is the main client in the service class, and the protocol is HTTP
When clientWorker starts, it initializes two thread pools, one for regular check configuration and one for auxiliary check.
Executor = Executors.newScheduledThreadPool (1, new ThreadFactory () {
@ Override
Public Thread newThread (Runnable r) {
Thread t = new Thread (r)
T.setName ("com.alibaba.nacos.client.Worker." + agent.getName ())
T.setDaemon (true)
Return t
}
});
ExecutorService = Executors.newScheduledThreadPool (Runtime.getRuntime () .availableProcessors (), new ThreadFactory () {
@ Override
Public Thread newThread (Runnable r) {
Thread t = new Thread (r)
T.setName ("com.alibaba.nacos.client.Worker.longPolling." + agent.getName ())
T.setDaemon (true)
Return t
}
});
Executor.scheduleWithFixedDelay (new Runnable () {
@ Override
Public void run () {
Try {
CheckConfigInfo ()
} catch (Throwable e) {
LOGGER.error ("[" + agent.getName () + "] [sub-check] rotate check error", e)
}
}
}, 1L, 10L, TimeUnit.MILLISECONDS)
Com.alibaba.nacos.client.config.impl.ClientWorker.LongPollingRunnable
This class is used for long polling tasks
Com.alibaba.nacos.client.config.impl.CacheData#checkListenerMd5 begins to refresh the configuration after comparing MD5
Com.alibaba.cloud.nacos.parser
The package provides converters for many file types
When loading data, a converter instance is found based on the file extension.
/ / com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder#loadNacosData
Private Map loadNacosData (String dataId, String group
String fileExtension) {
String data = null
Try {
Data = configService.getConfig (dataId, group, timeout)
If (StringUtils.isEmpty (data)) {
Log.warn (
"Ignore the empty nacos configuration and get it based on dataId [{}] & group [{}]"
DataId, group)
Return EMPTY_MAP
}
If (log.isDebugEnabled ()) {
Log.debug (String.format (
"Loading nacos data, dataId:'% slots, group:'% slots, data:% s", dataId
Group, data))
}
Map dataMap = NacosDataParserHandler.getInstance ()
.parseNacosData (data, fileExtension)
Return dataMap = = null? EMPTY_MAP: dataMap
}
Catch (NacosException e) {
Log.error ("get data from Nacos error,dataId: {},", dataId, e)
}
Catch (Exception e) {
Log.error ("parse data from Nacos error,dataId: {}, data: {},", dataId, data, e)
}
Return EMPTY_MAP
}
The data will be changed into key value and then converted to PropertySource
How to configure a startup configuration class
Since the configuration context is managed by SpringCloud, this injection is different from the previous SpringBoot.
Org.springframework.cloud.bootstrap.BootstrapConfiguration=\
Com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration
How to share a bean on SpringCloud and SpringBoot (for example)
@ Bean
Public NacosConfigProperties nacosConfigProperties (ApplicationContext context) {
If (context.getParent ()! = null
& & BeanFactoryUtils.beanNamesForTypeIncludingAncestors (
Context.getParent (), NacosConfigProperties.class) .length > 0) {
Return BeanFactoryUtils.beanOfTypeIncludingAncestors (context.getParent ()
NacosConfigProperties.class)
}
Return new NacosConfigProperties ()
}
About the process org.springframework.cloud.endpoint.event.RefreshEventListener// outer method of the refresh mechanism
Public synchronized Set refresh () {
Set keys = refreshEnvironment ()
This.scope.refreshAll ()
Return keys
}
/ /
Public synchronized Set refreshEnvironment () {
Map before = extract (
This.context.getEnvironment () .getPropertySources ()
AddConfigFilesToEnvironment ()
Set keys = changes (before
Extract (this.context.getEnvironment () .getPropertySources ()) .keySet ()
This.context.publishEvent (new EnvironmentChangeEvent (this.context, keys))
Return keys
}
This class handles RefreshEvent snooping
Navigate directly to org.springframework.cloud.context.refresh.ContextRefresher#refreshEnvironment, which is the main way to refresh the configuration, what to do:
Merge and get the configuration key value before refresh
Org.springframework.cloud.context.refresh.ContextRefresher#addConfigFilesToEnvironment simulates a new SpringApplication, triggers most of the SpringBoot startup process, so it also triggers to read the configuration, so it triggers the Locator mentioned above, and then gets a new Spring application, obtains a new aggregate configuration source, compares it with the old Spring application configuration source, puts the changed configuration to the old one, and then closes the new Spring application.
Compare the old and new configurations, take out the configuration, and trigger an event org.springframework.cloud.context.environment.EnvironmentChangeEvent
After jumping out of the method stack, execute org.springframework.cloud.context.scope.refresh.RefreshScope#refreshAll
Simple Analysis of EnvironmentChangeEvent
Org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder#rebind ()
The code is as follows:
@ ManagedOperation
Public boolean rebind (String name) {
If (! this.beans.getBeanNames (). Contains (name)) {
Return false
}
If (this.applicationContext! = null) {
Try {
Object bean = this.applicationContext.getBean (name)
/ / get the source object
If (AopUtils.isAopProxy (bean)) {
Bean = ProxyUtils.getTargetObject (bean)
}
If (bean! = null) {
/ / re-trigger the periodic method of destruction and initialization
This.applicationContext.getAutowireCapableBeanFactory ()
.destroyBean (bean)
/ / because the initialization life cycle is triggered, it can be triggered.
/ / org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization
This.applicationContext.getAutowireCapableBeanFactory ()
.initializeBean (bean, name)
Return true
}
}
Catch (RuntimeException e) {
This.errors.put (name, e)
Throw e
}
Catch (Exception e) {
This.errors.put (name, e)
Throw new IllegalStateException ("Cannot rebind to" + name, e)
}
}
Return false
}
After receiving the event in this method, some bean properties are rebound. Which Bean?
Org.springframework.cloud.context.properties.ConfigurationPropertiesBeans#postProcessBeforeInitialization one of the post-processors of bean later in life that the method executes in the Spring refresh context, it checks the annotation @ ConfigurationProperties, these bean are the rebound bean described in the first step above
@ Override
Public Object postProcessBeforeInitialization (Object bean, String beanName)
Throws BeansException {
If (isRefreshScoped (beanName)) {
Return bean
}
ConfigurationProperties annotation = AnnotationUtils
.findAnnotation (bean.getClass (), ConfigurationProperties.class)
If (annotation! = null) {
This.beans.put (beanName, bean)
}
Else if (this.metaData! = null) {
Annotation = this.metaData.findFactoryAnnotation (beanName
ConfigurationProperties.class)
If (annotation! = null) {
This.beans.put (beanName, bean)
}
}
Return bean
}
Simple analysis of org.springframework.cloud.context.scope.refresh.RefreshScope#refreshAll@ManagedOperation (description = "Dispose of the current instance of all beans")
+ "in this scope and force a refresh on next method execution.")
Public void refreshAll () {
Super.destroy ()
This.context.publishEvent (new RefreshScopeRefreshedEvent ())
}
Org.springframework.cloud.context.scope.GenericScope#destroy ()
Destroy the collection of BeanLifecycleWrapper instances
What is BeanLifecycleWrapper?
Private static class BeanLifecycleWrapper {
/ / the name of bean
Private final String name
/ / obtain bean
Private final ObjectFactory objectFactory
/ / A real instance
Private Object bean
/ / destroy function
Private Runnable callback
}
How is BeanLifecycleWrapper constructed?
@ Override
Public Object get (String name, ObjectFactory objectFactory) {
BeanLifecycleWrapper value = this.cache.put (name
New BeanLifecycleWrapper (name, objectFactory))
This.locks.putIfAbsent (name, new ReentrantReadWriteLock ())
Try {
Return value.getBean ()
}
Catch (RuntimeException e) {
This.errors.put (name, e)
Throw e
}
}
The above code can be traced back to a branch code that Spring created bean, org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean 347 lines of code.
String scopeName = mbd.getScope ()
Final Scope scope = this.scopes.get (scopeName)
If (scope = = null) {
Throw new IllegalStateException ("No Scope registered for scope name'" + scopeName + "'")
}
Try {
Object scopedInstance = scope.get (beanName, ()-> {
BeforePrototypeCreation (beanName)
Try {
Return createBean (beanName, mbd, args)
}
Finally {
AfterPrototypeCreation (beanName)
}
});
Bean = getObjectForBeanInstance (scopedInstance, name, beanName, mbd)
}
What happens after it's destroyed? In fact, it turns the bean bound by BeanLifecycleWrapper into null, so how to refresh the configuration? The @ RefreshScope tagged object is initialized as a proxy object at the beginning, and then when performing the get operation of its @ Value attribute, it will enter the proxy method, and the proxy method will get Target, where org.springframework.cloud.context.scope.GenericScope#get will be triggered.
Public Object getBean () {
If (this.bean = = null) {
Synchronized (this.name) {
If (this.bean = = null) {
/ / because bean is empty, it triggers a reinitialization of bean, and goes through the lifecycle process, so the configuration comes back.
This.bean = this.objectFactory.getObject ()
}
}
}
Return this.bean
}
Step on the pit
The above analysis is simple enough, so what are the pitfalls in using this configuration automatic refresh mechanism?
For objects that use @ RefreshScople, if you delete a row of attributes from the configuration center, the corresponding properties of the corresponding bean will become null, but objects that use @ ConfigaruationProperties will not. Why? Because the former is a re-life process of the whole bean, but the latter only executes the init method.
Whether you use @ RefreshScople or @ ConfigaruationProperties, you should not perform excessive logic in the destory and init methods, which affect the availability of the service and block too many requests at high concurrency. The latter will affect the latency of configuration refresh.
After reading the above, do you have any further understanding of the simple analysis of the SpringCloud configuration refresh mechanism? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.