真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

springboot2中怎么動(dòng)態(tài)加載properties文件

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)springboot2 中怎么動(dòng)態(tài)加載properties 文件,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括龍城網(wǎng)站建設(shè)、龍城網(wǎng)站制作、龍城網(wǎng)頁制作以及龍城網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,龍城網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到龍城省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

1、比較好的方案,采用文件監(jiān)控  依賴 commons-io2


            commons-io
            commons-io
            2.5
        

2、編寫監(jiān)聽器

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;

/** 
 * 自定義文件監(jiān)聽器 
 * @author   ysma
 */
@Slf4j
@Component
public 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 啟動(dòng) observer:{}", observer.toString());
    }

    @Override
    public void onDirectoryCreate(File directory) {
        log.info("FileListener [新建]:path:{}", directory.getPath());
    }

    @Override
    public void onDirectoryChange(File directory) {
        log.info("FileListener [修改]:path:{}", directory.getPath());
    }

    @Override
    public void onDirectoryDelete(File directory) {
        log.info("FileListener [刪除]:path:{}", directory.getPath());
    }

    @Override
    public void onStop(FileAlterationObserver observer) {
        log.debug("FileListener 停止 observer:{}", observer.toString());
    }

    @Override
    public void onFileCreate(File file) {
        log.info("FileListener [新建]:path:{}", file.getPath());
        refreshProperties();
        log.info("{}-文件新增,重新加載配置文件:{}", file.getName(), configDir);
    }

    @Override  
    public void onFileChange(File file) {
        log.info("FileListener [修改]:path:{}", file.getPath());
        if(file.getName().endsWith("properties")){
            log.info("文件修改,重新加載配置文件:{}", file.getName());
            refreshProperties(file.getPath());
        }
    }

    @Override  
    public void onFileDelete(File file) {
        log.info("FileListener [刪除]:path:{}", file.getPath());
        refreshProperties();
        log.info("{}-文件刪除,重新加載配置文件:{}", file.getName(), configDir);
    }

    private void refreshProperties(String... filePaths){
        try {
            if(propertyConfig == null){
                log.error("FileListener.refreshProperties propertyConfig 獲取失敗,無法刷新properties配置文件");
            } else {
                if(filePaths.length > 0){
                    //修改文件 重新加載該文件
                    String filePath = filePaths[0];
                    int index = filePath.indexOf(configDir);//定位config目錄的位置
                    String diyPath = filePath.substring(index);
                    propertyConfig.loadPoint(diyPath);
                } else {
                    //新增刪除文件 控制overview.properties進(jìn)行重新加載
                    propertyConfig.init();
                }
            }
        } catch (BeansException e) {
            log.error("FileListener 刷新配置文件失敗,path:{}", filePaths, e);
        }
    }
}

3、編寫配置類

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
 * 監(jiān)控 resouces目錄下文件的變化
 */
@Slf4j
@Configuration
public class FileListenerConfig {

    // 輪詢間隔 5 秒
    private static final long INTERVAL = TimeUnit.SECONDS.toMillis(5);

    @Autowired
    private PropertyConfig propertyConfig;

    @Autowired
    private VariableConfig variableConfig;

    @PostConstruct
    public void init(){
        //path尾綴 /
        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);
    }

    /**
     * 目錄和文件監(jiān)控:遍歷文件夾 遞歸監(jiān)控
     * @param dir 目錄
     */
    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("監(jiān)聽文件目錄:{}", dir);
            monitorFile(dir);
        }
    }

    /**
     * 監(jiān)聽文件變化
     */
    public void monitorFile(String rootDir){
        try {
            //1.構(gòu)造觀察類主要提供要觀察的文件或目錄,當(dāng)然還有詳細(xì)信息的filter
            FileAlterationObserver observer = new FileAlterationObserver(
                    rootDir,
                    FileFilterUtils.or(FileFilterUtils.fileFileFilter(),
                            FileFilterUtils.directoryFileFilter())
                    );

            //2.配置監(jiān)聽
            observer.addListener(new FileListener(
                    propertyConfig,
                    variableConfig.getConfigDir()));

            //3.配置Monitor,第一個(gè)參數(shù)單位是毫秒,是監(jiān)聽的間隔;第二個(gè)參數(shù)就是綁定我們之前的觀察對(duì)象
            FileAlterationMonitor monitor = new FileAlterationMonitor(INTERVAL, observer);
            //開始監(jiān)控
            monitor.start();
        } catch (Exception e) {
            log.error("FileListenerConfig.wrapSimple 監(jiān)聽失敗,rootDir:{}", rootDir, e);
        }
    }
}

