探索 SpringBoot (四)SpringMvc 深度解析

探索 SpringBoot (四)SpringMvc 深度解析

缘起

闲着无聊 写写博客。

Servlet & Tomcat & SpringMvc

  • 什么是 servlet?

简单的来说,Servlet 是Java 提供的Servlet 接口

  • 什么是 tomcat ?

简单的来说,tomcat 是实现的Servlet规范的 容器

  • 什么是 springmvc ?

简单的来说,springmvc 是spring 推出的实现Servlet规范的 MVC框架

一句话概括他们的联系

用户的请求经过 tomcat , 被封装 HttpServletRequest,经过 dispatcherservlet, 到达用户的 controller, 最后被封装成 HttpServletResponse 经过容器处理 然后响应给用户 (这里面的内容有点多 以后有时间写篇博客分析下)

DispatcherServlet

请求从到达 DispatcherServlet 的时候便正式进入了 springmvc . DispatcherServlet 工作主要分成两部分

1 初始化组件

在 FrameworkServlet 的 initWebApplicationContext --> onRefresh --> initStrategies 进行组件初始化

protected void initStrategies(ApplicationContext context) {
	initMultipartResolver(context);
	initLocaleResolver(context);
	initThemeResolver(context);
	initHandlerMappings(context);
	initHandlerAdapters(context);
	initHandlerExceptionResolvers(context);
	initRequestToViewNameTranslator(context);
	initViewResolvers(context);
	initFlashMapManager(context);
}

核心组件介绍

基本概念 

handler 处理者,可以简单理解成 controller 中的每个方法 就是一个 handler

1 HandlerMappings: 
可以理解成一个map , 用于寻找 路径(@RequestMap()中定义的) 所对应的 handle 方法

2 HandlerAdapters:

字面意思 就是一个适配器,看起来好像很难理解我们看看这个接口

public interface HandlerAdapter {
	boolean supports(Object handler);
	
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
	
	long getLastModified(HttpServletRequest request, Object handler);

}

我们再来看看接口实现

SimpleServletHandlerAdapter

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {

	((Servlet) handler).service(request, response);
	return null;
}

SimpleControllerHandlerAdapter

@Override
	@Nullable
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {

	return ((Controller) handler).handleRequest(request, response);
}

这下看明白了吧, 就是一个 请求的适配器。定义了一个 handle 接口,让子类去实现请求处理逻辑


3 HandlerExceptionResolver 异常处理的组件 没仔细研究

4 ViewResolver 视图解析 根据 viewName 和 locale 返回视图对象

View resolveViewName(String viewName, Locale locale) throws Exception;

5 MultipartResolver 处理上传请求
  • 九大组件可以参考

https://blog.csdn.net/hu_zhiting/article/details/73648939

2 响应处理

组件也简单介绍了下是对HTTP请求进行响应,作为Servlet,Web容器会调用Servlet的doGet()或者doPost()方法,在经过FrameworkServlet的processRequest()简单处理后,会调用DispatcherServlet的doService方法,在这个方法调用中封装了doDispatch() 处理请求

请求流程

1 请求到达 DispatcherServlet, 然后通过 HandlerMapping (默认通过 RequestMappingHandlerMapping)

2 调用 HandlerMapping 的 getHandler 方法得到 handler( HandlerExecutionChain)

3 根据 handler 获取 HandlerAdapter (RequestMappingHandlerAdapter)

4 HandlerAdapter 调用 handle,最后到达我们的 Controller 层

5 Controller 执行程序 返回 ModelAndView

6 调用 processDispatchResult 处理请求

7 最后 调用 View 的 render 渲染

SpringMvc 手动配置 & 自动装配

  • 我们来简单回忆下原来的 springmvc 要怎么配置吧

1 配置 DispathcherServlet

<servlet>
    <servlet-name>app</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/app-context.xml</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>app</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

2 配置 RequestMappingHandlerMapping RequestMappingHandlerAdapter InternalResourceViewResolver

  <context:component-scan base-package="xxx.controller"/>

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

springmvc 实现自动装配

1 实现 AbstractAnnotationConfigDispatcherServletInitializer

相当于上面的 第一步 配置 DispathcherServlet

