簡體   English   中英

如何在 servlet 過濾器中獲取 Spring bean?

[英]How can I get a Spring bean in a servlet filter?

我已經定義了一個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() {
        // ...
    }
}

我想在我的Filter獲取 bean UsersConnectionRepository ,所以我嘗試了以下操作:

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

但它總是返回null 如何在Filter獲取 Spring bean?

有三種方式:

  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編織)

嘗試:

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

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

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

還可以查看GenericFilterBean及其子類。

Spring有一個實用工具。

在您的Filter代碼中,覆蓋init方法,如下所示:

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

然后你只需將bean注入該過濾器,就像你注入的任何其他bean一樣。

@Inject
private UsersConnectionRepository repository;

在課程下面擴展。

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;
}

清楚地了解如何在上下文之間訪問bean

春天有兩種類型的背景
1.根上下文(ApplicationContext)
2. Servlet上下文(WebApplicationContext)

在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尚未初始化,因此我們可以說bean在初始化rootContext期間不可見/注冊)
但是在初始化servletContext之后你可以在servletContext中定義bean(你可以通過應用程序上下文獲取bean)

你可以打印並確認

applicationContext.getBeanDefinitionNames();


2.如果要在過濾器或另一個servlet上下文中訪問servlet上下文的bean,請將"org.springframework.web.servlet"基本包添加到root配置類/ xml中

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

添加后,您可以從應用程序上下文中獲取所有以下bean

springSecurityConfigtilesConfigurerthemeSourcethemeResolvermessageSourcelocaleResolverrequestMappingHandlerMappingmvcPathMatchermvcUrlPathHelpermvcContentNegotiationManagerviewControllerHandlerMappingbeanNameHandlerMappingresourceHandlerMappingmvcResourceUrlProviderdefaultServletHandlerMappingrequestMappingHandlerAdaptermvcConversionServicemvcValidatormvcUriComponentsContributorhttpRequestHandlerAdaptersimpleControllerHandlerAdapterhandlerExceptionResolvermvcViewResolvermvcHandlerMappingIntrospector

如果要從rootContext獲取自定義bean,請將基本包值添加到rootContext組件掃描,如下所示。

@Configuration
@ComponentScan(basePackages = { "com.your.configuration.package", "org.springframework.web.servlet" })
public class RootConfiguration

如果您希望在rootContext中提供注入依賴項,並且可以在servlet-filter中訪問,則上面給出的配置將非常有用。 例如,如果您在過濾器中捕獲異常並希望發送錯誤響應,該響應與HttpMessageConverter發送的響應相同,但它是在servletContext中配置的,那么您可能希望訪問該配置的轉換器以發送相同的響應。

請注意,下面的自動裝配在servlet過濾器中不起作用

@Autowired
private ApplicationContext appContext;

ApplicationContext自動裝配在servlet過濾器中不起作用,因為過濾器在spring容器初始化之前被初始化。(取決於你的過濾器和DelegatingProxyFilter的順序)

因此,要在filter中獲取applicationContext

public class YourFilter implements Filter
{
    private ApplicationContext appContext;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {
        Filter.super.init(filterConfig);
        appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig.getServletContext());
    }
}

希望它能清楚地了解如何在上下文之間訪問bean。

如果您使用彈簧安全性並擴展 OncePerRequestFilter,則另一種解決方案

@Component
public class CustomAuthorizationFilter extends OncePerRequestFilter{

    @Autowired
    ResourceConfig resourceConfig;

    public CustomAuthorizationFilter() {
            SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
    }
...your code
... //resourceConfig will not be null

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM