zoukankan      html  css  js  c++  java
  • 26. SpringBoot 初识缓存及 SimpleCacheConfiguration源码解析

    1.引入一下starter:

    web、cache、Mybatis、MySQL

    @MapperScan("com.everjiankang.cache.dao")
    @SpringBootApplication
    @EnableCaching       //启用缓存
    public class Springboot01CacheApplication {
        public static void main(String[] args) {
            SpringApplication.run(Springboot01CacheApplication.class, args);
        }
    }
    @Service
    public class UserServiceImpl implements UserService {
    
        @Autowired
        UserMapper userMapper;
    
    /**
         * 将方法的运行结果进行缓存;以后再要相同的数据,直接从缓存中获取,不用调用方法;
         * CacheManager管理多个Cache组件的,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有自己唯一一个名字;
         *
         *
         * 原理:
         *   1、自动配置类;CacheAutoConfiguration
         *   2、缓存的配置类
         *   org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
         *   org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
         *   org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
         *   org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
         *   org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
         *   org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
         *   org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
         *   org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
         *   org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration
         *   org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration【默认】
         *   org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
         *   3、哪个配置类默认生效:SimpleCacheConfiguration;
         *
         *   4、给容器中注册了一个CacheManager:ConcurrentMapCacheManager
         *   5、可以获取和创建ConcurrentMapCache类型的缓存组件;他的作用将数据保存在ConcurrentMap中;
         *
         *   运行流程:
         *   @Cacheable:
         *   1、方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;
         *      (CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建。
         *   2、去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;
         *      key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成key;
         *          SimpleKeyGenerator生成key的默认策略;
         *                  如果没有参数;key=new SimpleKey();
         *                  如果有一个参数:key=参数的值
         *                  如果有多个参数:key=new SimpleKey(params);
         *   3、没有查到缓存就调用目标方法;
         *   4、将目标方法返回的结果,放进缓存中
         *
         *   @Cacheable标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,
         *   如果没有就运行方法并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据;
         *
         *   核心:
         *      1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件
         *      2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator
         *
         *
         *   几个属性:
         *      cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
         *
         *      key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值  1-方法的返回值
         *              编写SpEL; #i d;参数id的值   #a0  #p0  #root.args[0]
         *              getEmp[2]
         *
         *      keyGenerator:key的生成器;可以自己指定key的生成器的组件id
         *              key/keyGenerator:二选一使用;
         *
         *
         *      cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器
         *
         *      condition:指定符合条件的情况下才缓存;
         *              ,condition = "#id>0"
         *          condition = "#a0>1":第一个参数的值》1的时候才进行缓存
         *
         *      unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
         *              unless = "#result == null"
         *              unless = "#a0==2":如果第一个参数的值是2,结果不缓存;
         *      sync:是否使用异步模式
         * @param id
         * @return
         *
         */
        @Cacheable(cacheNames = {"user"})
        @Override
        public User selectByPrimaryKey(Integer id) {
            return userMapper.selectByPrimaryKey(id);
        }
    
    }
    package org.springframework.boot.autoconfigure.cache;
    
    @Configuration
    @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({CacheAutoConfiguration.CacheConfigurationImportSelector.class})
    public class CacheAutoConfiguration {
        public CacheAutoConfiguration() {
        }
    
        @Bean
        @ConditionalOnMissingBean
        public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {
            return new CacheManagerCustomizers((List)customizers.orderedStream().collect(Collectors.toList()));
        }
    
        @Bean
        public CacheAutoConfiguration.CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) {
            return new CacheAutoConfiguration.CacheManagerValidator(cacheProperties, cacheManager);
        }
    
        static class CacheConfigurationImportSelector implements ImportSelector {
            CacheConfigurationImportSelector() {
            }
    
         /**在Spring Boot项目启动的过程中,导入缓存的配置组件*/
    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]); }         /** imports的值,缓存配置类
              org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
              org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
              org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
              org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
              org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration

              org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
              org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
              org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
              org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration
              org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
            */
            return imports; } } static class CacheManagerValidator implements InitializingBean { private final CacheProperties cacheProperties; private final ObjectProvider<CacheManager> cacheManager; CacheManagerValidator(CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) { this.cacheProperties = cacheProperties; this.cacheManager = cacheManager; } public void afterPropertiesSet() { Assert.notNull(this.cacheManager.getIfAvailable(), () -> { return "No cache manager could be auto-configured, check your configuration (caching type is '" + this.cacheProperties.getType() + "')"; }); } } @Configuration @ConditionalOnClass({LocalContainerEntityManagerFactoryBean.class}) @ConditionalOnBean({AbstractEntityManagerFactoryBean.class}) protected static class CacheManagerJpaDependencyConfiguration extends EntityManagerFactoryDependsOnPostProcessor { public CacheManagerJpaDependencyConfiguration() { super(new String[]{"cacheManager"}); } } }

     在配置文件中加入

      debug=true

    然后启动项目,控制台关于缓存的启动log如下:

       SimpleCacheConfiguration matched:
          - Cache org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration automatic cache type (CacheCondition)
          - @ConditionalOnMissingBean (types: org.springframework.cache.CacheManager; SearchStrategy: all) did not find any beans (OnBeanCondition)
    
      CaffeineCacheConfiguration:
          Did not match:
             - @ConditionalOnClass did not find required class 'com.github.benmanes.caffeine.cache.Caffeine' (OnClassCondition)
    
       CouchbaseCacheConfiguration:
          Did not match:
             - @ConditionalOnClass did not find required classes 'com.couchbase.client.java.Bucket', 'com.couchbase.client.spring.cache.CouchbaseCacheManager' (OnClassCondition)
    
    
       EhCacheCacheConfiguration:
          Did not match:
             - @ConditionalOnClass did not find required class 'net.sf.ehcache.Cache' (OnClassCondition)
    
       GenericCacheConfiguration:
          Did not match:
             - @ConditionalOnBean (types: org.springframework.cache.Cache; SearchStrategy: all) did not find any beans of type org.springframework.cache.Cache (OnBeanCondition)
          Matched:
             - Cache org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration automatic cache type (CacheCondition)
    
    
       HazelcastCacheConfiguration:
          Did not match:
             - @ConditionalOnClass did not find required classes 'com.hazelcast.core.HazelcastInstance', 'com.hazelcast.spring.cache.HazelcastCacheManager' (OnClassCondition)
    
    
       InfinispanCacheConfiguration:
          Did not match:
             - @ConditionalOnClass did not find required class 'org.infinispan.spring.provider.SpringEmbeddedCacheManager' (OnClassCondition)
    
    
       JCacheCacheConfiguration:
          Did not match:
             - @ConditionalOnClass did not find required class 'javax.cache.Caching' (OnClassCondition)
    
    
       NoOpCacheConfiguration:
          Did not match:
             - @ConditionalOnMissingBean (types: org.springframework.cache.CacheManager; SearchStrategy: all) 
              found beans of type 'org.springframework.cache.CacheManager' cacheManager (OnBeanCondition) Matched: - Cache org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration automatic cache type (CacheCondition) RedisCacheConfiguration: Did not match: - @ConditionalOnClass did not find required class 'org.springframework.data.redis.connection.RedisConnectionFactory' (OnClassCondition)
     
    @Configuration
    @ConditionalOnMissingBean({CacheManager.class})
    @Conditional({CacheCondition.class})
    class SimpleCacheConfiguration {
        private final CacheProperties cacheProperties;
        private final CacheManagerCustomizers customizerInvoker;
    
        SimpleCacheConfiguration(CacheProperties cacheProperties, CacheManagerCustomizers customizerInvoker) {
            this.cacheProperties = cacheProperties;
            this.customizerInvoker = customizerInvoker;
        }
    
        @Bean
        public ConcurrentMapCacheManager cacheManager() {
            ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
            List<String> cacheNames = this.cacheProperties.getCacheNames();
            if (!cacheNames.isEmpty()) {
                cacheManager.setCacheNames(cacheNames);
            }
    
            return (ConcurrentMapCacheManager)this.customizerInvoker.customize(cacheManager);
        }
    }
    package org.springframework.cache;
    
    import java.util.Collection;
    import org.springframework.lang.Nullable;
    
    public interface CacheManager {
        @Nullable
        Cache getCache(String var1);
    
        Collection<String> getCacheNames();
    }
    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package org.springframework.cache.concurrent;

    public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware { private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap(16); private boolean dynamic = true; private boolean allowNullValues = true; private boolean storeByValue = false; @Nullable private SerializationDelegate serialization; public ConcurrentMapCacheManager() { } public ConcurrentMapCacheManager(String... cacheNames) { this.setCacheNames(Arrays.asList(cacheNames)); } public void setCacheNames(@Nullable Collection<String> cacheNames) { if (cacheNames != null) { Iterator var2 = cacheNames.iterator(); while(var2.hasNext()) { String name = (String)var2.next(); this.cacheMap.put(name, this.createConcurrentMapCache(name)); } this.dynamic = false; } else { this.dynamic = true; } } public void setAllowNullValues(boolean allowNullValues) { if (allowNullValues != this.allowNullValues) { this.allowNullValues = allowNullValues; this.recreateCaches(); } } public boolean isAllowNullValues() { return this.allowNullValues; } public void setStoreByValue(boolean storeByValue) { if (storeByValue != this.storeByValue) { this.storeByValue = storeByValue; this.recreateCaches(); } } public boolean isStoreByValue() { return this.storeByValue; } public void setBeanClassLoader(ClassLoader classLoader) { this.serialization = new SerializationDelegate(classLoader); if (this.isStoreByValue()) { this.recreateCaches(); } } public Collection<String> getCacheNames() { return Collections.unmodifiableSet(this.cacheMap.keySet()); } @Nullable public Cache getCache(String name) { Cache cache = (Cache)this.cacheMap.get(name); if (cache == null && this.dynamic) { ConcurrentMap var3 = this.cacheMap; synchronized(this.cacheMap) { cache = (Cache)this.cacheMap.get(name); if (cache == null) { cache = this.createConcurrentMapCache(name); this.cacheMap.put(name, cache); } } } return cache; } private void recreateCaches() { Iterator var1 = this.cacheMap.entrySet().iterator(); while(var1.hasNext()) { Entry<String, Cache> entry = (Entry)var1.next(); entry.setValue(this.createConcurrentMapCache((String)entry.getKey())); } } protected Cache createConcurrentMapCache(String name) { SerializationDelegate actualSerialization = this.isStoreByValue() ? this.serialization : null; return new ConcurrentMapCache(name, new ConcurrentHashMap(256), this.isAllowNullValues(), actualSerialization); } }
    package org.springframework.cache.concurrent;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentMap;
    import java.util.function.Function;
    import org.springframework.cache.Cache.ValueRetrievalException;
    import org.springframework.cache.Cache.ValueWrapper;
    import org.springframework.cache.support.AbstractValueAdaptingCache;
    import org.springframework.core.serializer.support.SerializationDelegate;
    import org.springframework.lang.Nullable;
    import org.springframework.util.Assert;
    
    public class ConcurrentMapCache extends AbstractValueAdaptingCache {
        private final String name;
        private final ConcurrentMap<Object, Object> store;  //真正存数据的地方
        @Nullable
        private final SerializationDelegate serialization;
    
        public ConcurrentMapCache(String name) {
            this(name, new ConcurrentHashMap(256), true);
        }
    
        public ConcurrentMapCache(String name, boolean allowNullValues) {
            this(name, new ConcurrentHashMap(256), allowNullValues);
        }
    
        public ConcurrentMapCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues) {
            this(name, store, allowNullValues, (SerializationDelegate)null);
        }
    
        protected ConcurrentMapCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues, @Nullable SerializationDelegate serialization) {
            super(allowNullValues);
            Assert.notNull(name, "Name must not be null");
            Assert.notNull(store, "Store must not be null");
            this.name = name;
            this.store = store;
            this.serialization = serialization;
        }
    
        public final boolean isStoreByValue() {
            return this.serialization != null;
        }
    
        public final String getName() {
            return this.name;
        }
    
        public final ConcurrentMap<Object, Object> getNativeCache() {
            return this.store;
        }
    
        @Nullable
        protected Object lookup(Object key) {
            return this.store.get(key);
        }
    
        @Nullable
        public <T> T get(Object key, Callable<T> valueLoader) {
            return this.fromStoreValue(this.store.computeIfAbsent(key, (r) -> {
                try {
                    return this.toStoreValue(valueLoader.call());
                } catch (Throwable var5) {
                    throw new ValueRetrievalException(key, valueLoader, var5);
                }
            }));
        }
    
        public void put(Object key, @Nullable Object value) {
            this.store.put(key, this.toStoreValue(value));
        }
    
        @Nullable
        public ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
            Object existing = this.store.putIfAbsent(key, this.toStoreValue(value));
            return this.toValueWrapper(existing);
        }
    
        public void evict(Object key) {
            this.store.remove(key);
        }
    
        public void clear() {
            this.store.clear();
        }
    
        protected Object toStoreValue(@Nullable Object userValue) {
            Object storeValue = super.toStoreValue(userValue);
            if (this.serialization != null) {
                try {
                    return this.serializeValue(this.serialization, storeValue);
                } catch (Throwable var4) {
                    throw new IllegalArgumentException("Failed to serialize cache value '" + userValue + "'. Does it implement Serializable?", var4);
                }
            } else {
                return storeValue;
            }
        }
    
        private Object serializeValue(SerializationDelegate serialization, Object storeValue) throws IOException {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
    
            byte[] var4;
            try {
                serialization.serialize(storeValue, out);
                var4 = out.toByteArray();
            } finally {
                out.close();
            }
    
            return var4;
        }
    
        protected Object fromStoreValue(@Nullable Object storeValue) {
            if (storeValue != null && this.serialization != null) {
                try {
                    return super.fromStoreValue(this.deserializeValue(this.serialization, storeValue));
                } catch (Throwable var3) {
                    throw new IllegalArgumentException("Failed to deserialize cache value '" + storeValue + "'", var3);
                }
            } else {
                return super.fromStoreValue(storeValue);
            }
        }
    
        private Object deserializeValue(SerializationDelegate serialization, Object storeValue) throws IOException {
            ByteArrayInputStream in = new ByteArrayInputStream((byte[])((byte[])storeValue));
    
            Object var4;
            try {
                var4 = serialization.deserialize(in);
            } finally {
                in.close();
            }
    
            return var4;
        }
    }
    package org.springframework.cache.interceptor;
    
    public abstract class CacheAspectSupport extends AbstractCacheInvoker implements BeanFactoryAware, InitializingBean, SmartInitializingSingleton {
        @Nullable
        private Object execute(CacheOperationInvoker invoker, Method method, CacheAspectSupport.CacheOperationContexts contexts) {
            if (contexts.isSynchronized()) {
                CacheAspectSupport.CacheOperationContext context = (CacheAspectSupport.CacheOperationContext)contexts.get(CacheableOperation.class).iterator().next();
                if (this.isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
                    Object key = this.generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
                    Cache cache = (Cache)context.getCaches().iterator().next();
    
                    try {
                        return this.wrapCacheValue(method, cache.get(key, () -> {
                            return this.unwrapReturnValue(this.invokeOperation(invoker));
                        }));
                    } catch (ValueRetrievalException var10) {
                        throw (ThrowableWrapper)var10.getCause();
                    }
                } else {
                    return this.invokeOperation(invoker);
                }
            } else {
                this.processCacheEvicts(contexts.get(CacheEvictOperation.class), true, CacheOperationExpressionEvaluator.NO_RESULT);
                ValueWrapper cacheHit = this.findCachedItem(contexts.get(CacheableOperation.class));
                List<CacheAspectSupport.CachePutRequest> cachePutRequests = new LinkedList();
                if (cacheHit == null) {
                    this.collectPutRequests(contexts.get(CacheableOperation.class), CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
                }
    
                Object cacheValue;
                Object returnValue;
                if (cacheHit != null && !this.hasCachePut(contexts)) {
                    cacheValue = cacheHit.get();
                    returnValue = this.wrapCacheValue(method, cacheValue);
                } else {
                    returnValue = this.invokeOperation(invoker);
                    cacheValue = this.unwrapReturnValue(returnValue);
                }
    
                this.collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);
                Iterator var8 = cachePutRequests.iterator();
    
                while(var8.hasNext()) {
                    CacheAspectSupport.CachePutRequest cachePutRequest = (CacheAspectSupport.CachePutRequest)var8.next();
                    cachePutRequest.apply(cacheValue);
                }
    
                this.processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);
                return returnValue;
            }
        }
    
    
    private void performCacheEvict(CacheAspectSupport.CacheOperationContext context, CacheEvictOperation operation, @Nullable Object result) {
            Object key = null;
            Iterator var5 = context.getCaches().iterator();
    
            while(var5.hasNext()) {
                Cache cache = (Cache)var5.next();
                if (operation.isCacheWide()) {
                    this.logInvalidating(context, operation, (Object)null);
                    this.doClear(cache);
                } else {
                    if (key == null) {
                        key = this.generateKey(context, result);
                    }
    
                    this.logInvalidating(context, operation, key);
                    this.doEvict(cache, key);
                }
            }
    
        }
    
    
    }

    Key生成策略

    package org.springframework.cache.interceptor;
    
    import java.lang.reflect.Method;
    
    public class SimpleKeyGenerator implements KeyGenerator {
        public SimpleKeyGenerator() {
        }
    
        public Object generate(Object target, Method method, Object... params) {
            return generateKey(params);
        }
    
        public static Object generateKey(Object... params) {
            if (params.length == 0) {
                return SimpleKey.EMPTY;
            } else {
                if (params.length == 1) {
                    Object param = params[0];
                    if (param != null && !param.getClass().isArray()) {
                        return param;
                    }
                }
    
                return new SimpleKey(params);
            }
        }
    }

  • 相关阅读:
    【移动开发】Android应用程序中实用的代码框架(二)
    使用ListView应该注意的地方
    使用ListView应该注意的地方
    web技术文章
    [LeetCode] 565. Array Nesting
    [LeetCode]495. Teemo Attacking
    south 命令学习
    关于access_token过期的解决办法
    决策树总结《一》.md
    crontab命令
  • 原文地址:https://www.cnblogs.com/guchunchao/p/10091294.html
Copyright © 2011-2022 走看看