mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Add basic cache metrics support for Infinispan
Closes gh-3066
This commit is contained in:
parent
28d2955d03
commit
18d7634947
@ -97,6 +97,11 @@
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-spring4</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-messaging</artifactId>
|
||||
|
@ -21,6 +21,7 @@ import javax.cache.Caching;
|
||||
import com.hazelcast.core.IMap;
|
||||
import com.hazelcast.spring.cache.HazelcastCache;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import org.infinispan.spring.provider.SpringCache;
|
||||
|
||||
import org.springframework.boot.actuate.cache.CacheStatistics;
|
||||
import org.springframework.boot.actuate.cache.CacheStatisticsProvider;
|
||||
@ -29,7 +30,8 @@ import org.springframework.boot.actuate.cache.DefaultCacheStatistics;
|
||||
import org.springframework.boot.actuate.cache.EhCacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.cache.GuavaCacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.cache.HazelcastCacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.cache.JCacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.cache.InfinispanCacheStatisticsProvider;
|
||||
import org.springframework.boot.actuate.cache.JCacheCacheStatisticsProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
|
||||
@ -61,8 +63,8 @@ public class CacheStatisticsAutoConfiguration {
|
||||
static class JCacheCacheStatisticsProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public JCacheStatisticsProvider jCacheStatisticsProvider() {
|
||||
return new JCacheStatisticsProvider();
|
||||
public JCacheCacheStatisticsProvider jCacheCacheStatisticsProvider() {
|
||||
return new JCacheCacheStatisticsProvider();
|
||||
}
|
||||
|
||||
}
|
||||
@ -88,6 +90,17 @@ public class CacheStatisticsAutoConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ SpringCache.class })
|
||||
static class InfinispanCacheStatisticsProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
public InfinispanCacheStatisticsProvider infinispanCacheStatisticsProvider() {
|
||||
return new InfinispanCacheStatisticsProvider();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(com.google.common.cache.Cache.class)
|
||||
static class GuavaCacheStatisticsConfiguration {
|
||||
|
@ -18,42 +18,44 @@ package org.springframework.boot.actuate.cache;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.jcache.JCacheCache;
|
||||
|
||||
/**
|
||||
* {@link CacheStatisticsProvider} implementation for a JSR-107 compliant cache.
|
||||
* Base {@link CacheStatisticsProvider} implementation that uses JMX to
|
||||
* retrieve the cache statistics.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class JCacheStatisticsProvider implements CacheStatisticsProvider<JCacheCache> {
|
||||
public abstract class AbstractJmxCacheStatisticsProvider<C extends Cache>
|
||||
implements CacheStatisticsProvider<C> {
|
||||
|
||||
private static final Logger logger = LoggerFactory
|
||||
.getLogger(JCacheStatisticsProvider.class);
|
||||
.getLogger(AbstractJmxCacheStatisticsProvider.class);
|
||||
|
||||
private MBeanServer mBeanServer;
|
||||
|
||||
private Map<JCacheCache, ObjectName> caches = new ConcurrentHashMap<JCacheCache, ObjectName>();
|
||||
private Map<String, ObjectNameWrapper> caches =
|
||||
new ConcurrentHashMap<String, ObjectNameWrapper>();
|
||||
|
||||
|
||||
@Override
|
||||
public CacheStatistics getCacheStatistics(CacheManager cacheManager, JCacheCache cache) {
|
||||
public CacheStatistics getCacheStatistics(CacheManager cacheManager, C cache) {
|
||||
try {
|
||||
ObjectName objectName = getObjectName(cache);
|
||||
ObjectName objectName = internalGetObjectName(cache);
|
||||
if (objectName != null) {
|
||||
return getCacheStatistics(objectName);
|
||||
}
|
||||
@ -64,35 +66,33 @@ public class JCacheStatisticsProvider implements CacheStatisticsProvider<JCacheC
|
||||
}
|
||||
}
|
||||
|
||||
protected CacheStatistics getCacheStatistics(ObjectName objectName) {
|
||||
MBeanServer mBeanServer = getMBeanServer();
|
||||
DefaultCacheStatistics statistics = new DefaultCacheStatistics();
|
||||
Float hitPercentage = getAttribute(mBeanServer, objectName, "CacheHitPercentage",
|
||||
Float.class);
|
||||
Float missPercentage = getAttribute(mBeanServer, objectName,
|
||||
"CacheMissPercentage", Float.class);
|
||||
if ((hitPercentage != null && missPercentage != null)
|
||||
&& (hitPercentage > 0 || missPercentage > 0)) {
|
||||
statistics.setHitRatio(hitPercentage / (double) 100);
|
||||
statistics.setMissRatio(missPercentage / (double) 100);
|
||||
}
|
||||
return statistics;
|
||||
}
|
||||
/**
|
||||
* Return the {@link ObjectName} of the MBean that is managing the specified cache or
|
||||
* {@code null} if none is found.
|
||||
* @param cache the cache to handle
|
||||
* @return the object name of the cache statistics MBean
|
||||
*/
|
||||
protected abstract ObjectName getObjectName(C cache) throws MalformedObjectNameException;
|
||||
|
||||
protected ObjectName getObjectName(JCacheCache cache)
|
||||
/**
|
||||
* Return the current {@link CacheStatistics} snapshot from the MBean identified by the
|
||||
* specified {@link ObjectName}.
|
||||
* @param objectName the object name of the cache statistics MBean
|
||||
* @return the current cache statistics
|
||||
*/
|
||||
protected abstract CacheStatistics getCacheStatistics(ObjectName objectName);
|
||||
|
||||
|
||||
private ObjectName internalGetObjectName(C cache)
|
||||
throws MalformedObjectNameException {
|
||||
if (this.caches.containsKey(cache)) {
|
||||
return this.caches.get(cache);
|
||||
String cacheName = cache.getName();
|
||||
ObjectNameWrapper value = this.caches.get(cacheName);
|
||||
if (value != null) {
|
||||
return value.objectName;
|
||||
}
|
||||
Set<ObjectInstance> instances = getMBeanServer().queryMBeans(
|
||||
new ObjectName("javax.cache:type=CacheStatistics,Cache="
|
||||
+ cache.getName() + ",*"), null);
|
||||
if (instances.size() == 1) {
|
||||
ObjectName objectName = instances.iterator().next().getObjectName();
|
||||
this.caches.put(cache, objectName);
|
||||
return objectName;
|
||||
}
|
||||
return null; // None or more than one
|
||||
ObjectName objectName = getObjectName(cache);
|
||||
this.caches.put(cacheName, new ObjectNameWrapper(objectName));
|
||||
return objectName;
|
||||
}
|
||||
|
||||
protected MBeanServer getMBeanServer() {
|
||||
@ -102,18 +102,17 @@ public class JCacheStatisticsProvider implements CacheStatisticsProvider<JCacheC
|
||||
return this.mBeanServer;
|
||||
}
|
||||
|
||||
private static <T> T getAttribute(MBeanServer mBeanServer, ObjectName objectName,
|
||||
String attributeName, Class<T> type) {
|
||||
protected <T> T getAttribute(ObjectName objectName, String attributeName, Class<T> type) {
|
||||
try {
|
||||
Object attribute = mBeanServer.getAttribute(objectName, attributeName);
|
||||
Object attribute = getMBeanServer().getAttribute(objectName, attributeName);
|
||||
return type.cast(attribute);
|
||||
}
|
||||
catch (MBeanException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
catch (AttributeNotFoundException ex) {
|
||||
throw new IllegalStateException("Unexpected: jcache provider does not "
|
||||
+ "expose standard attribute " + attributeName, ex);
|
||||
throw new IllegalStateException("Unexpected: MBean with name '" + objectName + "' " +
|
||||
"does not expose attribute with name " + attributeName, ex);
|
||||
}
|
||||
catch (ReflectionException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
@ -124,4 +123,13 @@ public class JCacheStatisticsProvider implements CacheStatisticsProvider<JCacheC
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class ObjectNameWrapper {
|
||||
private final ObjectName objectName;
|
||||
|
||||
public ObjectNameWrapper(ObjectName objectName) {
|
||||
this.objectName = objectName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
*
|
||||
* 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.springframework.boot.actuate.cache;
|
||||
|
||||
import java.util.Set;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.infinispan.spring.provider.SpringCache;
|
||||
|
||||
/**
|
||||
* {@link CacheStatisticsProvider} implementation for Infinispan.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class InfinispanCacheStatisticsProvider extends AbstractJmxCacheStatisticsProvider<SpringCache> {
|
||||
|
||||
@Override
|
||||
protected ObjectName getObjectName(SpringCache cache) throws MalformedObjectNameException {
|
||||
Set<ObjectInstance> instances = getMBeanServer().queryMBeans(
|
||||
new ObjectName("org.infinispan:component=Statistics,type=Cache," +
|
||||
"name=\"" + cache.getName() + "(local)\",*"), null);
|
||||
if (instances.size() == 1) {
|
||||
return instances.iterator().next().getObjectName();
|
||||
}
|
||||
return null; // None or more than one
|
||||
}
|
||||
|
||||
protected CacheStatistics getCacheStatistics(ObjectName objectName) {
|
||||
DefaultCacheStatistics statistics = new DefaultCacheStatistics();
|
||||
Integer size = getAttribute(objectName, "numberOfEntries",
|
||||
Integer.class);
|
||||
if (size != null) {
|
||||
statistics.setSize((long) size);
|
||||
if (size > 0) { // Let's initialize the stats if we have some data
|
||||
Double hitRatio = getAttribute(objectName, "hitRatio",
|
||||
Double.class);
|
||||
if ((hitRatio != null)) {
|
||||
statistics.setHitRatio(hitRatio);
|
||||
statistics.setMissRatio(1 - hitRatio);
|
||||
}
|
||||
}
|
||||
}
|
||||
return statistics;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
*
|
||||
* 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.springframework.boot.actuate.cache;
|
||||
|
||||
import java.util.Set;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.springframework.cache.jcache.JCacheCache;
|
||||
|
||||
/**
|
||||
* {@link CacheStatisticsProvider} implementation for a JSR-107 compliant cache.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class JCacheCacheStatisticsProvider extends AbstractJmxCacheStatisticsProvider<JCacheCache> {
|
||||
|
||||
|
||||
protected ObjectName getObjectName(JCacheCache cache)
|
||||
throws MalformedObjectNameException {
|
||||
|
||||
Set<ObjectInstance> instances = getMBeanServer().queryMBeans(
|
||||
new ObjectName("javax.cache:type=CacheStatistics,Cache="
|
||||
+ cache.getName() + ",*"), null);
|
||||
if (instances.size() == 1) {
|
||||
return instances.iterator().next().getObjectName();
|
||||
}
|
||||
return null; // None or more than one
|
||||
}
|
||||
|
||||
protected CacheStatistics getCacheStatistics(ObjectName objectName) {
|
||||
DefaultCacheStatistics statistics = new DefaultCacheStatistics();
|
||||
Float hitPercentage = getAttribute(objectName, "CacheHitPercentage",
|
||||
Float.class);
|
||||
Float missPercentage = getAttribute(objectName,
|
||||
"CacheMissPercentage", Float.class);
|
||||
if ((hitPercentage != null && missPercentage != null)
|
||||
&& (hitPercentage > 0 || missPercentage > 0)) {
|
||||
statistics.setHitRatio(hitPercentage / (double) 100);
|
||||
statistics.setMissRatio(missPercentage / (double) 100);
|
||||
}
|
||||
return statistics;
|
||||
}
|
||||
|
||||
}
|
@ -17,14 +17,24 @@
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.cache.Caching;
|
||||
import javax.cache.configuration.MutableConfiguration;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.hazelcast.cache.HazelcastCachingProvider;
|
||||
import com.hazelcast.config.Config;
|
||||
import com.hazelcast.config.XmlConfigBuilder;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.spring.cache.HazelcastCacheManager;
|
||||
import org.infinispan.manager.DefaultCacheManager;
|
||||
import org.infinispan.manager.EmbeddedCacheManager;
|
||||
import org.infinispan.spring.provider.SpringEmbeddedCacheManager;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.actuate.autoconfigure.CacheStatisticsAutoConfiguration;
|
||||
|
||||
import org.springframework.boot.actuate.cache.CacheStatistics;
|
||||
import org.springframework.boot.actuate.cache.CacheStatisticsProvider;
|
||||
import org.springframework.cache.Cache;
|
||||
@ -42,14 +52,6 @@ import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.hazelcast.cache.HazelcastCachingProvider;
|
||||
import com.hazelcast.config.Config;
|
||||
import com.hazelcast.config.XmlConfigBuilder;
|
||||
import com.hazelcast.core.Hazelcast;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.spring.cache.HazelcastCacheManager;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@ -76,7 +78,7 @@ public class CacheStatisticsAutoConfigurationTests {
|
||||
public void basicJCacheCacheStatistics() {
|
||||
load(JCacheCacheConfig.class);
|
||||
CacheStatisticsProvider provider = this.context.getBean(
|
||||
"jCacheStatisticsProvider", CacheStatisticsProvider.class);
|
||||
"jCacheCacheStatisticsProvider", CacheStatisticsProvider.class);
|
||||
doTestCoreStatistics(provider, false);
|
||||
}
|
||||
|
||||
@ -96,6 +98,14 @@ public class CacheStatisticsAutoConfigurationTests {
|
||||
doTestCoreStatistics(provider, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicInfinispanCacheStatistics() {
|
||||
load(InfinispanConfig.class);
|
||||
CacheStatisticsProvider provider = this.context.getBean(
|
||||
"infinispanCacheStatisticsProvider", CacheStatisticsProvider.class);
|
||||
doTestCoreStatistics(provider, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicGuavaCacheStatistics() {
|
||||
load(GuavaConfig.class);
|
||||
@ -246,6 +256,28 @@ public class CacheStatisticsAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class InfinispanConfig {
|
||||
|
||||
@Bean
|
||||
public SpringEmbeddedCacheManager cacheManager() throws IOException {
|
||||
return new SpringEmbeddedCacheManager(embeddedCacheManager());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EmbeddedCacheManager embeddedCacheManager() throws IOException {
|
||||
Resource resource = new ClassPathResource("cache/test-infinispan.xml");
|
||||
InputStream in = resource.getInputStream();
|
||||
try {
|
||||
return new DefaultCacheManager(in);
|
||||
}
|
||||
finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class GuavaConfig {
|
||||
|
||||
|
9
spring-boot-actuator/src/test/resources/cache/test-infinispan.xml
vendored
Normal file
9
spring-boot-actuator/src/test/resources/cache/test-infinispan.xml
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<infinispan xmlns="urn:infinispan:config:7.2">
|
||||
|
||||
<cache-container default-cache="default">
|
||||
<local-cache name="books" statistics="true"/>
|
||||
<local-cache name="players" statistics="true"/>
|
||||
</cache-container>
|
||||
|
||||
</infinispan>
|
@ -2,7 +2,7 @@
|
||||
<infinispan xmlns="urn:infinispan:config:7.2">
|
||||
|
||||
<cache-container default-cache="default">
|
||||
<local-cache name="countries">
|
||||
<local-cache name="countries" statistics="true">
|
||||
<eviction max-entries="200"/>
|
||||
<expiration lifespan="600000"/>
|
||||
</local-cache>
|
||||
|
Loading…
Reference in New Issue
Block a user