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

Java緩存框架之Caffeine源碼解析

 更新時(shí)間:2023年11月13日 08:39:52   作者:阿靖哦  
這篇文章主要介紹了Java緩存框架之Caffeine源碼解析,Caffeine?是一個(gè)基于Java?8的高性能本地緩存框架,其結(jié)構(gòu)和?Guava?Cache?基本一樣,api也一樣,基本上很容易就能替換,需要的朋友可以參考下

前言

在系統(tǒng)中,有些數(shù)據(jù),訪問十分頻繁,往往把這些數(shù)據(jù)放入分布式緩存中,但為了減少網(wǎng)絡(luò)傳輸,加快響應(yīng)速度,緩存分布式緩存讀壓力,會(huì)把這些數(shù)據(jù)緩存到本地JVM中,大多是先取本地緩存中,再取分布式緩存中的數(shù)據(jù),Caffeine是一個(gè)高性能Java 緩存庫(kù),使用Java8對(duì)Guava緩存重寫版本,在Spring Boot 2.0中將取代Guava

一. SpringBoot緩存注解相關(guān)知識(shí)點(diǎn)

1. @Cacheable:

@Cacheable可以標(biāo)記在一個(gè)方法上,也可以標(biāo)記在一個(gè)類上。當(dāng)標(biāo)記在一個(gè)方法上時(shí)表示該方法是支持緩存的,當(dāng)標(biāo)記在一個(gè)類上時(shí)則表示該類所有的方法都是支持緩存的。對(duì)于一個(gè)支持緩存的方法,Spring會(huì)在其被調(diào)用后將其返回值緩存起來,以保證下次利用同樣的參數(shù)來執(zhí)行該方法時(shí)可以直接從緩存中獲取結(jié)果,而不需要再次執(zhí)行該方法。Spring在緩存方法的返回值時(shí)是以鍵值對(duì)進(jìn)行緩存的,值就是方法的返回結(jié)果,至于鍵的話,Spring又支持兩種策略,默認(rèn)策略和自定義策略,這個(gè)稍后會(huì)進(jìn)行說明。需要注意的是當(dāng)一個(gè)支持緩存的方法在對(duì)象內(nèi)部被調(diào)用時(shí)是不會(huì)觸發(fā)緩存功能的。@Cacheable可以指定三個(gè)屬性,value、key和condition。

