成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring 的緩存帝國,得益于這五個注解!

開發
本文我們分析了緩存技術,它在提升應用性能、降低數據庫壓力、改善用戶體驗方面發揮著重要作用。

在微服務,分布式的大環境下,緩存絕對是提升系統性能的關鍵手段,Spring作為 Java生態中最流行的企業級應用框架,它是如何實現緩存的呢?這篇文章,我們將深入探討 Spring中 5個核心的緩存注解。

一、什么是緩存?

緩存(Cache)是一種存儲機制,旨在臨時存儲數據副本,以便快速訪問。緩存一般位于應用程序與數據源(如數據庫)之間,能夠顯著降低數據訪問延遲和減輕數據源的壓力。

二、緩存的類型

緩存一般可以分為下面 4種類型:

  • 本地緩存:存在于應用程序本地內存中,例如使用ConcurrentHashMap、Guava Cache等。
  • 分布式緩存:跨多個應用實例共享的緩存,例如Redis、Memcached、EhCache的分布式配置等。
  • 持久化緩存:將緩存數據持久化到磁盤,以應對應用重啟后的數據恢復。
  • 非持久化緩存:緩存數據存儲于內存,應用重啟后數據丟失。

三、Spring緩存

Spring 從4.0版本起開始引入了 Cache模塊,并提供了一套統一的緩存API,隱藏了底層緩存實現的復雜性。開發者只需通過配置和注解即可實現緩存功能,支持多種緩存實現,如EhCache、Redis、Caffeine等。

Spring緩存模塊的核心組件包括:

  • CacheManager:管理多個Cache實例,根據需要選擇合適的Cache。
  • Cache:具體的緩存操作接口,定義了基本的緩存操作方法,如get、put、evict等。
  • CacheResolver:根據方法信息動態解析需要使用的Cache。
  • KeyGenerator:生成緩存鍵的策略。

通過合理配置和使用,Spring緩存抽象能夠靈活地滿足各種應用場景的需求。

四、Spring緩存注解詳解

Spring緩存注解主要有以下 5個:

  • @Cacheable
  • @CachePut
  • @CacheEvict
  • @Caching
  • @CacheConfig

下面我們將逐一對這些注解進行分析。

1. @Cacheable

@Cacheable注解用于方法級別,表示方法執行的結果可以被緩存。當方法被調用時,Spring會先檢查緩存中是否存在對應的鍵值對,如果存在,則直接返回緩存中的結果;如果不存在,則執行方法,并將結果存入緩存。

使用示例:

@Service
publicclass UserService {

    @Cacheable(value = "users", key = "#id")
    public User getUserById(Long id) {
        // 模擬數據庫訪問
        simulateSlowService();
        returnnew User(id, "John Doe");
    }

    private void simulateSlowService() {
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            thrownew IllegalStateException(e);
        }
    }
}

在上述示例中,getUserById方法被@Cacheable注解修飾,指定使用users緩存,并以方法參數id作為緩存鍵。首次調用該方法時,緩存中不存在對應的用戶信息,方法會被執行并將結果存入緩存。后續相同的調用將直接從緩存中獲取結果,避免了重復的業務邏輯執行。

關鍵屬性:

  • value / cacheNames:指定緩存的名稱,可以有多個,表示多個緩存同時生效。
  • key:指定緩存的鍵,支持SpEL表達式,默認基于方法參數生成。
  • condition:緩存條件,符合條件的情況下才進行緩存。
  • unless:否決緩存條件,符合條件的情況下不緩存。
  • keyGenerator:自定義鍵生成策略。
  • cacheManager:指定使用的緩存管理器。
  • cacheResolver:指定緩存解析器。

2. @CachePut

@CachePut注解同樣用于方法級別,但與@Cacheable不同,它總是執行方法,并將結果存入緩存。@CachePut適用于需要更新緩存但不影響方法執行結果的場景。

使用示例:

@Service
public class UserService {

    @CachePut(value = "users", key = "#user.id")
    public User updateUser(User user) {
        // 模擬更新數據庫
        return user;
    }
}

在上述示例中,updateUser方法被@CachePut注解修飾,每次調用該方法時,都會執行方法邏輯(更新操作),并將返回的User對象更新到users緩存中。這樣可以確保緩存中的數據與數據庫中的數據保持一致。

關鍵屬性:與@Cacheable相同,@CachePut也支持value、cacheNames、key等屬性,用于指定緩存名稱、鍵及其他配置。

3. @CacheEvict

@CacheEvict注解用于方法級別,表示在方法執行后,清除指定緩存中的一個或多個條目。它常用于刪除操作,以確保緩存中的數據與數據源保持一致。

使用示例:

@Service
public class UserService {

    @CacheEvict(value = "users", key = "#id")
    public void deleteUser(Long id) {
        // 模擬刪除數據庫
    }
}

在上述示例中,deleteUser方法被@CacheEvict注解修飾,指定從users緩存中移除鍵為id的條目。這樣,在用戶被刪除后,相應的緩存數據也被清除,防止緩存中的數據不一致。

關鍵屬性:

  • value / cacheNames:指定緩存的名稱。
  • key:指定要清除的緩存鍵。
  • allEntries:指定是否清除緩存中的所有條目,默認為false。
  • beforeInvocation:指定清除緩存的時機,默認為方法執行成功后。
  • cacheManager:指定使用的緩存管理器。
  • cacheResolver:指定緩存解析器。

4. @Caching

@Caching注解用于組合多個緩存注解,使得在一個方法上可以執行多個緩存操作。它適用于需要同時執行多個緩存行為的復雜場景。

使用示例:

@Service
public class UserService {

    @Caching(
        put = { @CachePut(value = "users", key = "#user.id"),
                @CachePut(value = "username", key = "#user.username") },
        evict = { @CacheEvict(value = "userCache", allEntries = true) }
    )
    public User addUser(User user) {
        // 模擬添加用戶到數據庫
        return user;
    }
}

在上述示例中,addUser方法通過@Caching注解同時執行了兩個@CachePut操作,將用戶信息存入不同的緩存中,并且執行了一個@CacheEvict操作,清除userCache中的所有條目。

關鍵屬性:

  • @Caching主要包含以下屬性:
  • cacheable:@Cacheable注解數組。
  • put:@CachePut注解數組。
  • evict:@CacheEvict注解數組。

通過組合不同類型的緩存注解,@Caching提供了更靈活的緩存操作能力。

5. @CacheConfig

@CacheConfig注解用于類級別,為該類中的所有緩存注解提供公共配置。例如,可以指定統一的緩存名稱、緩存管理器等,減少重復配置的工作量。

使用示例:

@Service
@CacheConfig(cacheNames = "users", cacheManager = "cacheManager")
publicclass UserService {

    @Cacheable(key = "#id")
    public User getUserById(Long id) {
        // 模擬數據庫訪問
        returnnew User(id, "John Doe");
    }

    @CachePut(key = "#user.id")
    public User updateUser(User user) {
        // 模擬更新數據庫
        return user;
    }

    @CacheEvict(key = "#id")
    public void deleteUser(Long id) {
        // 模擬刪除數據庫
    }
}

在上述示例中,@CacheConfig注解指定了默認的緩存名稱和緩存管理器,使得類中的所有緩存注解無需重復指定這些屬性,只需關注特定的鍵或其他配置。

關鍵屬性:

  • cacheNames / value:指定默認的緩存名稱。
  • cacheManager:指定默認的緩存管理器。
  • cacheResolver:指定默認的緩存解析器。
  • keyGenerator:指定默認的鍵生成策略。

@CacheConfig通過提供類級別的緩存配置,簡化了屬性的配置和維護,提高了代碼的可讀性和可維護性。

五、緩存框架

要使 Spring的緩存注解生效,必須配置一個緩存管理器(CacheManager)和相應的緩存提供者。Spring支持多種緩存實現,常見的包括 EhCache、Redis、Caffeine等。下面,我們介紹這 3種常用緩存提供者的配置方法。

1. EhCache

EhCache是一款常用的開源緩存庫,支持本地內存和磁盤存儲,配置靈活,適用于單機應用。

依賴配置(Maven):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.6</version>
</dependency>

配置示例:

創建一個EhCache配置文件ehcache.xml:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <diskStore path="java.io.tmpdir"/>
    <defaultCache 
        maxEntriesLocalHeap="1000" 
        eternal="false" 
        timeToIdleSeconds="300" 
        timeToLiveSeconds="600" 
        overflowToDisk="false"/>
    <cache name="users"
           maxEntriesLocalHeap="500"
           timeToLiveSeconds="3600"
           eternal="false"
           overflowToDisk="false"/>
</ehcache>

Spring配置:

@Configuration
@EnableCaching
publicclass CacheConfig {

    @Bean
    public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {
        EhCacheManagerFactoryBean factoryBean = new EhCacheManagerFactoryBean();
        factoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
        factoryBean.setShared(true);
        return factoryBean;
    }

    @Bean
    public CacheManager cacheManager(EhCacheManagerFactoryBean factoryBean) {
        returnnew EhCacheCacheManager(factoryBean.getObject());
    }
}

2. Redis

Redis是一種高性能的NoSQL緩存數據庫,支持分布式部署,適用于大規模應用場景。

依賴配置(Maven):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置示例(application.properties):

spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=yourpassword

Spring配置:

Spring Boot會自動配置RedisCacheManager,無需額外配置。如果需要自定義配置,可以如下:

@Configuration
@EnableCaching
publicclass RedisCacheConfig {

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        // 配置默認緩存過期時間等
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(60))
            .disableCachingNullValues();
        return RedisCacheManager.builder(connectionFactory)
            .cacheDefaults(config)
            .build();
    }
}

3. Caffeine

Caffeine是一個高性能的本地緩存庫,具有豐富的緩存策略和高并發性能。

依賴配置(Maven):

<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>3.1.6</version>
</dependency>

Spring配置:

@Configuration
@EnableCaching
publicclass CaffeineCacheConfig {

    @Bean
    public Caffeine<Object, Object> caffeineConfig() {
        return Caffeine.newBuilder()
                .expireAfterWrite(60, TimeUnit.MINUTES)
                .maximumSize(1000);
    }

    @Bean
    public CacheManager cacheManager(Caffeine<Object, Object> caffeine) {
        CaffeineCacheManager manager = new CaffeineCacheManager("users");
        manager.setCaffeine(caffeine);
        return manager;
    }
}

六、案例分析

下面我們通過一個簡單的 CRUD應用,演示如何在 Spring Boot項目中集成和使用緩存注解。

1. 項目介紹

構建一個用戶管理系統,包含用戶的增刪改查功能。通過緩存優化其中的讀取操作,以提升系統性能。

2. 環境搭建

技術棧:

  • Spring Boot:快速構建項目基礎。
  • Spring Data JPA:數據訪問層。
  • H2數據庫:內存數據庫,方便演示。
  • Spring Cache:緩存抽象。
  • EhCache:作為緩存實現。

依賴配置(Maven):

<dependencies>
    <!-- Spring Boot Web Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Data JPA Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- H2 Database -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Spring Boot Cache Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>

    <!-- EhCache -->
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>2.10.6</version>
    </dependency>

    <!-- Lombok(可選,用于簡化代碼) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>

3. 緩存配置

創建ehcache.xml文件:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
        maxEntriesLocalHeap="1000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="false"/>
    <cache name="users"
           maxEntriesLocalHeap="500"
           timeToLiveSeconds="3600"
           eternal="false"
           overflowToDisk="false"/>
</ehcache>

配置類:

@Configuration
@EnableCaching
publicclass CacheConfig {

    @Bean
    public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {
        EhCacheManagerFactoryBean factoryBean = new EhCacheManagerFactoryBean();
        factoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
        factoryBean.setShared(true);
        return factoryBean;
    }

    @Bean
    public CacheManager cacheManager(net.sf.ehcache.CacheManager cm) {
        returnnew EhCacheCacheManager(cm);
    }
}

4. 實體和倉庫

用戶實體類:

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @Id
    private Long id;
    private String username;
}

用戶倉庫接口:

public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
}

5. 服務層與緩存注解應用

@Service
@CacheConfig(cacheNames = "users")
publicclass UserService {

    @Autowired
    private UserRepository userRepository;

    @Cacheable(key = "#id")
    public User getUserById(Long id) {
        simulateSlowService();
        return userRepository.findById(id).orElse(null);
    }

    @Cacheable(key = "#username")
    public User getUserByUsername(String username) {
        simulateSlowService();
        return userRepository.findByUsername(username);
    }

    @CachePut(key = "#user.id")
    public User updateUser(User user) {
        return userRepository.save(user);
    }

    @CacheEvict(key = "#id")
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }

    private void simulateSlowService() {
        try {
            Thread.sleep(2000L); // 模擬耗時操作
        } catch (InterruptedException e) {
            thrownew IllegalStateException(e);
        }
    }
}

在上述示例中:

  • getUserById和getUserByUsername方法被@Cacheable注解修飾,表示查詢用戶時會先從緩存中查找,若緩存不存在則執行數據庫查詢并將結果緩存在users緩存中。
  • updateUser方法被@CachePut注解修飾,表示更新用戶信息時,會將更新后的用戶對象寫入緩存。
  • deleteUser方法被@CacheEvict注解修飾,表示刪除用戶時,會從緩存中移除對應的用戶信息。

6. 控制層

