Springboot Actuator的组件编写
前置说明
因为之前编写了redis-starter以及cache-starter, 然后最近有学习了springboot的actuator相关的知识,了解到springboot自己的spring-boot-starter-data-redis是有redis的健康状态监测的,然后spring-boot-starter-cache也有关于缓存命中的相关信息暴露,所以也想到了自己写的starter也加上相关的信息暴露并整合到springboot的actuator中进行暴露.
相关概念了解
-
RedisHealthIndicator
这个就是spring-boot-starter-data-redis提供的关于redis健康检测信息提供类,待会儿我也会模仿写一个. -
CacheStatisticsProvider,CacheStatistics
这两个就是spring-boot-starter-cache提供的,一个是缓存信息的提供类,一个是spring提供的缓存统计持有类.
CustomRedisHealthIndicator编写
首先 可以参考以下spring自身对redis健康检测的实现RedisHealthIndicator
...
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
RedisConnection connection = RedisConnectionUtils
.getConnection(this.redisConnectionFactory);
try {
if (connection instanceof RedisClusterConnection) {
ClusterInfo clusterInfo = ((RedisClusterConnection) connection)
.clusterGetClusterInfo();
builder.up().withDetail("cluster_size", clusterInfo.getClusterSize())
.withDetail("slots_up", clusterInfo.getSlotsOk())
.withDetail("slots_fail", clusterInfo.getSlotsFail());
}
else {
Properties info = connection.info();
builder.up().withDetail(VERSION, info.getProperty(REDIS_VERSION));
}
}
finally {
RedisConnectionUtils.releaseConnection(connection,
this.redisConnectionFactory);
}
}
...
可以看出其实主要是调用info接口来获取redis的信息,然后继续暴露.
我们继续模仿,如下面的代码所示
public class CustomRedisHealthIndicator extends AbstractHealthIndicator {
@Autowired
RedisUtil redisUtil;
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
try (Jedis jedis = redisUtil.getJedis()){
String info = jedis.info();
builder.up().withDetail("info", info);
}
}
}
这里简单的把info直接返回即可,然后将其进行自动装配,我们可以将自动装配的时间放到springboot的HealthIndicatorAutoConfiguration自动装配之前,这样可以确保我们的Indicator能被聚合进去,进行统一的展示, 代码如下
@AutoConfigureBefore(HealthIndicatorAutoConfiguration. class)
@Configuration
@ConditionalOnProperty(value = "redis.health", havingValue = "true")
public class CustomRedisHealthConfiguration {
@Bean
public CustomRedisHealthIndicator customRedisHealthIndicator(){
return new CustomRedisHealthIndicator();
}
}
CustomCachePublicMetrics编写
照理,还是先参考spring 的实现CachePublicMetrics
...
@Override
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;
}
...
private void addMetrics(Collection<Metric<?>> metrics, String cacheName,
List<CacheManagerBean> cacheManagerBeans) {
for (CacheManagerBean cacheManagerBean : cacheManagerBeans) {
CacheManager cacheManager = cacheManagerBean.getCacheManager();
Cache cache = unwrapIfNecessary(cacheManager.getCache(cacheName));
//获取信息
CacheStatistics statistics = getCacheStatistics(cache, cacheManager);
if (statistics != null) {
String prefix = cacheName;
if (cacheManagerBeans.size() > 1) {
prefix = cacheManagerBean.getBeanName() + "_" + prefix;
}
prefix = "cache." + prefix + (prefix.endsWith(".") ? "" : ".");
metrics.addAll(statistics.toMetrics(prefix));
}
}
}
...
@SuppressWarnings({ "rawtypes", "unchecked" })
private CacheStatistics getCacheStatistics(Cache cache, CacheManager cacheManager) {
if (this.statisticsProviders != null) {
for (CacheStatisticsProvider provider : this.statisticsProviders) {
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;
}
...
可以看到信息主要是从provider获取,随便看一个ConcurrentMapCacheStatisticsProvider
public class ConcurrentMapCacheStatisticsProvider
implements CacheStatisticsProvider<ConcurrentMapCache> {
@Override
public CacheStatistics getCacheStatistics(CacheManager cacheManager,
ConcurrentMapCache cache) {
DefaultCacheStatistics statistics = new DefaultCacheStatistics();
statistics.setSize((long) cache.getNativeCache().size());
return statistics;
}
}
因为我们实现的cache并没有用到spring的接口cacheManage和cache,所以就大概实现类似的功能如下
@AllArgsConstructor
public class CustomCacheStatistucsProvider {
private CacheUtil cacheUtil;
private CacheSupport cacheSupport;
private CacheProperties cacheProperties;
public CacheStatistics getCacheStatistics() {
DefaultCacheStatistics statistics = new DefaultCacheStatistics();
statistics.setSize((long) cacheUtil.size(cacheProperties.getPrefix() + "*")); //缓存个数
double hitRatio = cacheSupport.getSuccess().doubleValue() / cacheSupport.getTotal().doubleValue();
statistics.setHitRatio(hitRatio); //命中概率
statistics.setMissRatio(1 - hitRatio); //未命中概率
return statistics;
}
}
然后创建一个暴露类
public class CustomCachePublicMetrics implements PublicMetrics {
CustomCacheStatistucsProvider customCacheStatistucsProvider;
@Override
public Collection<Metric<?>> metrics() {
CacheStatistics cacheStatistics = customCacheStatistucsProvider.getCacheStatistics();
Collection<Metric<?>> metrics = cacheStatistics.toMetrics("cache.");
return metrics;
}
}
然后编写自动配置类,按照惯例其配置顺序在PublicMetricsAutoConfiguration之前
@AutoConfigureBefore(PublicMetricsAutoConfiguration.class)
@Configuration
@ConditionalOnProperty("cache.metric")
public class CustomCachePublicMetricsConfiguration {
@Bean
public CustomCacheStatistucsProvider customCacheStatistucsProvider(){
return new CustomCacheStatistucsProvider();
}
@Bean
public CustomCachePublicMetrics customCachePublicMetrics(){
return new CustomCachePublicMetrics();
}
}
这样我们的代码就基本编写完毕了.别忘了在spring.factories加上相关的配置类.