Spring中将bean自动装配到ServletFilter的4种方法
Servlet过滤器提供了一种强大的机制来拦截和操作传入请求。然而,在这些过滤器中访问 Spring 管理的 bean 可能会带来挑战。
在本教程中,我们将探索在Servlet过滤器中无缝获取 Spring bean 的各种方法,这是基于 Spring 的 Web 应用程序中的常见要求。
@Autowired
虽然 Spring 的依赖注入机制@Autowired是将依赖项注入到 Spring 管理的组件中的一种便捷方法,但它不能与Servlet过滤器无缝配合。这是因为Servlet过滤器是由Servlet容器初始化的,通常是在 Spring 的ApplicationContext完全加载和初始化之前。
因此,当容器实例化Servlet过滤器时,Spring 上下文可能尚不可用,从而在尝试使用@Autowired注释时导致 null 或未初始化的依赖项。让我们探索在Servlet过滤器中访问 Spring bean 的替代方法。
设置
让我们创建一个通用的LoggingService,它将自动连接到我们的过滤器中:
@Service |
然后,我们将创建过滤器,它将拦截传入的 HTTP 请求,以使用LoggingService依赖项记录 HTTP 方法和 URI 详细信息:
@Component |
让我们公开一个返回用户列表的RestController :
@RestController |
我们将设置测试来检查LoggingService是否已成功自动连接到我们的过滤器中:
@RunWith(SpringRunner.class) |
然而,在这个阶段,LoggingService 可能不会被注入到LoggingFilter中,因为 Spring 上下文尚不可用。我们将在以下部分中探讨解决此问题的各种选项。
1、在Servlet Filter中使用SpringBeanAutowiringSupport
Spring 的SpringBeanAutowiringSupport类提供对非 Spring 管理的类(例如Filter和Servlet)的依赖注入的支持。通过使用此类,Spring 可以将依赖项(例如LoggingService(Spring 管理的 bean))注入到LoggingFilter中。
init方法用于初始化Filter实例,我们将在 LoggingFilter 中重写此方法以使用SpringBeanAutowiringSupport:
@Override |
processInjectionBasedOnServletContext方法使用与ServletContext关联的ApplicationContext来执行自动装配。它首先从ServletContext检索 ApplicationContext ,然后使用它将依赖项自动装配到目标对象中。此过程涉及检查目标对象的字段中是否有@Autowired注释,然后从ApplicationContext解析并注入相应的 beans 。
该机制允许非 Spring 管理的对象(如过滤器和 servlet)从 Spring 的依赖注入功能中受益。
2、在Servlet Filter中使用WebApplicationContextUtils
WebApplicationContextUtils提供了一个实用方法,用于检索与 ServletContext 关联的ApplicationContext 。ApplicationContext包含 Spring 容器管理 的 所有 bean。
让我们重写LoggingFilter类的init方法:
@Override |
我们从ApplicationContext中检索LoggingService的实例,并将其分配给过滤器的loggingService字段。当我们需要在非 Spring 管理的组件(例如Servlet或Filter)中访问 Spring 管理的 bean ,并且无法使用基于注释或构造函数注入时,此方法非常有用。
需要注意的是,这种方法将过滤器与 Spring 紧密耦合,在某些情况下可能并不理想。
3、在配置中使用FilterRegistrationBean
FilterRegistrationBean用于以编程方式在 servlet 容器中注册Servlet过滤器。它提供了一种在应用程序的配置类中动态配置过滤器注册的方法。
通过使用@Bean和@Autowired注解该方法,LoggingService会自动注入到该方法中,从而允许将其传递给LoggingFilter构造函数。让我们在配置类中设置FilterRegistrationBean的方法:
@Bean |
然后,我们将在LoggingFilter中包含一个构造函数来支持上述配置:
public LoggingFilter(LoggingService loggingService) { |
这种方法集中了过滤器及其依赖项的配置,使代码更有组织性并且更易于维护。
4、在Servlet Filter中使用DelegatingFilterProxy
DelegatingFilterProxy 是一个Servlet过滤器,它允许将控制传递给有权 访问 Spring ApplicationContext的Filter类。
让我们配置DelegatingFilterProxy以委托给名为“loggingFilter”的 Spring 管理的 bean 。Spring 使用FilterRegistrationBean在应用程序启动时向Servlet容器注册过滤器:
@Bean |
让我们为之前定义的过滤器使用相同的 bean 名称:
@Component("loggingFilter") |
这种方法允许我们使用Spring的依赖注入来管理loggingFilter bean。
比较Servlet Filter中的依赖注入方法
DelegatingFilterProxy方法与SpringBeanAutowiringSupport和直接使用WebApplicationContextUtils的不同之处在于它如何将过滤器的执行委托给 Spring 管理的 bean,从而允许我们使用 Spring 的依赖注入。
DelegatingFilterProxy与典型的 Spring 应用程序架构更好地保持一致,并允许更清晰地分离关注点。FilterRegistrationBean方法允许对过滤器的依赖项注入进行更多控制,并集中依赖项的配置。
相比之下,SpringBeanAutowiringSupport和WebApplicationContextUtils是更底层的方法,在我们需要对过滤器的初始化过程进行更多控制或想要直接访问ApplicationContext 的某些场景中非常有用。然而,它们需要更多的手动设置,并且不提供与 Spring 依赖注入机制相同级别的集成。