spring boot 源码解析35-CacheStatisticsProvider,CacheStatistics

前言

讲过前面2篇文章的讲解,我们知道了spring boot 是如何集成spring cache的,那么我们接着来看一下org.springframework.boot.actuate.cache 中有关cache的实现.这部分的类图如下:

类图

我们本文关于CacheStatisticsProvider的实现只讲解EhCacheStatisticsProvider,ConcurrentMapCacheStatisticsProvider,其它的实现也是差不多的,这里就不解析了

本文的最后,我们来看一下CachePublicMetrics的实现(这才是我们的目的)

解析

CacheStatistics

CacheStatistics–>对于给定cache的统计快照,CacheStatistics 的实例有非常短的生命周期,它只代表在特定时间内的缓存统计.该接口声明了如下方法:

// 通过指定的前缀生成相关的Metric
Collection<Metric<?>> toMetrics(String prefix);

// 返回缓存的大小
Long getSize();

// 返回缓存命中率,其值为0至1之间,0 意味着命中率为0% , 1-->缓存命中率100%,返回null--> 当前的CacheStatistics 没有提供必要的信息
Double getHitRatio();

// 缓存丢失率,返回值在0至1之间,0-->缺失率0%, 1--> 缺失率100%,null--> 当前的CacheStatistics 没有提供必要的信息
Double getMissRatio();

DefaultCacheStatistics

DefaultCacheStatistics–> CacheStatistics的唯一实现

  1. 字段如下:

    // 缓存大小
    private Long size;
    
    // 缓存命中率
    private Double hitRatio;
    
    // 缓存缺失率
    private Double missRatio;
  2. 方法实现如下:

    1. toMetrics,代码如下:

      public Collection<Metric<?>> toMetrics(String prefix) {
          Collection<Metric<?>> result = new ArrayList<Metric<?>>();
          addMetric(result, prefix + "size", getSize());
          addMetric(result, prefix + "hit.ratio", getHitRatio());
          addMetric(result, prefix + "miss.ratio", getMissRatio());
          return result;
      }

      向结果集中添加缓存大小,缓存命中率,缓存缺失率的Metric.

      addMetric,代码如下:

      private <T extends Number> void addMetric(Collection<Metric<?>> metrics, String name,
              T value) {
          if (value != null) {
              metrics.add(new Metric<T>(name, value));
          }
      }
    2. getSize,getHitRatio,getMissRatio 方法只需返回该类所持有的字段即可.代码如下:

      public Long getSize() {
          return this.size;
      }
      
      public Double getHitRatio() {
          return this.hitRatio;
      }
      
      public Double getMissRatio() {
          return this.missRatio;
      }
  3. 此外还声明1个setGetCacheCounts(设置缓存命中率,缓存缺失率的方法)的方法,代码如下:

    public void setGetCacheCounts(long hitCount, long missCount) {
        long total = hitCount + missCount;
        if (total > 0) {
            double hitRatio = hitCount / (double) total;
            setHitRatio(hitRatio);
            setMissRatio(1 - hitRatio);
        }
    }
    1. 计算缓存的请求数(total)=hitCount+missCount
    2. 如果total大于0,则计算缓存命中率(hitCount/total),缓存缺失率(1-hitRatio)并赋值

CacheStatisticsProvider

CacheStatisticsProvider–>根据cache提供对应的CacheStatistics的接口,该接口是1个泛型接口,其泛型参数如下:

CacheStatisticsProvider<C extends Cache>

限定只能是Cache的子类.该类只声明了1个方法,如下:

// 根据给定的Cache 返回 CacheStatistics 的快照,返回null --> 如果给定的cache不能进行处理的话
CacheStatistics getCacheStatistics(CacheManager cacheManager, C cache);

ConcurrentMapCacheStatisticsProvider

