web-dev-qa-db-ja.com

サーブレットフィルターでSpring Beanを取得するにはどうすればよいですか?

javax.servlet.Filterを定義し、Java Springアノテーション付きのクラスがあります。

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

@Configuration
public class SocialConfig {

    // ...

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

    // ...
}

UsersConnectionRepositoryFilterのBeanを取得したいので、次のことを試しました。

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

ただし、常にnullを返します。 FilterでSpring Beanを取得するにはどうすればよいですか?

39
IturPablo

試してください:

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

usersConnectionRepositoryは、アプリケーションコンテキスト内のBeanの名前/ IDです。またはさらに良い:

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

GenericFilterBean とそのサブクラスもご覧ください。

32

3つの方法があります。

  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フィルター。ただし、他の2つのオプションのいずれかを選択します。 (このオプションはaspectjウィービングを使用します)

67
Bozho

Springにはこのためのユーティリティがあります。

フィルターコードで、次のようにinitメソッドをオーバーライドします。

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

次に、注入する他のBeanと同じ方法で、Beanをそのフィルターに@Injectします。

@Inject
private UsersConnectionRepository repository;
19
Elad Tabak

これをクラスの下に拡張します。

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;
}
2
Kelvin Phan

コンテキスト間でBeanにアクセスする方法を明確に把握するため

春には2種類のコンテキストがあります
1。ルートコンテキスト(ApplicationContext)
2。サーブレットコンテキスト(WebApplicationContext)

RootContextで定義されたBeanはservletContextに表示されますか? - はい

ルートコンテキストで定義されたBeanは、デフォルトですべてのサーブレットコンテキストで常に表示されます。たとえば、ルートコンテキストで定義された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。フィルタまたは別のサーブレットコンテキストでサーブレットコンテキストのBeanにアクセスする場合は、"org.springframework.web.servlet"ルート設定クラス/ 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で使用可能にし、サーブレットフィルターでアクセスできるようにする場合に役立ちます。たとえば、フィルターで例外をキャッチし、HttpMessageConverterによって送信された応答と同じエラー応答を送信するが、servletContextで構成されている場合、その構成されたコンバーターにアクセスして同じ応答を送信できます。

このことに注意してください、自動配線はサーブレットフィルターでは機能しません

@Autowired
private ApplicationContext appContext;

SpringContextが初期化される前にフィルターが初期化されるため、ApplicationContext自動配線はサーブレットフィルターでは機能しません。(フィルターとDelegatingProxyFilterの順序に依存します)

したがって、フィルターで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にアクセスする方法について明確なアイデアが得られることを願っています。