參數(shù)解釋例子
value緩存的名稱,在 spring 配置文件中定義,必須指定至少一個(gè)例如:@Cacheable(value=”mycache”)
key緩存的key,可以為空,如果指定要按照SpEL表達(dá)式編寫,如不指定,則按照方法所有參數(shù)組合@Cacheable(value=”testcache”,key=”#userName”)
condition緩存的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進(jìn)行緩存@Cacheable(value=”testcache”,condition=”#userName.length()>2”)

使用案例

 // key 是指?jìng)魅霑r(shí)的參數(shù)
 @Cacheable(value="users", key="#id")
 public Integer find(Integer id) {
     return id;
 }
// 表示第一個(gè)參數(shù)
@Cacheable(value="users", key="#p0")
 public Long find(Long id) {
     return id;
 }
// 表示User中的id值
 @Cacheable(value="users", key="#user.id")
 public User find(User user) {
      return user;
 }
 // 表示第一個(gè)參數(shù)里的id屬性值
 @Cacheable(value="users", key="#p0.id")
 public User find(User user) {
     return user;
 }

除了上面的案例使用方法,還有以下幾種

屬性名稱描述示例
methodName當(dāng)前方法名#root.methodName
method當(dāng)前方法#root.method.name
target當(dāng)前被調(diào)用的對(duì)象#root.target
targetClass當(dāng)前被調(diào)用的對(duì)象的class#root.targetClass
args當(dāng)前方法參數(shù)組成的數(shù)組#root.args[0]
caches當(dāng)前被調(diào)用的方法使用的Cache#root.caches[0].name

condition屬性指定發(fā)生的條件

有的時(shí)候我們可能并不希望緩存一個(gè)方法所有的返回結(jié)果。通過condition屬性可以實(shí)現(xiàn)這一功能。condition屬性默認(rèn)為空,表示將緩存所有的調(diào)用情形。其值是通過SpringEL表達(dá)式來指定的,當(dāng)為true時(shí)表示進(jìn)行緩存處理;當(dāng)為false時(shí)表示不進(jìn)行緩存處理,即每次調(diào)用該方法時(shí)該方法都會(huì)執(zhí)行一次。如下示例表示只有當(dāng)user的id為偶數(shù)時(shí)才會(huì)進(jìn)行緩存。

  // 根據(jù)條件判斷是否緩存
 @Cacheable(value="users", key="#user.id", condition="#user.id%2==0")
 public User find(User user) {
    return user;
 }

2. CacheEvict

@CacheEvict是用來標(biāo)注在需要清除緩存元素的方法或類上的。當(dāng)標(biāo)記在一個(gè)類上時(shí)表示其中所有的方法的執(zhí)行都會(huì)觸發(fā)緩存的清除操作。@CacheEvict可以指定的屬性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的語義與@Cacheable對(duì)應(yīng)的屬性類似。即value表示清除操作是發(fā)生在哪些Cache上的(對(duì)應(yīng)Cache的名稱);key表示需要清除的是哪個(gè)key,如未指定則會(huì)使用默認(rèn)策略生成的key;condition表示清除操作發(fā)生的條件。下面我們來介紹一下新出現(xiàn)的兩個(gè)屬性allEntries和beforeInvocation。

allEntries屬性

allEntries是boolean類型,表示是否需要清除緩存中的所有元素。默認(rèn)為false,表示不需要。當(dāng)指定了allEntries為true時(shí),Spring Cache將忽略指定的key。有的時(shí)候我們需要Cache一下清除所有的元素,這比一個(gè)一個(gè)清除元素更有效率。

   @CacheEvict(value="user", allEntries=true)
   public void delete(Integer id) {
      System.out.println(id);
   }

beforeInvocation屬性

清除操作默認(rèn)是在對(duì)應(yīng)方法成功執(zhí)行之后觸發(fā)的,即方法如果因?yàn)閽伋霎惓6茨艹晒Ψ祷貢r(shí)也不會(huì)觸發(fā)清除操作。使用beforeInvocation可以改變觸發(fā)清除操作的時(shí)間,當(dāng)我們指定該屬性值為true時(shí),Spring會(huì)在調(diào)用該方法之前清除緩存中的指定元素。

   @CacheEvict(value="user", beforeInvocation=true)
   public void delete(Integer id) {
      System.out.println(id);
   }

3. @Caching

@Caching注解可以讓我們?cè)谝粋€(gè)方法或者類上同時(shí)指定多個(gè)Spring Cache相關(guān)的注解。其擁有三個(gè)屬性:cacheable、put和evict,分別用于指定@Cacheable、@CachePut和@CacheEvict。

   @Caching(
        cacheable = @Cacheable("user"),
        evict = {
                @CacheEvict(value = "user1", key = "#id"),
                @CacheEvict(value = "user", allEntries = true)})
   public Integer find(Integer id) {
      return id;
   }

4. 自定義注解

Spring允許我們?cè)谂渲每删彺娴姆椒〞r(shí)使用自定義的注解,前提是自定義的注解上必須使用對(duì)應(yīng)的注解進(jìn)行標(biāo)注。如我們有如下這么一個(gè)使用@Cacheable進(jìn)行標(biāo)注的自定義注解

二. Caffeine相關(guān)知識(shí)點(diǎn)

Caffeine常用配置說明:

  • 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í)間間隔,刷新緩存

注意點(diǎn):

  • expireAfterWrite和expireAfterAccess同事存在時(shí),以expireAfterWrite為準(zhǔn)
  • maximumSize和maximumWeight不可以同時(shí)使用

配置案例:

spring:
# 配置緩存,初始緩存容量為10,最大容量為200,過期時(shí)間(這里配置寫入后過期時(shí)間為3秒)
  cache:
    type: caffeine
    caffeine:
      spec: initialCapacity=10,maximumSize=200,expireAfterWrite=3s

三. pringBoot集成Caffeine簡(jiǎn)單demo

1. pom文件

<?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.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gj</groupId>
    <artifactId>boot-cache-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>boot-cache-demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.gjing</groupId>
            <artifactId>tools-common</artifactId>
            <version>1.0.4</version>
        </dependency>
        <dependency>
            <groupId>cn.gjing</groupId>
            <artifactId>tools-starter-swagger</artifactId>
            <version>1.0.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>2.7.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2. 配置文件

server:
  port: 8080
spring:
  application:
    name: springboot-cache-demo
