最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot @value注解動態(tài)刷新問題小結(jié)

 更新時間:2023年09月26日 10:41:57   作者:fengyehongWorld  
@Value注解 所對應(yīng)的數(shù)據(jù)源來自項目的 Environment 中,我們可以將數(shù)據(jù)庫或其他文件中的數(shù)據(jù),加載到項目的 Environment 中,然后 @Value注解 就可以動態(tài)獲取到配置信息了,這篇文章主要介紹了SpringBoot @value注解動態(tài)刷新,需要的朋友可以參考下

一. 應(yīng)用場景

  • ?在SpringBoot工程中,我們一般會將一些配置信息放到 application.properties 配置文件中,然后創(chuàng)建一個配置類通過 @value 注解讀取配置文件中的配置信息后,進行各種業(yè)務(wù)處理。
  • ?但是有的情況下我們需要對配置信息進行更改,但是更改之后就需要重啟一次項目,影響客戶使用。
  • ?我們可以將配置信息存放到數(shù)據(jù)庫中,但是每使用一次配置信息就要去數(shù)據(jù)庫查詢顯然也不合適。
  • ?? @Value注解 所對應(yīng)的數(shù)據(jù)源來自項目的 Environment 中,我們可以將數(shù)據(jù)庫或其他文件中的數(shù)據(jù),加載到項目的 Environment 中,然后 @Value注解 就可以動態(tài)獲取到配置信息了。

二. 前期準(zhǔn)備

?模擬獲取數(shù)據(jù)庫(其他存儲介質(zhì): 配置文件,redis等)中的配置數(shù)據(jù)

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class DbUtil {
	// 從數(shù)據(jù)庫獲取郵件的用戶名信息
    public static Map<String, Object> getMailInfoFromDb() {
    	// 模擬從數(shù)據(jù)庫或者其他存儲介質(zhì)中獲取到的用戶名信息
    	String username = UUID.randomUUID().toString().substring(0, 6);
        Map<String, Object> result = new HashMap<>();
        // 此處的"mail.username" 對應(yīng) @Value("${mail.username}")
        result.put("mail.username", username);
        return result;
    }
}

?配置類

  • @RefreshScope是我們自定義的注解,用來動態(tài)的從項目的 Environment 中更新 @Value 所對應(yīng)的值。
  • application.properties 中的配置信息最終會被讀取到項目的 Environment 中,但是還有其他方式向 Environment 中手動放入值, ${mail.username} 的值來源于我們自己手動放入 Environment 中的值。
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import lombok.Data;
/**
 * 郵件配置信息
 */
@Configuration
@RefreshScope
@Data
public class MailConfig {
    @Value("${mail.username}")
    private String username;
}

?前臺頁面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@value注解動態(tài)刷新</title>
</head>
<body>
    <button id="btn1">點擊發(fā)送請求,動態(tài)刷新@value注解</button>
</body>
<script th:src="@{/js/public/jquery-3.6.0.min.js}"></script>
<script th:inline="javascript">
	$("#btn1").click(function() {
	    $.ajax({
	        url: "/test03/updateValue",
	        type: 'POST',
	        data: JSON.stringify(null),
	        contentType: 'application/json;charset=utf-8',
	        success: function (data, status, xhr) {
	            console.log(data);
	        }
	    });
	});
</script>
</html>

三. 實現(xiàn)Scope接口,創(chuàng)建自定義作用域類

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import java.util.concurrent.ConcurrentHashMap;
public class BeanRefreshScope implements Scope {
    public static final String SCOPE_REFRESH = "refresh";
    private static final BeanRefreshScope INSTANCE = new BeanRefreshScope();
    // 用此map來緩存bean
    private ConcurrentHashMap<String, Object> beanMap = new ConcurrentHashMap<>();
    // 禁止實例化
    private BeanRefreshScope() {
    }
    public static BeanRefreshScope getInstance() {
        return INSTANCE;
    }
    // 清理當(dāng)前實例緩存的map
    public static void clean() {
        INSTANCE.beanMap.clear();
    }
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Object bean = beanMap.get(name);
        if (bean == null) {
            bean = objectFactory.getObject();
            beanMap.put(name, bean);
        }
        return bean;
    }
	@Override
	public Object remove(String name) {
		return beanMap.remove(name);
	}
	@Override
	public void registerDestructionCallback(String name, Runnable callback) {
	}
	@Override
	public Object resolveContextualObject(String key) {
		return null;
	}
	@Override
	public String getConversationId() {
		return null;
	}
}

