Add cache actuator endpoint
This commits adds an actuator endpoint which lists the caches per context and cacheManager and provides a delete operation to clear the caches. As the statistics are exposed via the metrics endpoint they are not included See gh-12216
This commit is contained in:
committed by
Stephane Nicoll
parent
0699f65969
commit
1a57673345
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.autoconfigure.cache;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
|
||||
import org.springframework.boot.actuate.cache.CachesEndpoint;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link CachesEndpoint}.
|
||||
*
|
||||
* @author Johannes Edmeier
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(CacheManager.class)
|
||||
@AutoConfigureAfter(CacheAutoConfiguration.class)
|
||||
public class CachesEndpointAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(CacheManager.class)
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledEndpoint
|
||||
public CachesEndpoint cachesEndpoint(ApplicationContext context) {
|
||||
return new CachesEndpoint(context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2017 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for actuator cache concerns.
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.cache;
|
||||
@@ -3,6 +3,7 @@ org.springframework.boot.actuate.autoconfigure.amqp.RabbitHealthIndicatorAutoCon
|
||||
org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.cache.CachesEndpointAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthIndicatorAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryActuatorAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.ReactiveCloudFoundryActuatorAutoConfiguration,\
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2012-2017 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.autoconfigure.cache;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.cache.CachesEndpoint;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link CachesEndpointAutoConfiguration}.
|
||||
*
|
||||
* @author Johannes Edmeier
|
||||
*/
|
||||
public class CachesEndpointAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(CachesEndpointAutoConfiguration.class))
|
||||
.withUserConfiguration(CacheConfiguration.class);
|
||||
|
||||
@Test
|
||||
public void runShouldHaveEndpointBean() {
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(context).hasSingleBean(CachesEndpoint.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {
|
||||
this.contextRunner.withPropertyValues("management.endpoint.caches.enabled:false")
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(CachesEndpoint.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CacheConfiguration {
|
||||
|
||||
@Bean
|
||||
public CacheManager cacheManager() {
|
||||
return mock(CacheManager.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2012-2017 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.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* {@link Endpoint} to expose cache operations.
|
||||
*
|
||||
* @author Johannes Edmeuer
|
||||
* @since 2.0.2
|
||||
*/
|
||||
@Endpoint(id = "caches")
|
||||
public class CachesEndpoint {
|
||||
private final ApplicationContext context;
|
||||
|
||||
public CachesEndpoint(ApplicationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public CachesDescriptor caches() {
|
||||
List<CacheDescriptor> caches = new ArrayList<>();
|
||||
this.context.getBeansOfType(CacheManager.class)
|
||||
.forEach((name, cacheManager) -> caches.addAll(
|
||||
getCacheDescriptors(name, cacheManager.getCacheNames())));
|
||||
return new CachesDescriptor(caches);
|
||||
}
|
||||
|
||||
private Collection<? extends CacheDescriptor> getCacheDescriptors(String cacheManager,
|
||||
Collection<String> cacheNames) {
|
||||
return cacheNames.stream().map(cacheName -> new CacheDescriptor(cacheName, cacheManager)).collect(toList());
|
||||
}
|
||||
|
||||
@DeleteOperation
|
||||
public void clearCaches(@Nullable String cacheManager, @Nullable String cacheName) {
|
||||
if (cacheManager == null) {
|
||||
this.context.getBeansOfType(CacheManager.class)
|
||||
.forEach((name, manager) -> this.clearCaches(manager, cacheName));
|
||||
} else {
|
||||
this.clearCaches(this.context.getBean(cacheManager, CacheManager.class), cacheName);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearCaches(CacheManager cacheManager, String cacheName) {
|
||||
if (cacheName == null) {
|
||||
cacheManager.getCacheNames().forEach(cn -> cacheManager.getCache(cn).clear());
|
||||
} else {
|
||||
Cache cache = cacheManager.getCache(cacheName);
|
||||
if (cache != null) {
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description of an application context's caches, primarily
|
||||
* intended for serialization to JSON.
|
||||
*/
|
||||
public static final class CachesDescriptor {
|
||||
private final List<CacheDescriptor> caches;
|
||||
|
||||
private CachesDescriptor(List<CacheDescriptor> caches) {
|
||||
this.caches = caches;
|
||||
}
|
||||
|
||||
public List<CacheDescriptor> getCaches() {
|
||||
return this.caches;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description of a {@link Cache}, primarily intended for serialization to
|
||||
* JSON.
|
||||
*/
|
||||
public static final class CacheDescriptor {
|
||||
private final String name;
|
||||
private final String cacheManager;
|
||||
|
||||
public CacheDescriptor(String name, String cacheManager) {
|
||||
this.name = name;
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getCacheManager() {
|
||||
return cacheManager;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Actuator support for caches.
|
||||
*/
|
||||
package org.springframework.boot.actuate.cache;
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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 org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link CachesEndpoint}.
|
||||
*
|
||||
* @author Johannes Edmeier
|
||||
*/
|
||||
public class CachesEndpointTests {
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(
|
||||
AutoConfigurations.of(CacheAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
public void cacheReportIsReturned() {
|
||||
//@formatter:off
|
||||
this.contextRunner.withUserConfiguration(Config.class)
|
||||
.run(context -> assertThat(context.getBean(CachesEndpoint.class).caches().getCaches())
|
||||
.hasSize(2)
|
||||
.anySatisfy(cache -> {
|
||||
assertThat(cache.getName()).isEqualTo("first");
|
||||
assertThat(cache.getCacheManager()).isEqualTo("cacheManager");
|
||||
}).anySatisfy(cache -> {
|
||||
assertThat(cache.getName()).isEqualTo("second");
|
||||
assertThat(cache.getCacheManager()).isEqualTo("cacheManager");
|
||||
})
|
||||
);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheIsCleared() {
|
||||
this.contextRunner.withUserConfiguration(Config.class).run((context) -> {
|
||||
Cache firstCache = context.getBean("firstCache", Cache.class);
|
||||
firstCache.put("key", "vale");
|
||||
Cache secondCache = context.getBean("secondCache", Cache.class);
|
||||
secondCache.put("key", "value");
|
||||
context.getBean(CachesEndpoint.class).clearCaches(null, null);
|
||||
assertThat(firstCache.get("key", String.class)).isNull();
|
||||
assertThat(secondCache.get("key", String.class)).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void namedCacheIsCleared() {
|
||||
this.contextRunner.withUserConfiguration(Config.class).run((context) -> {
|
||||
Cache firstCache = context.getBean("firstCache", Cache.class);
|
||||
firstCache.put("key", "value");
|
||||
Cache secondCache = context.getBean("secondCache", Cache.class);
|
||||
secondCache.put("key", "value");
|
||||
context.getBean(CachesEndpoint.class).clearCaches(null, "first");
|
||||
assertThat(firstCache.get("key", String.class)).isNull();
|
||||
assertThat(secondCache.get("key", String.class)).isEqualTo("value");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknwonCache() {
|
||||
this.contextRunner.withUserConfiguration(Config.class).run((context) -> {
|
||||
Cache firstCache = context.getBean("firstCache", Cache.class);
|
||||
firstCache.put("key", "value");
|
||||
Cache secondCache = context.getBean("secondCache", Cache.class);
|
||||
secondCache.put("key", "value");
|
||||
context.getBean(CachesEndpoint.class).clearCaches(null, "UNKNWON");
|
||||
assertThat(firstCache.get("key", String.class)).isEqualTo("value");
|
||||
assertThat(secondCache.get("key", String.class)).isEqualTo("value");
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public static class Config {
|
||||
@Bean
|
||||
public Cache firstCache() {
|
||||
return new ConcurrentMapCache("first");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Cache secondCache() {
|
||||
return new ConcurrentMapCache("second");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CachesEndpoint endpoint(ApplicationContext context) {
|
||||
return new CachesEndpoint(context);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user