Spring中用到的几种典型的设计模式

末蓝、 2023-02-14 10:42 99阅读 0赞

Spring 框架中用到的设计模式非常多,不下十几种。本文只挑选几种典型的来解析。

适配器模式应用在Spring MVC中

Spring MVC定义一个Controller最常用的方式是,通过@Controller注解来标记某个类是Controller类,通过@RequesMapping注解来标记函数对应的URL。不过,定义一个Controller远不止这一种方法。我们还可以通过让类实现Controller接口或者Servlet接口,来定义一个 Controller。这三种定义方式示例代码,如下所示:

  1. //方法一:通过@Controller、@RequestMapping来定义
  2. @Controller
  3. public class DemoController {
  4. @RequestMapping("/getUserName")
  5. public ModelAndView getUserName() {
  6. ModelAndView model = new ModelAndView("Greeting");
  7. model.addObject("message", "TOM");
  8. return model;
  9. }
  10. }
  11. //方法二:实现Controller接口 + xml配置文件:配置DemoController与URL的对应关系
  12. public class DemoControllerImpl implements Controller {
  13. @Override
  14. public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
  15. ModelAndView model = new ModelAndView("HelloWorld");
  16. model.addObject("message", "HelloWorld");
  17. return model;
  18. }
  19. }
  20. //方法三:继承HttpServlet抽象类 + xml配置文件:配置DemoExtendServletController类与URL的对应关系
  21. public class DemoExtendServletController extends HttpServlet {
  22. @Override
  23. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  24. this.doPost(req, resp);
  25. }
  26. @Override
  27. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  28. resp.getWriter().write("Hello World!");
  29. }
  30. }

在应用启动的时候,Spring容器会加载这些Controller类,并且解析出URL对应的处理函数,封装成Handler对象,存储到HandlerMapping对象中。当有请求到来的时候,DispatcherServlet从HanderMapping中,查找请求URL对应的Handler,然后调用执行Handler对应的函数代码,最后将执行结果返回给客户端。

但是不同方式定义的Controller,其函数的定义(函数名、入参、返回值等)是不统一的。方法一中的函数的定义很随意、不固定,方法二中的函数定义是 handleRequest()、方法三中的函数定义是HttpServlet的service()方法(实际上这里用到了模板方法模式,Servlet中的service()调用了doGet()或doPost()方法,DispatcherServlet调用的是service()方法)。

DispatcherServlet需要根据不同类型的Controller,调用不同的函数,下面是伪代码:

  1. Handler handler = handlerMapping.get(URL);
  2. if (handler instanceof Controller) {
  3. ((Controller)handler).handleRequest();
  4. } else if (handler instanceof Servlet) {
  5. ((Servlet)handler).service(...);
  6. } else if (handler.getClass().getAnnotation(Controller.class) != null) {
  7. //反射调用RequestMapping修饰的方法...
  8. }

这种实现方式会有很多if-else分支判断,而且,如果要增加一个新的 Controller的定义方法,我们就要在DispatcherServlet类代码中,对应地增加一段如上伪代码所示的if逻辑,这显然不符合开闭原则。

可以利用是适配器模式对代码进行改造,让其满足开闭原则,能更好地支持扩展,适配器其中一个作用是“统一多个类的接口设计”。利用适配器模式,我们将不同方式定义的Controller类中的函数适配为统一的函数定义。这样,我们就能在DispatcherServlet类代码中,移除掉if-else分支判断逻辑,调用统一的函数。

