CacheAutoConfiguration.java
6.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package com.infoloop.tianting.cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.concurrent.TimeUnit;
/**
* 缓存自动配置类
* 在Spring Boot启动时自动配置缓存相关组件
*/
@Slf4j
@Configuration
@EnableCaching
@ConditionalOnClass({Caffeine.class, StringRedisTemplate.class})
@EnableConfigurationProperties(CacheProperties.class)
@ConditionalOnProperty(name = "cache.enabled", havingValue = "true", matchIfMissing = true)
public class CacheAutoConfiguration {
@Autowired
private CacheProperties cacheProperties;
/**
* 配置Caffeine缓存管理器
*/
@Bean
@ConditionalOnMissingBean
public com.github.benmanes.caffeine.cache.Cache<String, Object> caffeineCache() {
Caffeine<Object, Object> caffeine = Caffeine.newBuilder()
.initialCapacity(cacheProperties.getCaffeine().getInitialCapacity())
.maximumSize(cacheProperties.getCaffeine().getMaximumSize())
.expireAfterWrite(cacheProperties.getCaffeine().getExpireAfterWrite(), TimeUnit.SECONDS);
// 如果配置了访问后过期时间,则启用
if (cacheProperties.getCaffeine().getExpireAfterAccess() > 0) {
caffeine.expireAfterAccess(cacheProperties.getCaffeine().getExpireAfterAccess(), TimeUnit.SECONDS);
}
// 优化并发性能:使用调用线程执行过期任务,减少线程切换开销
caffeine.executor(Runnable::run);
if (cacheProperties.getCaffeine().isRecordStats()) {
caffeine.recordStats();
}
log.info("Caffeine缓存配置完成: initialCapacity={}, maximumSize={}, expireAfterWrite={}s, expireAfterAccess={}s",
cacheProperties.getCaffeine().getInitialCapacity(),
cacheProperties.getCaffeine().getMaximumSize(),
cacheProperties.getCaffeine().getExpireAfterWrite(),
cacheProperties.getCaffeine().getExpireAfterAccess());
return caffeine.build();
}
/**
* 配置Caffeine缓存服务
*/
@Bean("caffeineCacheService")
@ConditionalOnMissingBean(name = "caffeineCacheService")
public CaffeineCacheService caffeineCacheService(com.github.benmanes.caffeine.cache.Cache<String, Object> caffeineCache) {
log.info("Caffeine缓存服务配置完成");
return new CaffeineCacheService(caffeineCache);
}
/**
* 配置ObjectMapper用于JSON序列化
* 针对Lombok @Data类优化,支持标准的序列化/反序列化
*/
@Bean("cacheObjectMapper")
@ConditionalOnMissingBean(name = "cacheObjectMapper")
public com.fasterxml.jackson.databind.ObjectMapper cacheObjectMapper() {
com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
mapper.findAndRegisterModules(); // 注册所有模块,包括Java 8时间模块
// 基本配置
mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.configure(com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
// 为Lombok @Data类启用类型信息,这样可以正确反序列化
mapper.activateDefaultTyping(
com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator.builder()
.allowIfSubType(Object.class)
.build(),
com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping.NON_FINAL,
com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY
);
log.info("缓存专用ObjectMapper配置完成(优化支持Lombok @Data类)");
return mapper;
}
/**
* 配置Redis缓存服务
*/
@Bean("redisCacheService")
@ConditionalOnMissingBean(name = "redisCacheService")
public RedisCacheService redisCacheService(StringRedisTemplate redisTemplate,
@org.springframework.beans.factory.annotation.Qualifier("cacheObjectMapper")
com.fasterxml.jackson.databind.ObjectMapper objectMapper) {
log.info("Redis缓存服务配置完成");
return new RedisCacheService(redisTemplate, objectMapper);
}
/**
* 配置缓存服务(主要使用多级缓存)
*/
@Bean("multiLevelCacheService")
@ConditionalOnMissingBean(name = "multiLevelCacheService")
public MultiLevelCacheService multiLevelCacheService(
CaffeineCacheService caffeineCacheService,
RedisCacheService redisCacheService,
CacheProperties cacheProperties) {
log.info("多级缓存服务配置完成");
return new MultiLevelCacheService(caffeineCacheService, redisCacheService, cacheProperties);
}
/**
* 配置Spring Cache管理器 - 桥接到多级缓存服务
*/
@Bean
@Primary
@ConditionalOnMissingBean(CacheManager.class)
public CacheManager cacheManager(
@org.springframework.beans.factory.annotation.Qualifier("multiLevelCacheService")
CacheService cacheService,
CacheProperties cacheProperties) {
log.info("Spring Cache管理器配置完成,桥接到多级缓存服务");
return new MultiLevelCacheManager(cacheService, cacheProperties);
}
/**
* 配置缓存健康检查
*/
@Bean
@ConditionalOnMissingBean
public CacheHealthIndicator cacheHealthIndicator() {
log.info("缓存健康检查配置完成");
return new CacheHealthIndicator();
}
/**
* 配置缓存管理控制器
*/
@Bean
@ConditionalOnMissingBean
public CacheManagementController cacheManagementController() {
log.info("缓存管理控制器配置完成");
return new CacheManagementController();
}
}