4、編寫properties配置類

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;

/**
 * 配置文件組件
 */
@Slf4j
@Component
public class PropertyConfig {

    private volatile Map propertyPathMap = new HashMap<>();

    //擴(kuò)展為caffeine緩存  避免hashMap產(chǎn)生運(yùn)行時(shí)修改異常
    private volatile Map propertyFieldMap = new HashMap<>();

    @Autowired
    private VariableConfig variableConfig;

    @PostConstruct
    public void init(){
        //根目錄
        loadPoint(variableConfig.getOverview());
    }

    /**
     * 從path開始逐步加載所有
     */
    public PropertiesConfiguration loadPoint(String path){
        try {
            //1.加載配置
            PropertiesConfiguration config = PropertyUtil.loadProperty(path);
            if(config != null){
                //2.遍歷key集合
                Iterator keys = config.getKeys();
                while (keys.hasNext()){
                    String key = keys.next();
                    String[] fields = config.getStringArray(key);//默認(rèn)按列表獲取,默認(rèn)英文逗號(hào)分隔,
                    for(String field : fields){
                        if(StringUtils.isNotEmpty(field) && field.endsWith("properties")){
                            //4.遞歸實(shí)現(xiàn)
                            PropertiesConfiguration pointConfig = loadPoint(field);
                            propertyFieldMap.put(field, pointConfig);
                        }
                    }
                }
                log.info("PropertyConfig.loadPoint path:{} 配置文件加載完畢", path);
                propertyPathMap.put(path, config);
                return config;
            } else {
                log.error("PropertyConfig.loadPoint path為空,請(qǐng)檢查是否正確調(diào)用");
            }
        } catch (ConfigurationException | FileNotFoundException e) {
            log.error("PropertyConfig.loadPoint 加載配置文件:{}失敗", path, e);
        }
        return null;
    }

    /**
     *  設(shè)置caffeine緩存
     *  sync:設(shè)置如果緩存過期是不是只放一個(gè)請(qǐng)求去請(qǐng)求數(shù)據(jù)庫,其他請(qǐng)求阻塞,默認(rèn)是false
     *  @return 優(yōu)先返回緩存
     *  key的設(shè)置參見: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、補(bǔ)充properties文件加載工具

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 {

    //加載文件的頻率 單位:毫秒
    private static final long RELOAD_PERIOD = 5000L;

    /**
     * getClassLoader().getResource方法就是在resources目錄下查找
     * 當(dāng)傳入值 path 以前綴/開頭 則應(yīng)使用class.getResource直接查詢,否則使用class.getClassLoader().getResource進(jìn)行查詢
     * @param path 文件路徑
     * @throws ConfigurationException Exception
     * @throws FileNotFoundException Exception
     */
    public static PropertiesConfiguration loadProperty(String path) throws ConfigurationException, FileNotFoundException {
        //1.空判斷
        if(StringUtils.isEmpty(path)){
            return null;
        } else {
            path = path.replaceAll("\\\\", "/");//以Linux路徑為準(zhǔn)

           /**
             * 2.依據(jù)開頭自主選擇加載方法
             * 第一:前面有 "/" 代表了工程的根目錄,例如工程名叫做myproject,"/"代表了myproject
             * 第二:前面沒有 "" 代表當(dāng)前類的目錄
             */
            URL url = path.startsWith("/") ? PropertyUtil.class.getResource(path) :
                    PropertyUtil.class.getClassLoader().getResource(path);

            if(url == null){
                throw new FileNotFoundException(path);
            }

            //3.加載配置文件
            PropertiesConfiguration config = new PropertiesConfiguration();
            //設(shè)置掃描文件的最小時(shí)間間隔 重新加載文件時(shí)會(huì)導(dǎo)致tomcat重啟!!!
            /*FileChangedReloadingStrategy fileChangedReloadingStrategy = new FileChangedReloadingStrategy();
            fileChangedReloadingStrategy.setRefreshDelay(RELOAD_PERIOD);
            config.setReloadingStrategy(fileChangedReloadingStrategy);*/
            config.setAutoSave(true);
            //getResource和getResourceAsStream是有緩存的,這里重寫文件流
            config.load(new FileInputStream(url.getPath()));
            return config;
        }
    }
}

