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

SpringBoot 緩存源碼分析

 更新時(shí)間:2025年12月16日 08:56:54   作者:guslegend  
JSR107是Java規(guī)范請(qǐng)求,定義了緩存接口,如CachingProvider、CacheManager、Cache等,SpringCache是Spring對(duì)緩存的抽象,通過@EnableCaching開啟緩存注解,使用@Cacheable、@CachePut、@CacheEvict等注解進(jìn)行緩存操作,本文介紹SpringBoot 緩存的相關(guān)知識(shí),感興趣的朋友一起看看

JSR107

在我們了解SpringBoot緩存深入的時(shí)候,我們首先需要了解JSR107。

JSR:

  • 是Java Specification Requset 的縮寫,Java規(guī)范請(qǐng)求;
  • 其是Java提供的一個(gè)接口規(guī)范,類似于jdbc規(guī)范,但是沒有具體的實(shí)現(xiàn),具體的實(shí)現(xiàn)就是redis等這些緩存。

JSR107核心接口:

  • CachingProvider(緩存提供者):創(chuàng)建,配置,獲取,管理和控制多個(gè)CacheManager;
  • CacheManager(緩存管理器):創(chuàng)建,配置,獲取,管理和控制多個(gè)唯一命名的Cache,Cache存在于CacheManager的上下文中,一個(gè)CacheManager僅對(duì)應(yīng)一個(gè)CachingProvider;
  • Cache(緩存):是由CacheManager管理的,CacheManager僅對(duì)應(yīng)一個(gè)Cache的生命周期,Cache存在于CacheManager的上下文中。類似于map的數(shù)據(jù)結(jié)構(gòu),并臨時(shí)存儲(chǔ)以key為索引的值。一個(gè)Cache僅被一個(gè)CacheManager所擁有;
  • Entry(緩存鍵值對(duì)):是一個(gè)存儲(chǔ)在Cache中的key-value對(duì);
  • Expiry(緩存時(shí)效):每一個(gè)存儲(chǔ)在Cache中的條目都有一個(gè)定義的有效期。一旦超過這個(gè)時(shí)間,條目就會(huì)自動(dòng)過期,過期后,條目將不可用訪問,更新和刪除操作。緩存有效期可以通過ExpiryPolicy設(shè)置。

要使用JSR107需要導(dǎo)入相關(guān)的maven依賴

<dependency>
  <groupId>javax.cache</groupId>
  <artifactId>cache-api</artifactId>
</dependency>

Spring的緩存抽象

Spring Cache:

  • 只負(fù)責(zé)維護(hù)抽象層,具體的實(shí)戰(zhàn)由自己的技術(shù)選型來決定;
  • 將緩存處理和緩存技術(shù)解除耦合;
  • 每次調(diào)用緩存功能方法時(shí),Spring會(huì)檢查指定參數(shù)的目標(biāo)方法是否已經(jīng)被調(diào)用;
  • 如果有就直接從緩存中獲取方法調(diào)用后的結(jié)果,如果沒有就調(diào)用方法并緩存結(jié)果返回給用戶,下次直接從緩存中獲取即可。

當(dāng)我們使用Spring Cache緩存抽象的時(shí)候,我們需要關(guān)注兩點(diǎn):

  1. 確定那些方法需要被緩存;
  2. 緩存策略。

Spring 緩存使用

重要概念和緩存注解

在正式開始進(jìn)入SpringCache實(shí)戰(zhàn)之間,我們需要先了解一下Spring Cache 的緩存注解和幾個(gè)重要概念。

概率/注解

作用

Cache

緩存接口,定義緩存操作。實(shí)現(xiàn)有RedisCache等

CacheManaer

緩存管理器,管理各種緩存(Cache)組件

@Cacheable

主要針對(duì)方法配置,能夠根據(jù)方法的請(qǐng)求參數(shù)對(duì)其結(jié)果進(jìn)行緩存

@CacheEvict

清空緩存

@CachePut

保證方法被調(diào)用,又希望結(jié)果被緩存

@EnableCaching

開啟緩存注解

keyGenerator

緩存數(shù)據(jù)時(shí)key生成

serialize

緩存數(shù)據(jù)時(shí)value序列化策略