四. 創(chuàng)建自定義作用域注解

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
// 使用自定義作用域
@Scope(BeanRefreshScope.SCOPE_REFRESH)
@Documented
public @interface RefreshScope {
    ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}

五. 刷新配置類的工具類

  • @Value 注解所對應(yīng)的值來源于項目的 Environment 中,也就是來源于 ConfigurableEnvironment 中。
  • 每當(dāng)需要更新配置的時候,調(diào)用我們自定義的 refreshMailPropertySource 方法,從各種存儲介質(zhì)中獲取最新的配置信息存儲到項目的 Environment 中。
import org.springframework.beans.factory.annotation.Autowired;
// import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class RefreshConfigUtil {
	// 獲取環(huán)境配置對象
	@Autowired
	private ConfigurableEnvironment environment;
	private final static String MAIL_CONFIG_NAMW = "mail_config";
	// @Autowired
	// private GenericApplicationContext context;
    /**
     * 模擬改變數(shù)據(jù)庫中的配置信息
     */
    public void updateDbConfigInfo() {
        // 更新context中的mailPropertySource配置信息
        this.refreshMailPropertySource();
        // 清空BeanRefreshScope中所有bean的緩存
        BeanRefreshScope.getInstance();
        BeanRefreshScope.clean();
    }
    public void refreshMailPropertySource() {
        /**
         * @Value中的數(shù)據(jù)源來源于Spring的「org.springframework.core.env.PropertySource」中
         * 此處為獲取項目中的全部@Value相關(guān)的數(shù)據(jù)
         */
        MutablePropertySources propertySources = environment.getPropertySources();
        propertySources.forEach(System.out::println);
        // 模擬從數(shù)據(jù)庫中獲取配置信息
        Map<String, Object> mailInfoFromDb = DbUtil.getMailInfoFromDb();
        // 將數(shù)據(jù)庫查詢到的配置信息放到MapPropertySource中(MapPropertySource類是spring提供的一個類,是PropertySource的子類)
        MapPropertySource mailPropertySource = new MapPropertySource(MAIL_CONFIG_NAMW, mailInfoFromDb);
        // 將配置信息放入 環(huán)境配置對象中
        propertySources.addLast(mailPropertySource);
    }
}

六. 配置類加載

  • 實現(xiàn)了 CommandLineRunner 接口,在項目啟動的時候調(diào)用一次 run 方法。
  • 將自定義作用域 和 存儲介質(zhì)中的數(shù)據(jù)添加到項目中。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class ConfigLoad implements CommandLineRunner {
	@Autowired
	private ConfigurableListableBeanFactory beanFactory;
	@Autowired
	private RefreshConfigUtil refreshConfigUtil;
	@Override
	public void run(String... args) throws Exception {
		// 將我們自定義的作用域添加到Bean工廠中
		beanFactory.registerScope(BeanRefreshScope.SCOPE_REFRESH, BeanRefreshScope.getInstance());
		// 將從存儲介質(zhì)中獲取到的數(shù)據(jù)添加到項目的Environment中。
		refreshConfigUtil.refreshMailPropertySource();
	}
}

七. 測試

  • 進入測試頁面的時候,獲取3次配置類
  • 在測試頁面點擊更新按鈕的時候,更新配置類之后,打印配置類,觀察配置信息的變化。
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/test03")
public class Test03Controller {
	@Autowired
	private GenericApplicationContext context;
	@Autowired
	private RefreshConfigUtil refreshConfigUtil;
	@Autowired
	private MailConfig mailConfig;
	@GetMapping("/init")
	public ModelAndView init() throws InterruptedException {
	    System.out.println("------配置未更新的情況下,輸出3次開始------");
	    for (int i = 0; i < 3; i++) {
	        System.out.println(mailConfig);
	        TimeUnit.MILLISECONDS.sleep(200);
	    }
	    System.out.println("------配置未更新的情況下,輸出3次結(jié)束------");
	    System.out.println("======================================================================");
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("test03");
		return modelAndView;
	}
	@PostMapping("/updateValue")
	@ResponseBody
	public void updateValue(@RequestBody Test03Form form) throws Exception {
		System.out.println("------配置未更新的情況下,輸出1次開始------");
		MailConfig mailInfo = context.getBean(MailConfig.class);
		System.out.println(mailInfo);
		System.out.println("------配置未更新的情況下,輸出1次開始------");
		System.out.println("------配置更新之后,輸出開始------");
		refreshConfigUtil.updateDbConfigInfo();
		System.out.println(mailInfo);
		System.out.println("------配置更新之后,輸出結(jié)束------");
	}
}

