欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot Cache緩存概念講解

 更新時間:2022年12月30日 14:27:42   作者:wenxueliu@HW  
這篇文章主要介紹了Springboot cache緩存,使用緩存最關(guān)鍵的一點就是保證緩存與數(shù)據(jù)庫的數(shù)據(jù)一致性,本文給大家介紹最常用的緩存操作模式,對Springboot cache緩存操作流程感興趣的朋友一起看看吧

Spring 3.1中引入了基于注解的Cache的支持,在spring-context包中定義了org.springframework.cache.CacheManager和org.springframework.cache.Cache接口,用來統(tǒng)一不同的緩存的技術(shù)。

CacheManager是Spring提供的各種緩存技術(shù)管理的抽象接口,而Cache接口包含緩存的增加、刪除、讀取等常用操作。針對CacheManager,Spring又提供了多種實現(xiàn),比如基于Collection來實現(xiàn)的SimpleCacheManager、基于ConcurrentHashMap實現(xiàn)的ConcurrentMapCacheManager、基于EhCache實現(xiàn)的EhCacheCacheManager和基于JCache標準實現(xiàn)的JCacheCacheManager等。

Spring Cache提供了@CacheConfig、@Cacheable、@CachePut、@CacheEvict等注解來完成緩存的透明化操作,相關(guān)功能如下。

  • @CacheConfig:用于類上,緩存一些公共設(shè)置。
  • @Cacheable:用于方法上,根據(jù)方法的請求參數(shù)對結(jié)果進行緩存,下次讀取時直接讀取緩存內(nèi)容。
  • @CachePut:用于方法上,能夠根據(jù)方法的請求參數(shù)對其結(jié)果進行緩存,和@Cacheable不同的是,它每次都會觸發(fā)真實方法的調(diào)用
  • @CacheEvict:用于方法上,清除該方法的緩存,用在類上清除整個類的方法的緩存。在了解了Spring Cache的基本作用的和定義之后,下面來看在Spring Boot中是如何對Cache進行自動配置的

Cache自動配置

在Spring Boot中,關(guān)于Cache的默認自動配置類只有CacheAutoConfiguration,主要用于緩存抽象的自動配置,當通過@EnableCaching啟用緩存機制時,根據(jù)情況可創(chuàng)建CacheManager。對于緩存存儲可以通過配置自動檢測或明確指定。CacheAutoConfiguration同樣在META-INF/spring.factories文件中配置注冊。

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

下面先來看CacheAutoConfiguration類的注解部分代碼實現(xiàn)。

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
    HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
@Import(CacheConfigurationImportSelector.class)
public class CacheAutoConfiguration { 
...
}

1、@ConditionalOnClass 指定需要在classpath下存在CacheManager類。

2、@ConditionalOnBean 指定需要存在CacheAspectSupport的Bean時才生效,換句話說,就是需要在使用了@EnableCaching時才有效。這是因為該注解隱式的導致了CacheInterceptor對應(yīng)的Bean的初始化,而CacheInterceptor為CacheAspectSupport的子類。

3、@ConditionalOnMissingBean指定名稱為cacheResolver的CacheManager對象不存在時生效。@EnableConfigurationProperties加載緩存的CacheProperties配置項,配置前綴為spring.cache。

4、@EnableConfigurationProperties加載緩存的CacheProperties配置項,配置前綴為spring.cache。@AutoConfigureAfter指定該自動配置必須在緩存數(shù)據(jù)基礎(chǔ)組件自動配置之后進行,這里包括Couchbase、Hazelcast、HibernateJpa和Redis的自動配置。

5、@Import導入CacheConfigurationImportSelector,其實是導入符合條件的Spring Cache使用的各類基礎(chǔ)緩存框架(或組件)的配置。

ImportSelector

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;
    }
}

導入類的獲取是通過實現(xiàn)ImportSelector接口來完成的,具體獲取步驟位于selectImports方法中。該方法中,首先獲取枚舉類CacheType中定義的緩存類型數(shù)據(jù),CacheType中定義支持的緩存類型如下。