說明:

  1. @Cacheable標(biāo)注在方法上,表示該方法的結(jié)果需要被緩存起來;
  2. 緩存的鍵由keyGenerator的策略決定,緩存的值的形式是由serialize決定(序列化還是json格式);
  3. 標(biāo)注上該注解之后,在緩存時(shí)效內(nèi)再次調(diào)用該方法將不會(huì)調(diào)用方法本身而是直接從緩存中獲取結(jié)果;
  4. @CachePut也是標(biāo)注在方法上,和@Cacheable相似也會(huì)將方法的返回值存儲(chǔ)起來,不同的是標(biāo)注@CachePut的方法每次都會(huì)被調(diào)用,而且每次都會(huì)將結(jié)果緩存起來,適用對(duì)象的更新。

環(huán)境搭建

首先我們要?jiǎng)?chuàng)建數(shù)據(jù)庫表結(jié)構(gòu)

SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `department_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `gender` int(11) DEFAULT NULL,
  `d_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后添加maven依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.9.RELEASE</version>
        <relativePath/>
        <!--  lookup parent from repository  -->
    </parent>
    <groupId>com.guslegend</groupId>
    <artifactId>SpringCacheDemo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

接下來生成實(shí)體類,controller層,service層,mapper層。

還有我們需要開啟mybatis的駝峰映射,和配置日志級(jí)別,方便我們查看sql語句,看緩存是否生效。

緩存初體驗(yàn)

首先我們需要再啟動(dòng)類上添加@EnableCaching,允許使用緩存。

Cacheable

屬性名

描述

cacheNames/value

指定緩存的名字,用于區(qū)分不同緩存組件;可通過該屬性指定緩存鍵值,將一個(gè)緩存鍵值分到多個(gè)緩存中。

key

緩存數(shù)據(jù)時(shí)的 key 值,默認(rèn)使用方法參數(shù)值,支持 SpEL 表達(dá)式生成 key。

keyGenerator

緩存的生成策略,與 key 功能一致,支持自定義生成規(guī)則。

cacheManager

定義緩存管理器(如 ConcurrentHashMap、Redis 等)。

cacheResolver

與 cacheManager 功能一致,二者選其一。

condition

指定緩存的條件,滿足條件時(shí)才緩存(如#id>0

表示入?yún)⒋笥?0 時(shí)緩存),支持 SpEL 表達(dá)式。

unless

緩存后判斷條件,滿足時(shí)不緩存(如#result==null

表示結(jié)果為 null 時(shí)不緩存),支持 SpEL 表達(dá)式。

sync

是否使用異步模式進(jìn)行緩存。

注意:

  • 即滿足condition又滿足unless條件的也不進(jìn)行緩存;
  • 使用異步模式進(jìn)行緩存時(shí)(sync=true):unless條件將不被支持。

名字

位置

描述

示例

methodName

root object

當(dāng)前被調(diào)用的方法名

#root.methodName

method

root object

當(dāng)前被調(diào)用的方法

#root.method.name

target

root object

當(dāng)前被調(diào)用的目標(biāo)對(duì)象

#root.target

targetClass

root object

當(dāng)前被調(diào)用的目標(biāo)對(duì)象類

root.targetClass

args

root object

當(dāng)前被調(diào)用的方法的參數(shù)列表

#root.args[0]

caches

root object

當(dāng)前方法調(diào)用使用的緩存列表(如 cacheNames={"cache1","cache2"} 則有兩個(gè) cache)

#root.caches[0].name

argument name

evaluation context

方法參數(shù)的名字,可直接用 #參數(shù)名或 #p0/#a0(0 代表參數(shù)索引)

#iban, #a0, #p0

result

evaluation context

方法執(zhí)行后的返回值(僅當(dāng)方法執(zhí)行之后判斷有效,如 cacheable 的 unless、cachePut 的表達(dá)式、cacheEvict 的beforeInvocation=false)

#result

實(shí)戰(zhàn),進(jìn)行兩次查詢方法,只出現(xiàn)一次sql語句   

@GetMapping("/{id}")
    @Cacheable(cacheNames = "emp",key = "#id",condition = "#id>0",unless = "#result == null ")
    public Employee getEmpById(@PathVariable("id") Integer id) {
        return employeeService.getEmpById(id);
    }

