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 load properties file dynamically in springboot2

2025-04-08 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

In this issue, the editor will bring you about how to dynamically load properties files in springboot2. The article is rich in content and analyzes and describes for you from a professional point of view. I hope you can get something after reading this article.

1. For a better solution, file monitoring depends on commons-io2.

Commons-io commons-io 2.5

2. Write listeners

Import java.io.File;import com.dingxianginc.channelaggregation.webconfig.properties.PropertyConfig;import lombok.extern.slf4j.Slf4j;import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;import org.apache.commons.io.monitor.FileAlterationObserver;import org.springframework.beans.BeansException;import org.springframework.stereotype.Component;/** * Custom File listener * @ author ysma * / @ Slf4j@Componentpublic class FileListener extends FileAlterationListenerAdaptor {private PropertyConfig propertyConfig; private String configDir Public FileListener () {} public FileListener (PropertyConfig propertyConfig, String configDir) {this.propertyConfig = propertyConfig; this.configDir = configDir;} @ Override public void onStart (FileAlterationObserver observer) {log.debug ("FileListener start observer: {}", observer.toString ());} @ Override public void onDirectoryCreate (File directory) {log.info ("FileListener [New]: path: {}", directory.getPath ()) } @ Override public void onDirectoryChange (File directory) {log.info ("FileListener [modify]: path: {}", directory.getPath ());} @ Override public void onDirectoryDelete (File directory) {log.info ("FileListener [delete]: path: {}", directory.getPath ());} @ Override public void onStop (FileAlterationObserver observer) {log.debug ("FileListener stops observer: {}", observer.toString ()) } @ Override public void onFileCreate (File file) {log.info ("FileListener [New]: path: {}", file.getPath ()); refreshProperties (); log.info ("{}-File added, reload configuration file: {}", file.getName (), configDir) } @ Override public void onFileChange (File file) {log.info ("FileListener [modify]: path: {}", file.getPath ()); if (file.getName () .endsWith ("properties")) {log.info ("File modification, reload configuration file: {}", file.getName ()); refreshProperties (file.getPath ()) } @ Override public void onFileDelete (File file) {log.info ("FileListener [delete]: path: {}", file.getPath ()); refreshProperties (); log.info ("{}-File deletion, reload configuration file: {}", file.getName (), configDir);} private void refreshProperties (String... FilePaths) {try {if (propertyConfig = = null) {log.error ("failed to get FileListener.refreshProperties propertyConfig, unable to refresh properties configuration file");} else {if (filePaths.length > 0) {/ / modify the file to reload the file String filePath = filePaths [0] Int index = filePath.indexOf (configDir); / / locate the location of the config directory String diyPath = filePath.substring (index); propertyConfig.loadPoint (diyPath);} else {/ / add delete files to control overview.properties to reload propertyConfig.init () } catch (BeansException e) {log.error ("FileListener failed to refresh configuration file, path: {}", filePaths, e);}

3. Write configuration classes

Import com.dingxianginc.channelaggregation.util.VariableConfig;import com.dingxianginc.channelaggregation.webconfig.properties.PropertyConfig;import lombok.extern.slf4j.Slf4j;import org.apache.commons.io.filefilter.FileFilterUtils;import org.apache.commons.io.monitor.FileAlterationMonitor;import org.apache.commons.io.monitor.FileAlterationObserver;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct;import java.io.File;import java.util.Objects;import java.util.concurrent.TimeUnit / * * @ author ysma 2019-07-30 * Monitor the changes of files in the resouces directory * / @ Slf4j@Configurationpublic class FileListenerConfig {/ / polling interval 5 seconds private static final long INTERVAL = TimeUnit.SECONDS.toMillis (5); @ Autowired private PropertyConfig propertyConfig; @ Autowired private VariableConfig variableConfig @ PostConstruct public void init () {/ / path suffix / String path = Objects.requireNonNull (Thread.currentThread (). GetContextClassLoader (). GetResource (")) .getPath (); String configDir = variableConfig.getConfigDir (); String dir = configDir.startsWith (" / ")? Path + configDir.substring (1): path + configDir; monitor (dir);} / * directory and file monitoring: traversing folder recursive monitoring * @ param dir directory * / public void monitor (String dir) {File resource = new File (dir); if (resource.isDirectory ()) {File [] files = resource.listFiles () If (files! = null) {for (File file: files) {monitor (file.getPath ());}} log.info ("listening file directory: {}", dir); monitorFile (dir) }} / * listen for file changes * / public void monitorFile (String rootDir) {try {/ / 1. The construction observation class mainly provides the files or directories to be observed, and of course, filter FileAlterationObserver observer = new FileAlterationObserver (rootDir, FileFilterUtils.or (FileFilterUtils.fileFileFilter (), FileFilterUtils.directoryFileFilter (); / / 2. Configure listening observer.addListener (new FileListener (propertyConfig, variableConfig.getConfigDir (); / / 3. To configure Monitor, the first parameter is in milliseconds, which is the monitoring interval; the second parameter is to bind our previous observation object FileAlterationMonitor monitor = new FileAlterationMonitor (INTERVAL, observer); / / start monitoring monitor.start ();} catch (Exception e) {log.error ("FileListenerConfig.wrapSimple snooping failed, rootDir: {}", rootDir, e);}

4. Write properties configuration class

Import com.dingxianginc.channelaggregation.util.VariableConfig;import lombok.extern.slf4j.Slf4j;import org.apache.commons.configuration.ConfigurationException;import org.apache.commons.configuration.PropertiesConfiguration;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;import java.io.FileNotFoundException;import java.util.HashMap;import java.util.Iterator;import java.util.Map / * configuration file component * / @ Slf4j@Componentpublic class PropertyConfig {private volatile Map propertyPathMap = new HashMap (); / / extended to caffeine cache to avoid runtime modification exception private volatile Map propertyFieldMap = new HashMap (); @ Autowired private VariableConfig variableConfig; @ PostConstruct public void init () {/ / root loadPoint (variableConfig.getOverview ()) } / * gradually load all * / public PropertiesConfiguration loadPoint (String path) {try {/ / 1 from path. Load configuration PropertiesConfiguration config = PropertyUtil.loadProperty (path); if (config! = null) {/ / 2. Traversing the key collection Iterator keys = config.getKeys (); while (keys.hasNext ()) {String key = keys.next (); String [] fields = config.getStringArray (key) / / get it by list by default, separated by commas by default, for (String field: fields) {if (StringUtils.isNotEmpty (field) & & field.endsWith ("properties")) {/ / 4. Recursive implementation PropertiesConfiguration pointConfig = loadPoint (field); propertyFieldMap.put (field, pointConfig);} log.info ("PropertyConfig.loadPoint path: {} configuration file loaded", path) PropertyPathMap.put (path, config); return config;} else {log.error ("PropertyConfig.loadPoint path is empty, please check whether it is called correctly");}} catch (ConfigurationException | FileNotFoundException e) {log.error ("PropertyConfig.loadPoint loading configuration file: {} failed", path, e) } return null } / * set caffeine cache * sync: set whether only one request will be sent to request the database if the cache expires, and other requests will block The default is false * @ return priority return cache * key. For more information, please see: https://blog.csdn.net/cr898839618/article/details/81109291 * / @ Cacheable (value = "channel_agg", sync = true) public Map getPropertyPathMap () {return propertyPathMap @ Cacheable (value = "channel_agg", sync = true) public Map getPropertyFieldMap () {return propertyFieldMap;}}

5. Supplement the properties file loading tool

Import org.apache.commons.configuration.ConfigurationException;import org.apache.commons.configuration.PropertiesConfiguration;import org.apache.commons.lang3.StringUtils;import java.io.*;import java.net.URL;public class PropertyUtil {/ / the frequency of loading files in milliseconds private static final long RELOAD_PERIOD = 5000L / * getClassLoader (). GetResource method is to find * when the input value path prefix / beginning should use class.getResource direct query, otherwise use class.getClassLoader (). GetResource to query * @ param path file path * @ throws ConfigurationException Exception * @ throws FileNotFoundException Exception * / public static PropertiesConfiguration loadProperty (String path) throws ConfigurationException, FileNotFoundException {/ / 1. Null judgment if (StringUtils.isEmpty (path)) {return null;} else {path = path.replaceAll ("\", "/"); / / subject to Linux path / * 2. Choose the loading method independently according to the beginning * first: the "/" represents the root directory of the project, for example, the project is called myproject, "/" represents myproject * second: there is no "" directory that represents the current class * / URL url = path.startsWith ("/")? PropertyUtil.class.getResource (path): PropertyUtil.class.getClassLoader (). GetResource (path); if (url = = null) {throw new FileNotFoundException (path);} / / 3. Loading configuration file PropertiesConfiguration config = new PropertiesConfiguration (); / / setting the minimum time interval for scanning files to reload files will cause tomcat to restart! / * FileChangedReloadingStrategy fileChangedReloadingStrategy = new FileChangedReloadingStrategy (); fileChangedReloadingStrategy.setRefreshDelay (RELOAD_PERIOD); config.setReloadingStrategy (fileChangedReloadingStrategy); * / config.setAutoSave (true) / / getResource and getResourceAsStream are cached. The file stream config.load (new FileInputStream (url.getPath (); return config;}} is overwritten here.

6. Caffeine is referenced in the configuration class of properties file.

Rely on the jar package:

Org.springframework.boot spring-boot-starter-cache com.github.ben-manes.caffeine caffeine 2.7.0

7. Simple configuration: application.properties is as follows. Cache is enabled in the Application startup class: @ EnableCaching

Spring.cache.type=caffeinespring.cache.cache-names=channel_aggspring.cache.caffeine.spec=initialCapacity=100,maximumSize=5000,expireAfterAccess=10s

8. Detailed explanation of caffeine configuration parameters

Annotations are widely used in Spring and almost become its symbol. Here we talk about using annotations to integrate caching.

The main notes on caffeine cache are as follows

@ Cacheable triggers the cache entry (here it is usually placed on the creation and acquisition methods)

@ CacheEvict triggers the cached eviction (on the deletion method)

@ CachePut updates the cache and does not affect method execution (for modified methods, the methods under this annotation are always executed)

@ Caching combines multiple caches on a single method (this annotation allows a method to set multiple annotations at the same time)

@ CacheConfig sets some cache-related common configurations at the class level (in conjunction with other caches)

See: caffeine is introduced through spring annotations

The simplified version of the code version is as follows:

Import com.github.benmanes.caffeine.cache.CacheLoader;import com.github.benmanes.caffeine.cache.Caffeine;import org.springframework.cache.CacheManager;import org.springframework.cache.caffeine.CaffeineCacheManager;import java.util.Collections;import java.util.concurrent.TimeUnit;/*@Slf4j@Configuration@deprecated uses configuration method this way is left for extended configuration mode testing see @ see ChannelAggregationApplicationTests.testCache*/@Deprecated@SuppressWarnings ("all") public class CacheConfig {private static final String CACHE_NAME = "channel_agg" / / configure CacheManager / * @ Bean (name = "caffeine") * / public CacheManager cacheManagerWithCaffeine () {CaffeineCacheManager cacheManager = new CaffeineCacheManager () / * initialCapacity= [integer]: initial cache space size * maximumSize= [long]: maximum number of cache entries * maximumWeight= [long]: maximum cache weight * expireAfterAccess= [durationseconds]: expired after a fixed time after the last write or access * expireAfterWrite= [durationseconds]: fixed after the last write Fixed time expiration * refreshAfterWrite= [durationseconds]: a fixed time interval has elapsed since the cache was created or last updated Refresh cache * weakKeys: open weak reference of key * weakValues: open weak reference of value * softValues: open soft reference of value * recordStats: develop statistical function * / Caffeine caffeine = Caffeine.newBuilder () / initial capacity of cache / / the maximum number of caches used by maximumSize to control cache MaximumSize and maximumWeight (maximum weight) cannot be used at the same time, .maximumSize (5000) / / expires too long after the last write or access. Refresh reAfterAccess (2, TimeUnit.HOURS) / / how long to refresh after creation or update, specify that refreshAfterWrite also needs to set cacheLoader .refreshAfterWrite (10, TimeUnit.SECONDS) CacheManager.setCaffeine (caffeine); cacheManager.setCacheLoader (cacheLoader ()); cacheManager.setCacheNames (Collections.singletonList (CACHE_NAME)); / / multiple cache can be created based on the name, but multiple cache use the same policy cacheManager.setAllowNullValues (false); / / whether the allowed value is empty return cacheManager } / * this Bean,refreshAfterWrite configuration property must be specified to take effect * / / * @ Bean*/ public CacheLoader cacheLoader () {return new CacheLoader () {@ Override public Object load (Object key) throws Exception {return null } / / override this method to return the oldValue value to refresh the cache @ Override public Object reload (Object key, Object oldValue) throws Exception {return oldValue;}} }} above is how to dynamically load properties files in the springboot2 shared by the editor. If you happen to have similar doubts, you might as well refer to the above analysis to understand. If you want to know more about it, you are welcome to follow the industry information channel.

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

Internet Technology

Wechat

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

12
Report