// 支持的緩存類型(按照優(yōu)先級定義)
public enum CacheType {
    // 使用上下文中的Cache Bean進行通用緩存
    GENERIC,
    // JCache(JSR-107)支持的緩存
    JCACHE,
    // EhCache支持的緩存
    EHCACHE,
    // Hazelcast支持的緩存
    HAZELCAST,
    // Infinispan支持的緩存
    INFINISPAN,
    // Couchbase支持的緩存
    COUCHBASE,
    // Redis支持的緩存
    REDIS,
    // Caffeine支持的緩存
    CAFFEINE,
    // 內(nèi)存基本的簡單緩存
    SIMPLE,
    // 不支持緩存
    NONE
}

枚舉類CacheType中定義了以上支持的緩存類型,而且上面的緩存類型默認是按照優(yōu)先級從前到后的順序排列的。selectImports方法中,當獲取CacheType中定義的緩存類型數(shù)組之后,遍歷該數(shù)組并通過CacheConfigurations的getConfigurationClass方法獲得每種類型緩存對應(yīng)的自動配置類(注解@Configuration的類)。CacheConfigurations相關(guān)代碼如下。

final class CacheConfigurations {
    private static final Map<CacheType, Class<?>> MAPPINGS;
    // 定義CacheType與@Configuration之間的對應(yīng)關(guān)系
    static {
        Map<CacheType, Class<?>> mappings = new EnumMap<>(CacheType.class);
        mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class);
        mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class);
        mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class);
        mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class);
        mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class);
        mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class);
        mappings.put(CacheType.REDIS, RedisCacheConfiguration.class);
        mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class);
        mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class);
        mappings.put(CacheType.NONE, NoOpCacheConfiguration.class);
        MAPPINGS = Collections.unmodifiableMap(mappings);
    }
    // 根據(jù)CacheType類型獲得對應(yīng)的@Configuration類
    static String getConfigurationClass(CacheType cacheType) {
        Class<?> configurationClass = MAPPINGS.get(cacheType);
        Assert.state(configurationClass != null, () -> "Unknown cache type " + cacheType);
        return configurationClass.getName();
    }
    ...
}

我們會發(fā)現(xiàn)通過@Import注解,CacheAutoConfiguration導入了CacheType中定義的所有類型的自動配置,也就是Spring Boot目前支持的緩存類型。而具體會自動配置哪種類型的緩存,還需要看導入的自動配置類里面的生效條件。

GenericCacheConfiguration

// 實例化CacheManagerCustomizers
@Bean
@ConditionalOnMissingBean
public CacheManagerCustomizers cacheManagerCustomizers(
        ObjectProvider<CacheManagerCustomizer<?>> customizers) {
    return new CacheManagerCustomizers(
            customizers.orderedStream().collect(Collectors.toList()));
}

cacheManagerCustomizers方法初始化了CacheManagerCustomizers對象的Bean,主要是將容器中存在的一個或多個CacheManagerCustomizer的Bean組件包裝為CacheManager-Customizers,并將Bean注入容器。

CacheManagerValidator

cacheAutoConfigurationValidator方法初始化了CacheManagerValidator的Bean,該Bean用于確保容器中存在一個CacheManager對象,以達到緩存機制可以繼續(xù)被配置和使用的目的,同時該Bean也用來提供有意義的異常聲明。

// 實例化CacheManagerValidator
@Bean
public CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties-
cacheProperties,
        ObjectProvider<CacheManager> cacheManager) {
    return new CacheManagerValidator(cacheProperties, cacheManager);
}
// CacheManagerValidator的具體定義,用于檢查并拋出有意義的異常
static class CacheManagerValidator implements InitializingBean {
    private final CacheProperties cacheProperties;
    private final ObjectProvider<CacheManager> cacheManager;
    CacheManagerValidator(CacheProperties cacheProperties, ObjectProvider<Cache-
Manager> cacheManager) {
        this.cacheProperties = cacheProperties;
        this.cacheManager = cacheManager;
    }
    @Override
    public void afterPropertiesSet() {
        Assert.notNull(this.cacheManager.getIfAvailable(),
                () -> "No cache manager could be auto-configured, check your configuration (caching " + "type is '"  + this.cacheProperties.getType() + "')");
    }
}

Redis Cache