@Cacheable源碼分析

  1. 在運(yùn)行方法之間會(huì)先去查詢Cache(緩存組件),按照cacheNames指定的名字獲?。–acheManager)先獲取相應(yīng)的緩存,第一次獲取緩存如果沒有Cache組件會(huì)自動(dòng)創(chuàng)建;
  2. 去Cache里面查找緩存的內(nèi)容,使用的key默認(rèn)就是方法的參數(shù);key默認(rèn)是使用keyGenerator生成的,默認(rèn)使用SimpleKeyGenerator;
  3. 沒有查詢到緩存就調(diào)用目標(biāo)方法;
  4. 將目標(biāo)方法返回的結(jié)果放到緩存里面。

@CachePut @CacheEnvict @CacheConfig

@CachePut

調(diào)用方法,有更新緩存數(shù)據(jù),一般用于更新操作,在更新緩存時(shí)一定要和想要更新的緩存有相同的緩存名稱和相同的key(可類比同一張表的同一條數(shù)據(jù))。

@PutMapping("/update")
    @CachePut(cacheNames = "emp",key = "#employee.id")
    public void updateEmp(@RequestBody Employee employee) {
        employeeService.updateEmployee(employee);
    }

@CacheEnvict

緩存清除,清除緩存時(shí)要指定緩存的名字和key,相當(dāng)于告訴數(shù)據(jù)庫要?jiǎng)h除哪個(gè)表中的哪個(gè)數(shù)據(jù),key默認(rèn)為參數(shù)值。

屬性:

  • value/cacheNames:緩存的名字;
  • key:緩存的鍵;
  • allEnries:是否清除指定緩存中的所有鍵值對(duì),默認(rèn)為false,設(shè)置為true時(shí)會(huì)清除緩存中的所有鍵值對(duì),與key屬性二選一使用;
  • beforeInvocation:在@CacheEnvict注解的方法調(diào)用之間清除指定緩存,默認(rèn)為false,即在方法調(diào)用之后清除緩存,設(shè)置為true時(shí)則會(huì)在方法調(diào)用之間清除緩存(子啊方法調(diào)用之前還是之后清除緩存的區(qū)別在于方法調(diào)用時(shí)是否會(huì)出現(xiàn)異常,若不出現(xiàn)異常,這兩種設(shè)置沒有區(qū)別,若出現(xiàn)異常,設(shè)置為在方法調(diào)用之后清除緩存則不起作用,因?yàn)榉椒ㄕ{(diào)用失敗了)。
@Delete("/{id}")
    @CacheEvict(cacheNames = "emp",key = "#id",beforeInvocation = true)
    public void deleteEmp(@PathVariable("id") Integer id) {
        employeeService.deleteEmployee(id);
    }

@CacheConfig

作用:標(biāo)注在類上,抽取緩存相關(guān)的公共配置,可抽取的公共配置有緩存的名字,主鍵生成器等

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheConfig {
    String[] cacheNames() default {};
    String keyGenerator() default "";
    String cacheManager() default "";
    String cacheResolver() default "";
}

實(shí)列:通過@CacheConfig的cacheNames屬性指定緩存的名字之后,該類中的其他緩存注解就不必再寫value或者cacheName了,會(huì)使用該名字作為value或cacheName的值,也會(huì)遵循就近原則。

@Service
@CacheConfig(cacheNames = "emp")
public class EmployeeServiceImpl implements EmployeeService {
    @Autowired
    private EmployeeMapper employeeMapper;
    @Override
    @Cacheable(key = "#empId")
    public Employee getEmpById(int empId) {
        return  employeeMapper.getEmpById(empId);
    }
}

自定義RedisCacheManager

通過前面運(yùn)用緩存,我們發(fā)現(xiàn)緩存亂碼了

這時(shí)我們就需要自定義RedisCacheManager將其加入到SpringIOC容器中解決這個(gè)問題

@Configuration
public class CacheConfig {
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory
                                                  redisConnectionFactory) {
// 分別創(chuàng)建String和JSON格式序列化對(duì)象,對(duì)緩存數(shù)據(jù)key和value進(jìn)行轉(zhuǎn)換
        RedisSerializer<String> strSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jacksonSeial =
                new Jackson2JsonRedisSerializer(Object.class);
// 解決查詢緩存轉(zhuǎn)換異常的問題
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);
// 定制緩存數(shù)據(jù)序列化方式及時(shí)效
        RedisCacheConfiguration config =
                RedisCacheConfiguration.defaultCacheConfig()
                        .entryTtl(Duration.ofDays(1))
                        .serializeKeysWith(RedisSerializationContext.SerializationPair
                                .fromSerializer(strSerializer))
                        .serializeValuesWith(RedisSerializationContext.SerializationPair
                                .fromSerializer(jacksonSeial))
                        .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager
                .builder(redisConnectionFactory).cacheDefaults(config).build();
        return cacheManager;
    }
}

