How can I add a filter class in Spring Boot?
Is there any annotation for a Filter
class (for web applications) in Spring Boot? Perhaps @Filter
?
I want to add a custom filter in my project.
The Spring Boot Reference Guide mentioned about
FilterRegistrationBean
, but I am not sure how to use it.
If you want to setup a third-party filter you can use FilterRegistrationBean
.
For example, the equivalent of web.xml:
<filter>
<filter-name>SomeFilter</filter-name>
<filter-class>com.somecompany.SomeFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SomeFilter</filter-name>
<url-pattern>/url/*</url-pattern>
<init-param>
<param-name>paramName</param-name>
<param-value>paramValue</param-value>
</init-param>
</filter-mapping>
These will be the two beans in your @Configuration
file:
@Bean
public FilterRegistrationBean someFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(someFilter());
registration.addUrlPatterns("/url/*");
registration.addInitParameter("paramName", "paramValue");
registration.setName("someFilter");
registration.setOrder(1);
return registration;
}
public Filter someFilter() {
return new SomeFilter();
}
The above was tested with Spring Boot 1.2.3.
Here is an example of one method of including a custom filter in a Spring Boot MVC application. Be sure to include the package in a component scan:
package com.dearheart.gtsc.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Component
public class XClacksOverhead implements Filter {
public static final String X_CLACKS_OVERHEAD = "X-Clacks-Overhead";
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader(X_CLACKS_OVERHEAD, "GNU Terry Pratchett");
chain.doFilter(req, res);
}
@Override
public void destroy() {}
@Override
public void init(FilterConfig arg0) throws ServletException {}
}
There are three ways to add your filter,
- Annotate your filter with one of the Spring stereotypes such as
@Component
- Register a
@Bean
withFilter
type in Spring@Configuration
- Register a
@Bean
withFilterRegistrationBean
type in Spring@Configuration
Either #1 or #2 will do if you want your filter applies to all requests without customization, use #3 otherwise. You don't need to specify component scan for #1 to work as long as you place your filter class in the same or sub-package of your SpringApplication
class. For #3, use along with #2 is only necessary when you want Spring to manage your filter class such as have it auto wired dependencies. It works just fine for me to new my filter which doesn't need any dependency autowiring/injection.
Although combining #2 and #3 works fine, I was surprised it doesn't end up with two filters applying twice. My guess is that Spring combines the two beans as one when it calls the same method to create both of them. In case you want to use #3 alone with authowiring, you can AutowireCapableBeanFactory
. The following is an example,
private @Autowired AutowireCapableBeanFactory beanFactory;
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
Filter myFilter = new MyFilter();
beanFactory.autowireBean(myFilter);
registration.setFilter(myFilter);
registration.addUrlPatterns("/myfilterpath/*");
return registration;
}
There isn't a special annotation to denote a servlet filter. You just declare a @Bean
of type Filter
(or FilterRegistrationBean
). An example (adding a custom header to all responses) is in Boot's own EndpointWebMvcAutoConfiguration;
If you only declare a Filter
it will be applied to all requests. If you also add a FilterRegistrationBean
you can additionally specify individual servlets and url patterns to apply.
Note:
As of Spring Boot 1.4, FilterRegistrationBean
is not deprecated and simply moved packages from org.springframework.boot.context.embedded.FilterRegistrationBean
to org.springframework.boot.web.servlet.FilterRegistrationBean
UPDATE: 2017-12-16:
There are two simple ways to do this in Spring Boot 1.5.8.RELEASE and there isn't any need for XML.
First way:
If you do not have any specific URL pattern, you can use @Component like this (full code and details are here https://www.surasint.com/spring-boot-filter/):
@Component
public class ExampleFilter implements Filter {
...
}
Second way:
If you want to use URL patterns, you can use @WebFilter like this (full code and details are here https://www.surasint.com/spring-boot-filter-urlpattern/):
@WebFilter(urlPatterns = "/api/count")
public class ExampleFilter implements Filter {
...
}
But you also need to add @ServletComponentScan annotation in your @SpringBootApplication class:
@ServletComponentScan
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
...
}
Note that @Component is Spring's annotation, but @WebFilter is not. @WebFilter is Servlet 3 annotation.
Both ways, you just need a basic Spring Boot dependency in pom.xml (there isn't any need for an explicit Tomcat embedded jasper)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<groupId>com.surasint.example</groupId>
<artifactId>spring-boot-04</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
WARNING: The first way, if the Controller in Spring Boot returns to a JSP file, the request will pass the filter twice.
While, in the second way, the request will pass the filter only once.
I prefer the second way, because it is more similar to default behavior in the Servlet specification.
You can see more test log here: https://www.surasint.com/spring-boot-webfilter-instead-of-component/