来具体看下Spring的代码实现。Spring定义了统一的接口HandlerAdapter,并且对每种Controller定义了对应的适配器类。这些适配器类包括:AnnotationMethodHandlerAdapter、SimpleControllerHandlerAdapter、SimpleServletHandlerAdapter等,源码如下。

  1. //统一的controller处理器适配接口
  2. public interface HandlerAdapter {
  3. boolean supports(Object var1);
  4. ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
  5. long getLastModified(HttpServletRequest var1, Object var2);
  6. }
  7. // 对应实现Controller接口的Controller
  8. public class SimpleControllerHandlerAdapter implements HandlerAdapter {
  9. public SimpleControllerHandlerAdapter() {
  10. }
  11. @Override
  12. public boolean supports(Object handler) {
  13. return handler instanceof Controller;
  14. }
  15. @Override
  16. public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  17. return ((Controller)handler).handleRequest(request, response);
  18. }
  19. @Override
  20. public long getLastModified(HttpServletRequest request, Object handler) {
  21. return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;
  22. }
  23. }
  24. // 对应实现Servlet接口的Controller
  25. public class SimpleServletHandlerAdapter implements HandlerAdapter {
  26. public SimpleServletHandlerAdapter() {
  27. }
  28. @Override
  29. public boolean supports(Object handler) {
  30. return handler instanceof Servlet;
  31. }
  32. @Override
  33. public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  34. ((Servlet)handler).service(request, response);
  35. return null;
  36. }
  37. //省略...
  38. }
  39. //AnnotationMethodHandlerAdapter对应通过注解实现的Controller,
  40. public class AnnotationMethodHandlerAdapter extends WebContentGenerator
  41. implements HandlerAdapter, Ordered, BeanFactoryAware {
  42. @Override
  43. public boolean supports(Object handler) {
  44. return getMethodResolver(handler).hasHandlerMethods();
  45. }
  46. @Override
  47. public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
  48. throws Exception {
  49. Class<?> clazz = ClassUtils.getUserClass(handler);
  50. Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
  51. if (annotatedWithSessionAttributes == null) {
  52. annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
  53. this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
  54. }
  55. if (annotatedWithSessionAttributes) {
  56. checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
  57. } else {
  58. checkAndPrepare(request, response, true);
  59. }
  60. //...省略
  61. return invokeHandlerMethod(request, response, handler);
  62. }
  63. //...省略
  64. }

在DispatcherServlet类中,我们就不需要区分对待不同的Controller对象了,统一调用HandlerAdapter的handle()函数就可以了,这样就没有烦人的if-else逻辑了。以下摘抄Spring-web-mvc-5.1.14.RELEASE-sources.jar中的DispatcherServlet类中与HandlerAdapter相关的部分核心代码,可以看到在容器启动后,通过调用initHandlerAdapters()函数获取context中的类型为HandlerAdapter的bean列表,在doDispatch()函数中会根据当前handler的类型,挑选出合适的适配器。

  1. public class DispatcherServlet extends FrameworkServlet {
  2. /** List of HandlerAdapters used by this servlet. */
  3. @Nullable
  4. private List<HandlerAdapter> handlerAdapters;
  5. /** Detect all HandlerAdapters or just expect "handlerAdapter" bean?. */
  6. private boolean detectAllHandlerAdapters = true;
  7. //省略大部分属性....
  8. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  9. HttpServletRequest processedRequest = request;
  10. HandlerExecutionChain mappedHandler = null;
  11. boolean multipartRequestParsed = false;
  12. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  13. try {
  14. ModelAndView mv = null;
  15. Exception dispatchException = null;
  16. try {
  17. processedRequest = checkMultipart(request);
  18. multipartRequestParsed = (processedRequest != request);
  19. // Determine handler for the current request.
  20. mappedHandler = getHandler(processedRequest);
  21. if (mappedHandler == null) {
  22. noHandlerFound(processedRequest, response);
  23. return;
  24. }
  25. // Determine handler adapter for the current request.
  26. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  27. //中间部分省略...
  28. // Actually invoke the handler.
  29. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  30. //各种catch异常的逻辑省略...
  31. }
  32. }
  33. //获取适配器,找到第一个匹配的就返回
  34. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
  35. if (this.handlerAdapters != null) {
  36. for (HandlerAdapter adapter : this.handlerAdapters) {
  37. if (adapter.supports(handler)) {
  38. return adapter;
  39. }
  40. }
  41. }
  42. throw new ServletException("No adapter for handler [" + handler +
  43. "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
  44. }
  45. @Override
  46. protected void onRefresh(ApplicationContext context) {
  47. initStrategies(context);
  48. }
  49. protected void initStrategies(ApplicationContext context) {
  50. //省略...
  51. initHandlerAdapters(context);
  52. //省略...
  53. }
  54. //初始化适配器列表
  55. private void initHandlerAdapters(ApplicationContext context) {
  56. this.handlerAdapters = null;
  57. if (this.detectAllHandlerAdapters) {
  58. // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
  59. Map<String, HandlerAdapter> matchingBeans =
  60. BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
  61. if (!matchingBeans.isEmpty()) {
  62. this.handlerAdapters = new ArrayList<>(matchingBeans.values());
  63. // We keep HandlerAdapters in sorted order.
  64. AnnotationAwareOrderComparator.sort(this.handlerAdapters);
  65. }
  66. }
  67. //以下省略...
  68. }
  69. }

