How to Get a Spring Bean in a Servlet Filter

How can I get a Spring bean in a servlet filter?

Try:

UsersConnectionRepository bean = 
(UsersConnectionRepository)WebApplicationContextUtils.
getRequiredWebApplicationContext(filterConfig.getServletContext()).
getBean("usersConnectionRepository");

Where usersConnectionRepository is a name/id of your bean in the application context. Or even better:

UsersConnectionRepository bean = WebApplicationContextUtils.
getRequiredWebApplicationContext(filterConfig.getServletContext()).
getBean(UsersConnectionRepository.class);

Also have a look at GenericFilterBean and its subclasses.

how to autowire bean in the servlet filters in spring application?

You should add a FilterRegistrationBean to your main Application class (class annotated with @SpringBootApplication) and let Spring provide instance of the AuditHandler:

@Bean
@Autowired
public FilterRegistrationBean auditFilterRegistration(AuditHandler handler) {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new AuditFilter(handler));
filterRegistrationBean.setOrder(3); // ordering in the filter chain
return filterRegistrationBean;
}

If this doesn't work (e.g. your AuditHandler implementation is not annotated properly or it's not on the default package scanning path) you can instruct Spring to provide it (also in your @SpringBootApplication annotated class):

@Bean
public AuditHandler auditHandler() {
return new AuditHandlerImplementation();
}

Accessing Spring beans from servlet filters and tags

For filters - use Filter.init():

public void init(FilterConfig config) {
WebApplicationContext springContext =
WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
}

For tags - use TagSupport.pageContext (note that it's not available in SimpleTagSupport):

WebApplicationContext springContext = 
WebApplicationContextUtils.getWebApplicationContext(pageContext.getServletContext());

Why Servlet Filter can be Spring Bean?

We have to make a distinction between a regular Spring application and a Spring Boot application here. As with both, you can register a servlet filter as a bean, but the mechanism is a bit different.

Spring Framework

In plain Spring use the DelegatingFilterProxy to achieve this. The task of the DelegatingFilterProxy is to look for a bean with the same name as the filter in the root application context (the ApplicationContext registered through the ContextLoaderListener). This bean has to be your managed servlet filter.

@Configuration
@EnableWebMvc
public class WebConfiguration {

@Bean
public void YourFilter myFilter() { ... }
}

Then for the web application you would register a DelegatingFilterProxy with the name myFilter to make this work.

public class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

public void onStartup(ServletContext servletContext)
throws ServletException {
super.onStartup(servletContext);
servletContext.addFilter("myFilter", DelegatingFilterProxy.class);
}

Spring Boot

In Spring Boot it is a bit different as Spring Boot is also in control of your servlet container, like Tomcat. It basically means that Tomcat is also a managed bean in your ApplicationContext and Spring Boot can inject dependencies into it. So when Spring Boot detects a bean for the servlet filter it will automatically add it to the filter chain (without the need of a DelegatingFilterProxy).

Which means only an @Bean for your filter is needed.

@Configuration
public class WebConfiguration {

@Bean
public YourFilter myFilter() { ... }
}

Additionally you can configure things like URLs etc. by adding an additional FilterRegistrationBean for this filter.

Conclusion

For plain Spring the DelegatingFilterProxy has been around since Spring 1.2 which was released in 2005. This means if you are reading really, really, really old articles (before 2005) this was true, however with the addition of the DelegatingFilterProxy, this isn't anymore. With the release of Spring Boot, this became even a lesser issue, is it more or less is the only way to register a filter (as a managed bean).

How to Inject Dependencies into a Servlet Filter with Spring Boot Filter Registration Bean?

If you create an object by yourself, using new, and this object is not returned by a @Bean-annotated method, then it's not a Spring bean, and Spring will thus not inject anything in it.

You can just add an @Bean-annotated method returning new MyFilter(), and call that method from myFilter() to get the bean, or add a MyFilter as argument to myFilter().

Example:

@Bean
@Order(1)
public FilterRegistrationBean<MyFilter> myFilter() {
FilterRegistrationBean<MyFilter> contextFilter = new FilterRegistrationBean<>();
contextFilter.setFilter(theActualFilter());
contextFilter.addUrlPattern("/api/*");
return contextFilter;
}

@Bean
public MyFilter theActualFilter() {
return new MyFilter(); // now this is a Spring bean
}

or

@Bean
@Order(1)
public FilterRegistrationBean<MyFilter> myFilter(MyFilter theActualFilter) {
FilterRegistrationBean<MyFilter> contextFilter = new FilterRegistrationBean<>();
contextFilter.setFilter(theActualFilter);
contextFilter.addUrlPattern("/api/*");
return contextFilter;
}

@Bean
public MyFilter theActualFilter() {
return new MyFilter(); // now this is a Spring bean
}

Filters - Servlets and Spring beans integration NullPointerException

You are going to get 2 different instances of your UserFilter, one managed by Servlet Container, another by Spring - the UserFilter created by the Servlet Container will of course have a null WebContentDAOIF.

The solution is to let Spring manage your UserFilter (and properly inject the WebContentDAOIF). Then use Spring's DelegatingFilterProxy, to handle the filtering which ultimately delegates to your UserFilter.

In your web.xml, remove your UserFilter declaration and declare the DelegatingFilterProxy instead.

<filter>
<filter-name>userFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>userFilter</param-value>
</init-param>
</filter>


Related Topics



Leave a reply



Submit