MVC的工作原理

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

ServletContainerInitializer容器初始化
这是一个接口,用来规范容器的初始化操作,在Spring MVC中,实现类是SpringServletContainerInitializer:
@HandlesTypes(WebApplicationInitializer.class)public class SpringServletContainerInitializer implements ServletContainerInitializer {@Overridepublic void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)throws ServletException {List<WebApplicationInitializer> initializers = new LinkedList<>();// webAppInitializerClasses 就是servlet3.0规范中为我们收集的 WebApplicationInitializer 接口的实现类的class// 从webAppInitializerClasses中筛选并实例化出合格的相应的类if (webAppInitializerClasses != null) {for (Class<?> waiClass : webAppInitializerClasses) {// Be defensive: Some servlet containers provide us with invalid classes,// no matter what @HandlesTypes says...if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&WebApplicationInitializer.class.isAssignableFrom(waiClass)) {try {initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass).newInstance());}catch (Throwable ex) {throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);}}}}if (initializers.isEmpty()) {...}servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");AnnotationAwareOrderComparator.sort(initializers);for (WebApplicationInitializer initializer : initializers) {initializer.onStartup(servletContext);}}}
- SpringServletContainerInitializer 由支持Servlet3.0+的Servlet容器实例化并调用。
- Servlet容器还会查询classpath下SpringServletContainerInitializer类上修饰的@HandlesTypes注解所标注的WebApplicationInitializer接口的实现类. 这一步也是容器帮我们完成的。
- SpringServletContainerInitializer通过实现ServletContainerInitializer将自身并入到Servlet容器的生命周期中, 并通过自身定义的WebApplicationInitializer将依赖于Spring框架的系统初始化需求与Servlet容器解耦. 即依赖于spring的系统可以通过实现WebApplicationInitializer来实现自定义的初始化逻辑. 而不需要去实现ServletContainerInitializer。
ServletRegistration注册
实现了ServletContextInitializer,约定了在Servlet启动时,调用#onStartup。
- 当前注册bean的优先级,通过属性order指定,缺省值为最低优先级Ordered.LOWEST_PRECEDENCE。
- 当前注册bean是否被禁用,通过属性enabled指定。如果被禁用,Servlet容器启动时并不执行该注册bean的注册动作。缺省值为true。
- 通过抽象方法的方式约定了实现子类必须实现某些功能,比如具体注册什么以及具体的注册逻辑都必须由子类实现提供。
FilterRegistration过滤器
注册过滤器组件,具体可以配合@Bean将组件注册到容器中,同样地,ServletRegistration也可以注册,主要代码如下:
@Configurationpublic class Config {/*** 注册一个Filter** @return FilterRegistrationBean*/@Beanpublic FilterRegistrationBean registerFilter() {// 创建Filter注册BeanFilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();// 创建自定义的Filter对象SecondFilter filter = new SecondFilter();// 注册Filterregistration.setFilter(filter);// 设置Filter名称registration.setName("second_filter");// 设置Fliter匹配规则registration.addUrlPatterns("/*");// 设置排序,在存在多个Filter实例的情况下确定Filter的执行顺序registration.setOrder(1);return registration;}/*** 注册一个Servlet** @return ServletRegistrationBean*/@Beanpublic ServletRegistrationBean registerServlet() {// 创建Servlet注册BeanServletRegistrationBean<Servlet> registration = new ServletRegistrationBean<>();// 创建自定义的Servlet对象SecondServlet servlet = new SecondServlet();// 注册Servletregistration.setServlet(servlet);// 设置Servlet名称registration.setName("second_servlet");// 设置Servlet配置规则registration.addUrlMappings("/second_servlet");// 设置加载参数registration.setLoadOnStartup(1);return registration;}/*** 注册一个Listener** @return ServletListenerRegistrationBean*/@Beanpublic ServletListenerRegistrationBean registerListener() {// 创建Listener注册BeanServletListenerRegistrationBean<EventListener> registration = new ServletListenerRegistrationBean<>();// 创建自定义的Listener对象SecondListener listener = new SecondListener();// 注册Listenerregistration.setListener(listener);// 设置排序,在存在多个Listener实例的情况下确定Listener的执行顺序registration.setOrder(1);return registration;}}
各个拦截组件调用顺序
@Autowired和@Resource的区别
都可以用来自动注入bean,写在字段或setter方法上。
@Autowired默认按照类型装配,@Resource默认按照名称装配。
存在多个Bean
比如这个接口有许多个实现类,那么我们需要在注入上面注解@Qualifier(实现类Bean名称)。
不存在Bean
要在括号内写入required=false,比如:@Autowired(required = false)。
@RestController 和 @Controller 有什么区别?
@RestController 注解,在 @Controller 基础上,增加了 @ResponseBody 注解,更加适合目前前后端分离的架构下,提供 Restful API ,返回例如 JSON 数据格式。当然,返回什么样的数据格式,根据客户端的 ACCEPT 请求头来决定。