注意事項:本文只是進行了相關(guān)實踐,相關(guān)原理請參照參考資料。

參考資料

  1. Spring系列第25篇:@Value【用法、數(shù)據(jù)來源、動態(tài)刷新】
  2. 【基礎(chǔ)系列】SpringBoot配置信息之配置刷新
  3. 【基礎(chǔ)系列】SpringBoot之自定義配置源的使用姿勢
  4. 【基礎(chǔ)系列】SpringBoot應(yīng)用篇@Value注解支持配置自動刷新能力擴展
  5. Spring Boot 中動態(tài)更新 @Value 配置

到此這篇關(guān)于SpringBoot @value注解動態(tài)刷新的文章就介紹到這了,更多相關(guān)SpringBoot 動態(tài)刷新內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java實現(xiàn)微信紅包 拼手氣紅包

    java實現(xiàn)微信紅包 拼手氣紅包

    這篇文章主要為大家詳細介紹了java實現(xiàn)微信紅包,拼手氣紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • 解決feign之間文件上傳報錯:Error converting request body的問題

    解決feign之間文件上傳報錯:Error converting request body

    這篇文章主要介紹了解決feign之間文件上傳報錯:Error converting request body的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • Javaweb使用getPart接收表單文件過程解析

    Javaweb使用getPart接收表單文件過程解析

    這篇文章主要介紹了Javaweb使用getPart接收表單文件過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07
  • java實戰(zhàn)之猜字小游戲

    java實戰(zhàn)之猜字小游戲

    這篇文章主要介紹了java實戰(zhàn)之猜字小游戲,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java的小伙伴們有很好的幫助呦,需要的朋友可以參考下
    2021-04-04
  • @FeignClient的使用和Spring?Boot的版本適配方式

    @FeignClient的使用和Spring?Boot的版本適配方式

    這篇文章主要介紹了@FeignClient的使用和Spring?Boot的版本適配方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java String轉(zhuǎn)換時為null的解決方法

    Java String轉(zhuǎn)換時為null的解決方法

    這篇文章主要介紹了Java String轉(zhuǎn)換時為null的解決方法,需要的朋友可以參考下
    2017-07-07
  • Spring?boot讀取外部化配置的方法

    Spring?boot讀取外部化配置的方法

    大家好,本篇文章主要講的是Spring?boot讀取外部化配置的方法,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-02-02
  • Java 判斷實體對象及所有屬性是否為空的操作

    Java 判斷實體對象及所有屬性是否為空的操作

    這篇文章主要介紹了Java 判斷實體對象及所有屬性是否為空的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 實例詳解SpringBoot默認的JSON解析方案

    實例詳解SpringBoot默認的JSON解析方案

    JSON數(shù)據(jù)現(xiàn)在是我們開發(fā)中用的最多的,百分之九十的數(shù)據(jù)都是通過JSON方式進行傳輸,下面這篇文章主要給大家介紹了關(guān)于SpringBoot默認的JSON解析方案的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • Spring Boot 項目中整合 MyBatis 和 PageHelper的基本步驟

    Spring Boot 項目中整合 MyBatis 和 PageHel

    這篇文章主要介紹了Spring Boot 項目中整合 MyBatis 和 PageHelper的操作步驟,整合 PageHelper 到 Spring Boot 項目中主要包括添加依賴、配置數(shù)據(jù)源與 MyBatis、配置 PageHelper 以及在業(yè)務(wù)邏輯中使用 PageHelper 進行分頁查詢,需要的朋友可以參考下
    2024-04-04

最新評論

太白县| 拉萨市| 榕江县| 上虞市| 合川市| 汶川县| 尼木县| 新丰县| 正阳县| 分宜县| 舞阳县| 尤溪县| 成武县| 大田县| 万全县| 玛曲县| 浦北县| 淮南市| 曲周县| 随州市| 灯塔市| 洪雅县| 方正县| 聂荣县| 定远县| 同德县| 松阳县| 张北县| 弋阳县| 涿鹿县| 连平县| 曲沃县| 宁远县| 延边| 襄城县| 安泽县| 洪江市| 科技| 分宜县| 年辖:市辖区| 万山特区|