策略模式的应用

Spring中的AOP是通过动态代理来实现的。具体到代码实现,Spring支持两种动态代理实现方式,一种是JDK提供的动态代理实现方式,另一种是Cglib提供的动态代理实现方式。前者需要被代理的类有抽象的接口定义,后者不需要。针对不同的被代理类,Spring会在运行时动态地选择不同的动态代理实现方式

动态选择代理策略,这里就用到了策略模式。策略模式包含三部分,策略的定义、创建和使用。具体到Spring中的策略模式,策略的定义这一部分很简单,我们只需要定义一个策略接口,让不同的策略类都实现这一个策略接口。对应到Spring的源码AopProxy是策略接口,JdkDynamicAopProxy、CglibAopProxy是两个实现了AopProxy接口的策略类。其中,AopProxy接口的定义如下所示:

  1. public interface AopProxy {
  2. Object getProxy();
  3. Object getProxy(ClassLoader var1);
  4. }

策略的创建一般通过工厂方法来实现。对应到Spring源码,AopProxyFactory是一个工厂类接口,DefaultAopProxyFactory是一个默认的工厂类,用来创建AopProxy对象。两者的源码如下所示:

  1. public interface AopProxyFactory {
  2. AopProxy createAopProxy(AdvisedSupport var1) throws AopConfigException;
  3. }
  4. public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
  5. @Override
  6. public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  7. //optimized默认是false || proxy-target-class=true || 没有接口
  8. if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
  9. Class<?> targetClass = config.getTargetClass();
  10. if (targetClass == null) {
  11. throw new AopConfigException("TargetSource cannot determine target class: " +
  12. "Either an interface or a target is required for proxy creation.");
  13. }
  14. //被代理类是接口,创建JDK代理
  15. if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
  16. return new JdkDynamicAopProxy(config);
  17. }
  18. return new ObjenesisCglibAopProxy(config);
  19. }
  20. else {
  21. return new JdkDynamicAopProxy(config);
  22. }
  23. }
  24. /** * Determine whether the supplied {@link AdvisedSupport} has only the * {@link org.springframework.aop.SpringProxy} interface specified * (or no proxy interfaces specified at all). */
  25. private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
  26. Class<?>[] ifcs = config.getProxiedInterfaces();
  27. return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
  28. }
  29. }

策略模式的典型应用场景,一般是通过环境变量、状态值、计算结果等动态地决定使用哪个策略。对应到Spring源码中,我们可以参看刚刚给出的DefaultAopProxyFactory类中的createAopProxy()函数的代码实现。其中包含了多处if-else分支,用来判断要用哪种策略生成代理类。

Spring对观察者模式的实现

Java及Google Guava都提供了观察者模式的实现框架。Java 提供的框架比较简单,只包含java.util.Observable和java.util.Observer两个类。Google Guava提供的框架功能比较完善和强大:通过EventBus事件总线来实现观察者模式,可以参见之前的博文观察者模式及EventBus框架简单实现去了解Guava是怎样实现观察者模式的。

