diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfiguration.java
index 01133efdbe..158dd240b4 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfiguration.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfiguration.java
@@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -45,6 +46,7 @@ import org.springframework.web.servlet.HandlerMapping;
@ConditionalOnClass({ Servlet.class, ServletRegistration.class,
OncePerRequestFilter.class, HandlerMapping.class })
@AutoConfigureAfter(MetricRepositoryAutoConfiguration.class)
+@ConditionalOnProperty(name="endpoints.metrics.filter.enabled", matchIfMissing=true)
public class MetricFilterAutoConfiguration {
@Autowired
diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricsFilter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricsFilter.java
index d006be6c58..b49f25697f 100644
--- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricsFilter.java
+++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricsFilter.java
@@ -99,6 +99,9 @@ final class MetricsFilter extends OncePerRequestFilter {
if (is4xxClientError(status)) {
return UNKNOWN_PATH_SUFFIX;
}
+ if (is3xxRedirection(status)) {
+ return UNKNOWN_PATH_SUFFIX;
+ }
return path;
}
@@ -126,6 +129,15 @@ final class MetricsFilter extends OncePerRequestFilter {
}
}
+ private boolean is3xxRedirection(int status) {
+ try {
+ return HttpStatus.valueOf(status).is3xxRedirection();
+ }
+ catch (Exception ex) {
+ return false;
+ }
+ }
+
private String getKey(String string) {
// graphite compatible metric names
String value = string.replace("/", ".");
diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfigurationTests.java
index 09742c9214..ecd1237ed7 100644
--- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfigurationTests.java
+++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfigurationTests.java
@@ -16,8 +16,26 @@
package org.springframework.boot.actuate.autoconfigure;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.mockito.BDDMockito.willAnswer;
+import static org.mockito.BDDMockito.willThrow;
+import static org.mockito.Matchers.anyDouble;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.io.IOException;
+
import javax.servlet.Filter;
import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
@@ -27,9 +45,11 @@ import org.springframework.boot.actuate.metrics.GaugeService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.stereotype.Component;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.PathVariable;
@@ -37,21 +57,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.NestedServletException;
-import static org.hamcrest.Matchers.equalTo;
-import static org.junit.Assert.assertThat;
-import static org.mockito.BDDMockito.willAnswer;
-import static org.mockito.BDDMockito.willThrow;
-import static org.mockito.Matchers.anyDouble;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
/**
* Tests for {@link MetricFilterAutoConfiguration}.
*
@@ -130,6 +138,23 @@ public class MetricFilterAutoConfigurationTests {
context.close();
}
+ @Test
+ public void records302HttpInteractionsAsSingleMetric() throws Exception {
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
+ Config.class, MetricFilterAutoConfiguration.class, RedirectFilter.class);
+ MetricsFilter filter = context.getBean(MetricsFilter.class);
+ MockMvc mvc = MockMvcBuilders.standaloneSetup(new MetricFilterTestController())
+ .addFilter(filter).addFilter(context.getBean(RedirectFilter.class))
+ .build();
+ mvc.perform(get("/unknownPath/1")).andExpect(status().is3xxRedirection());
+ mvc.perform(get("/unknownPath/2")).andExpect(status().is3xxRedirection());
+ verify(context.getBean(CounterService.class), times(2)).increment(
+ "status.302.unmapped");
+ verify(context.getBean(GaugeService.class), times(2)).submit(
+ eq("response.unmapped"), anyDouble());
+ context.close();
+ }
+
@Test
public void skipsFilterIfMissingServices() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
@@ -214,4 +239,19 @@ public class MetricFilterAutoConfigurationTests {
}
}
+ @Component
+ @Order(0)
+ public static class RedirectFilter extends OncePerRequestFilter {
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request,
+ HttpServletResponse response, FilterChain chain) throws ServletException,
+ IOException {
+ // send redirect before filter chain is executed, like Spring Security sending
+ // us back to a login page
+ response.sendRedirect("http://example.com");
+ }
+
+ }
+
}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java
index 61383d5a0c..2bff6719dd 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java
@@ -20,12 +20,10 @@ import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.transaction.jta.JtaTransactionManager;
/**
* Configuration for Spring AMQP annotation driven endpoints.
@@ -37,18 +35,12 @@ import org.springframework.transaction.jta.JtaTransactionManager;
@ConditionalOnClass(EnableRabbit.class)
class RabbitAnnotationDrivenConfiguration {
- @Autowired(required = false)
- private JtaTransactionManager transactionManager;
-
@Bean
@ConditionalOnMissingBean(name = "rabbitListenerContainerFactory")
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
- ConnectionFactory connectionFactory) {
+ ConnectionFactory connectionFactory, RabbitProperties config) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
- if (this.transactionManager != null) {
- factory.setTransactionManager(this.transactionManager);
- }
return factory;
}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java
index ef04f23ebb..454c8c96ee 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java
@@ -97,7 +97,7 @@ public class RabbitAutoConfiguration {
@Bean
@ConditionalOnMissingBean(RabbitTemplate.class)
- public RabbitTemplate rabbitTemplate() {
+ public RabbitTemplate rabbitTemplate(RabbitProperties config) {
return new RabbitTemplate(this.connectionFactory);
}
diff --git a/spring-boot-samples/spring-boot-sample-web-secure/pom.xml b/spring-boot-samples/spring-boot-sample-web-secure/pom.xml
index 275120b4c7..d8cf7c2e73 100644
--- a/spring-boot-samples/spring-boot-sample-web-secure/pom.xml
+++ b/spring-boot-samples/spring-boot-sample-web-secure/pom.xml
@@ -19,6 +19,10 @@
${basedir}/../..
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
org.springframework.boot
spring-boot-starter-security