Ver código fonte

新增缓存监控

zhouhao 8 anos atrás
pai
commit
4c41891d5e

+ 4 - 0
hsweb-web-concurrent/hsweb-web-concurrent-cache/pom.xml

@@ -21,5 +21,9 @@
             <artifactId>spring-boot-starter-redis</artifactId>
             <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>org.hsweb</groupId>
+            <artifactId>hsweb-web-core</artifactId>
+        </dependency>
     </dependencies>
 </project>

+ 3 - 17
hsweb-web-concurrent/hsweb-web-concurrent-cache/src/main/java/org/hsweb/concureent/cache/ConcurrentMapCacheManagerAutoConfig.java

@@ -1,5 +1,6 @@
 package org.hsweb.concureent.cache;
 
+import org.hsweb.concureent.cache.monitor.SimpleMonitorCache;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
 import org.springframework.cache.Cache;
 import org.springframework.cache.CacheManager;
@@ -20,16 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
 public class ConcurrentMapCacheManagerAutoConfig extends CachingConfigurerSupport {
     @Bean
     public KeyGenerator keyGenerator() {
-        return (target, method, params) -> {
-            StringBuilder sb = new StringBuilder();
-            sb.append(target.getClass().getName());
-            sb.append(method.getName());
-            for (Object obj : params) {
-                if (obj == null) obj = "null";
-                sb.append(obj.hashCode());
-            }
-            return sb.toString();
-        };
+        return new SimpleKeyGenerator();
     }
 
     @Bean
@@ -37,13 +29,7 @@ public class ConcurrentMapCacheManagerAutoConfig extends CachingConfigurerSuppor
         SimpleCacheManager cacheManager = new SimpleCacheManager() {
             @Override
             protected Cache getMissingCache(String name) {
-                return new ConcurrentMapCache(name, false) {
-                    @Override
-                    public void put(Object key, Object value) {
-                        if (key == null || value == null) return;
-                        super.put(key, value);
-                    }
-                };
+                return new SimpleMonitorCache(name);
             }
         };
         cacheManager.setCaches(new HashSet<>());

+ 3 - 12
hsweb-web-concurrent/hsweb-web-concurrent-cache/src/main/java/org/hsweb/concureent/cache/RedisCacheManagerAutoConfig.java

@@ -34,22 +34,13 @@ public class RedisCacheManagerAutoConfig extends CachingConfigurerSupport {
 
     @Bean
     public KeyGenerator wiselyKeyGenerator() {
-        return (target, method, params) -> {
-            StringBuilder sb = new StringBuilder();
-            sb.append(target.getClass().getName());
-            sb.append(method.getName());
-            for (Object obj : params) {
-                if (obj == null) obj = "null";
-                sb.append(obj.hashCode());
-            }
-            return sb.toString();
-        };
+        return new SimpleKeyGenerator();
     }
 
     @Bean
     public RedisTemplate<String, String> redisTemplate(
-            RedisConnectionFactory factory) {
-        StringRedisTemplate template = new StringRedisTemplate(factory);
+            RedisConnectionFactory redisConnectionFactory) {
+        StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory);
         template.setValueSerializer(new JdkSerializationRedisSerializer());
         return template;
     }

+ 39 - 0
hsweb-web-concurrent/hsweb-web-concurrent-cache/src/main/java/org/hsweb/concureent/cache/SimpleKeyGenerator.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015-2016 http://hsweb.me
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hsweb.concureent.cache;
+
+import org.springframework.cache.interceptor.KeyGenerator;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author zhouhao
+ * @TODO
+ */
+public class SimpleKeyGenerator implements KeyGenerator {
+    @Override
+    public Object generate(Object target, Method method, Object... params) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(target.getClass().getName());
+        sb.append(method.getName());
+        for (Object obj : params) {
+            if (obj == null) obj = "null";
+            sb.append(obj.hashCode());
+        }
+        return sb.toString();
+    }
+}

+ 93 - 0
hsweb-web-concurrent/hsweb-web-concurrent-cache/src/main/java/org/hsweb/concureent/cache/monitor/SimpleMonitorCache.java

