web-dev-qa-db-fra.com

Comment puis-je obtenir un bean Spring dans un filtre de servlet?

J'ai défini un javax.servlet.Filter et j'ai Java avec annotations Spring.

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

@Configuration
public class SocialConfig {

    // ...

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

    // ...
}

Je veux obtenir le bean UsersConnectionRepository dans mon Filter, j'ai donc essayé ce qui suit:

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

Mais il renvoie toujours null. Comment puis-je obtenir un bean Spring dans un Filter?

39
IturPablo

Essayer:

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

usersConnectionRepository est un nom/id de votre bean dans le contexte de l'application. Ou encore mieux:

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

Jetez également un œil à GenericFilterBean et ses sous-classes.

32
Tomasz Nurkiewicz

Il existe trois façons:

  1. Utilisez WebApplicationContextUtils:

    public void init(FilterConfig cfg) { 
        ApplicationContext ctx = WebApplicationContextUtils
          .getRequiredWebApplicationContext(cfg.getServletContext());
        this.bean = ctx.getBean(YourBeanType.class);
    }
    
  2. En utilisant DelegatingFilterProxy - vous mappez ce filtre et déclarez votre filtre comme bean. Le proxy délégué invoquera alors tous les beans qui implémentent l'interface Filter.

  3. Utilisation @Configurable sur votre filtre. Je préférerais cependant l'une des deux autres options. (Cette option utilise le tissage aspectj)

67
Bozho

Le printemps a un utilitaire juste pour ça.

Dans votre code de filtre, remplacez la méthode init comme ceci:

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

Ensuite, il vous suffit d'injecter vos beans dans ce filtre, de la même manière que tout autre bean que vous injecteriez.

@Inject
private UsersConnectionRepository repository;
19
Elad Tabak

étend cette classe ci-dessous.

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

Pour avoir une idée claire de la façon dont les beans sont accessibles entre les contextes

Il existe deux types de contexte au printemps
1. Contexte racine (ApplicationContext)
2. Contexte de servlet (WebApplicationContext)

Les beans définis dans rootContext sont-ils visibles dans servletContext? - OUI

Les beans définis dans le contexte racine sont toujours visibles dans tous les contextes de servlet par défaut. par exemple, le bean dataSource défini dans le contexte racine est accessible dans le contexte de servlet comme indiqué ci-dessous.

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

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

    ...
}

Les beans définis dans servletContext sont-ils visibles dans rootContext - oui *

(Pourquoi * en Oui)
1. L'initialisation de l'ordre du contexte est rootContext en premier et servletContext ensuite. Pendant l'initialisation de rootContext, c'est-à-dire dans la classe de configuration du contexte racine/xml, si vous essayez d'obtenir le bean défini dans servletContext, vous obtiendrez NULL. (car servletContext n'est pas encore initialisé, donc on peut dire que les beans ne sont pas visibles/enregistrés lors de l'initialisation de rootContext)
Mais vous pouvez obtenir des beans définis dans servletContext après l'initialisation de servletContext (vous pouvez obtenir des beans via le contexte d'application)

vous pouvez l'imprimer et le confirmer en

applicationContext.getBeanDefinitionNames();


2. Si vous souhaitez accéder aux beans du contexte de servlet dans le filtre ou dans un autre contexte de servlet, ajoutez "org.springframework.web.servlet" package de base pour votre classe de configuration racine/xml

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

après l'ajout, vous pouvez obtenir tous les beans ci-dessous à partir du contexte de l'application

springSecurityConfig, tilesConfigurer, themeSource, themeResolver, messageSource, localeResolver, requestMappingHandlerMapping, mvcPathMatcher, mvcUrlPathHelper, mvcContentNegotiationManager, viewControllerHandlerMapping, beanNameHandlerMapping, resourceHandlerMapping, mvcResourceUrlProvider, defaultServletHandlerMapping, requestMappingHandlerAdapter, mvcConversionService, mvcValidator, mvcUriComponentsContributor, httpRequestHandlerAdapter, simpleControllerHandlerAdapter, handlerExceptionResolver, mvcViewResolver, mvcHandlerMappingIntrospector

Si vous souhaitez obtenir vos beans personnalisés à partir de rootContext, ajoutez la valeur du package de base à l'analyse des composants rootContext comme indiqué ci-dessous.

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

La configuration ci-dessus sera utile si vous voulez que la dépendance injectée soit disponible dans votre rootContext et accessible dans votre filtre de servlet. Par exemple, si vous interceptez une exception dans le filtre et souhaitez envoyer une réponse d'erreur identique à la réponse envoyée par HttpMessageConverter mais qu'elle est configurée dans servletContext, vous souhaiterez peut-être accéder à ce convertisseur configuré pour envoyer la même réponse.

Notez que le câblage automatique ci-dessous ne fonctionnera pas dans les filtres de servlet

@Autowired
private ApplicationContext appContext;

Le câblage automatique ApplicationContext ne fonctionnera pas dans le filtre de servlet, car les filtres sont initialisés avant l'initialisation du conteneur de ressort (cela dépend de l'ordre de votre filtre et de DelegatingProxyFilter)

Donc, pour obtenir applicationContext dans le filtre

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

J'espère que cela donne une idée claire de la façon dont les beans sont accessibles entre les contextes.

0