Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to analyze the partial source code of Eureka configuration in micro-service

2025-04-11 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)05/31 Report--

This article will explain in detail how to analyze the source code of Eureka configuration in microservices. The content of the article is of high quality, so the editor will share it with you for reference. I hope you will have a certain understanding of the relevant knowledge after reading this article.

Brief introduction

Today, we start to study the source code of Eureka, starting with the source code of the configuration section, and then add to other parts later.

In addition, I analyze the source code more at the design level than the code for each process in sequence. On the one hand, it is because of the limited space, on the other hand, because I think it is more meaningful to do so.

Project environment

Os:win 10

Jdk:1.8.0_231

Eureka:1.10.11

Maven:3.6.3

Start with an example

The class ConcurrentCompositeConfiguration is the core of the Eureka configuration system. In this example, we use it to add, delete, modify and query property and register a custom listener to listen for property changes.

@ Test public void test01 () {/ / create configuration object final ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration () / / registered listeners listen for changes to property config.addConfigurationListener (new ConfigurationListener () {public void configurationChanged (ConfigurationEvent event) {/ / add property if (AbstractConfiguration.EVENT_ADD_PROPERTY = = event.getType () & &! event.isBeforeUpdate ()) { System.err.println ("add property:" + event.getPropertyName () + "=" + event.getPropertyValue ()) Return;} / / Delete property if (AbstractConfiguration.EVENT_CLEAR_PROPERTY = = event.getType ()) {System.err.println ("clear property:" + event.getPropertyName ()); return } / / Update property if (AbstractConfiguration.EVENT_SET_PROPERTY = = event.getType () & & event.isBeforeUpdate () & &! config.getString (event.getPropertyName ()) .equals (event.getPropertyValue () {System.err .println ("update property:" + event.getPropertyName () + ":" + config.getString (event.getPropertyName ()) + "= >" + event.getPropertyValue ()) Return;}); / / add property config.addProperty ("author", "zzs"); / / get property System.err.println (config.getString ("author")); / / change property config.setProperty ("author", "zzf") / / Delete property config.clearProperty ("author");} / / run the above method, and the console prints content: / / add property:author=zzs / / zzs / / update property:author:zzs== > zzf / / clear property:author

As you can see, when we change the property, the methods in the listener are triggered, and with this, we can implement dynamic configuration.

Later, it will be found that the underlying layer of Eureka uses ConcurrentCompositeConfiguration to add, delete, modify and check configuration parameters, and supports dynamic configuration based on the mechanism of event listening.

Another interesting place.

Let's take another look at a UML diagram. The two functions of ConcurrentCompositeConfiguration mentioned in the above example are obtained by implementing Configuration and inheriting EventSource, which is nothing special. I delve into it because I found something else interesting.

Let's focus on its three member attributes (all of which are of type AbstractConfiguration):

ConfigList: a collection of configuration objects held. The configuration object of this collection has priority. For example, if I add Configuration1 and Configuration2, when we getProperty (String), we will first get it from Configuration1. If we can't find it, we will get it from Configuration2.

OverrideProperties: the highest priority configuration object. When we getProperty (String), we will get it from here first, but we will go to configList to find it.

ContainerConfiguration: the configuration object that guarantees the bottom. It is usually the last one of the configList (note, not necessarily the last 1). We add, delete and modify the property in the ConcurrentCompositeConfiguration, and this is the object we actually operate on.

In order to better understand their role, I wrote a test example.

@ Test public void test02 () {/ / create configuration object ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration (); / / add configuration 1 ConcurrentMapConfiguration config1 = new ConcurrentMapConfiguration (); config1.addProperty ("author", "zzs"); config.addConfiguration (config1, "CONFIG_01"); / / add configuration 2 ConcurrentMapConfiguration config2 = new ConcurrentMapConfiguration () Config2.addProperty ("author", "zzf"); config.addConfiguration (config2, "CONFIG_02"); / / add property config.addProperty ("author", "zhw") to the default containerConfiguration; / / = the priority of the following test configList = System.err.println (config.getString ("author")) / delete property config1.clearProperty ("author") in config1; System.err.println (config.getString ("author")); / / delete property config2.clearProperty ("author") in config2; System.err.println (config.getString ("author")) / / = priority of the following test overrideProperties = / / add property config.setOverrideProperty of overrideProperties ("author", "lt"); System.err.println (config.getString ("author"));} / / run the above method, and the console prints content: / / zzs / / zzf / / zhw / / lt

In addition, when we create a ConcurrentCompositeConfiguration, we generate a containerConfiguration, which by default is always at the end of the collection, and every time a new configuration object is added, it is inserted in front of the containerConfiguration.

Who will load the configuration

As you can see from the above example, ConcurrentCompositeConfiguration does not actively load the configuration, so Eureka needs to add the configuration to ConcurrentCompositeConfiguration itself, which is done by another class, ConfigurationManager.

ConfigurationManager is used as a singleton object to initialize the configuration object and to provide methods for loading the configuration file (which will be called later by DefaultEurekaClientConfig and DefaultEurekaServerConfig).

Let's look at the initialization of the configuration object. The configuration object is initialized when the ConfigurationManager is loaded and can be found in its static block of code. What I intercepted is the most critical part of the code.

Private static AbstractConfiguration createDefaultConfigInstance () {ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration (); try {/ / load the configuration of the specified url / / set url through the archaius.configurationSource.additionalUrls startup parameter, separated by multiple commas DynamicURLConfiguration defaultURLConfig = new DynamicURLConfiguration (); config.addConfiguration (defaultURLConfig, URL_CONFIG_NAME) } catch (Throwable e) {logger.warn ("Failed to create default dynamic configuration", e);} if (! Boolean.getBoolean (DISABLE_DEFAULT_SYS_CONFIG)) {/ / load the configuration of System.getProperties () / / you can control whether to add SystemConfiguration sysConfig = new SystemConfiguration () through the archaius.dynamicProperty.disableSystemConfig startup parameter Config.addConfiguration (sysConfig, SYS_CONFIG_NAME);} if (! Boolean.getBoolean (DISABLE_DEFAULT_ENV_CONFIG)) {/ / load the configuration of System.getenv () / / you can control whether to add EnvironmentConfiguration envConfig = new EnvironmentConfiguration () through the archaius.dynamicProperty.disableEnvironmentConfig startup parameter; config.addConfiguration (envConfig, ENV_CONFIG_NAME) } / / this is a custom guaranteed configuration ConcurrentCompositeConfiguration appOverrideConfig = new ConcurrentCompositeConfiguration (); config.addConfiguration (appOverrideConfig, APPLICATION_PROPERTIES); config.setContainerConfigurationIndex (config.getIndexOfConfiguration (appOverrideConfig)); / / you can change the guaranteed configuration return config;}

As you can see, Eureka supports specifying configuration files through url, as long as you specify startup parameters, which will help us to configure the project more flexibly. By default, it also loads all system and environment parameters.

In addition, when we set the following startup parameters, we can change the configuration through JMX.

-Darchaius.dynamicPropertyFactory.registerConfigWithJMX=true

After the configuration object is initialized, ConfigurationManager provides a method for us to load the configuration file (local or remote), as follows.

/ / the difference between the two is that the former will generate a new configuration to add to configList; and the latter will directly add property to appOverrideConfig public static void loadCascadedPropertiesFromResources (String configName) throws IOException; public static void loadAppOverrideProperties (String appConfigName); how to get the latest parameters

The content of dynamic configuration is not easy to understand directly from the source code, so let's start with a simple example to realize our own dynamic configuration step by step. In the following method, I changed the property, but couldn't get the updated value. I'm sure we all know the reason.

@ Test public void test03 () {/ / get configuration object AbstractConfiguration config = ConfigurationManager.getConfigInstance (); / / add a property config.addProperty ("author", "zzs"); String author = config.getString ("author", ""); System.err.println (author) / / change property config.setProperty ("author", "zzf"); System.err.println (author);} / / run the above method, and the console prints content: / / zzs / / zzs

In order to get the updated value, I changed the code like this. I don't define variables to hold the value of property, and I get it back every time. Obviously, this can be successful.

@ Test public void test04 () {/ / get configuration object AbstractConfiguration config = ConfigurationManager.getConfigInstance (); / / add a property config.addProperty ("author", "zzs"); System.err.println (config.getString ("author", ")); / / change property config.setProperty (" author "," zzf ") System.err.println (config.getString ("author", "));} / / run the above method, and the console prints content: / / zzs / / zzf

But there is a problem with the above approach, we all know that getting property from ConcurrentCompositeConfiguration is troublesome, because I need to traverse the configList and convert parameters. It's not reasonable to take it like this every time.

So I added the cache to reduce this overhead, and of course I had to refresh the cache when the property changed.

@ Test public void test05 () {/ / cache Map cache = new ConcurrentHashMap (); / / get configuration object AbstractConfiguration config = ConfigurationManager.getConfigInstance (); / / add a property config.addProperty ("author", "zzs"); String value = cache.computeIfAbsent ("author", x-> config.getString (x, "")) System.err.println (value); / / add listeners to listen for changes to property config.addConfigurationListener (new ConfigurationListener () {public void configurationChanged (ConfigurationEvent event) {/ / delete property if (AbstractConfiguration.EVENT_CLEAR_PROPERTY = = event.getType ()) {cache.remove (event.getPropertyName () Return;} / / Update property if (AbstractConfiguration.EVENT_SET_PROPERTY = = event.getType () & &! event.isBeforeUpdate ()) {cache.put (event.getPropertyName (), String.valueOf (event.getPropertyValue (); return }); / / change property config.setProperty ("author", "zzf"); System.err.println (cache.get ("author"));} / / run the above method, and print the content in the console: / / zzs / / zzf

Through the example above, we have implemented dynamic configuration.

Now let's take a look at how Eureka is implemented. DynamicPropertyFactory and DynamicStringProperty classes are used here, and dynamic configuration is also implemented through them.

@ Test public void test06 () {/ / get the configuration object AbstractConfiguration config = ConfigurationManager.getConfigInstance (); / / add a property config.addProperty ("author", "zzs"); / / get property DynamicPropertyFactory dynamicPropertyFactory = DynamicPropertyFactory.getInstance () through DynamicPropertyFactory; DynamicStringProperty stringProperty = dynamicPropertyFactory.getStringProperty ("author", "") System.err.println (stringProperty.get ()); / / change property config.setProperty ("author", "zzf"); System.err.println (stringProperty.get ());} / / run the above method, the console prints content: / / zzs / / zzf

As for the principle, it is actually similar to our example above. As you can see from the UML diagram, there is a cache table in DynamicProperty, and every time you get the property, you will get it from here first.

Now that you have a cache, you should have a listener, as you can see in the DynamicProperty.initialize (DynamicPropertySupport) method.

Static synchronized void initialize (DynamicPropertySupport config) {dynamicPropertySupportImpl = config; / / registered listener config.addConfigurationListener (new DynamicPropertyListener ()); updateAllProperties ();} Eureka have those types of configurations

In the above analysis, we use ConfigurationManager to initialize the configuration object and use DynamicPropertyFactory to implement dynamic configuration. These things form the basis of the configuration system of Eureka and are more general. Based on this, there are some more specific configuration objects for Eureka.

In Eureka, there are three types of configurations (it's important to understand this):

EurekaInstanceConfig: configuration information for the current instance identity, that is, who am I?

EurekaServerConfig: some configuration information that affects the current interaction behavior between EurekaServer and client or peer nodes, that is, how to interact?

EurekaClientConfig: some configuration information that affects the current instance and Eureka Server interaction behavior, that is, with whom? How do you interact?

All three objects hold references to DynamicPropertyFactory, so they support dynamic configuration. In addition, they still use ConfigurationManager to load the configuration files they want. For example, EurekaInstanceConfig and EurekaClientConfig are responsible for loading eureka-client.properties, while EurekaServerConfig is responsible for loading eureka-server.properties.

This is the end of the source code analysis on how to configure Eureka in micro-services. I hope the above content can be helpful to you and learn more knowledge. If you think the article is good, you can share it for more people to see.

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.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report