@@ -0,0 +1,93 @@
+/*
+ * Copyright 2015-2016 http://hsweb.me
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hsweb.concureent.cache.monitor;
+
+import org.hsweb.web.core.cache.monitor.MonitorCache;
+import org.springframework.cache.concurrent.ConcurrentMapCache;
+
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class SimpleMonitorCache extends ConcurrentMapCache implements MonitorCache {
+
+    private final AtomicInteger totalTimes = new AtomicInteger(0);
+    private final AtomicInteger hitTimes = new AtomicInteger(0);
+    private final AtomicInteger putTimes = new AtomicInteger(0);
+
+    public SimpleMonitorCache(String name) {
+        super(name,false);
+    }
+
+    @Override
+    public Set<Object> keySet() {
+        return getNativeCache().keySet();
+    }
+
+    @Override
+    public int size() {
+        return getNativeCache().size();
+    }
+
+    @Override
+    public long getTotalTimes() {
+        return totalTimes.get();
+    }
+
+    @Override
+    public long getHitTimes() {
+        return hitTimes.get();
+    }
+
+    @Override
+    public ValueWrapper get(Object key) {
+        ValueWrapper wrapper = super.get(key);
+        totalTimes.addAndGet(1);
+        if (wrapper != null) {
+            hitTimes.addAndGet(1);
+        }
+        return wrapper;
+    }
+
+    @Override
+    public <T> T get(Object key, Class<T> type) {
+        T value = super.get(key, type);
+        totalTimes.addAndGet(1);
+        if (value != null) {
+            hitTimes.addAndGet(1);
+        }
+        return value;
+    }
+
+    @Override
+    public void put(Object key, Object value) {
+        if (key == null || value == null) return;
+        putTimes.addAndGet(1);
+        super.put(key, value);
+    }
+
+    @Override
+    public ValueWrapper putIfAbsent(Object key, Object value) {
+        if (key == null || value == null) return null;
+        putTimes.addAndGet(1);
+        return super.putIfAbsent(key, value);
+    }
+
+    @Override
+    public long getPutTimes() {
+        return putTimes.get();
+    }
+}

+ 191 - 0
hsweb-web-controller/src/main/java/org/hsweb/web/controller/monitor/CacheMonitorController.java

@@ -0,0 +1,191 @@
+/*
+ * Copyright 2015-2016 http://hsweb.me
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hsweb.web.controller.monitor;
+
+import org.hsweb.web.core.authorize.annotation.Authorize;
+import org.hsweb.web.core.cache.monitor.MonitorCache;
+import org.hsweb.web.core.exception.NotFoundException;
+import org.hsweb.web.core.logger.annotation.AccessLogger;
+import org.hsweb.web.core.message.ResponseMessage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * 缓存监控控制器,用于管理缓存,监控等操作
+ */
+@RestController
+@RequestMapping("/monitor")
+@Authorize(module = "monitor-cache")
+@AccessLogger("缓存监控")
+public class CacheMonitorController {
+
+    @Autowired(required = false)
+    private Map<String, CacheManager> cacheManagerMap = new LinkedHashMap<>();
+
+    @RequestMapping(value = "/caches", method = RequestMethod.GET)
+    @AccessLogger("获取管理器")
+    public ResponseMessage getManagerList() {
+        return ResponseMessage.ok(cacheManagerMap.keySet());
+    }
+
+    @RequestMapping(value = "/cache/{name}", method = RequestMethod.GET)
+    @AccessLogger("获取所有名称")
+    public ResponseMessage getNameList(@PathVariable("name") String name) {
+        CacheManager cacheManager = cacheManagerMap.get(name);
+        if (cacheManager != null) {
+            return ResponseMessage.ok(cacheManager.getCacheNames());
+        }
+        throw new NotFoundException("缓存不存在");
+    }
+
+    @AccessLogger("获取值")
+    @RequestMapping(value = "/cache/{managerName}/{cacheName}/{key:.+}", method = RequestMethod.GET)
+    public ResponseMessage getValue(@PathVariable("managerName") String managerName,
+                                    @PathVariable("cacheName") String cacheName,
+                                    @PathVariable("key") String key) {
+        Cache.ValueWrapper val = getCache(managerName, cacheName).get(key);
+        if (val != null) return ResponseMessage.ok(val.get());
+        throw new NotFoundException("值不存在");
+    }
+
+    @RequestMapping(value = "/cache/{managerName}/{cacheName}/{key:.+}", method = RequestMethod.DELETE)
+    @Authorize(action = "D")
+    @AccessLogger("删除指定key的值")
+    public ResponseMessage getEvict(@PathVariable("managerName") String managerName,
+                                    @PathVariable("cacheName") String cacheName,
+                                    @PathVariable("key") String key) {
+        getCache(managerName, cacheName).evict(key);
+        return ResponseMessage.ok();
+    }
+
+    @RequestMapping(value = "/cache/{managerName}/{cacheName}", method = RequestMethod.DELETE)
+    @Authorize(action = "D")
+    @AccessLogger("清空")
+    public ResponseMessage clearEvict(@PathVariable("managerName") String managerName,
+                                      @PathVariable("cacheName") String cacheName) {
+        getCache(managerName, cacheName).clear();
+        return ResponseMessage.ok();
+    }
+
+    @RequestMapping(value = "/cache/{managerName}/{cacheName}", method = RequestMethod.GET)
+    @AccessLogger("获取键列表")
+    public ResponseMessage getKetSet(@PathVariable("managerName") String managerName,
+                                     @PathVariable("cacheName") String cacheName) {
+        return ResponseMessage.ok(getMonitorCache(managerName, cacheName).keySet());
+    }
+
+    @AccessLogger("获取缓存命中次数")
+    @RequestMapping(value = "/cache-hits/{managerName}/{cacheName}", method = RequestMethod.GET)
+    public ResponseMessage getHitTimes(@PathVariable("managerName") String managerName,
+                                       @PathVariable("cacheName") String cacheName) {
+        return ResponseMessage.ok(getMonitorCache(managerName, cacheName).getHitTimes());
+    }
+
+    @AccessLogger("获取缓存更新次数")
+    @RequestMapping(value = "/cache-puts/{managerName}/{cacheName}", method = RequestMethod.GET)
+    public ResponseMessage getPutTimes(@PathVariable("managerName") String managerName,
+                                       @PathVariable("cacheName") String cacheName) {
+        return ResponseMessage.ok(getMonitorCache(managerName, cacheName).getPutTimes());
+    }
+
+    @AccessLogger("获取缓存数量")
+    @RequestMapping(value = "/cache-size/{managerName}/{cacheName}", method = RequestMethod.GET)
+    public ResponseMessage getSize(@PathVariable("managerName") String managerName,
+                                   @PathVariable("cacheName") String cacheName) {
+        return ResponseMessage.ok(getMonitorCache(managerName, cacheName).size());
+    }
+
+    @AccessLogger("获取缓存获取次数")
+    @RequestMapping(value = "/cache-total/{managerName}/{cacheName}", method = RequestMethod.GET)
+    public ResponseMessage getTotalTimes(@PathVariable("managerName") String managerName,
+                                         @PathVariable("cacheName") String cacheName) {
+        return ResponseMessage.ok(getMonitorCache(managerName, cacheName).getTotalTimes());
+    }
+
+    @AccessLogger("获取缓存命中总次数")
+    @RequestMapping(value = "/cache-hits", method = RequestMethod.GET)
+    public ResponseMessage getHitTimes() {
+        return ResponseMessage.ok(getTimes(MonitorCache::getHitTimes));
+    }
+
+    @AccessLogger("获取缓存更新次数")
+    @RequestMapping(value = "/cache-puts", method = RequestMethod.GET)
+    public ResponseMessage getPutTimes() {
+        return ResponseMessage.ok(getTimes(MonitorCache::getPutTimes));
+    }
+
+    @AccessLogger("获取缓存获取次数")
+    @RequestMapping(value = "/cache-total", method = RequestMethod.GET)
+    public ResponseMessage getTotalTimes() {
+        return ResponseMessage.ok(getTimes(MonitorCache::getTotalTimes));
+    }
+
+    @AccessLogger("获取缓存数量")
+    @RequestMapping(value = "/cache-size", method = RequestMethod.GET)
+    public ResponseMessage getSize() {
+        return ResponseMessage.ok(getTimes(MonitorCache::size));
+    }
+
+    public long getTimes(TimesGetter getter) {
+        long times = cacheManagerMap.values().stream()
+                .mapToLong(cacheManager -> getTimes(cacheManager, getter))
+                .reduce((i1, i2) -> i1 + i2).orElseGet(() -> 0);
+        return times;
+    }
+
+    public long getTimes(CacheManager cacheManager, TimesGetter getter) {
+        long times = cacheManager.getCacheNames().parallelStream()
+                .map(name -> cacheManager.getCache(name))
+                .filter(cache -> cache instanceof MonitorCache)
+                .map(cache -> (MonitorCache) cache)
+                .mapToLong(getter::get)
+                .reduce((i1, i2) -> i1 + i2).orElseGet(() -> 0);
+        return times;
+    }
+
+    protected MonitorCache getMonitorCache(String managerName, String cacheName) {
+        Cache cache = getCache(managerName, cacheName);
+        if (cache instanceof MonitorCache) {
+            return ((MonitorCache) cache);
+        }
+        throw new NotFoundException("缓存不支持监控");
+    }
+
+    protected Cache getCache(String managerName, String cacheName) {
+        CacheManager cacheManager = cacheManagerMap.get(managerName);
+        if (cacheManager != null) {
+            Cache cache = cacheManager.getCache(cacheName);
+            if (cache != null) {
+                return cache;
+            }
+        }
+        throw new NotFoundException("缓存不存在");
+    }
+
+    interface TimesGetter {
+        long get(MonitorCache cache);
+    }
+
+}

+ 60 - 0
hsweb-web-core/src/main/java/org/hsweb/web/core/cache/monitor/MonitorCache.java

@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015-2016 http://hsweb.me
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hsweb.web.core.cache.monitor;
+
+import org.springframework.cache.Cache;
+
+import java.util.Set;
+
+/**
+ * 缓存监控功能
+ */
+public interface MonitorCache extends Cache {
+
+    /**
+     * 缓存中所有key
+     *
+     * @return {@link Set<Object>} key集合
+     */
+    Set<Object> keySet();
+
+    /**
+     * @return 缓存数量
+     */
+    int size();
+
+    /**
+     * 调用命中次数
+     *
+     * @return 调用次数
+     */
+    long getTotalTimes();
+
+    /**
+     * 缓存命中次数
+     *
+     * @return 命中次数
+     */
+    long getHitTimes();
+
+    /**
+     * 执行缓存更新次数
+     *
+     * @return 缓存更新次数
+     */
+    long getPutTimes();
+}