亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot整合Redis實(shí)現(xiàn)常用功能超詳細(xì)過(guò)程

 更新時(shí)間:2022年08月20日 09:08:34   作者:look-word  
這篇文章主要介紹了SpringBoot整合Redis實(shí)現(xiàn)常用功能,登陸功能是每個(gè)項(xiàng)目必備的功能吧,但是想設(shè)計(jì)好,卻是很難,下面介紹兩種登陸功能的解決方式,需要的朋友可以參考下

SpringBoot整合Redis實(shí)現(xiàn)常用功能建議大小伙們,在寫業(yè)務(wù)的時(shí)候,提前畫好流程圖,思路會(huì)清晰很多。文末有解決緩存穿透和擊穿的通用工具類。

1 登陸功能

我想,登陸功能是每個(gè)項(xiàng)目必備的功能吧,但是想設(shè)計(jì)好,卻是很難!下面介紹兩種登陸功能的解決方式:

  • 基于Session實(shí)現(xiàn)登錄流程
  • 基于Redis實(shí)現(xiàn)登錄流程

1.1 基于Session實(shí)現(xiàn)登錄流程

功能流程:

發(fā)送驗(yàn)證碼:

  • 用戶在提交手機(jī)號(hào)后,會(huì)校驗(yàn)手機(jī)號(hào)是否合法,如果不合法,則要求用戶重新輸入手機(jī)號(hào)

  • 如果手機(jī)號(hào)合法,后臺(tái)此時(shí)生成對(duì)應(yīng)的驗(yàn)證碼,同時(shí)將驗(yàn)證碼進(jìn)行保存,然后再通過(guò)短信的方式將驗(yàn)證碼發(fā)送給用戶

短信驗(yàn)證碼登錄、注冊(cè):

  • 用戶將驗(yàn)證碼和手機(jī)號(hào)進(jìn)行輸入,后臺(tái)從session中拿到當(dāng)前驗(yàn)證碼,然后和用戶輸入的驗(yàn)證碼進(jìn)行校驗(yàn),如果不一致,則無(wú)法通過(guò)校驗(yàn),如果一致,則后臺(tái)根據(jù)手機(jī)號(hào)查詢用戶,
  • 如果用戶不存在,則為用戶創(chuàng)建賬號(hào)信息,保存到數(shù)據(jù)庫(kù),無(wú)論是否存在,都會(huì)將用戶信息保存到session中,方便后續(xù)獲得當(dāng)前登錄信息

校驗(yàn)登錄狀態(tài):

  • 用戶在請(qǐng)求時(shí)候,會(huì)從cookie中攜帶者JsessionId到后臺(tái),后臺(tái)通過(guò)JsessionId從session中拿到用戶信息,如果沒(méi)有session信息,則進(jìn)行攔截,如果有session信息,則
  • 將用戶信息保存到threadLocal中,并且放行

1.1.1 session共享問(wèn)題

基于session方式實(shí)現(xiàn)登陸功能,最大的缺點(diǎn)就是在多臺(tái)tomcat下session無(wú)法共享,就會(huì)下出現(xiàn)下面問(wèn)題。

核心思路分析:

每個(gè)tomcat中都有一份屬于自己的session,假設(shè)用戶第一次訪問(wèn)第一臺(tái)tomcat,并且把自己的信息存放到第一臺(tái)服務(wù)器的session中,但是第二次這個(gè)用戶訪問(wèn)到了第二臺(tái)tomcat,那么在第二臺(tái)服務(wù)器上,肯定沒(méi)有第一臺(tái)服務(wù)器存放的session,所以此時(shí) 整個(gè)登錄攔截功能就會(huì)出現(xiàn)問(wèn)題,我們能如何解決這個(gè)問(wèn)題呢?早期的方案是session拷貝,就是說(shuō)雖然每個(gè)tomcat上都有不同的session,但是每當(dāng)任意一臺(tái)服務(wù)器的session修改時(shí),都會(huì)同步給其他的Tomcat服務(wù)器的session,這樣的話,就可以實(shí)現(xiàn)session的共享了

