一、JCache
在Java编程中,有一套基于缓存的规范,名为 J SR 107(JCACHE - Java Temporary Caching API),该规范主要定义了以下几个关键类型
1、javax.cache.Cache<K, V>
缓存是一种类似 Map 的数据结构,用于临时存储应用程序数据。
- 类似Map,Cache存储键值对,每个键值对称为Cache.Entry
- 允许使用 Java 泛型来提高应用程序类型安全性
- Iterable类型,即可被迭代
每个Cache实例都有一个名字,以及许多操作Cache中数据的方法,例如:
方法 | 含义 |
boolean containsKey(K key) | 判断Cache中是否存在指定的key |
V get(K key) | 从Cache中获取指定key的数据 |
void put(K key, V value) | 将缓存数据存入Cache |
boolean putIfAbsent(K key, V value) | 如果key不存在则将数据存入Cache |
boolean remove(K key) | 从Cache中移除指定key的数据 |
boolean replace(K key, V oldValue, V newValue) | 以原子方式替换键的条目 |
void clear() | 清除缓存的内容,而不通知侦听器或 CacheWriters |
void close() | 关闭缓存会向生成或拥有缓存的 CacheManager 发出信号,表明不应再管理该缓存 |
String getName() | Cache的名称 |
void loadAll(Set<? extends K> keys, boolean replaceExistingValues, CompletionListener completionListener) | 使用为给定键配置的 CacheLoader 将指定的条目异步加载到缓存中 |
2、javax.cache.CacheManager
CacheManager 提供了一种建立、配置、获取、关闭和销毁唯一命名的缓存的方法。
由 CacheManager 生成和拥有的缓存通常共享公共基础结构,例如,公共 ClassLoader 和特定于实现的属性。
CacheManager 的实现还可以在所管理的缓存之间提供和共享外部资源,例如,托管缓存的内容可以存储在同一集群中。
方法 | 含义 |
<K, V, C extends Configuration<K, V>> Cache<K, V> createCache(String cacheName, C configuration) | 创建Cache |
<K, V> Cache<K, V> getCache(String cacheName) | 获取指定名称的Cache |
void destroyCache(String cacheName) | 销毁cache |
void close() |
3、javax.cache.spi.CachingProvider
方法 | 含义 |
CacheManager getCacheManager(URI uri, ClassLoader classLoader, Properties properties) | 获取Cachemanager |
CacheManager getCacheManager(URI uri, ClassLoader classLoader) | 获取Cachemanager |
CacheManager getCacheManager() | 获取Cachemanager |
void close() |
4、javax.cache.Caching
该类通过SPI方式加载CachingProvider实现类,并通过静态方法返回CachingProvider
5、缓存配置
private Cache<String,String> createCache(String cacheName){
CachingProvider provider = Caching.getCachingProvider() ;
CacheManager cacheManager = provider.getCacheManager() ;
return cacheManager.createCache(cacheName,configuration()) ;
}
private MutableConfiguration<String,String> configuration(){
MutableConfiguration<String,String> configuration = new MutableConfiguration<>() ;
configuration.setTypes(String.class, String.class);
configuration.setExpiryPolicyFactory(AccessedExpiryPolicy.factoryOf(Duration.ONE_HOUR));
return configuration ;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
参考:
- https://github.com/jsr107/jsr107spec
- https://download.oracle.com/otn-pub/jcp/jcache-2_9-pfd-spec/JSR107ProposedFinalDraftSpecification.pdf
- https://www.ehcache.org/documentation/3.0/107.html
- https://docs.spring.io/spring-framework/reference/integration/cache/jsr-107.html
二、Spring Cache
1、Spring对缓存的抽象
2、缓存管理器
3、缓存切面
4、切面介入
通过注解@EnableCaching
可以开启spring的缓存配置。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
CachingConfigurationSelector
public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
private static final String PROXY_JCACHE_CONFIGURATION_CLASS =
"org.springframework.cache.jcache.config.ProxyJCacheConfiguration";
private static final String CACHE_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.cache.aspectj.AspectJCachingConfiguration";
private static final String JCACHE_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.cache.aspectj.AspectJJCacheConfiguration";
private static final boolean jsr107Present;
private static final boolean jcacheImplPresent;
static {
ClassLoader classLoader = CachingConfigurationSelector.class.getClassLoader();
jsr107Present = ClassUtils.isPresent("javax.cache.Cache", classLoader);
jcacheImplPresent = ClassUtils.isPresent(PROXY_JCACHE_CONFIGURATION_CLASS, classLoader);
}
/**
* Returns {@link ProxyCachingConfiguration} or {@code AspectJCachingConfiguration}
* for {@code PROXY} and {@code ASPECTJ} values of {@link EnableCaching#mode()},
* respectively. Potentially includes corresponding JCache configuration as well.
*/
@Override
public String[] selectImports(AdviceMode adviceMode) {
return switch (adviceMode) {
case PROXY -> getProxyImports();
case ASPECTJ -> getAspectJImports();
};
}
/**
* Return the imports to use if the {@link AdviceMode} is set to {@link AdviceMode#PROXY}.
* <p>Take care of adding the necessary JSR-107 import if it is available.
*/
private String[] getProxyImports() {
List<String> result = new ArrayList<>(3);
result.add(AutoProxyRegistrar.class.getName());
result.add(ProxyCachingConfiguration.class.getName());
if (jsr107Present && jcacheImplPresent) {
result.add(PROXY_JCACHE_CONFIGURATION_CLASS);
}
return StringUtils.toStringArray(result);
}
/**
* Return the imports to use if the {@link AdviceMode} is set to {@link AdviceMode#ASPECTJ}.
* <p>Take care of adding the necessary JSR-107 import if it is available.
*/
private String[] getAspectJImports() {
List<String> result = new ArrayList<>(2);
result.add(CACHE_ASPECT_CONFIGURATION_CLASS_NAME);
if (jsr107Present && jcacheImplPresent) {
result.add(JCACHE_ASPECT_CONFIGURATION_CLASS_NAME);
}
return StringUtils.toStringArray(result);
}
}
- 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.
5、KeyGenerator
三、Springboot中使用缓存
1、CacheAutoConfiguration
spring-boot-autoconfigure-3.0.8.jar!org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
//在指定的这些配置类后执行. 这些配置类中会创建连接,例如:RedisConnectionFactory
@AutoConfiguration(after = { CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class,
HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
//如果缺少名为cacheResolver,类型为CacheManager的Bean时
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
//spring cache的配置
@EnableConfigurationProperties(CacheProperties.class)
//导入配置
@Import({ CacheConfigurationImportSelector.class, CacheManagerEntityManagerFactoryDependsOnPostProcessor.class })
public class CacheAutoConfiguration {
/**
* {@link ImportSelector} to add {@link CacheType} configuration classes.
*/
static class CacheConfigurationImportSelector implements ImportSelector {
// 重点:加载配置
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
CacheType[] types = CacheType.values();
String[] imports = new String[types.length];
for (int i = 0; i < types.length; i++) {
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
}
return imports;
}
}
}
- 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.
2、CacheType
该枚举中定义了spring框架中支持的缓存组件
package org.springframework.boot.autoconfigure.cache;
/**
* Supported cache types (defined in order of precedence).
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Eddú Meléndez
* @since 1.3.0
*/
public enum CacheType {
/**
* Generic caching using 'Cache' beans from the context.
*/
GENERIC,
/**
* JCache (JSR-107) backed caching.
*/
JCACHE,
/**
* Hazelcast backed caching.
*/
HAZELCAST,
/**
* Couchbase backed caching.
*/
COUCHBASE,
/**
* Infinispan backed caching.
*/
INFINISPAN,
/**
* Redis backed caching.
*/
REDIS,
/**
* Cache2k backed caching.
*/
CACHE2K,
/**
* Caffeine backed caching.
*/
CAFFEINE,
/**
* Simple in-memory caching.
*/
SIMPLE,
/**
* No caching.
*/
NONE
}
- 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.
3、CacheConfigurations
该类中记录了各种缓存组件对应的配置类
/**
* Mappings between {@link CacheType} and {@code @Configuration}.
*
* @author Phillip Webb
* @author Eddú Meléndez
* @author Sebastien Deleuze
*/
final class CacheConfigurations {
private static final Map<CacheType, String> MAPPINGS;
static {
// 所有支持缓存组件对应的配置类
Map<CacheType, String> mappings = new EnumMap<>(CacheType.class);
mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class.getName());
mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class.getName());
mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class.getName());
mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class.getName());
mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class.getName());
mappings.put(CacheType.REDIS, RedisCacheConfiguration.class.getName());
mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class.getName());
mappings.put(CacheType.CACHE2K, Cache2kCacheConfiguration.class.getName());
mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class.getName());
mappings.put(CacheType.NONE, NoOpCacheConfiguration.class.getName());
MAPPINGS = Collections.unmodifiableMap(mappings);
}
private CacheConfigurations() {}
// 根据缓存组件类型获取配置类的全路径
static String getConfigurationClass(CacheType cacheType) {
String configurationClassName = MAPPINGS.get(cacheType);
Assert.state(configurationClassName != null, () -> "Unknown cache type " + cacheType);
return configurationClassName;
}
static CacheType getType(String configurationClassName) {
for (Map.Entry<CacheType, String> entry : MAPPINGS.entrySet()) {
if (entry.getValue().equals(configurationClassName)) {
return entry.getKey();
}
}
throw new IllegalStateException("Unknown configuration class " + configurationClassName);
}
}
- 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.
接在了很多配置,这里以JCacheCacheConfiguration为例
4、JCacheCacheConfiguration
package org.springframework.boot.autoconfigure.cache;
/**
* Cache configuration for JSR-107 compliant providers.
*
* @author Stephane Nicoll
* @author Madhura Bhave
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Caching.class, JCacheCacheManager.class })
@ConditionalOnMissingBean(org.springframework.cache.CacheManager.class)
@Conditional({ CacheCondition.class, JCacheCacheConfiguration.JCacheAvailableCondition.class })
@Import(HazelcastJCacheCustomizationConfiguration.class)
class JCacheCacheConfiguration implements BeanClassLoaderAware {
private ClassLoader beanClassLoader;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
// 重点:将javax.cache.CacheManager类型的Bean
// 包装成org.springframework.cache.jcache.JCacheCacheManager
@Bean
JCacheCacheManager cacheManager(CacheManagerCustomizers customizers, CacheManager jCacheCacheManager) {
JCacheCacheManager cacheManager = new JCacheCacheManager(jCacheCacheManager);
return customizers.customize(cacheManager);
}
@Bean
@ConditionalOnMissingBean
CacheManager jCacheCacheManager(CacheProperties cacheProperties,
ObjectProvider<javax.cache.configuration.Configuration<?, ?>> defaultCacheConfiguration,
ObjectProvider<JCacheManagerCustomizer> cacheManagerCustomizers,
ObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers) throws IOException {
CacheManager jCacheCacheManager = createCacheManager(cacheProperties, cachePropertiesCustomizers);
List<String> cacheNames = cacheProperties.getCacheNames();
if (!CollectionUtils.isEmpty(cacheNames)) {
for (String cacheName : cacheNames) {
jCacheCacheManager.createCache(cacheName,
defaultCacheConfiguration.getIfAvailable(MutableConfiguration::new));
}
}
cacheManagerCustomizers.orderedStream().forEach((customizer) -> customizer.customize(jCacheCacheManager));
return jCacheCacheManager;
}
private CacheManager createCacheManager(CacheProperties cacheProperties,
ObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers) throws IOException {
CachingProvider cachingProvider = getCachingProvider(cacheProperties.getJcache().getProvider());
Properties properties = createCacheManagerProperties(cachePropertiesCustomizers, cacheProperties);
Resource configLocation = cacheProperties.resolveConfigLocation(cacheProperties.getJcache().getConfig());
if (configLocation != null) {
return cachingProvider.getCacheManager(configLocation.getURI(), this.beanClassLoader, properties);
}
return cachingProvider.getCacheManager(null, this.beanClassLoader, properties);
}
private CachingProvider getCachingProvider(String cachingProviderFqn) {
if (StringUtils.hasText(cachingProviderFqn)) {
return Caching.getCachingProvider(cachingProviderFqn);
}
return Caching.getCachingProvider();
}
private Properties createCacheManagerProperties(
ObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers, CacheProperties cacheProperties) {
Properties properties = new Properties();
cachePropertiesCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(cacheProperties, properties));
return properties;
}
/**
* Determine if JCache is available. This either kicks in if a provider is available
* as defined per {@link JCacheProviderAvailableCondition} or if a
* {@link CacheManager} has already been defined.
*/
@Order(Ordered.LOWEST_PRECEDENCE)
static class JCacheAvailableCondition extends AnyNestedCondition {
JCacheAvailableCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@Conditional(JCacheProviderAvailableCondition.class)
static class JCacheProvider {}
@ConditionalOnSingleCandidate(CacheManager.class)
static class CustomJCacheCacheManager {}
}
/**
* Determine if a JCache provider is available. This either kicks in if a default
* {@link CachingProvider} has been found or if the property referring to the provider
* to use has been set.
*/
@Order(Ordered.LOWEST_PRECEDENCE)
static class JCacheProviderAvailableCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConditionMessage.Builder message = ConditionMessage.forCondition("JCache");
String providerProperty = "spring.cache.jcache.provider";
if (context.getEnvironment().containsProperty(providerProperty)) {
return ConditionOutcome.match(message.because("JCache provider specified"));
}
Iterator<CachingProvider> providers = Caching.getCachingProviders().iterator();
if (!providers.hasNext()) {
return ConditionOutcome.noMatch(message.didNotFind("JSR-107 provider").atAll());
}
providers.next();
if (providers.hasNext()) {
return ConditionOutcome.noMatch(message.foundExactly("multiple JSR-107 providers"));
}
return ConditionOutcome.match(message.foundExactly("single JSR-107 provider"));
}
}
}
- 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.
5、创建javax.cache.CacheManager类型Bean
接下来我们可以进行缓存的配置,如下所示:
@Configuration
@EnableCaching
public class CacheConfiguration {
// 注意:其它的配置此处忽略
@Bean
public javax.cache.CacheManager jCacheCacheManager(RedissonClient redissonClient){
javax.cache.CacheManager jCacheCacheManager = Caching.getCachingProvider("org.redisson.jcache.JCachingProvider").getCacheManager(null, this.beanClassLoader, new Properties());
// 自定义扩展,根据配置的缓存名创建Cache
cacheManagerCustomizer(redissonClient, jcacheConfiguration(redissonClient)).customize(jCacheCacheManager);
return jCacheCacheManager;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
可见,通过JCacheCacheConfiguration可完成将javax.cache.CacheManager
包装成org.springframework.cache.CacheManager
,从而使用Spring框架的提供的缓存注解。
6、缓存配置框架
7、常用Redis的装配
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisConnectionFactory.class)
@AutoConfigureAfter(RedisAutoConfiguration.class)
//要生效则需要创建RedisConnectionFactory类型
@ConditionalOnBean(RedisConnectionFactory.class)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class RedisCacheConfiguration {
//创建org.springframework.cache.CacheManager
@Bean
RedisCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers,
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers,
RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(
determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
List<String> cacheNames = cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) {
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
}
if (cacheProperties.getRedis().isEnableStatistics()) {
builder.enableStatistics();
}
redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
return cacheManagerCustomizers.customize(builder.build());
}
private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(
CacheProperties cacheProperties,
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
ClassLoader classLoader) {
return redisCacheConfiguration.getIfAvailable(() -> createConfiguration(cacheProperties, classLoader));
}
private org.springframework.data.redis.cache.RedisCacheConfiguration createConfiguration(
CacheProperties cacheProperties, ClassLoader classLoader) {
Redis redisProperties = cacheProperties.getRedis();
org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
.defaultCacheConfig();
//默认使用JDK的序列化
config = config
.serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
}
- 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.
我们可以自己创建RedisConnectionFactory,也可是直接使用springboot自带的方式(RedisAutoConfiguration)
@AutoConfiguration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
//内部创建连接-RedisConnectionFactory
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
使用lettuce连接redis配置
/**
* Redis connection configuration using Lettuce.
*
* @author Mark Paluch
* @author Andy Wilkinson
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisClient.class)
@ConditionalOnProperty(name = "spring.data.redis.client-type", havingValue = "lettuce", matchIfMissing = true)
class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
LettuceConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisStandaloneConfiguration> standaloneConfigurationProvider,
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
super(properties, standaloneConfigurationProvider, sentinelConfigurationProvider, clusterConfigurationProvider);
}
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
LettuceConnectionFactory redisConnectionFactory(
ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,
ClientResources clientResources) {
LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(builderCustomizers, clientResources,
getProperties().getLettuce().getPool());
return createLettuceConnectionFactory(clientConfig);
}
// ... ...
}
- 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.
配置项示例
spring:
data:
redis:
database: 0
url:
host:
username:
password:
port: 6379
ssl:
timeout:
connectTimeout:
clientName:
clientType: lettuce #lettuce,jedis
sentinel:
master:
nodes:
username:
password:
cluster:
nodes:
maxRedirects:
jedis:
pool:
enabled:
maxIdle: 8
minIdle: 0
maxActive: 8
maxWait: -1
timeBetweenEvictionRuns:
lettuce:
pool:
cluster:
- 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.
四、基于缓存的分布式锁
主要还是使用Redisson
提供的分布式锁功能来实现
使用示例
说明:可以通过redisson中提供的RedissonSpringCacheManager将redisson融入到spring cache中