实际上,Spring中的事件驱动模型也叫作发布订阅模式,是观察者模式的一个典型的应用。Spring中实现的观察者模式包含三部分:Event事件(相当于消息)、Listener 监听者(相当于观察者)、Publisher发送者(相当于被观察者)。我们通过一个例子来看下,Spring提供的观察者模式使用代码如下所示:

  1. // Event事件
  2. public class DemoEvent extends ApplicationEvent {
  3. private String message;
  4. public DemoEvent(Object source, String message) {
  5. super(source);
  6. }
  7. public String getMessage() {
  8. return this.message;
  9. }
  10. }
  11. // Listener监听者
  12. @Component
  13. public class DemoListener implements ApplicationListener<DemoEvent> {
  14. @Override
  15. public void onApplicationEvent(DemoEvent demoEvent) {
  16. String message = demoEvent.getMessage();
  17. System.out.println(message);
  18. }
  19. }
  20. // Publisher发送者
  21. @Component
  22. public class DemoPublisher {
  23. public void publishEvent(DemoEvent demoEvent) {
  24. SpringContext.getApplicationContext.publishEvent(demoEvent);
  25. }
  26. }
  27. // 创建一个Spring上下文bean,拿到ApplicationContext
  28. @Component
  29. public class SpringContext implements ApplicationContextAware {
  30. private static ApplicationContext applicationContext;
  31. @Override
  32. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  33. SpringContext.applicationContext = applicationContext;
  34. }
  35. public static ApplicationContext getApplicationContext() {
  36. return applicationContext;
  37. }
  38. }

框架使用起来并不复杂,主要包含三部分工作:定义一个继承 ApplicationEvent的事件(DemoEvent);定义一个实现了 ApplicationListener的监听器(DemoListener);定义一个发送者(DemoPublisher),发送者调用ApplicationContext来发送事件消息。其中,ApplicationEvent和ApplicationListener的代码实现都非常简单,内部并不包含太多属性和方法。实际上,它们最大的作用是做类型标识之用:继承自ApplicationEvent的类是事件,实现了ApplicationListener的类是监听器。

