Throw questions ❓

Through the configuration center, applications can receive configuration changes in real time. However, some beans in applications are managed through the Spring container. After configuration changes, how to modify the state of corresponding beans in the Spring container?

For example: what if you change the JDBC parameter configuration at run time and restart the application? Or modify the properties of the corresponding DataSource Bean? If you are modifying a Bean’s properties, is it useful to modify them directly? How do you do that?

This article discusses trying to modify the configuration at run time using the example of modifying JDBC parameters at run time, and concludes with a general solution.

Vo: The idea is more important than the result.

👨🏻💻

Difficulty 1: Dynamic modification of JDBC parameters, assuming that the URL and password are changed, but the old connection is still using the old configuration, how to do this? Does the old connection fail immediately or after some time? What about threads that use old connections?

In the process of dynamic switching, there must be a transition from the old connection to the new connection, and the transition should be as smooth as possible. For example, it can be done through the operation level: after the URL and password are changed, there will still be a period of time to support the normal access of the old connection, to ensure a smooth transition of the program.

Difficulty 2: Where exactly is the DataSource Bean referenced? Can you replace it clean? How can an old connection be abandoned and closed?

After modifying the JDBC parameters, the next step is to find the user of the DataSource Bean and change the DataSource Bean used by the user to the new configuration. Then, close the old connection and let the user use the new one.

Try to solve 🤔

This article attempts to solve this problem by using the HikariCP connection pool as an example. HikariCP is the default database connection pool after SpringBoot2.0 and is touted as the fastest database connection pool in the Java world today.

Solution 1: HikariCP has its own API for dynamic configuration modification

HikariCP comes with apis to dynamically modify the configuration of the database.

Quote 1: github.com/brettwooldr…

Quote 2: github.com/brettwooldr…

. HikariDataSource dataSource = .... HikariConfigMXBean hikariConfigMXBean = dataSource.getHikariConfigMXBean(); hikariConfigMXBean.setPassword("..."); .Copy the code

I didn’t try this plan carefully (why? Of course, there is a better solution below ~), but its Github document describes it like this, the official first-hand information, the possibility of error is relatively small, if there is a problem, you can also go to Github to raise the relevant issue.

Advantages: Using native apis to dynamically modify configurations, simple and reliable. Disadvantages: the parameters that can be modified are limited, and the DataSource implementation is strongly bound.

Solution 2: Dynamically modify the DataSource

No more nonsense, directly on the code:

Scheme 2 ideas from org. Springframework.. JDBC datasource. Lookup. AbstractRoutingDataSource. This class is used to solve the problem of multiple data sources. You can find different DataSource based on different key, and then get the corresponding Connection.

Similarly, DynamicDataSource implements the DataSource interface and has a member variable AtomicReference

dataSourceReference. DataSourceReference provides the DataSource. When a JDBC parameter is modified at run time, a new DataSource object can be created to replace the value of the dataSourceReference, exposing the DynamicDataSource object, which is insensitive to the user.

So is that enough? Think about it for a minute.

Remember the difficulty of the premise? Using this method, the underlying DataSource can quietly replace the instance object. How to close the connection for the old DataSource?

HikariCP provides a method to close the connection. You should be able to find similar methods if you use other database connection pools.

Summary: The method passesDynamicDataSourceTo wrap the realDataSourceProvider, which allows dynamic replacement of the underlying DataSource instance object at run time. Also, remember to turn off the old DataSource after the replacement. Compared to scheme 1, this scheme supports modification of arbitrary JDBC attributes without strong dependenciesDataSourceImplementer apis, more general and flexible.

Related code address: github.com/shenjianeng…

Dynamic modification of arbitrary Bean properties 🚀

Improvement Plan 2

Now that we have solved the DataSource case, can we further abstract this solution to dynamically modify the properties of any Bean?

In fact, things are not as simple as I thought. Even if DynamicRefreshProxy is abstracted, there are still the following difficulties:

  1. Beans that require dynamic configuration changes pass throughDynamicRefreshProxyTo create a proxy object
  2. After dynamically modifying the configuration, you need to modify itAtomicReference<Object> atomicReferenceThe reference value
  3. You need to provide a method to close the resource associated with the old object, which is called after the old object has been replaced

Here the author can provide an idea to solve these problems:

Through custom annotations, for example@DynamicRefreshable, and then provide a BeanPostProcessor to create a proxy object to replace the original object while saving the correspondingDynamicRefreshProxyObject that listens for changes to the corresponding propertyDynamicRefreshProxyThe object of theatomicReferenceTo close the resource, call the corresponding method of the original object.

Spring Cloud Refresh Scope

A new Scope is available in Spring Cloud: Refresh Scope

Refresh Scope

Cloud. Spring. IO/spring – clou…

The Bean marked @refreshscope is reinitialized when the configuration changes, but this requires a call to ContextRefresher#refresh or RefreshScope#refreshAll. The difference is that the ContextRefresher#refresh method calls not only RefreshScope#refreshAll but also ContextRefresher#refresh environment internally.

A simple DEMO is as follows:

How about a reboot? ✌ ️

Remember the questions and difficulties raised at the beginning?

Difficulty 2: Where exactly is the DataSource Bean referenced? Can you replace it clean? How can an old connection be abandoned and closed?

It is difficult to verify that a resource has been shut down properly, and it is related to the specific health status of the current project.After replacing the DataSource instance, the associated API is called to close the connection. However,doShutdownDataSourceMethod is only tried a few times, and after a certain number of attempts, the close method is called directly to close the database. If you’re tryingMAX_RETRY_TIMESAfter that, the connection is still not closed? Does the close method guarantee that all related resources are closed? Or is it better to restart the method? !

Do you do hot update beans? Or reboot?


Welcome to pay attention to personal public account: