在Spring框架中,緩存是一種常見的優化手段,用于減少對數據庫或其他資源的訪問次數,從而提高應用性能。Spring提供了強大的緩存抽象,支持多種緩存實現(如EhCache、Redis、Caffeine等),并可以通過注解或編程方式輕松集成。
本文以EhCache為例,來演示Spring框架如何做緩存。以下是Spring實現EhCache緩存的實現方式和步驟:
1、引入緩存依賴
在pom.xml
中添加EhCache相應的依賴:
<dependency>
? ? <groupId>org.springframework.boot</groupId>
? ? <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
? ? <groupId>org.ehcache</groupId>
? ? <artifactId>ehcache</artifactId>
</dependency>
2、配置緩存管理器
在Spring Boot中,可以通過配置類來定義緩存管理器。以下是一些EhCache緩存實現的配置示例:
package com.config;import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;@Configuration
@EnableCaching // 啟用Spring緩存支持
public class CacheConfig {@Beanpublic EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {EhCacheManagerFactoryBean bean = new EhCacheManagerFactoryBean();bean.setConfigLocation(new ClassPathResource("ehcache.xml")); // 指定配置文件路徑bean.setShared(true); // 共享EhCache實例return bean;}@Beanpublic CacheManager cacheManager() {return new EhCacheCacheManager(ehCacheManagerFactoryBean().getObject());}
}
3、配置ehcache.xml
文件
需要在src/main/resources
目錄下創建ehcache.xml
配置文件:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"><diskStore path="java.io.tmpdir"/><defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="false"memoryStoreEvictionPolicy="LRU"/><cache name="USER_SESSION"maxElementsInMemory="500"eternal="false"timeToIdleSeconds="300"timeToLiveSeconds="600"/> </ehcache><!-- name:緩存名稱。--> <!-- maxElementsInMemory:緩存最大個數。--> <!-- eternal:對象是否永久有效,一但設置了,timeout將不起作用。--> <!-- timeToIdleSeconds:設置對象在失效前的允許閑置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閑置時間無窮大。--> <!-- timeToLiveSeconds:設置對象在失效前允許存活時間(單位:秒)。最大時間介于創建時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。--> <!-- overflowToDisk:當內存中對象數量達到maxElementsInMemory時,Ehcache將會對象寫到磁盤中。--> <!-- diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每個Cache都應該有自己的一個緩沖區。--> <!-- maxElementsOnDisk:硬盤最大緩存個數。--> <!-- diskPersistent:是否緩存虛擬機重啟期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.--> <!-- diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。--> <!-- memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你可以設置為FIFO(先進先出)或是LFU(較少使用)。--> <!-- clearOnFlush:內存數量最大時是否清除。-->
?在application.yml
中配置EhCache
指定EhCache的XML配置文件路徑:
spring:cache:type: ehcacheehcache:config: classpath:ehcache.xml
4、使用緩存注解
Spring提供了多個注解來簡化緩存的使用,最常用的是@Cacheable
、@CachePut
和@CacheEvict
。
@Cacheable?
注解用于方法上,表示該方法的返回值會被緩存。如果緩存中存在值,則不會執行方法體;
@CachePut?
注解用于更新緩存。無論緩存中是否存在值,都會執行方法體,并將返回值更新到緩存中;
@CacheEvict?
注解用于清除緩存。?
value
:指定緩存的名稱,與ehcache.xml中的name保持一致;
key
:指定緩存的鍵,默認是方法的參數。參考格式:'方法名_' + #參數名
package com.service.cache;import com.domain.User;
import com.mapstruct.UserMapper;
import com.repository.UserRepository;
import com.web.dto.UserDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Optional;@Slf4j
@Service
@RequiredArgsConstructor
public class UserCacheService {private final UserRepository userRepository;private final UserMapper userMapper;@Cacheable(value = "USER_SESSION", key = "'getUserById_' + #id")public User getUserById(Integer id) {if (id == null)return new User();Optional<User> userOptional = userRepository.findById(id);return userOptional.isPresent()? userOptional.get() : new User();}@Cacheable(value = "USER_SESSION", key = "'getUsersByRoleId_' + #roleId")public List<UserDto> getUsersByRoleId(Integer roleId) {if (roleId == null){List<User> optionals = userRepository.findAllByIsDeleteIsFalseOrderByNameAsc();return userMapper.toDto(optionals);} else {List<User> optionals = userRepository.findAllByRoleIdAndIsDeleteIsFalse(roleId);return userMapper.toDto(optionals);}}@CachePut(value = "USER_SESSION", key = "#id")public String updateDataById(String id, String newData) {System.out.println("Updating data in database...");return newData;}@CacheEvict(value = "USER_SESSION", key = "#id")public void deleteDataById(String id) {System.out.println("Deleting data from database...");}}
5、最后啟動ehcache
使用@EnableCaching注解啟動緩存:
package com.start;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableScheduling;@EnableCaching
@EnableScheduling
@SpringBootApplication
@EntityScan("com.domain")
@SecurityScheme(name = "token", scheme = "Bearer", type = SecuritySchemeType.HTTP, in = SecuritySchemeIn.QUERY)
public class StartDataApplication extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication.run(StartDataApplication.class, args);}@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(StartDataApplication.class);}
}