ConcurrentMapCacheStatisticsProvider–>提供ConcurrentMapCache对应的CacheStatistics的实现.

  1. 该类的声明如下:

    public class ConcurrentMapCacheStatisticsProvider
        implements CacheStatisticsProvider<ConcurrentMapCache>

    泛型参数为ConcurrentMapCache

  2. 方法实现如下:

    public CacheStatistics getCacheStatistics(CacheManager cacheManager,
            ConcurrentMapCache cache) {
        DefaultCacheStatistics statistics = new DefaultCacheStatistics();
        statistics.setSize((long) cache.getNativeCache().size());
        return statistics;
    }

    方法逻辑很简单,直接实例化DefaultCacheStatistics,然后将ConcurrentMapCache中的缓存用的map的size赋值给DefaultCacheStatistics即可. 没有提供缓存命中率,缓存缺失率的统计

  3. 自动装配:

    声明在ConcurrentMapCacheStatisticsConfiguration中,代码如下:

    @Configuration
    @ConditionalOnClass(ConcurrentMapCache.class)
    static class ConcurrentMapCacheStatisticsConfiguration {
    
        @Bean
        public ConcurrentMapCacheStatisticsProvider concurrentMapCacheStatisticsProvider() {
            return new ConcurrentMapCacheStatisticsProvider();
        }
    
    }
    1. 由于ConcurrentMapCacheStatisticsConfiguration是CacheStatisticsAutoConfiguration的静态内部类.而在CacheStatisticsAutoConfiguration中声明了如下注解:

      @Configuration
      @AutoConfigureAfter(CacheAutoConfiguration.class)
      @ConditionalOnBean(CacheManager.class)

      因此,当BeanFactory中存在CacheManager类型的bean时ConcurrentMapCacheStatisticsConfiguration才会生效.

    2. @ConditionalOnClass(ConcurrentMapCache.class) –> 当ConcurrentMapCache.class在当前类路径下时生效.

EhCacheStatisticsProvider

EhCacheStatisticsProvider–> 提供EhCacheCache对应的CacheStatistics的实现

  1. getCacheStatistics 实现如下:

    public CacheStatistics getCacheStatistics(CacheManager cacheManager,
            EhCacheCache cache) {
        DefaultCacheStatistics statistics = new DefaultCacheStatistics();
        // 1. 获得StatisticsGateway
        StatisticsGateway ehCacheStatistics = cache.getNativeCache().getStatistics();
        // 2. 设置size
        statistics.setSize(ehCacheStatistics.getSize());
        // 3. 计算缓存命中率,如果其值没有溢出的话,则设置缓存命中率和缓存缺失率
        double hitRatio = cacheHitRatio(ehCacheStatistics);
        if (!Double.isNaN(hitRatio)) {
            // ratio is calculated 'racily' and can drift marginally above unity,
            // so we cap it here
            double sanitizedHitRatio = (hitRatio > 1 ? 1 : hitRatio);
            statistics.setHitRatio(sanitizedHitRatio);
            statistics.setMissRatio(1 - sanitizedHitRatio);
        }
        return statistics;
    }
    1. 获得StatisticsGateway
    2. 设置size
    3. 计算缓存命中率,如果其值没有溢出的话,则设置缓存命中率和缓存缺失率.代码如下:

      private double cacheHitRatio(StatisticsGateway stats) {
          long hitCount = stats.cacheHitCount();
          long missCount = stats.cacheMissCount();
          return ((double) hitCount) / (hitCount + missCount);
      }
  2. 自动装配:

    同样,也是声明在CacheStatisticsAutoConfiguration的静态内部类中–>EhCacheCacheStatisticsProviderConfiguration.代码如下:

    @Configuration
    @ConditionalOnClass({ EhCacheCache.class, Ehcache.class, StatisticsGateway.class })
    static class EhCacheCacheStatisticsProviderConfiguration {
    
        @Bean
        public EhCacheStatisticsProvider ehCacheCacheStatisticsProvider() {
            return new EhCacheStatisticsProvider();
        }
    
    }

    因此,当满足如下条件时生效:

    1. BeanFactory中存在CacheManager类型的bean
    2. 在当前的类路径下存在 EhCacheCache.class, Ehcache.class, StatisticsGateway.class