在观察者模式中,观察者是需要事先注册到被观察者中的。那在Spring的实现中,观察者注册到了哪里呢?又是如何注册的呢?Spring把观察者注册到了ApplicationContext对象中。这里的ApplicationContext就相当于Google EventBus框架中的“事件总线”。不过ApplicationContext这个类并不只是为观察者模式服务的。它底层依赖BeanFactory(IOC 的主要实现类),提供应用启动、运行时的上下文信息。具体到源码来说,ApplicationContext只是一个接口,具体的代码实现包含在它的实现类AbstractApplicationContext中,该类中事件相关的代码摘抄如下:

  1. public abstract class AbstractApplicationContext extends DefaultResourceLoader
  2. implements ConfigurableApplicationContext, DisposableBean {
  3. //....省略
  4. /** Helper class used in event publishing */
  5. private ApplicationEventMulticaster applicationEventMulticaster;
  6. /** Statically specified listeners */
  7. private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
  8. @Override
  9. public void publishEvent(ApplicationEvent event) {
  10. publishEvent(event, null);
  11. }
  12. @Override
  13. public void publishEvent(Object event) {
  14. publishEvent(event, null);
  15. }
  16. protected void publishEvent(Object event, ResolvableType eventType) {
  17. Assert.notNull(event, "Event must not be null");
  18. if (logger.isTraceEnabled()) {
  19. logger.trace("Publishing event in " + getDisplayName() + ": " + event);
  20. }
  21. // Decorate event as an ApplicationEvent if necessary
  22. ApplicationEvent applicationEvent;
  23. if (event instanceof ApplicationEvent) {
  24. applicationEvent = (ApplicationEvent) event;
  25. } else {
  26. applicationEvent = new PayloadApplicationEvent<Object>(this, event);
  27. if (eventType == null) {
  28. eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
  29. }
  30. }
  31. // Multicast right now if possible - or lazily once the multicaster is initialized
  32. if (this.earlyApplicationEvents != null) {
  33. this.earlyApplicationEvents.add(applicationEvent);
  34. } else {
  35. getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
  36. }
  37. // Publish event via parent context as well...
  38. if (this.parent != null) {
  39. if (this.parent instanceof AbstractApplicationContext) {
  40. ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
  41. } else {
  42. this.parent.publishEvent(event);
  43. }
  44. }
  45. }
  46. @Override
  47. public void addApplicationListener(ApplicationListener<?> listener) {
  48. Assert.notNull(listener, "ApplicationListener must not be null");
  49. if (this.applicationEventMulticaster != null) {
  50. this.applicationEventMulticaster.addApplicationListener(listener);
  51. } else {
  52. this.applicationListeners.add(listener);
  53. }
  54. }
  55. // ApplicationEventMulticaster初始化
  56. protected void initApplicationEventMulticaster() {
  57. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  58. if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
  59. this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
  60. if (logger.isDebugEnabled()) {
  61. logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
  62. }
  63. } else {
  64. this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
  65. beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
  66. if (logger.isDebugEnabled()) {
  67. logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
  68. APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
  69. "': using default [" + this.applicationEventMulticaster + "]");
  70. }
  71. }
  72. }
  73. protected void registerListeners() {
  74. // Register statically specified listeners first.
  75. for (ApplicationListener<?> listener : getApplicationListeners()) {
  76. getApplicationEventMulticaster().addApplicationListener(listener);
  77. }
  78. // Do not initialize FactoryBeans here: We need to leave all regular beans
  79. // uninitialized to let post-processors apply to them!
  80. String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
  81. for (String listenerBeanName : listenerBeanNames) {
  82. getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
  83. }
  84. // Publish early application events now that we finally have a multicaster...
  85. Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
  86. this.earlyApplicationEvents = null;
  87. if (earlyEventsToProcess != null) {
  88. for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
  89. getApplicationEventMulticaster().multicastEvent(earlyEvent);
  90. }
  91. }
  92. }
  93. //....省略
  94. }

从上面的代码中,我们发现,真正的消息发送以及观察者注册实际上是通过 ApplicationEventMulticaster这个类来完成的。这个类的源码我只摘抄最关键的一部分,也就是multicastEvent()这个消息发送函数。部分关键代码如下,它通过线程池,支持异步非阻塞、同步阻塞这两种类型的观察者模式。

  1. public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
  2. private Executor taskExecutor;
  3. public SimpleApplicationEventMulticaster() {
  4. }
  5. public void setTaskExecutor(Executor taskExecutor) {
  6. this.taskExecutor = taskExecutor;
  7. }
  8. protected Executor getTaskExecutor() {
  9. return this.taskExecutor;
  10. }
  11. @Override
  12. public void multicastEvent(ApplicationEvent event) {
  13. multicastEvent(event, resolveDefaultEventType(event));
  14. }
  15. @Override
  16. public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
  17. ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
  18. for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
  19. Executor executor = getTaskExecutor();
  20. if (executor != null) {
  21. executor.execute(new Runnable() {
  22. @Override
  23. public void run() {
  24. invokeListener(listener, event);
  25. }
  26. });
  27. } else {
  28. invokeListener(listener, event);
  29. }
  30. }
  31. }
  32. }

借助Spring提供的观察者模式的骨架代码,如果我们要在Spring下实现某个事件的发送和监听,只需要做很少的工作:定义事件、定义监听器、往ApplicationContext中发送事件就可以了。剩下的工作都由Spring框架来完成。这体现了Spring框架的扩展性,也就是在不需要修改任何代码的情况下,扩展新的事件和监听。在Spring boot中可支持直接使用@EnableAsync、@EventListener等注解定义异步或同步监听器。

模板方法模式的应用

Java IO类库中的很多类都用到了模板方法模式,许多xxxxTemplate类都用到了回调模式,详情见模板方法模式与回调函数这篇博客。