6、properties文件配置類中引用了caffeine

     依賴jar包:


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

7、簡單配置:application.properties如下,Application啟動(dòng)類中啟用緩存: @EnableCaching

spring.cache.type=caffeine
spring.cache.cache-names=channel_agg
spring.cache.caffeine.spec=initialCapacity=100,maximumSize=5000,expireAfterAccess=10s

8、caffeine配置參數(shù)詳解

注解在Spring中的應(yīng)用很廣泛,幾乎成為了其標(biāo)志,這里說下使用注解來集成緩存。 
caffeine cache方面的注解主要有以下5個(gè)

@Cacheable 觸發(fā)緩存入口(這里一般放在創(chuàng)建和獲取的方法上)
@CacheEvict 觸發(fā)緩存的eviction(用于刪除的方法上)
@CachePut 更新緩存且不影響方法執(zhí)行(用于修改的方法上,該注解下的方法始終會(huì)被執(zhí)行)
@Caching 將多個(gè)緩存組合在一個(gè)方法上(該注解可以允許一個(gè)方法同時(shí)設(shè)置多個(gè)注解)
@CacheConfig 在類級(jí)別設(shè)置一些緩存相關(guān)的共同配置(與其它緩存配合使用)

可參見:caffeine 通過spring注解方式引入

代碼版簡版如下:

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 使用配置方式 此方式留待擴(kuò)展
 配置方式測(cè)試見
 @see ChannelAggregationApplicationTests.testCache
*/
@Deprecated
@SuppressWarnings("all")
public class CacheConfig {

    private static final String CACHE_NAME = "channel_agg";

    //配置CacheManager
    /*@Bean(name = "caffeine")*/
    public CacheManager cacheManagerWithCaffeine() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();

        /**
         * initialCapacity=[integer]: 初始的緩存空間大小
         * maximumSize=[long]: 緩存的最大條數(shù)
         * maximumWeight=[long]: 緩存的最大權(quán)重
         * expireAfterAccess=[duration秒]: 最后一次寫入或訪問后經(jīng)過固定時(shí)間過期
         * expireAfterWrite=[duration秒]: 最后一次寫入后經(jīng)過固定時(shí)間過期
         * refreshAfterWrite=[duration秒]: 創(chuàng)建緩存或者最近一次更新緩存后經(jīng)過固定的時(shí)間間隔,刷新緩存
         * weakKeys: 打開key的弱引用
         * weakValues:打開value的弱引用
         * softValues:打開value的軟引用
         * recordStats:開發(fā)統(tǒng)計(jì)功能
         */
        Caffeine caffeine = Caffeine.newBuilder()
                //cache的初始容量值
                .initialCapacity(100)
                //maximumSize用來控制cache的最大緩存數(shù)量,maximumSize和maximumWeight(最大權(quán)重)不可以同時(shí)使用,
                .maximumSize(5000)
                //最后一次寫入或者訪問后過久過期
                .expireAfterAccess(2, TimeUnit.HOURS)
                //創(chuàng)建或更新之后多久刷新,指定了refreshAfterWrite還需要設(shè)置cacheLoader
                .refreshAfterWrite(10, TimeUnit.SECONDS);

        cacheManager.setCaffeine(caffeine);
        cacheManager.setCacheLoader(cacheLoader());
        cacheManager.setCacheNames(Collections.singletonList(CACHE_NAME));//根據(jù)名字可以創(chuàng)建多個(gè)cache,但是多個(gè)cache使用相同的策略
        cacheManager.setAllowNullValues(false);//是否允許值為空
        return cacheManager;
    }

    /**
     * 必須要指定這個(gè)Bean,refreshAfterWrite配置屬性才生效
     */
    /*@Bean*/
    public CacheLoader cacheLoader() {
        return new CacheLoader() {
            @Override
            public Object load(Object key) throws Exception { return null;}

            // 重寫這個(gè)方法將oldValue值返回回去,進(jìn)而刷新緩存
            @Override
            public Object reload(Object key, Object oldValue) throws Exception {
                return oldValue;
            }
        };
    }
}

上述就是小編為大家分享的springboot2 中怎么動(dòng)態(tài)加載properties 文件了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


當(dāng)前標(biāo)題:springboot2中怎么動(dòng)態(tài)加載properties文件
文章來源:http://weahome.cn/article/psjeps.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部