spring mvc 调用流程
springmvc handler和Adapter的关系
handlerMapping | handlerAdapter | 描述 |
---|
Controller | SimpleControllerHandlerAdapter | 标准控制器,返回ModelAndView |
HttpRequestHandler | HttpRequestHandlerAdapter | 处理业务不返回ModelAndView |
Servlet | SimpleServletHandlerAdapter | servlet的处理方式 |
HandlerMethod | RequestMappingHandlerAdapter | @requestMapping对应方法处理 |
- handlerMapping继承关系图
- handlerAdapter 继承关系图
SimpleUrlHandlerMapping的xml配置
- 由于在
DispatcherServlet.properties
中默认没有配置SimpleUrlHandlerMapping
所以这里需要在xml文件中配置 - xml配置内容如下:
<bean id="helloController" class="com.demo.mvc.controller.HelloController"/>
<bean
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello">helloController</prop>
</props>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/" />
<property name="suffix" value=".jsp" />
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
</bean>
- 在
Controller
类中,HelloController
需要实现Controller接口,也就是能够使Controller满足是controller满足
BeanNameUrlHandlerMapping的配置
<bean id="/beanName.do"
class="com.demo.mvc.controller.BeanNameHandler"/>
- Controller中实现的Adapter,可以实现
Contoller
或者HttpRequestHandler
、HttpServlet
,例如:
public class BeanNameHandler implements HttpRequestHandler
RequestMappingHandlerMapping和RequestMappingHandlerAdapter的使用
- 以上的处理url中一个Controller只能处理一个url,但是在
RequestMappingHandlerMapping
通过注解的方式可以实现同一个Controller可以处理多个url,
<context:component-scan base-package="com.demo.mvc.controller"/>
@Controller
@RequestMapping("/say")
public class RequestMappingController {
@RequestMapping("/hello")
@ResponseBody
public String sayHello() {
return "你好";
}
}
View
- adapter处理完成之后,通过org.springframework.web.servlet.DispatcherServlet#render方法来处理视图
HandlerExceptionResolver 异常处理
- 在spring mvc中需要配置
- 实现接口
HandlerExceptionResolver
- 在xml文件中配置实现的类
- 在spring boot中配置公共的异常处理类
@RestControllerAdvice
public class GlobalException {
@ExceptionHandler(value = BusinessException.class)
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
public String myException(HttpServletRequest request) {
System.out.println(request.getContextPath());
return "服务器内部异常";
}
}
HandlerInterceptor 拦截器
- 拦截器和filter的区别
- filter是servlet提供的功能,拦截器是spring提供的功能
- filter不能使用spring的对象,而拦截器可以使用spring中的对象
- filter是在请求之前进行过滤,而拦截器可以在请求前后都可以进行处理
- spring mvc的实现方式
- 实现接口
HandlerInterceptor
- 在xml中配置实现的类
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.demo.mvc.controller.MyInterceptor">
</bean>
</mvc:interceptor>
</mvc:interceptors>
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor).addPathPatterns("/*");
}
}
- 拦截器是在获取HandlerMapping的时候加入拦截器的
注解功能实现的原理( mvc:annotation-driven/)
- 接口
NamespaceHandler
的实现MvcNamespaceHandler
会加载AnnotationDrivenBeanDefinitionParser
来加载mapping和adapter,springmvc默认的用了BeanNameUrlHandlerMapping
以及SimpleControllerHandlerAdapter
和HttpRequestHandlerAdapter
两个适配器
上下文注入
- 在spring mvc启动的过程中,会初始化servelt的时候会加载init方法,这个时候会把spring的上下文注入进来,并且会初始化springmvc相关的类
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
configureAndRefreshWebApplicationContext(wac);
return wac;
}
- 上下文最终保存在
FrameworkServlet
的方法initWebApplicationContext中,属性名为:
public static final String SERVLET_CONTEXT_PREFIX = FrameworkServlet.class.getName() + ".CONTEXT.";
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
- 这里的上下文和
org.springframework.web.context.ContextLoaderListener
的区别
ContextLoaderListener
会把spring的上面设置到servletContext的root属性中去`servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);- 在
FrameServlet
的initWebApplicationContext
的方法中会设置父上下文为spring的上下文,而且会加载spring mvc本身的上下文信息
`
HttpMethodMapping加载
- 在servlet的init方法调用的时候会注册url跟handler关系到HttpMethod中去,在调用的时候通过反射的方式来调用相关的方法