职责链模式实现Spring Interceptor

职责链模式:将能够处理同一类请求的对象连成一条链,使这些对象都有机会处理请求,所提交的请求沿着链传递。从而避免请求的发送者和接受者之间的耦合关系。链上的对象逐个判断是否有能力处理该请求,如果能则就处理,如果不能,则传给链上的下一个对象,直到有一个对象处理它为止。

用一张生动一些的图来描述一下,就是下面这样。在公司中不同的岗位拥有不同的职责与权限。以上述的请假流程为例,当员工请 1天假时,只要组长审批就可以了,不需要流转到主管和总监。如果职责链上的某个环节无法处理当前的请求,在含有下个环节时,则会把请求转交给下个环节来处理。
20210225151454397.png

职责链的UML图如下:
20200606204433117.png

职责链模式的典型示例代码如下:

  1. public interface IHandler {
  2. boolean handle();
  3. }
  4. public class HandlerA implements IHandler {
  5. @Override
  6. public boolean handle() {
  7. boolean handleResult = false;
  8. //...
  9. return handleResult;
  10. }
  11. }
  12. public class HandlerB implements IHandler {
  13. @Override
  14. public boolean handle() {
  15. boolean handleResult = false;
  16. //...
  17. return handleResult;
  18. }
  19. }
  20. public class HandlerChain {
  21. private List<IHandler> handlers = new ArrayList<>();
  22. public void addHandler(IHandler handler) {
  23. this.handlers.add(handler);
  24. }
  25. public void handle() {
  26. for (IHandler handler : handlers) {
  27. boolean handleResult = handler.handle();
  28. if (handleResult) {
  29. break;
  30. }
  31. }
  32. }
  33. }
  34. // 使用举例
  35. public class Application {
  36. public static void main(String[] args) {
  37. HandlerChain chain = new HandlerChain();
  38. chain.addHandler(new HandlerA());
  39. chain.addHandler(new HandlerB());
  40. chain.handle();
  41. }
  42. }

Spring框架中的Interceptor用来实现对HTTP请求进行拦截处理。它与Servlet Filter有所不同,Servlet Filter是Servlet规范的一部分,实现依赖于Web容器。Spring Interceptor是Spring MVC框架的一部分,由Spring MVC来提供实现。客户端发送的请求,会先经过Servlet Filter,然后再经过Spring Interceptor,最后到达具体的业务代码中。具体处理流程如下图所示:

20200606202425740.jpg

对应到Spring Interceptor的源码就是HandlerInterceptor接口和 HandlerExecutionChain。HandlerInterceptor接口源码如下, 对请求的拦截定义为preHandle()方法,对响应的拦截定义为postHandle()方法。

  1. public interface HandlerInterceptor {
  2. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
  3. throws Exception;
  4. void postHandle(
  5. HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
  6. throws Exception;
  7. void afterCompletion(
  8. HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
  9. throws Exception;
  10. }

以下示例代码,写一个ControllerInterceptor类去实现HandlerInterceptor接口。

  1. @Component
  2. public class ControllerInterceptor implements HandlerInterceptor {
  3. @Override
  4. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  5. System.out.println("拦截客户端发送来的请求.");
  6. return true; // 继续后续的处理
  7. }
  8. @Override
  9. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  10. System.out.println("拦截发送给客户端的响应.");
  11. }
  12. @Override
  13. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  14. System.out.println("这里总是被执行.");
  15. }
  16. }

向Spring MVC框架配置自定义的ControllerInterceptor。

  1. @Configuration
  2. public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
  3. @Resource
  4. private ControllerInterceptor controllerInterceptor;
  5. @Override
  6. public void addInterceptors(InterceptorRegistry registry) {
  7. registry.addInterceptor(controlToolInterceptor).addPathPatterns("/**");
  8. super.addInterceptors(registry);
  9. }
  10. }