CachePublicMetrics

CachePublicMetrics–>提供缓存统计的PublicMetrics实现,实现了PublicMetrics接口.

  1. 字段,构造器如下:

    // key--> cacheManager bean 对应的id,value --> CacheManager
    @Autowired
    private Map<String, CacheManager> cacheManagers;
    
    @Autowired
    // beanFactory中所有类型为CacheStatisticsProvider的bean
    private Collection<CacheStatisticsProvider<?>> statisticsProviders;
    
    // 1.5.4 版本废弃
    @Deprecated
    public CachePublicMetrics() {
    }
    
    public CachePublicMetrics(Map<String, CacheManager> cacheManagers,
            Collection<CacheStatisticsProvider<?>> statisticsProviders) {
        this.cacheManagers = cacheManagers;
        this.statisticsProviders = statisticsProviders;
    }
  2. metrics,实现如下:

    public Collection<Metric<?>> metrics() {
        Collection<Metric<?>> metrics = new HashSet<Metric<?>>();
    
        for (Map.Entry<String, List<CacheManagerBean>> entry : getCacheManagerBeans()
                .entrySet()) {
            addMetrics(metrics, entry.getKey(), entry.getValue());
        }
        return metrics;
    }
    1. 遍历cacheManagers,获得key–> 缓存集名称,value–>CacheManagerBean(CacheManager对应的id,CacheManager 的封装).代码如下:

      private MultiValueMap<String, CacheManagerBean> getCacheManagerBeans() {
          // key--> 缓存集名称,value--> CacheManager对应的id,CacheManager 的封装
          MultiValueMap<String, CacheManagerBean> cacheManagerNamesByCacheName = new LinkedMultiValueMap<String, CacheManagerBean>();
          // 1. 遍历cacheManagers依次进行处理
          for (Map.Entry<String, CacheManager> entry : this.cacheManagers.entrySet()) {
              // 2. 遍历CacheManager的CacheNames 依次进行处理
              for (String cacheName : entry.getValue().getCacheNames()) {
                  cacheManagerNamesByCacheName.add(cacheName,
                          new CacheManagerBean(entry.getKey(), entry.getValue()));
              }
          }
          return cacheManagerNamesByCacheName;
      }
      1. 遍历cacheManagers依次进行处理
      2. 遍历CacheManager的CacheNames依次将其添加到结果集中

      其中,CacheManagerBean 就是对CacheManager的封装.代码如下:

      private static class CacheManagerBean {
      
          private final String beanName;
      
          private final CacheManager cacheManager;
      
          CacheManagerBean(String beanName, CacheManager cacheManager) {
              this.beanName = beanName;
              this.cacheManager = cacheManager;
          }
      
          public String getBeanName() {
              return this.beanName;
          }
      
          public CacheManager getCacheManager() {
              return this.cacheManager;
          }
      }
    2. 遍历第1步的结果,依次调用addMetrics方法进行添加,代码如下:

      private void addMetrics(Collection<Metric<?>> metrics, String cacheName,
              List<CacheManagerBean> cacheManagerBeans) {
          for (CacheManagerBean cacheManagerBean : cacheManagerBeans) {
              // 1. 获得对应的CacheManager
              CacheManager cacheManager = cacheManagerBean.getCacheManager();
              // 2. 获得cacheName所对应的Cache
              Cache cache = unwrapIfNecessary(cacheManager.getCache(cacheName));
              // 3. 根据cache和cacheManager 获得 对应的CacheStatistics
              CacheStatistics statistics = getCacheStatistics(cache, cacheManager);
              if (statistics != null) {
                  // 4. 如果statistics不等于null,则生成前缀后加入到metrics中
                  String prefix = cacheName;
                  if (cacheManagerBeans.size() > 1) {
                      prefix = cacheManagerBean.getBeanName() + "_" + prefix;
                  }
                  prefix = "cache." + prefix + (prefix.endsWith(".") ? "" : ".");
                  metrics.addAll(statistics.toMetrics(prefix));
              }
          }
      }
      1. 获得对应的CacheManager
      2. 获得cacheName所对应的Cache,其中调用了unwrapIfNecessary,代码如下:

        private Cache unwrapIfNecessary(Cache cache) {
            if (ClassUtils.isPresent(
                    "org.springframework.cache.transaction.TransactionAwareCacheDecorator",
                    getClass().getClassLoader())) {
                return TransactionAwareCacheDecoratorHandler.unwrapIfNecessary(cache);
            }
            return cache;
        }
        1. 如果在当前类路径下存在org.springframework.cache.transaction.TransactionAwareCacheDecorator,则通过TransactionAwareCacheDecoratorHandler来获得cache. 由于在项目中加入了spring-boot-starter-cache,因此间接的引入了spring-context-support,TransactionAwareCacheDecorator就在此包中.因此,这里是会执行的
        2. 否则,直接返回.

        TransactionAwareCacheDecoratorHandler#unwrapIfNecessary 实现如下:

        private static Cache unwrapIfNecessary(Cache cache) {
            try {
                if (cache instanceof TransactionAwareCacheDecorator) {
                    return ((TransactionAwareCacheDecorator) cache).getTargetCache();
                }
            }
            catch (NoClassDefFoundError ex) {
                // Ignore
            }
            return cache;
        }

        如果是TransactionAwareCacheDecorator的实例,则直接获得其持有的cache,否则,直接返回

      3. 根据cache和cacheManager 获得 对应的CacheStatistics.代码如下:

        private CacheStatistics getCacheStatistics(Cache cache, CacheManager cacheManager) {
            if (this.statisticsProviders != null) {
                // 1. 如果statisticsProviders 不等于null,则依次遍历之
                for (CacheStatisticsProvider provider : this.statisticsProviders) {
                    // 2. 获得CacheStatisticsProvider的泛型参数,如果其泛型参数类型和指定的Cache类似的话,则调用CacheStatisticsProvider#getCacheStatistics
                    // 获得对应的CacheStatistics
                    Class<?> cacheType = ResolvableType
                            .forClass(CacheStatisticsProvider.class, provider.getClass())
                            .resolveGeneric();
                    if (cacheType.isInstance(cache)) {
                        CacheStatistics statistics = provider.getCacheStatistics(cacheManager,
                                cache);
                        if (statistics != null) {
                            return statistics;
                        }
                    }
                }
            }
            return null;
        }
        1. 如果statisticsProviders 不等于null,则依次遍历之
        2. 获得CacheStatisticsProvider的泛型参数,如果其泛型参数类型和指定的Cache类似的话,则调用CacheStatisticsProvider#getCacheStatistics获得对应的CacheStatistics
      4. 如果statistics不等于null

        1. 如果cacheManagerBeans有多个,则prefix= CacheManager bean 的id+”_”+cacheName
        2. 在prefix前加上cache.的前缀
      5. 生成Metrics后加入到结果集中

  3. 自动装配:

    声明在CacheStatisticsConfiguration中,代码如下:

    @Configuration
    @ConditionalOnClass(CacheManager.class)
    @ConditionalOnBean(CacheManager.class)
    static class CacheStatisticsConfiguration {
    
        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnBean(CacheStatisticsProvider.class)
        public CachePublicMetrics cachePublicMetrics(
                Map<String, CacheManager> cacheManagers,
                Collection<CacheStatisticsProvider<?>> statisticsProviders) {
            return new CachePublicMetrics(cacheManagers, statisticsProviders);
        }
    
    }

    当满足以下条件时生效:

    1. @ConditionalOnClass(CacheManager.class)–>在当前类路径下存在CacheManager.class时生效
    2. @ConditionalOnBean(CacheManager.class)–> 在BeanFactory中存在CacheManager类型的bean时生效
    3. @ConditionalOnMissingBean –> BeanFactory中不存在CachePublicMetrics类型的bean时生效
    4. @ConditionalOnBean(CacheStatisticsProvider.class)–> 在BeanFactory中存在CacheStatisticsProvider类型的bean时生效
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值