我已经定义了一个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?
答案 0 :(得分:66)
有三种方式:
使用WebApplicationContextUtils
:
public void init(FilterConfig cfg) {
ApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(cfg.getServletContext());
this.bean = ctx.getBean(YourBeanType.class);
}
使用DelegatingFilterProxy
- 映射该过滤器,并将过滤器声明为bean。然后,委派代理将调用实现Filter
接口的所有bean。
在过滤器上使用@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)
spring中有两种类型的上下文
1.根上下文(由ContextLoaderListener加载的上下文)
2. Servlet上下文(上下文由DispatcherServlet加载)
默认情况下,在根上下文中定义的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;
...
}
(为什么*是)
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
springSecurityConfig
,tilesConfigurer
,themeSource
,themeResolver
,messageSource
,localeResolver
,requestMappingHandlerMapping
,mvcPathMatcher
,mvcUrlPathHelper
,mvcContentNegotiationManager
,viewControllerHandlerMapping
,beanNameHandlerMapping
,resourceHandlerMapping
,mvcResourceUrlProvider
,defaultServletHandlerMapping
,requestMappingHandlerAdapter
,{ {1}},mvcConversionService
,mvcValidator
,mvcUriComponentsContributor
,httpRequestHandlerAdapter
,simpleControllerHandlerAdapter
,handlerExceptionResolver
,mvcViewResolver
如果要在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提供了清晰的思路。