Inject dependencies into your filters using DelegatingFilterProxy

In this post, we’re going to look at how to inject dependencies into your web application filters. To achieve this, we’re going to use Spring’s DelegatingFilterProxy.

Now consider the following.

Say we got an AuditHandler that takes care of the audit of incoming requests in our web application.

Since audit isn't the topic of this post, I've made the handler simply print the ip address.

public class AuditHandler {

    public void auditRequest(ServletRequest request) {
        System.out.println("Received request from " + request.getRemoteAddr());
    }
}

What we want, is to be able to create an AuditFilter, that will call the AuditHandler when new requests are received.

public class AuditFilter implements Filter {

    private AuditHandler auditHandler;

    public AuditFilter(AuditHandler auditHandler) {
        this.auditHandler = auditHandler;
    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        auditHandler.auditRequest(request);
        chain.doFilter(request, response);
    }

    public void init(FilterConfig filterConfig) throws ServletException {}

    public void destroy() {}
}

Now, instead of just creating a new instance of the AuditHandler, we want to inject the handler into our filter.

By using DelegatingFilterProxy, we're able to define our filter as a bean in the applicationContext.xml instead of adding the filter directly into web.xml.

<bean id="auditHandler" class="AuditHandler">  
</bean>

<bean id="auditFilter" class="AuditFilter">  
    <constructor-arg ref="auditHandler"/>
</bean>  

Next, we need to use this bean when defining the filter in web.xml. This is done by using the DelegatingFilterProxy as the filter-class and the target bean name as the filter-name.

<filter>  
    <filter-name>auditFilter</filter-name>
    <filter-class>
        org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
</filter>  

Now, by testing our application you'll see that it gives the correct output.

Received request from 127.0.0.1  

Sending parameters from the web.xml to the filter

Let's continue our example with the following scenario.

We have a bunch of web applications, and we want to use our filter in all of them. However, we want to know which web application that is reporting about a given request.

To achieve this, we add a parameter in web.xml that we can fetch in our filter.

<filter>  
    <filter-name>auditFilter</filter-name>
    <filter-class>
        org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
    <init-param>
        <param-name>appName</param-name>
        <param-value>di-example</param-value>
    </init-param>
</filter>  

Next, let's refactor our filter to fetch the appName in the init method.

public class AuditFilter implements Filter {

    private final AuditHandler auditHandler;
    private String appName;

    public AuditFilter(AuditHandler auditHandler) {
        this.auditHandler = auditHandler;
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        auditHandler.auditRequest(appName, request);
        chain.doFilter(request, response);
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        appName = filterConfig.getInitParameter("appName");
    }

    public void destroy() {}
}

Ok, everything seems to be in place, but when running the application we see that the output is wrong.

null: Received request from 127.0.0.1  

As you can see, the application name is null.

The reason for this is that when using DelegatingFilterProxy, the lifecycle methods, like init and destroy, are not invoked.

We need to force this invocation by setting the targetFilterLifecycle as true in the filter definition in web.xml.

<filter>  
    <filter-name>auditFilter</filter-name>
    <filter-class>
        org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>appName</param-name>
        <param-value>di-example</param-value>
    </init-param>
</filter>  

If we now try to run our web application again, you'll see that we successfully get the application name printed as well.

di-example: Received request from 127.0.0.1  

For more information, check out the DelegatingFilterProxy documentation.

You can also find the source code of the example on GitHub.

Enjoyed the post?

If you don't want to miss future posts, make sure to subscribe