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
?
Essayer:
UsersConnectionRepository bean =
(UsersConnectionRepository)WebApplicationContextUtils.
getRequiredWebApplicationContext(filterConfig.getServletContext()).
getBean("usersConnectionRepository");
Où 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.
Il existe trois façons:
Utilisez WebApplicationContextUtils
:
public void init(FilterConfig cfg) {
ApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(cfg.getServletContext());
this.bean = ctx.getBean(YourBeanType.class);
}
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
.
Utilisation @Configurable
sur votre filtre. Je préférerais cependant l'une des deux autres options. (Cette option utilise le tissage aspectj)
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;
é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;
}
Il existe deux types de contexte au printemps
1. Contexte racine (ApplicationContext)
2. Contexte de servlet (WebApplicationContext)
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;
...
}
(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.