RedisCacheConfiguration

我們以RedisCacheConfiguration為例進行分析。源碼如下

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisConnectionFactory.class)
@AutoConfigureAfter(RedisAutoConfiguration.class)
@ConditionalOnBean(RedisConnectionFactory.class)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class RedisCacheConfiguration {
	@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));
		}
		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();
		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;
	}
}

@ConditionalOnClass:當 RedisConnectionFactory 在存在時

@AutoConfigureAfter:在 RedisAutoConfiguration 之后加載

@ConditionalOnBean:RedisConnectionFactory 實例化之后

@ConditionalOnMissingBean:當 CacheManager 的 Bean 不存在時進行實例化操作

@Conditional:滿足 CacheCondition 條件時,進行實例化操作

CacheCondition

class CacheCondition extends SpringBootCondition {
    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, Annotated-
TypeMetadata metadata) {
        String sourceClass = "";
        if (metadata instanceof ClassMetadata) {
            sourceClass = ((ClassMetadata) metadata).getClassName();
        }
        ConditionMessage.Builder message = ConditionMessage.forCondition("Cache", 
sourceClass);
        Environment environment = context.getEnvironment();
        try {
            // 創(chuàng)建指定環(huán)境的Binder,然后綁定屬性到對象上
            BindResult<CacheType> specified = Binder.get(environment).bind("spring.
cache.type", CacheType.class);
            // 如果未綁定,則返回匹配
            if (!specified.isBound()) {
                return ConditionOutcome.match(message.because("automatic cache type"));
            }
            // 獲取所需的緩存類型
            CacheType required = CacheConfigurations.getType(((AnnotationMetadata) 
metadata).getClassName());
            // 如果已綁定,并且綁定的類型與所需的緩存類型相同,則返回匹配
            if (specified.get() == required) {
                return ConditionOutcome.match(message.because(specified.get() + " cache type"));
            }
        } catch (BindException ex) {
        }
        // 其他情況則返回不匹配
        return ConditionOutcome.noMatch(message.because("unknown cache type"));
    }
}

CacheCondition的核心邏輯就是首先通過Binder進行指定屬性和類的綁定,然后通過綁定結(jié)果(BindResult)進行判斷:如果判斷結(jié)果是未綁定,則直接返回條件匹配;否則,判斷綁定的緩存類型與所需的緩存類型是否相等,如果相等則返回條件匹配;其他情況則返回條件不匹配。

RedisCacheManager

1、管理多個 RedisCache

2、每個 RedisCache 包含一個 name

3、每個 RedisCache 可以包含一個 RedisCacheConfiguration(可以有默認配置)

4、支持配置是否動態(tài)增加 Cache

public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
	private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
	private volatile Set<String> cacheNames = Collections.emptySet();
}
public class RedisCacheManager extends AbstractTransactionSupportingCacheManager {
    private final RedisCacheWriter cacheWriter;
    private final RedisCacheConfiguration defaultCacheConfig;
    private final Map<String, RedisCacheConfiguration> initialCacheConfiguration;
    private final boolean allowInFlightCacheCreation;
    protected Collection<RedisCache> loadCaches() {
        List<RedisCache> caches = new LinkedList();
        Iterator var2 = this.initialCacheConfiguration.entrySet().iterator();
        while(var2.hasNext()) {
            Entry<String, RedisCacheConfiguration> entry = (Entry)var2.next();
            caches.add(this.createRedisCache((String)entry.getKey(), (RedisCacheConfiguration)entry.getValue()));
        }
        return caches;
    }
    protected RedisCache getMissingCache(String name) {
        return this.allowInFlightCacheCreation ? this.createRedisCache(name, this.defaultCacheConfig) : null;
    }
    public Map<String, RedisCacheConfiguration> getCacheConfigurations() {
        Map<String, RedisCacheConfiguration> configurationMap = new HashMap(this.getCacheNames().size());
        this.getCacheNames().forEach((it) -> {
            RedisCache cache = (RedisCache)RedisCache.class.cast(this.lookupCache(it));
            configurationMap.put(it, cache != null ? cache.getCacheConfiguration() : null);
        });
        return Collections.unmodifiableMap(configurationMap);
    }
    protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
        return new RedisCache(name, this.cacheWriter, cacheConfig != null ? cacheConfig : this.defaultCacheConfig);
    }
}

RedisCache

public class RedisCache extends AbstractValueAdaptingCache {
    private static final byte[] BINARY_NULL_VALUE;
    private final String name;
    private final RedisCacheWriter cacheWriter;
    private final RedisCacheConfiguration cacheConfig;
    private final ConversionService conversionService;
}

RedisCache 的特點

1、key 支持非 String 類型,比如 Map 和 Collection

2、RedisCacheWriter 是更底層的實現(xiàn),RedisCache 對 RedisCacheWriter 進行封裝。

3、通過 ConversionService 對 key 進行轉(zhuǎn)換

RedisCacheWriter

通過 RedisConnectionFactory 取一個 RedisConnection,然后執(zhí)行命令。putIfAbsent 支持分布式鎖。

到此這篇關(guān)于SpringBoot Cache緩存概念講解的文章就介紹到這了,更多相關(guān)SpringBoot Cache內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Maven實現(xiàn)項目構(gòu)建工具

    Maven實現(xiàn)項目構(gòu)建工具

    本文主要介紹了Maven實現(xiàn)項目構(gòu)建工具,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • log4j2異步打印性能提升方式

    log4j2異步打印性能提升方式

    這篇文章主要介紹了log4j2異步打印性能提升方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java語言之LinkedList和鏈表的實現(xiàn)方法

    Java語言之LinkedList和鏈表的實現(xiàn)方法

    LinkedList是由傳統(tǒng)的鏈表數(shù)據(jù)結(jié)構(gòu)演變而來的,鏈表是一種基本的數(shù)據(jù)結(jié)構(gòu),它可以動態(tài)地增加或刪除元素,下面這篇文章主要給大家介紹了關(guān)于Java語言之LinkedList和鏈表的實現(xiàn)方法,需要的朋友可以參考下
    2023-05-05
  • 解析spring-security權(quán)限控制和校驗的問題

    解析spring-security權(quán)限控制和校驗的問題

    這篇文章主要介紹了解析spring-security權(quán)限控制和校驗的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • mybatis?實體類字段大小寫問題?字段獲取不到值的解決

    mybatis?實體類字段大小寫問題?字段獲取不到值的解決

    這篇文章主要介紹了mybatis?實體類字段大小寫問題?字段獲取不到值的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Thread線程的基礎(chǔ)知識及常見疑惑點總結(jié)

    Thread線程的基礎(chǔ)知識及常見疑惑點總結(jié)

    在本篇內(nèi)容里小編給大家分享的是關(guān)于Thread線程的基礎(chǔ)知識及常見疑惑點,對此有學習需求的朋友們可以學習參考下。
    2019-05-05
  • java之this關(guān)鍵字用法實例分析

    java之this關(guān)鍵字用法實例分析

    這篇文章主要介紹了java之this關(guān)鍵字用法實例分析,較為詳細的講述了Java中this關(guān)鍵字的用法及適用范圍,并附帶實例程序加以說明,需要的朋友可以參考下
    2014-09-09
  • Java字符串查找的三種方式

    Java字符串查找的三種方式

    本篇文章給大家整理了關(guān)于Java字符串查找的三種方式,并把其中需要留意的地方做了標注,一起參考學習下。
    2018-03-03
  • Springboot+Spring Security實現(xiàn)前后端分離登錄認證及權(quán)限控制的示例代碼

    Springboot+Spring Security實現(xiàn)前后端分離登錄認證及權(quán)限控制的示例代碼

    本文主要介紹了Springboot+Spring Security實現(xiàn)前后端分離登錄認證及權(quán)限控制的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • SpringBoot Feign使用教程超全面講解

    SpringBoot Feign使用教程超全面講解

    現(xiàn)在的微服務(wù)項目不少都使用的是springboot+Feign構(gòu)建的項目,微服務(wù)之間的調(diào)用都離不開feign來進行遠程調(diào)用,這篇文章主要介紹了SpringBoot Feign使用教程,需要的朋友可以參考下
    2022-11-11

最新評論