# 配置數(shù)據(jù)庫(kù)信息和連接池
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/cache?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
    password: root
    username: root
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      minimum-idle: 1
      maximum-pool-size: 15
      idle-timeout: 30000
      connection-timeout: 20000
# 開啟jpa自動(dòng)建表
  jpa:
    database: mysql
    hibernate:
      ddl-auto: update
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
# 配置緩存,初始緩存容量,最大容量,過期時(shí)間(這里配置寫入后過期時(shí)間)
  cache:
    type: caffeine
    caffeine:
      spec: initialCapacity=10,maximumSize=200,expireAfterWrite=3s
# 配置controller路徑
swagger:
  base-package: com.gj.web
  title: springboot使用caffeine緩存

3. 啟動(dòng)類

@SpringBootApplication
@EnableSwagger
@EnableJpaAuditing
@EnableCaching
public class BootCacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(BootCacheDemoApplication.class, args);
    }
}

4. 定義一個(gè)實(shí)體

/**
 * @author Gjing
 **/
@Entity
@Table(name = "custom")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class Custom {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "custom_name", columnDefinition = "varchar(20) not null comment '用戶名'")
    private String customName;

    @Column(name = "custom_number", columnDefinition = "int not null comment '用戶編號(hào)'")
    private Integer customNumber;

    @Column(name = "create_time", columnDefinition = "datetime")
    @CreatedDate
    private Date createTime;

    @Column(name = "update_time", columnDefinition = "datetime")
    @LastModifiedDate
    private Date updateTime;
}

5. 定義持久層接口

/**
 * @author Gjing
 **/
@Repository
public interface CustomRepository extends JpaRepository<Custom,Integer> {
    /**
     * 通過用戶名查詢
     * @param customName 用戶名
     * @return 用戶
     */
    Custom findByCustomName(String customName);
}

6. 定義service

/**
 * @author Gjing
 **/
@Service
@Slf4j
public class CustomService {
    @Resource
    private CustomRepository customRepository;


    /**
     * 獲取一個(gè)用戶
     *
     * @param customId 用戶id
     * @return custom
     */
    @Cacheable(value = "user", key = "#customId")
    public Custom getCustom(Integer customId) {
        log.warn("通過數(shù)據(jù)庫(kù)去查詢,用戶id為:{}", customId);
        return customRepository.findById(customId)
                .orElseThrow(() -> new UserNotFoundException("Users don't exist"));
    }

    @CacheEvict(value = "user", key = "#customId")
    public void deleteCustom(Integer customId) {
        Custom custom = customRepository.findById(customId)
                .orElseThrow(() -> new UserNotFoundException("Users don't exist"));
        customRepository.delete(custom);
    }

    public Boolean insertCustom(String customName) {
        Custom custom = customRepository.findByCustomName(customName);
        if (custom == null) {
            customRepository.save(Custom.builder()
                    .customName(customName)
                    .customNumber(Integer.valueOf(RandomUtil.generateNumber(6)))
                    .build());
            return true;
        }
        return false;
    }
}

7. 定義異常

/**
 * @author Gjing
 **/
public class UserNotFoundException extends RuntimeException{
    public UserNotFoundException(String message) {
        super(message);
    }
}

/**
 * @author Gjing
 **/
@RestControllerAdvice
class DemoExceptionHandler {
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity userNot(UserNotFoundException e) {
        return ResponseEntity.badRequest().body(ErrorResult.error(e.getMessage()));
    }
}

8. 定義接口

/**
 * @author Gjing
 **/
@RestController
public class CustomController {
    @Resource
    private CustomService customService;

    @PostMapping("/custom")
    @ApiOperation(value = "添加用戶", httpMethod = "POST")
    @ApiImplicitParam(name = "customName", value = "用戶名", required = true, dataType = "String", paramType = "Query")
    public ResponseEntity insertCustom(String customName) {
        Boolean insertCustom = customService.insertCustom(customName);
        if (insertCustom) {
            return ResponseEntity.ok("New successful");
        }
        return ResponseEntity.ok("Add failed, user already exists");
    }

    @GetMapping("/custom/{custom-id}")
    @ApiOperation(value = "查詢指定用戶", httpMethod = "GET")
    public ResponseEntity getCustom(@PathVariable("custom-id") Integer customId) {
        return ResponseEntity.ok(customService.getCustom(customId));
    }

