在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 {
@Bean
public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {
EhCacheManagerFactoryBean bean = new EhCacheManagerFactoryBean();
bean.setConfigLocation(new ClassPathResource("ehcache.xml")); // 指定配置文件路径
bean.setShared(true); // 共享EhCache实例
return bean;
}
@Bean
public 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"/> <defaultCache maxElementsInMemory="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: ehcache ehcache: 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);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(StartDataApplication.class);
}
}