Spring Interceptor也是基于职责链模式实现的,HandlerExecutionChain类就是职责链模式中的处理器链。它的实现不需要使用递归,主要是因为它将请求和响应的拦截工作,拆分到了两个函数中去实现。HandlerExecutionChain的关键源码摘抄如下:

  1. public class HandlerExecutionChain {
  2. private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
  3. private final Object handler;
  4. private HandlerInterceptor[] interceptors;
  5. private List<HandlerInterceptor> interceptorList;
  6. private int interceptorIndex = -1;
  7. public HandlerExecutionChain(Object handler) {
  8. this(handler, (HandlerInterceptor[]) null);
  9. }
  10. public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) {
  11. if (handler instanceof HandlerExecutionChain) {
  12. HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
  13. this.handler = originalChain.getHandler();
  14. this.interceptorList = new ArrayList<HandlerInterceptor>();
  15. CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
  16. CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
  17. } else {
  18. this.handler = handler;
  19. this.interceptors = interceptors;
  20. }
  21. }
  22. public void addInterceptor(HandlerInterceptor interceptor) {
  23. initInterceptorList().add(interceptor);
  24. }
  25. public void addInterceptors(HandlerInterceptor... interceptors) {
  26. if (!ObjectUtils.isEmpty(interceptors)) {
  27. CollectionUtils.mergeArrayIntoCollection(interceptors, initInterceptorList());
  28. }
  29. }
  30. private List<HandlerInterceptor> initInterceptorList() {
  31. if (this.interceptorList == null) {
  32. this.interceptorList = new ArrayList<HandlerInterceptor>();
  33. if (this.interceptors != null) {
  34. // An interceptor array specified through the constructor
  35. CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList);
  36. }
  37. }
  38. this.interceptors = null;
  39. return this.interceptorList;
  40. }
  41. boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
  42. HandlerInterceptor[] interceptors = getInterceptors();
  43. if (!ObjectUtils.isEmpty(interceptors)) {
  44. for (int i = 0; i < interceptors.length; i++) {
  45. HandlerInterceptor interceptor = interceptors[i];
  46. if (!interceptor.preHandle(request, response, this.handler)) {
  47. triggerAfterCompletion(request, response, null);
  48. return false;
  49. }
  50. this.interceptorIndex = i;
  51. }
  52. }
  53. return true;
  54. }
  55. void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
  56. HandlerInterceptor[] interceptors = getInterceptors();
  57. if (!ObjectUtils.isEmpty(interceptors)) {
  58. for (int i = interceptors.length - 1; i >= 0; i--) {
  59. HandlerInterceptor interceptor = interceptors[i];
  60. interceptor.postHandle(request, response, this.handler, mv);
  61. }
  62. }
  63. }
  64. void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
  65. throws Exception {
  66. HandlerInterceptor[] interceptors = getInterceptors();
  67. if (!ObjectUtils.isEmpty(interceptors)) {
  68. for (int i = this.interceptorIndex; i >= 0; i--) {
  69. HandlerInterceptor interceptor = interceptors[i];
  70. try {
  71. interceptor.afterCompletion(request, response, this.handler, ex);
  72. }
  73. catch (Throwable ex2) {
  74. logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
  75. }
  76. }
  77. }
  78. }
  79. }

在Spring框架中,DispatcherServlet的doDispatch()方法用来分发请求,它在真正的业务逻辑执行前后,会执行HandlerExecutionChain中的 applyPreHandle()和applyPostHandle()函数,用来实现对请求与响应的拦截功能。

职责链模式常用在框架开发中,用来实现框架的过滤器、拦截器功能,让框架的使用者在不需要修改框架源码的情况下,添加新的过滤拦截功能,体现了对扩展开放、对修改关闭的设计原则。

发表评论

表情:
评论列表 (有 0 条评论,99人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Spring设计模式

    Design Patterns(设计模式) 表示面向对象软件开发中最好的计算机编程实践。 Spring 框架中广泛使用了不同类型的设计模式,下面我们来看看到底有哪些设计模式?