您的位置:首页 > 编程语言 > Java开发

spring boot 源码解析35-CacheStatisticsProvider,CacheStatistics

2018-01-24 13:16 831 查看

前言

讲过前面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的唯一实现

字段如下:

// 缓存大小
private Long size;

// 缓存命中率
private Double hitRatio;

// 缓存缺失率
private Double missRatio;


方法实现如下:

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


getSize,getHitRatio,getMissRatio 方法只需返回该类所持有的字段即可.代码如下:

public Long getSize() {
return this.size;
}

public Double getHitRatio() {
return this.hitRatio;
}

public Double getMissRatio() {
return this.missRatio;
}


此外还声明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);
}
}


计算缓存的请求数(total)=hitCount+missCount

如果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的实现.

该类的声明如下:

public class ConcurrentMapCacheStatisticsProvider
implements CacheStatisticsProvider<ConcurrentMapCache>


泛型参数为ConcurrentMapCache

方法实现如下:

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


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

自动装配:

声明在ConcurrentMapCacheStatisticsConfiguration中,代码如下:

@Configuration
@ConditionalOnClass(ConcurrentMapCache.class)
static class ConcurrentMapCacheStatisticsConfiguration {

@Bean
public ConcurrentMapCacheStatisticsProvider concurrentMapCacheStatisticsProvider() {
return new ConcurrentMapCacheStatisticsProvider();
}

}


由于ConcurrentMapCacheStatisticsConfiguration是CacheStatisticsAutoConfiguration的静态内部类.而在CacheStatisticsAutoConfiguration中声明了如下注解:

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


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

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

EhCacheStatisticsProvider

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

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


获得StatisticsGateway

设置size

计算缓存命中率,如果其值没有溢出的话,则设置缓存命中率和缓存缺失率.代码如下:

private double cacheHitRatio(StatisticsGateway stats) {
long hitCount = stats.cacheHitCount();
long missCount = stats.cacheMissCount();
return ((double) hitCount) / (hitCount + missCount);
}


自动装配:

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

@Configuration
@ConditionalOnClass({ EhCacheCache.class, Ehcache.class, StatisticsGateway.class })
static class EhCacheCacheStatisticsProviderConfiguration {

@Bean
public EhCacheStatisticsProvider ehCacheCacheStatisticsProvider() {
return new EhCacheStatisticsProvider();
}

}


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

BeanFactory中存在CacheManager类型的bean

在当前的类路径下存在 EhCacheCache.class, Ehcache.class, StatisticsGateway.class

CachePublicMetrics

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

字段,构造器如下:

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


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


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


遍历cacheManagers依次进行处理

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


遍历第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));
}
}
}


获得对应的CacheManager

获得cacheName所对应的Cache,其中调用了unwrapIfNecessary,代码如下:

private Cache unwrapIfNecessary(Cache cache) {
if (ClassUtils.isPresent(
"org.springframework.cache.transaction.TransactionAwareCacheDecorator",
getClass().getClassLoader())) {
return TransactionAwareCacheDecoratorHandler.unwrapIfNecessary(cache);
}
return cache;
}


如果在当前类路径下存在org.springframework.cache.transaction.TransactionAwareCacheDecorator,则通过TransactionAwareCacheDecoratorHandler来获得cache. 由于在项目中加入了spring-boot-starter-cache,因此间接的引入了spring-context-support,TransactionAwareCacheDecorator就在此包中.因此,这里是会执行的

否则,直接返回.

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,否则,直接返回

根据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 =
ad73
ResolvableType
.forClass(CacheStatisticsProvider.class, provider.getClass())
.resolveGeneric();
if (cacheType.isInstance(cache)) {
CacheStatistics statistics = provider.getCacheStatistics(cacheManager,
cache);
if (statistics != null) {
return statistics;
}
}
}
}
return null;
}


如果statisticsProviders 不等于null,则依次遍历之

获得CacheStatisticsProvider的泛型参数,如果其泛型参数类型和指定的Cache类似的话,则调用CacheStatisticsProvider#getCacheStatistics获得对应的CacheStatistics

如果statistics不等于null

如果cacheManagerBeans有多个,则prefix= CacheManager bean 的id+”_”+cacheName

在prefix前加上cache.的前缀

生成Metrics后加入到结果集中

自动装配:

声明在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);
}

}


当满足以下条件时生效:

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

@ConditionalOnBean(CacheManager.class)–> 在BeanFactory中存在CacheManager类型的bean时生效

@ConditionalOnMissingBean –> BeanFactory中不存在CachePublicMetrics类型的bean时生效

@ConditionalOnBean(CacheStatisticsProvider.class)–> 在BeanFactory中存在CacheStatisticsProvider类型的bean时生效
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring 源码 缓存 class