到此這篇關(guān)于SpringBoot 緩存源碼分析的文章就介紹到這了,更多相關(guān)SpringBoot 緩存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring標(biāo)準(zhǔn)的xml文件頭實(shí)例分析

    Spring標(biāo)準(zhǔn)的xml文件頭實(shí)例分析

    這篇文章主要介紹了Spring標(biāo)準(zhǔn)的xml文件頭實(shí)例分析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • 聊聊Java中的Native修飾符

    聊聊Java中的Native修飾符

    這篇文章主要介紹了Java中的Native修飾符使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Scala 操作Redis使用連接池工具類RedisUtil

    Scala 操作Redis使用連接池工具類RedisUtil

    這篇文章主要介紹了Scala 操作Redis使用連接池工具類RedisUtil,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 升級(jí)dubbo2.7.4.1版本平滑遷移到注冊(cè)中心nacos

    升級(jí)dubbo2.7.4.1版本平滑遷移到注冊(cè)中心nacos

    這篇文章主要為大家介紹了2.7.4.1的dubbo平滑遷移到注冊(cè)中心nacos的兩種版本升級(jí)方案,以及為什要升級(jí),有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-02-02
  • 使用Java實(shí)現(xiàn)創(chuàng)建Excel表單控件

    使用Java實(shí)現(xiàn)創(chuàng)建Excel表單控件

    在數(shù)據(jù)填報(bào)時(shí),創(chuàng)建Excel表單控件是一項(xiàng)常見的任務(wù),它可以極大地簡化數(shù)據(jù)收集和處理的過程,本文主要介紹了如何使用Java實(shí)現(xiàn)創(chuàng)建Excel表單控件,感興趣的可以了解下
    2024-03-03
  • Spring?cloud?OpenFeign中動(dòng)態(tài)URl、動(dòng)態(tài)傳遞接口地址代碼示例

    Spring?cloud?OpenFeign中動(dòng)態(tài)URl、動(dòng)態(tài)傳遞接口地址代碼示例

    openFeign是作為微服務(wù)之間調(diào)用的解決方案,每個(gè)微服務(wù)項(xiàng)目是必不可少的,下面這篇文章主要給大家介紹了關(guān)于Spring?cloud?OpenFeign中動(dòng)態(tài)URl、動(dòng)態(tài)傳遞接口地址的相關(guān)資料,需要的朋友可以參考下
    2024-02-02
  • Java中Optional.of()方法及源碼解析(非常詳細(xì)!)

    Java中Optional.of()方法及源碼解析(非常詳細(xì)!)

    這篇文章主要給大家介紹了關(guān)于Java中Optional.of()方法及源碼解析的相關(guān)資料,Java中java.util .Optional類的of()方法用于獲得該Optional類中具有指定類型的指定值的一個(gè)實(shí)例,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-06-06
  • Java編寫緩存工具類的示例代碼

    Java編寫緩存工具類的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何基于Java編寫一個(gè)緩存工具類,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴可以了解一下
    2023-07-07
  • Mybatis 逆向工程的三種方法詳解

    Mybatis 逆向工程的三種方法詳解

    這篇文章主要介紹了Mybatis 逆向工程的三種方法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Spring Boot Actuator監(jiān)控的簡單使用方法示例代碼詳解

    Spring Boot Actuator監(jiān)控的簡單使用方法示例代碼詳解

    這篇文章主要介紹了Spring Boot Actuator監(jiān)控的簡單使用,本文通過實(shí)例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06

最新評(píng)論

新竹市| 嫩江县| 吉木乃县| 大石桥市| 龙江县| 郧西县| 潢川县| 曲麻莱县| 安平县| 嘉禾县| 黄平县| 澳门| 乐至县| 平度市| 临清市| 汉川市| 泰顺县| 宁化县| 永定县| 永清县| 林西县| 丹东市| 苗栗市| 宜宾市| 浙江省| 依兰县| 镇宁| 蒙山县| 从化市| 安阳县| 榕江县| 丰县| 南投县| 林州市| 盐池县| 鱼台县| 桃园县| 太湖县| 武威市| 平湖市| 平江县|