但是這種方案具有兩個(gè)大問(wèn)題

1、每臺(tái)服務(wù)器中都有完整的一份session數(shù)據(jù),服務(wù)器壓力過(guò)大。

2、session拷貝數(shù)據(jù)時(shí),可能會(huì)出現(xiàn)延遲

所以咱們后來(lái)采用的方案都是基于redis來(lái)完成,我們把session換成redis,redis數(shù)據(jù)本身就是共享的,就可以避免session共享的問(wèn)題了

1.2 Redis替代Session

1.2.1、設(shè)計(jì)key的結(jié)構(gòu)

首先我們要思考一下利用redis來(lái)存儲(chǔ)數(shù)據(jù),那么到底使用哪種結(jié)構(gòu)呢?由于存入的數(shù)據(jù)比較簡(jiǎn)單,我們可以考慮使用String,或者是使用哈希,如下圖,如果使用String,同學(xué)們注意他的value,用多占用一點(diǎn)空間,如果使用哈希,則他的value中只會(huì)存儲(chǔ)他數(shù)據(jù)本身,如果不是特別在意內(nèi)存,其實(shí)使用String就可以啦。

1.2.2、設(shè)計(jì)key的具體細(xì)節(jié)

所以我們可以使用String結(jié)構(gòu),就是一個(gè)簡(jiǎn)單的key,value鍵值對(duì)的方式,但是關(guān)于key的處理,session他是每個(gè)用戶都有自己的session,但是redis的key是共享的,咱們就不能使用code了

在設(shè)計(jì)這個(gè)key的時(shí)候,我們之前講過(guò)需要滿足兩點(diǎn):

1、key要具有唯一性2、key要方便攜帶

如果我們采用phone:手機(jī)號(hào)這個(gè)的數(shù)據(jù)來(lái)存儲(chǔ)當(dāng)然是可以的,但是如果把這樣的敏感數(shù)據(jù)存儲(chǔ)到redis中并且從頁(yè)面中帶過(guò)來(lái)畢竟不太合適,所以我們?cè)诤笈_(tái)生成一個(gè)隨機(jī)串token,然后讓前端帶來(lái)這個(gè)token就能完成我們的整體邏輯了.

1.2.3、整體訪問(wèn)流程

當(dāng)注冊(cè)完成后,用戶去登錄會(huì)去校驗(yàn)用戶提交的手機(jī)號(hào)和驗(yàn)證碼,是否一致,如果一致,則根據(jù)手機(jī)號(hào)查詢用戶信息,不存在則新建,最后將用戶數(shù)據(jù)保存到redis,并且生成token作為redis的key,當(dāng)我們校驗(yàn)用戶是否登錄時(shí),會(huì)去攜帶著token進(jìn)行訪問(wèn),從redis中取出token對(duì)應(yīng)的value,判斷是否存在這個(gè)數(shù)據(jù),如果沒(méi)有則攔截,如果存在則將其保存到threadLocal中,并且放行。

2 緩存功能

2.1 什么是緩存?

緩存(Cache),就是數(shù)據(jù)交換的緩沖區(qū),俗稱的緩存就是緩沖區(qū)內(nèi)的數(shù)據(jù),一般從數(shù)據(jù)庫(kù)中獲取,存儲(chǔ)于本地代碼(例如:

例1:Static final ConcurrentHashMap<K,V> map = new ConcurrentHashMap<>(); 本地用于高并發(fā)

例2:static final Cache<K,V> USER_CACHE = CacheBuilder.newBuilder().build(); 用于redis等緩存

例3:Static final Map<K,V> map =  new HashMap(); 本地緩存

由于其被Static修飾,所以隨著類的加載而被加載到內(nèi)存之中,作為本地緩存,由于其又被final修飾,所以其引用(例3:map)和對(duì)象(例3:new HashMap())之間的關(guān)系是固定的,不能改變,因此不用擔(dān)心賦值(=)導(dǎo)致緩存失效;

2.1.1 為什么要使用緩存

一句話:因?yàn)?code>速度快,好用

緩存數(shù)據(jù)存儲(chǔ)于代碼中,而代碼運(yùn)行在內(nèi)存中,內(nèi)存的讀寫性能遠(yuǎn)高于磁盤,緩存可以大大降低用戶訪問(wèn)并發(fā)量帶來(lái)的服務(wù)器讀寫壓力

實(shí)際開(kāi)發(fā)過(guò)程中,企業(yè)的數(shù)據(jù)量,少則幾十萬(wàn),多則幾千萬(wàn),這么大數(shù)據(jù)量,如果沒(méi)有緩存來(lái)作為"避震器",系統(tǒng)是幾乎撐不住的,所以企業(yè)會(huì)大量運(yùn)用到緩存技術(shù);

但是緩存也會(huì)增加代碼復(fù)雜度和運(yùn)營(yíng)的成本:

2.1.2 如何使用緩存

實(shí)際開(kāi)發(fā)中,會(huì)構(gòu)筑多級(jí)緩存來(lái)使系統(tǒng)運(yùn)行速度進(jìn)一步提升,例如:本地緩存與redis中的緩存并發(fā)使用

瀏覽器緩存:主要是存在于瀏覽器端的緩存

應(yīng)用層緩存:可以分為tomcat本地緩存,比如之前提到的map,或者是使用redis作為緩存

數(shù)據(jù)庫(kù)緩存:在數(shù)據(jù)庫(kù)中有一片空間是 buffer pool,增改查數(shù)據(jù)都會(huì)先加載到mysql的緩存中

CPU緩存:當(dāng)代計(jì)算機(jī)最大的問(wèn)題是 cpu性能提升了,但內(nèi)存讀寫速度沒(méi)有跟上,所以為了適應(yīng)當(dāng)下的情況,增加了cpu的L1,L2,L3級(jí)的緩存

2.2.使用緩存

2.2.1 、緩存模型和思路

標(biāo)準(zhǔn)的操作方式就是查詢數(shù)據(jù)庫(kù)之前先查詢緩存,如果緩存數(shù)據(jù)存在,則直接從緩存中返回,如果緩存數(shù)據(jù)不存在,再查詢數(shù)據(jù)庫(kù),然后將數(shù)據(jù)存入redis

2.3 緩存更新策略

緩存更新是redis為了節(jié)約內(nèi)存而設(shè)計(jì)出來(lái)的一個(gè)東西,主要是因?yàn)閮?nèi)存數(shù)據(jù)寶貴,當(dāng)我們向redis插入太多數(shù)據(jù),此時(shí)就可能會(huì)導(dǎo)致緩存中的數(shù)據(jù)過(guò)多,所以redis會(huì)對(duì)部分?jǐn)?shù)據(jù)進(jìn)行更新,或者把他叫為淘汰更合適。

內(nèi)存淘汰:redis自動(dòng)進(jìn)行,當(dāng)redis內(nèi)存達(dá)到咱們?cè)O(shè)定的max-memery的時(shí)候,會(huì)自動(dòng)觸發(fā)淘汰機(jī)制,淘汰掉一些不重要的數(shù)據(jù)(可以自己設(shè)置策略方式)

超時(shí)剔除:當(dāng)我們給redis設(shè)置了過(guò)期時(shí)間ttl之后,redis會(huì)將超時(shí)的數(shù)據(jù)進(jìn)行刪除,方便咱們繼續(xù)使用緩存

主動(dòng)更新:我們可以手動(dòng)調(diào)用方法把緩存刪掉,通常用于解決緩存和數(shù)據(jù)庫(kù)不一致問(wèn)題

2.3.1 、數(shù)據(jù)庫(kù)緩存不一致解決方案:

由于我們的緩存的數(shù)據(jù)源來(lái)自于數(shù)據(jù)庫(kù),而數(shù)據(jù)庫(kù)的數(shù)據(jù)是會(huì)發(fā)生變化的,因此,如果當(dāng)數(shù)據(jù)庫(kù)中數(shù)據(jù)發(fā)生變化,而緩存卻沒(méi)有同步,此時(shí)就會(huì)有一致性問(wèn)題存在,其后果是:

用戶使用緩存中的過(guò)時(shí)數(shù)據(jù),就會(huì)產(chǎn)生類似多線程數(shù)據(jù)安全問(wèn)題,從而影響業(yè)務(wù),產(chǎn)品口碑等;怎么解決呢?有如下幾種方案

Cache Aside Pattern 人工編碼方式:緩存調(diào)用者在更新完數(shù)據(jù)庫(kù)后再去更新緩存,也稱之為雙寫方案(一般采用

Read/Write Through Pattern : 由系統(tǒng)本身完成,數(shù)據(jù)庫(kù)與緩存的問(wèn)題交由系統(tǒng)本身去處理

Write Behind Caching Pattern :調(diào)用者只操作緩存,其他線程去異步處理數(shù)據(jù)庫(kù),實(shí)現(xiàn)最終一致

2.3.2 、數(shù)據(jù)庫(kù)和緩存不一致采用什么方案

綜合考慮使用方案一,但是方案一調(diào)用者如何處理呢?這里有幾個(gè)問(wèn)題

操作緩存和數(shù)據(jù)庫(kù)時(shí)有三個(gè)問(wèn)題需要考慮:

如果采用第一個(gè)方案,那么假設(shè)我們每次操作數(shù)據(jù)庫(kù)后,都操作緩存,但是中間如果沒(méi)有人查詢,那么這個(gè)更新動(dòng)作實(shí)際上只有最后一次生效,中間的更新動(dòng)作意義并不大,我們可以把緩存刪除,等待再次查詢時(shí),將緩存中的數(shù)據(jù)加載出來(lái)

  • 刪除緩存還是更新緩存?
  • 更新緩存:每次更新數(shù)據(jù)庫(kù)都更新緩存,無(wú)效寫操作較多
  • 刪除緩存:更新數(shù)據(jù)庫(kù)時(shí)讓緩存失效,查詢時(shí)再更新緩存
  • 如何保證緩存與數(shù)據(jù)庫(kù)的操作的同時(shí)成功或失?。?ul>
  • 單體系統(tǒng),將緩存與數(shù)據(jù)庫(kù)操作放在一個(gè)事務(wù)
  • 分布式系統(tǒng),利用TCC等分布式事務(wù)方案

應(yīng)該具體操作緩存還是操作數(shù)據(jù)庫(kù),我們應(yīng)當(dāng)是先操作數(shù)據(jù)庫(kù),再刪除緩存,原因在于,如果你選擇第一種方案,在兩個(gè)線程并發(fā)來(lái)訪問(wèn)時(shí),假設(shè)線程1先來(lái),他先把緩存刪了,此時(shí)線程2過(guò)來(lái),他查詢緩存數(shù)據(jù)并不存在,此時(shí)他寫入緩存,當(dāng)他寫入緩存后,線程1再執(zhí)行更新動(dòng)作時(shí),實(shí)際上寫入的就是舊的數(shù)據(jù),新的數(shù)據(jù)被舊數(shù)據(jù)覆蓋了。

  • 先操作緩存還是先操作數(shù)據(jù)庫(kù)?
  • 先刪除緩存,再操作數(shù)據(jù)庫(kù)(存在線程安全問(wèn)題)
  • 先操作數(shù)據(jù)庫(kù),再刪除緩存

2.4 緩存穿透問(wèn)題的解決思路

緩存穿透 :緩存穿透是指客戶端請(qǐng)求的數(shù)據(jù)在緩存中和數(shù)據(jù)庫(kù)中都不存在,這樣緩存永遠(yuǎn)不會(huì)生效,這些請(qǐng)求都會(huì)打到數(shù)據(jù)庫(kù)。

常見(jiàn)的解決方案有兩種:

  • 緩存空對(duì)象
  • 優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單,維護(hù)方便
  • 缺點(diǎn):
  • 額外的內(nèi)存消耗
  • 可能造成短期的不一致
  • 布隆過(guò)濾
  • 優(yōu)點(diǎn):內(nèi)存占用較少,沒(méi)有多余key
  • 缺點(diǎn):
  • 實(shí)現(xiàn)復(fù)雜
  • 存在誤判可能

緩存空對(duì)象思路分析:當(dāng)我們客戶端訪問(wèn)不存在的數(shù)據(jù)時(shí),先請(qǐng)求redis,但是此時(shí)redis中沒(méi)有數(shù)據(jù),此時(shí)會(huì)訪問(wèn)到數(shù)據(jù)庫(kù),但是數(shù)據(jù)庫(kù)中也沒(méi)有數(shù)據(jù),這個(gè)數(shù)據(jù)穿透了緩存,直擊數(shù)據(jù)庫(kù),我們都知道數(shù)據(jù)庫(kù)能夠承載的并發(fā)不如redis這么高,如果大量的請(qǐng)求同時(shí)過(guò)來(lái)訪問(wèn)這種不存在的數(shù)據(jù),這些請(qǐng)求就都會(huì)訪問(wèn)到數(shù)據(jù)庫(kù),簡(jiǎn)單的解決方案就是哪怕這個(gè)數(shù)據(jù)在數(shù)據(jù)庫(kù)中也不存在,我們也把這個(gè)數(shù)據(jù)存入到redis中去,這樣,下次用戶過(guò)來(lái)訪問(wèn)這個(gè)不存在的數(shù)據(jù),那么在redis中也能找到這個(gè)數(shù)據(jù)就不會(huì)進(jìn)入到緩存了.

布隆過(guò)濾:布隆過(guò)濾器其實(shí)采用的是哈希思想來(lái)解決這個(gè)問(wèn)題,通過(guò)一個(gè)龐大的二進(jìn)制數(shù)組,走哈希思想去判斷當(dāng)前這個(gè)要查詢的這個(gè)數(shù)據(jù)是否存在,如果布隆過(guò)濾器判斷存在,則放行,這個(gè)請(qǐng)求會(huì)去訪問(wèn)redis,哪怕此時(shí)redis中的數(shù)據(jù)過(guò)期了,但是數(shù)據(jù)庫(kù)中一定存在這個(gè)數(shù)據(jù),在數(shù)據(jù)庫(kù)中查詢出來(lái)這個(gè)數(shù)據(jù)后,再將其放入到redis中

假設(shè)布隆過(guò)濾器判斷這個(gè)數(shù)據(jù)不存在,則直接返回

這種方式優(yōu)點(diǎn)在于節(jié)約內(nèi)存空間,存在誤判,誤判原因在于:布隆過(guò)濾器走的是哈希思想,只要哈希思想,就可能存在哈希沖突

小總結(jié):

緩存穿透產(chǎn)生的原因是什么?

  • 用戶請(qǐng)求的數(shù)據(jù)在緩存中和數(shù)據(jù)庫(kù)中都不存在,不斷發(fā)起這樣的請(qǐng)求,給數(shù)據(jù)庫(kù)帶來(lái)巨大壓力

緩存穿透的解決方案有哪些?

  • 緩存null值
  • 布隆過(guò)濾
  • 增強(qiáng)id的復(fù)雜度,避免被猜測(cè)id規(guī)律
  • 做好數(shù)據(jù)的基礎(chǔ)格式校驗(yàn)
  • 加強(qiáng)用戶權(quán)限校驗(yàn)
  • 做好熱點(diǎn)參數(shù)的限流

3.工具類

此工具類已經(jīng)對(duì)緩存穿透,和緩存擊穿實(shí)現(xiàn)了通用功能。

可以對(duì)比上敘的流程圖查閱

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import static com.hmdp.utils.RedisConstants.CACHE_NULL_TTL;

/**
 * @author : look-word
 * 2022-08-19 17:02
 **/
@Component
public class CacheClient {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    public void set(String key, Object value, Long time, TimeUnit unit) {
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), time, unit);
    }

    /**
     * 設(shè)置邏輯過(guò)期時(shí)間
     */
    public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit) {
        // .封裝邏輯時(shí)間
        RedisData redisData = new RedisData();
        redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
        redisData.setData(value);
        String redisDataJson = JSONUtil.toJsonStr(redisData);
        // 寫入Redis
        stringRedisTemplate.opsForValue().set(key, redisDataJson);
    }

    /**
     * 解決緩存穿透 對(duì)未存在的數(shù)據(jù) 設(shè)置為null
     */
    public <R, ID> R queryWithPassThrough
    (String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long cacheTime, TimeUnit cacheUnit) {
        // 緩存key
        String key = keyPrefix + id;
        // 1 查詢緩存中是否命中
        String json = stringRedisTemplate.opsForValue().get(key);
        if (StrUtil.isNotBlank(json)) {
            R r = JSONUtil.toBean(json, type);
            return r;
        }
        // 解決緩存穿透 數(shù)據(jù)庫(kù)不存在的數(shù)據(jù) 緩存 也不存在 惡意請(qǐng)求
        if (json != null) {
            return null;
        }

        // 2 查詢數(shù)據(jù)庫(kù) 存在 存入緩存 返回給前端
        R r = dbFallback.apply(id);
        if (r == null) {
            // 解決緩存穿透
            stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);
            return null;
        }
        // 2.1 轉(zhuǎn)換成json 存入緩存中
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(r), cacheTime, cacheUnit);

        return r;
    }

    // 線程池
    public static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);

    /**
     * 解決緩存擊穿 邏輯過(guò)期時(shí)間方式
     */
    public <R, ID> R queryWithLogicalExpire
    (String keyPrefix, ID id, Class<R> type, String lockKeyPrefix, Function<ID, R> dbFallback, Long expiredTime, TimeUnit expiredUnit) {
        // 緩存key
        String key = keyPrefix + id;
        // 1 查詢緩存中是否命中
        String redisDataJson = stringRedisTemplate.opsForValue().get(key);
        if (StrUtil.isBlank(redisDataJson)) {
            return null;
        }
        // 2.命中 查看是否過(guò)期,
        //     2.1 未過(guò)期 直接返回舊數(shù)據(jù)
        //     2.2 過(guò)期 獲取鎖 查詢數(shù)據(jù)寫入Redis設(shè)置新的過(guò)期時(shí)間
        //     2.3 過(guò)期 未獲取鎖 返回 舊數(shù)據(jù)
        RedisData redisData = JSONUtil.toBean(redisDataJson, RedisData.class);
        LocalDateTime expireTime = redisData.getExpireTime();
        R r = JSONUtil.toBean((JSONObject) redisData.getData(), type);
        if (LocalDateTime.now().isBefore(expireTime)) {
            return r;
        }
        String lockKey = lockKeyPrefix + id;
        // 獲取鎖
        boolean isLock = tryLock(lockKey);
        if (isLock) {
            CACHE_REBUILD_EXECUTOR.submit(() -> {
                try {
                    // 查詢數(shù)據(jù)庫(kù)
                    R r1 = dbFallback.apply(id);
                    // 存儲(chǔ)Redis 設(shè)置邏輯過(guò)期 過(guò)期時(shí)間
                    setWithLogicalExpire(key, r1, expiredTime, expiredUnit);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    // 釋放鎖
                    unlock(lockKey);
                }
            });
        }
        // 未獲取到鎖
        return r;
    }

    /**
     * 獲取鎖
     */
    public boolean tryLock(String key) {
        Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 100, TimeUnit.SECONDS);
        return BooleanUtil.isTrue(flag);
    }

    /**
     * 釋放鎖
     */
    public void unlock(String key) {
        stringRedisTemplate.delete(key);
    }

}

到此這篇關(guān)于SpringBoot整合Redis實(shí)現(xiàn)常用功能超詳細(xì)過(guò)程的文章就介紹到這了,更多相關(guān)SpringBoot整合Redis內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot自定義路由覆蓋實(shí)現(xiàn)流程詳解

    SpringBoot自定義路由覆蓋實(shí)現(xiàn)流程詳解

    這篇文章主要介紹了SpringBoot自定義路由覆蓋實(shí)現(xiàn)流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-01-01
  • 詳解 Java HashMap 實(shí)現(xiàn)原理

    詳解 Java HashMap 實(shí)現(xiàn)原理

    這篇文章主要介紹了詳解 Java HashMap 實(shí)現(xiàn)原理的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-03-03
  • java刪除文件和文件夾具體實(shí)現(xiàn)

    java刪除文件和文件夾具體實(shí)現(xiàn)

    這篇文章介紹了java刪除文件和文件夾具體實(shí)現(xiàn),有需要的朋友可以參考一下
    2013-10-10
  • java 多線程交通信號(hào)燈模擬過(guò)程詳解

    java 多線程交通信號(hào)燈模擬過(guò)程詳解

    這篇文章主要介紹了java 多線程交通信號(hào)燈模擬過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • 分析Java中為什么String不可變

    分析Java中為什么String不可變

    Java中為什么String是不可變性的。今天我們從多角度解析為什么Java把String做成不可變的。
    2021-06-06
  • SpringBoot Aop 詳解和多種使用場(chǎng)景解析

    SpringBoot Aop 詳解和多種使用場(chǎng)景解析

    aop面向切面編程,是編程中一個(gè)很重要的思想本篇文章主要介紹的是SpringBoot切面Aop的使用和案例,對(duì)SpringBoot Aop相關(guān)知識(shí)感興趣的朋友跟隨小編一起看看吧
    2021-08-08
  • SpringBoot 緩存 Caffeine使用解析

    SpringBoot 緩存 Caffeine使用解析

    這篇文章主要介紹了SpringBoot 緩存 Caffeine使用解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 自定義注解+Spel實(shí)現(xiàn)分布式鎖方式

    自定義注解+Spel實(shí)現(xiàn)分布式鎖方式

    這篇文章主要介紹了自定義注解+Spel實(shí)現(xiàn)分布式鎖方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 使用Lucene實(shí)現(xiàn)一個(gè)簡(jiǎn)單的布爾搜索功能

    使用Lucene實(shí)現(xiàn)一個(gè)簡(jiǎn)單的布爾搜索功能

    Lucene是一個(gè)全文搜索框架,而不是應(yīng)用產(chǎn)品。因此它并不像www.baidu.com 或者google Desktop那么拿來(lái)就能用,它只是提供了一種工具讓你能實(shí)現(xiàn)這些產(chǎn)品。接下來(lái)通過(guò)本文給大家介紹使用Lucene實(shí)現(xiàn)一個(gè)簡(jiǎn)單的布爾搜索功能
    2017-04-04
  • java 實(shí)現(xiàn)下壓棧的操作(能動(dòng)態(tài)調(diào)整數(shù)組大小)

    java 實(shí)現(xiàn)下壓棧的操作(能動(dòng)態(tài)調(diào)整數(shù)組大小)

    這篇文章主要介紹了java 實(shí)現(xiàn)下壓棧的操作(能動(dòng)態(tài)調(diào)整數(shù)組大小),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02

最新評(píng)論