    @DeleteMapping("/custom")
    @ApiOperation(value = "刪除指定用戶", httpMethod = "DELETE")
    @ApiImplicitParam(name = "customId", value = "用戶id", required = true, dataType = "int", paramType = "Query")
    public ResponseEntity deleteCustom(Integer customId) {
        customService.deleteCustom(customId);
        return ResponseEntity.ok("Delete successful");
    }
}

啟動(dòng)后訪問//localhost:8080/swagger-ui.html即可測(cè)試,第一次獲取數(shù)據(jù)會(huì)從數(shù)據(jù)庫(kù)中查詢,接下來會(huì)直接讀取緩存直到緩存失效

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

相關(guān)文章

  • java 獲取HttpRequest Header的幾種方法(必看篇)

    java 獲取HttpRequest Header的幾種方法(必看篇)

    下面小編就為大家?guī)硪黄猨ava 獲取HttpRequest Header的幾種方法(必看篇)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-09-09
  • PostMan post請(qǐng)求發(fā)送Json數(shù)據(jù)的方法

    PostMan post請(qǐng)求發(fā)送Json數(shù)據(jù)的方法

    下面小編就為大家分享一篇PostMan post請(qǐng)求發(fā)送Json數(shù)據(jù)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • SpringBoot中配置文件敏感信息加密解密的實(shí)現(xiàn)方案詳解

    SpringBoot中配置文件敏感信息加密解密的實(shí)現(xiàn)方案詳解

    在現(xiàn)代企業(yè)級(jí)應(yīng)用中,application.yml 或 application.properties 常用于配置數(shù)據(jù)庫(kù)等中間件的連接信息,但將明文密碼直接寫入配置文件中存在諸多風(fēng)險(xiǎn),下面我們就來看看如何對(duì)配置文件敏感信息加密解密吧
    2025-06-06
  • Mybatis-plus分頁(yè)查詢不生效問題排查全過程

    Mybatis-plus分頁(yè)查詢不生效問題排查全過程

    最近寫分頁(yè)的時(shí)候,遇到了分頁(yè)無法正常發(fā)揮作用的問題,下面這篇文章主要給大家介紹了關(guān)于Mybatis-plus分頁(yè)查詢不生效問題排查的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • Java使用新浪微博API通過賬號(hào)密碼方式登陸微博的實(shí)例

    Java使用新浪微博API通過賬號(hào)密碼方式登陸微博的實(shí)例

    這篇文章主要介紹了Java使用新浪微博API通過賬號(hào)密碼方式登陸微博的實(shí)例,一般來說第三方App都是采用OAuth授權(quán)認(rèn)證然后跳轉(zhuǎn)之類的方法,而本文所介紹的賬號(hào)方式則更具有自由度,需要的朋友可以參考下
    2016-02-02
  • flowable表梳理步驟詳解

    flowable表梳理步驟詳解

    這篇文章主要介紹了flowable表梳理步驟詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • 基于Spring實(shí)現(xiàn)自定義錯(cuò)誤信息返回詳解

    基于Spring實(shí)現(xiàn)自定義錯(cuò)誤信息返回詳解

    這篇文章主要為大家詳細(xì)介紹了如何基于Spring實(shí)現(xiàn)自定義錯(cuò)誤信息返回效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-03-03
  • Java實(shí)現(xiàn)計(jì)算器的代碼

    Java實(shí)現(xiàn)計(jì)算器的代碼

    這篇文章主要為大家介紹了Java實(shí)現(xiàn)計(jì)算器的詳細(xì)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • 關(guān)于@RequestParam的使用所遇到的404問題

    關(guān)于@RequestParam的使用所遇到的404問題

    這篇文章主要介紹了關(guān)于@RequestParam的使用所遇到的404問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • JDBC中Statement和Preparement的使用講解

    JDBC中Statement和Preparement的使用講解

    今天小編就為大家分享一篇關(guān)于JDBC中Statement和Preparement的使用講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01

最新評(píng)論

花垣县| 唐海县| 广安市| 和林格尔县| 山东省| 璧山县| 南木林县| 锦屏县| 九寨沟县| 江达县| 綦江县| 寿宁县| 福州市| 友谊县| 陵水| 永济市| 绥德县| 天柱县| 双牌县| 万州区| 来安县| 通渭县| 永顺县| 高平市| 衡阳县| 潼南县| 平谷区| 枣阳市| 鄢陵县| 曲松县| 尤溪县| 泸西县| 新巴尔虎左旗| 万荣县| 章丘市| 巩留县| 石渠县| 栾城县| 安乡县| 梨树县| 蓬莱市|