如何在servlet过滤器中获取Spring bean?

时间:2011-10-24 21:12:34

标签: spring servlets servlet-filters

我已经定义了一个javax.servlet.Filter,我有一个带有Spring注释的Java类。

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;

@Configuration
public class SocialConfig {

    // ...

    @Bean
    public UsersConnectionRepository usersConnectionRepository() {
        // ...
    }

    // ...
}

我想在我的UsersConnectionRepository中获取bean Filter,所以我尝试了以下内容:

public void init(FilterConfig filterConfig) throws ServletException {
    UsersConnectionRepository bean = (UsersConnectionRepository) filterConfig.getServletContext().getAttribute("#{connectionFactoryLocator}");
}

但它总是返回null。如何在Filter中获取Spring bean?

5 个答案:

答案 0 :(得分:66)

有三种方式:

  1. 使用WebApplicationContextUtils

    public void init(FilterConfig cfg) { 
        ApplicationContext ctx = WebApplicationContextUtils
          .getRequiredWebApplicationContext(cfg.getServletContext());
        this.bean = ctx.getBean(YourBeanType.class);
    }
    
  2. 使用DelegatingFilterProxy - 映射该过滤器,并将过滤器声明为bean。然后,委派代理将调用实现Filter接口的所有bean。

  3. 在过滤器上使用@Configurable。我更喜欢其他两个选项中的一个。 (此选项使用aspectj编织)

答案 1 :(得分:32)

尝试:

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

其中usersConnectionRepository是应用程序上下文中bean的名称/ id。甚至更好:

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

另请查看GenericFilterBean及其子类。

答案 2 :(得分:19)

Spring只为此提供了实用工具。

在您的过滤器代码中,覆盖init方法,如下所示:

public void init(FilterConfig cfg) { 
    super.init(cfg);
    SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}

然后你只需将bean注入该过滤器,就像你要注入的任何其他bean一样。

@Inject
private UsersConnectionRepository repository;

答案 3 :(得分:1)

在课程下面进行了扩展。

abstract public class SpringServletFilter implements Filter{
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //must provide autowiring support to inject SpringBean
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, filterConfig.getServletContext());      
    }

    @Override
    public void destroy() { }

    abstract public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException;
}

答案 4 :(得分:1)

要清楚地了解如何在上下文之间访问bean

spring中有两种类型的上下文
1.根上下文(由ContextLoaderListener加载的上下文)
2. Servlet上下文(上下文由DispatcherServlet加载)

rootContext中定义的bean在servletContext中可见吗? -是的

默认情况下,在根上下文中定义的Bean在所有servlet上下文中始终可见。例如,可以在servlet上下文中访问在根上下文中定义的dataSource bean,如下所示。

@Configuration
public class RootConfiguration
{
    @Bean
    public DataSource dataSource()
    {
       ...
    }
}

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.pvn.mvctiles")
public class ServletConfiguration implements WebMvcConfigurer
{
    @Autowired
    private DataSource dataSource;

    ...
}

在servletContext中定义的bean是否在rootContext中可见-是*

(为什么*是)
1.上下文顺序的初始化首先是rootContext,然后是ServletContext。 在rootContext初始化期间,即在根上下文配置类/ xml中,如果尝试获取servletContext中定义的bean,则将获得NULL。 (因为ServletContext尚未初始化,因此可以说在rootContext初始化期间不可见/未注册Bean)
但是您可以在初始化ServletContext后获得在ServletContext中定义的bean(可以通过应用程序上下文获取bean)

您可以通过以下方式打印并确认

applicationContext.getBeanDefinitionNames();


2.如果要在过滤器或另一个servlet上下文中访问servlet上下文的bean,请将"org.springframework.web.servlet"基本包添加到根配置类/ xml

@Configuration
@ComponentScan(basePackages = "org.springframework.web.servlet" )
public class RootConfiguration

添加后,您可以从应用程序上下文中获取所有下面的bean

springSecurityConfigtilesConfigurerthemeSourcethemeResolvermessageSourcelocaleResolverrequestMappingHandlerMappingmvcPathMatchermvcUrlPathHelpermvcContentNegotiationManagerviewControllerHandlerMappingbeanNameHandlerMappingresourceHandlerMappingmvcResourceUrlProviderdefaultServletHandlerMappingrequestMappingHandlerAdapter,{ {1}},mvcConversionServicemvcValidatormvcUriComponentsContributorhttpRequestHandlerAdaptersimpleControllerHandlerAdapterhandlerExceptionResolvermvcViewResolver

如果要在rootContext中获取自定义bean,请如下所示将基本包值添加到rootContext组件扫描中。

mvcHandlerMappingIntrospector

如果希望注入的依赖项在rootContext中可用并且可以在servlet过滤器中进行访问,则上述给定的配置将非常有用。例如,如果您在过滤器中捕获异常并想要发送与@Configuration @ComponentScan(basePackages = { "com.your.configuration.package", "org.springframework.web.servlet" }) public class RootConfiguration 发送的响应相同但在ServletContext中配置的错误响应,则您可能希望访问该已配置的转换器以发送相同的响应。

请注意,下面的自动装配不适用于servlet过滤器

HttpMessageConverter

ApplicationContext自动装配在servlet过滤器中不起作用,因为过滤器是在初始化Spring容器之前初始化的。(取决于过滤器和DelegatingProxyFilter的顺序)

因此,要在过滤器中获取applicationContext

@Autowired
private ApplicationContext appContext;

希望它为如何在上下文之间访问bean提供了清晰的思路。