MVC的工作原理

image-20200216210725288.png

  1. 客户端的所有请求都交给前端控制器DispatcherServlet来处理,它会负责调用系统的其他模块来真正处理用户的请求。
  2. DispatcherServlet收到请求后,将根据请求的信息(包括URL、HTTP协议方法、请求头、请求参数、Cookie等)以及HandlerMapping的配置找到处理该请求的Handler(任何一个对象都可以作为请求的Handler)。
  3. 在这个地方Spring会通过HandlerAdapter对该处理器进行封装。
  4. HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用。
  5. Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息。
  6. ModelAndView的视图是逻辑视图,DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作。
  7. 当得到真正的视图对象后,DispatcherServlet会利用视图对象对模型数据进行渲染。
  8. 客户端得到响应,可能是一个普通的HTML页面,也可以是XML或JSON字符串,还可以是一张图片或者一个PDF文件。

Servlet3.0注解

image-20200216213727679.png

ServletContainerInitializer容器初始化

这是一个接口,用来规范容器的初始化操作,在Spring MVC中,实现类是SpringServletContainerInitializer:

  1. @HandlesTypes(WebApplicationInitializer.class)
  2. public class SpringServletContainerInitializer implements ServletContainerInitializer {
  3. @Override
  4. public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
  5. throws ServletException {
  6. List<WebApplicationInitializer> initializers = new LinkedList<>();
  7. // webAppInitializerClasses 就是servlet3.0规范中为我们收集的 WebApplicationInitializer 接口的实现类的class
  8. // 从webAppInitializerClasses中筛选并实例化出合格的相应的类
  9. if (webAppInitializerClasses != null) {
  10. for (Class<?> waiClass : webAppInitializerClasses) {
  11. // Be defensive: Some servlet containers provide us with invalid classes,
  12. // no matter what @HandlesTypes says...
  13. if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
  14. WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
  15. try {
  16. initializers.add((WebApplicationInitializer)
  17. ReflectionUtils.accessibleConstructor(waiClass).newInstance());
  18. }
  19. catch (Throwable ex) {
  20. throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
  21. }
  22. }
  23. }
  24. }
  25. if (initializers.isEmpty()) {
  26. ...
  27. }
  28. servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
  29. AnnotationAwareOrderComparator.sort(initializers);
  30. for (WebApplicationInitializer initializer : initializers) {
  31. initializer.onStartup(servletContext);
  32. }
  33. }
  34. }
  1. SpringServletContainerInitializer 由支持Servlet3.0+的Servlet容器实例化并调用。
  2. Servlet容器还会查询classpath下SpringServletContainerInitializer类上修饰的@HandlesTypes注解所标注的WebApplicationInitializer接口的实现类. 这一步也是容器帮我们完成的。
  3. SpringServletContainerInitializer通过实现ServletContainerInitializer将自身并入到Servlet容器的生命周期中, 并通过自身定义的WebApplicationInitializer将依赖于Spring框架的系统初始化需求Servlet容器解耦. 即依赖于spring的系统可以通过实现WebApplicationInitializer来实现自定义的初始化逻辑. 而不需要去实现ServletContainerInitializer。

ServletRegistration注册

实现了ServletContextInitializer,约定了在Servlet启动时,调用#onStartup。

  1. 当前注册bean的优先级,通过属性order指定,缺省值为最低优先级Ordered.LOWEST_PRECEDENCE。
  2. 当前注册bean是否被禁用,通过属性enabled指定。如果被禁用,Servlet容器启动时并不执行该注册bean的注册动作。缺省值为true。
  3. 通过抽象方法的方式约定了实现子类必须实现某些功能,比如具体注册什么以及具体的注册逻辑都必须由子类实现提供。

FilterRegistration过滤器

注册过滤器组件,具体可以配合@Bean将组件注册到容器中,同样地,ServletRegistration也可以注册,主要代码如下:

  1. @Configuration
  2. public class Config {
  3. /**
  4. * 注册一个Filter
  5. *
  6. * @return FilterRegistrationBean
  7. */
  8. @Bean
  9. public FilterRegistrationBean registerFilter() {
  10. // 创建Filter注册Bean
  11. FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
  12. // 创建自定义的Filter对象
  13. SecondFilter filter = new SecondFilter();
  14. // 注册Filter
  15. registration.setFilter(filter);
  16. // 设置Filter名称
  17. registration.setName("second_filter");
  18. // 设置Fliter匹配规则
  19. registration.addUrlPatterns("/*");
  20. // 设置排序,在存在多个Filter实例的情况下确定Filter的执行顺序
  21. registration.setOrder(1);
  22. return registration;
  23. }
  24. /**
  25. * 注册一个Servlet
  26. *
  27. * @return ServletRegistrationBean
  28. */
  29. @Bean
  30. public ServletRegistrationBean registerServlet() {
  31. // 创建Servlet注册Bean
  32. ServletRegistrationBean<Servlet> registration = new ServletRegistrationBean<>();
  33. // 创建自定义的Servlet对象
  34. SecondServlet servlet = new SecondServlet();
  35. // 注册Servlet
  36. registration.setServlet(servlet);
  37. // 设置Servlet名称
  38. registration.setName("second_servlet");
  39. // 设置Servlet配置规则
  40. registration.addUrlMappings("/second_servlet");
  41. // 设置加载参数
  42. registration.setLoadOnStartup(1);
  43. return registration;
  44. }
  45. /**
  46. * 注册一个Listener
  47. *
  48. * @return ServletListenerRegistrationBean
  49. */
  50. @Bean
  51. public ServletListenerRegistrationBean registerListener() {
  52. // 创建Listener注册Bean
  53. ServletListenerRegistrationBean<EventListener> registration = new ServletListenerRegistrationBean<>();
  54. // 创建自定义的Listener对象
  55. SecondListener listener = new SecondListener();
  56. // 注册Listener
  57. registration.setListener(listener);
  58. // 设置排序,在存在多个Listener实例的情况下确定Listener的执行顺序
  59. registration.setOrder(1);
  60. return registration;
  61. }
  62. }

各个拦截组件调用顺序

image-20200216215004856.png

@Autowired和@Resource的区别

都可以用来自动注入bean,写在字段或setter方法上。
@Autowired默认按照类型装配,@Resource默认按照名称装配。

存在多个Bean

比如这个接口有许多个实现类,那么我们需要在注入上面注解@Qualifier(实现类Bean名称)。

不存在Bean

要在括号内写入required=false,比如:@Autowired(required = false)

@RestController 和 @Controller 有什么区别?

@RestController 注解,在 @Controller 基础上,增加了 @ResponseBody 注解,更加适合目前前后端分离的架构下,提供 Restful API ,返回例如 JSON 数据格式。当然,返回什么样的数据格式,根据客户端的 ACCEPT 请求头来决定。