@RestController
@RequestMapping("/api/users")
publicclass UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }

    @GetMapping("/username/{username}")
    public ResponseEntity<User> getUserByUsername(@PathVariable String username) {
        User user = userService.getUserByUsername(username);
        return ResponseEntity.ok(user);
    }

    @PostMapping
    public ResponseEntity<User> addUser(@RequestBody User user) {
        User savedUser = userService.updateUser(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

7. 測試緩存效果

(1) 啟動應用程序。

(2) 調用GET /api/users/{id}接口:

  • 首次調用會觸發數據庫查詢并緩存結果。
  • 第二次調用相同的接口,將直接從緩存中獲取用戶信息,響應速度更快。

(3) 調用POST /api/users接口更新用戶:更新操作會通過@CachePut注解將新的用戶信息更新到緩存中。

(4) 調用DELETE /api/users/{id}接口刪除用戶:刪除操作會通過@CacheEvict注解從緩存中移除用戶信息。

通過上述步驟,可以驗證緩存的實際效果,發現讀取操作的響應時間明顯降低。

七、增強功能

1. 自定義緩存鍵生成策略

默認情況下,Spring根據方法的參數生成緩存鍵。對于復雜的業務場景,可能需要自定義緩存鍵生成策略。

自定義KeyGenerator:

@Component("customKeyGenerator")
public class CustomKeyGenerator implements KeyGenerator {
    @Override
    public Object generate(Object target, Method method, Object... params) {
        return method.getName() + "_" + Arrays.stream(params)
                .map(Object::toString)
                .collect(Collectors.joining("_"));
    }
}

使用自定義KeyGenerator:

@Cacheable(cacheNames = "users", keyGenerator = "customKeyGenerator")
public User getUser(Long id, String type) {
    // 方法實現
}

2. 緩存條件與排除

通過condition和unless屬性,可以控制是否進行緩存操作。

  • condition:在滿足條件時才進行緩存。
  • unless:在滿足條件時不進行緩存。

示例:

@Cacheable(value = "users", key = "#id", condition = "#id > 10", unless = "#result.username == 'admin'")
public User getUserById(Long id) {
    // 方法實現
}

在上述示例中:

  • 只有當id > 10時,方法執行結果才會被緩存。
  • 即使滿足condition條件,如果result.username == 'admin',則不緩存結果。

3. 緩存同步與異步

在分布式系統中,緩存的一致性和同步性是至關重要的。Spring Cache本身不直接提供同步機制,但可以通過結合其他工具實現。

方案:

  • 使用消息隊列(如Kafka、RabbitMQ)同步緩存更新。
  • 利用分布式鎖(如Redis的RedLock)防止緩存擊穿和緩存穿透。
  • 實現基于事件驅動的緩存更新策略。

4. 緩存與事務的結合

在涉及事務的操作中,緩存的更新需要與事務保持一致性。

方案:

  • 緩存更新操作應在事務提交后執行,確保數據的一致性。
  • 使用@CacheEvict的beforeInvocation屬性控制緩存清除的時機。

示例:

@CacheEvict(value = "users", key = "#id", beforeInvocation = false)
@Transactional
public void deleteUser(Long id) {
    userRepository.deleteById(id);
}

在上述示例中,緩存清除操作將在事務提交后執行,確保數據成功刪除后再清除緩存。

八、總結

本文,我們分析了緩存技術,它在提升應用性能、降低數據庫壓力、改善用戶體驗方面發揮著重要作用。

另外,我們重點分析了 Spring中 5個核心的緩存注解以及示例分析,Spring通過提供全面的緩存抽象和簡潔的緩存注解,使得開發者能夠輕松地集成和管理緩存機制。

責任編輯:趙寧寧 來源: 猿java
相關推薦

2017-11-16 19:47:34

2009-05-07 20:16:12

虛擬化數據中心VMware

2023-10-26 08:36:05

2023-03-23 21:45:24

OpenAI微軟必應人工智能

2009-05-11 19:00:04

虛擬化數據中心Vmware

2020-08-27 19:27:47

工業企業邊緣計算電信運營商

2009-10-22 09:02:22

Windows 7新西蘭發售

2013-05-13 09:35:10

虛擬化數據

2011-03-30 16:19:46

SQL Server邏輯數據庫設計

2023-02-10 13:57:41

2015-11-25 08:34:52

云之訊

2023-07-28 13:23:31

AIChatGPT

2023-07-07 07:35:28

2021-04-28 14:14:35

云計算微軟技術

2022-09-28 08:52:48

Go編程語言

2021-06-29 19:26:29

緩存Spring CachSpring

2023-03-10 07:38:01

微軟谷歌AI聊天機器人

2022-08-08 17:38:45

Spring策略事務

2024-04-16 00:00:00

Spring微服務架構

2019-04-22 08:31:00

Docker容器工具
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美成人a | 天天干,夜夜操 | 亚洲一区综合 | 黄网站免费在线看 | 久久久成人网 | 成人在线观看免费 | 亚洲美女网站 | 女女百合av大片一区二区三区九县 | 黄色免费在线观看 | 国产精品国产精品 | 亚洲一区二区日韩 | 欧美一区二区成人 | 久久久婷婷 | 亚洲一区二区三区在线播放 | 欧美日韩成人在线 | 亚洲免费一区二区 | 久久久久久亚洲 | 色吧久久 | 亚洲综合在线视频 | 亚洲自拍偷拍欧美 | 日韩中文字幕视频 | 一级毛片视频在线观看 | 亚洲不卡在线视频 | 91精品国产综合久久国产大片 | 中文字幕国产高清 | 久久久久国产精品午夜一区 | 奇米av| 999精品在线 | 国产欧美一区二区精品久导航 | 国产成人免费视频网站高清观看视频 | 欧美精品一区二区三区蜜桃视频 | 国产美女自拍视频 | 午夜在线电影网 | 日本视频一区二区三区 | 国产精品视频在线播放 | 久久精品成人 | 毛片a级 | 色综合九九 | 一区二区三区四区av | 精品国产乱码久久久久久闺蜜 | 日本精品久久 |