/**
 * Spring Web Mvc 自动装配的实现
 *
 * Created by jun on 2018/11/26.
 */
public class DefaultAnnotationConfigDispatcherServletInitializer
        extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Nullable
    @Override
    protected Class<?>[] getRootConfigClasses() {
        // web.xml
        return new Class[0];
    }

    @Nullable
    @Override
    protected Class<?>[] getServletConfigClasses() {
        // dispatcherservlet
        return new Class[] {DispatcherServletConfiguration.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }
}

2 实现 WebMvcConfigurer

@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {

    <!--<bean id="viewResolver" //class="org.springframework.web.servlet.view.InternalResourceViewResolver">-->
//        <!--<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>-->
//        <!--<property name="prefix" value="/WEB-INF/jsp/"/>-->
//        <!--<property name="suffix" value=".jsp"/>-->
//    <!--</bean>-->
    @Bean
    public ViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/jsp/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new HandlerInterceptor() {
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                System.out.println("拦截中...");
                return true;
            }
        });
    }
}

这里相当于 上文的

InternalResourceViewResolver RequestMappingHandlerAdapter RequestMappingHandlerMapping

但是 我们明明只看到了 InternalResourceViewResolver呀,其余的两个呢

我们看看这个注解 @EnableWebMvc

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

。。。

最后 我们在 DelegatingWebMvcConfiguration 的父类 WebMvcConfigurationSupport 中发现了两个bean

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
	RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
	adapter.setContentNegotiationManager(mvcContentNegotiationManager());
	
	...
}

@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
	RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
	mapping.setOrder(0);
	mapping.setInterceptors(getInterceptors());
}

读到这里,也许你明白了

自动配置 只是用 @Bean 注解的方式,将原来在 xml 中配置的bean ,放在代码中配置

在 SpringBoot 里面的实现

SpringBoot 里面 springmvc 自动装配的实现主要是用到 WebMvcAutoConfiguration 这个类

1 SpringBoot 里 dispatcherServlet 的装配

...
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
		TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
...

我们看这行的注解 大概意思是这个类的装配要在 

DispatcherServletAutoConfiguration 之后


我们看看 DispatcherServletAutoConfiguration 干了啥

@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
	DispatcherServlet dispatcherServlet = new DispatcherServlet();
	dispatcherServlet.setDispatchOptionsRequest(
			this.webMvcProperties.isDispatchOptionsRequest());
	dispatcherServlet.setDispatchTraceRequest(
			this.webMvcProperties.isDispatchTraceRequest());
	dispatcherServlet.setThrowExceptionIfNoHandlerFound(
			this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
	dispatcherServlet.setEnableLoggingRequestDetails(
			this.httpProperties.isLogRequestDetails());
	return dispatcherServlet;
}

我们找到了 dispathcerservlet 的装配

@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {

我们再往后看看

ServletWebServerFactoryAutoConfiguration

public class ServletWebServerFactoryAutoConfiguration {

@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(
		ServerProperties serverProperties) {
	return new ServletWebServerFactoryCustomizer(serverProperties);
}

@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
		ServerProperties serverProperties) {
	return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}

大概就是定义了一些容器

  • 在上面我们可以看出 DispatcherServletAutoConfiguration 主要是加载和配置了 dispatcherServlet

2 SpringBoot 里 其他组件的装配 的装配

我们在 WebMvcAutoConfiguration 下面的代码中可以看到

@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {

private final WebMvcProperties mvcProperties;

@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
	RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
	adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null
			|| this.mvcProperties.isIgnoreDefaultModelOnRedirect());
	return adapter;
}

@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
	// Must be @Primary for MvcUriComponentsBuilder to work
	return super.requestMappingHandlerMapping();
}
    
}

这里无非就是覆盖 DelegatingWebMvcConfiguration 的方法,通过外部化配置。加载了 DelegatingWebMvcConfiguration 加载了 springmvc 的基础组件

总结

我们通过 以下几种方式回忆了下 springmvc

1 手动 xml 配置

2 通过 @EnableWebMvc

3 通过 SpringBoot 的自动装配

其实 SpringBoot 自动装配也不是太难,就是通过一些外部化配置,和 @Bean 注解的方式
践行 约定优于配置。我们做了一些简化。核心还是 spring。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值