- 前端控制器 DispatcherServlet
- 映射处理器 HandlerMapping
- 处理器适配器 HandlerAdapter
- 视图解析器 ViewResolver
核心架构的具体流程步骤如下:
1.用户发送请求——>DispatcherServlet
Dispatcher作为统一的访问点,进行全局的流程控制。
前端控制器收到请求之后自己不进行处理,而是委托给其他解析器进行处理。
【Dispatcher在spring中的代码配置】
一般来说,DispatcherServlet配置如下:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
该DispatcherServlet默认使用WebApplicationContext作为上下文,Spring默认配置文件为“/WEB-INF/[servlet名字]-servlet.xml”。但是DispatcherServlet也可以配置自己的初始化参数,覆盖默认配置:
因此我们可以通过添加初始化参数:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
使用如上配置,Spring Web MVC框架将加载“classpath*:applicationContext.xml”来进行初始化上下文而不是“/WEB-INF/[servlet名字]-servlet.xml”。
2.DispatcherServlet——>HandlerMapping
HandlerMapping充当着URL和Controller之间映射关系配置的角色,它的工作就是为每个请求找到合适的处理器Handler,也就是定位Controller。
HandlerMapping会把请求映射为HandlerExecutionChain对象。
HandlerExecutionChain是一个很有趣的东西,它包括我们要执行的处理方法(Controller)和一组Interceptor(拦截器,非必须),我们可以把它想象为一个执行request最基本的单元。
【HandlerMapping在spring中的代码配置】
在Spring中,HandlerMapping有以下4种映射方式。
(1)BeanNameUrlHandlerMapping(默认)
按照controller的name来映射寻找controlller,它是默认存在的,因此无需在配置文件中配置。
<!-- 配置controller -->
<bean id="testController" name="/hello.do" class="com.roy.controller.TestController"/>
<!-- 按照controller的name来映射寻找controlller,默认存在的 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
(2)SimplerUrlHandlerMapping
使用简单url映射,与默认的映射可以各自独立存在。可以使用此映射来分类配置controller和配置url的各自职责。
<!-- 配置controller -->
<bean id="testController" class="com.roy.controller.TestController"/>
<!-- 按照url来映射 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.do">testController</prop>
</props>
</property>
</bean>
(3)ContraollerClassNameHandlerMapping
这个实际上是去掉控制器中的Controller后,将剩余的部分跟URL匹配,比如,如果不用这个MAPPING的话,要这样搞:
<beans >
<bean name="/welcome.htm"
class="com.mkyong.common.controller.WelcomeController" />
<bean name="/helloGuest.htm"
class="com.mkyong.common.controller.HelloGuestController" />
</beans>
用了这个mapping的话可以这样了:
<beans >
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
<bean class="com.mkyong.common.controller.WelcomeController" />
<bean class="com.mkyong.common.controller.HelloGuestController" />
</beans>
(4)RequestMappingHandlerMapping
RequestMappingHandlerMapping ,用于注解@Controller,@RequestMapping来定义controller。RequestMappingHandlerMapping这个类的对象,只能在controller层用,并且要在申明了@RequestMapping的方法里面用。,从RequestMappingHandlerMapping的源码注释里面可以看出:
/**
* Creates {@link RequestMappingInfo} instances from type and method-level
* {@link RequestMapping @RequestMapping} annotations in
* {@link Controller @Controller} classes.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.1
*/
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
//省略
}
3、DispatcherServlet——>HandlerAdapter
当HandlerMapping获取到执行请求的Controller之后,需要一个帮助定位具体请求方法的处理类,这个类就是HandlerAdapter。
DispatcherServlte会根据HandlerMapping传过来的controller与已经注册好了的HandlerAdapter一一匹配,看哪一种HandlerAdapter是支持该Controller类型的。HandlerAdapter会检查处理类相应处理方法的参数,确定如何转换需要的参数传入调用方法,以及相关Annotation的配置,最终确定使用处理类的哪个处理方法处理请求。
采用HandlerAdapter的原因是因为Controller的类型不同,有多重实现方式,调用的方式是不确定的。因此Spring定义了一个适配接口,使得每一个Controller有一种对应的适配器实现类,让适配器代替Controller执行相应的方法。
如果没有适配器会怎样呢?下面代码是没有经过适配器直接调用Controller:
if(mappedHandler.getHandler() instanceof MultiActionController){
((MultiActionController)mappedHandler.getHandler()).xxx
}else if(mappedHandler.getHandler() instanceof XXX){
...
}else if(...){
...
}
...
这样做的后果就是每增加一个Controller,就要在代码中增加一行if(mappedHandler.getHandler() instanceof XXX),代码将难以维护。
但是如果有了适配器就不一样了,看一下代码,不论实现何种Controller,适配器总能经过适配以后得到想要的结果,匹配成功之后右适配器执行对应的Controller对应方法 ,而无需每调用一个Controller就写一次mappedHandler.getHandler() instanceof XXX 。
//定义一个Adapter接口
public interface HandlerAdapter {
public boolean supports(Object handler);
public void handle(Object handler);
}
//以下是三种Controller实现
public interface Controller {
}
public class HttpController implements Controller{
public void doHttpHandler(){
System.out.println("http...");
}
}
public class SimpleController implements Controller{
public void doSimplerHandler(){
System.out.println("simple...");
}
}
public class AnnotationController implements Controller{
public void doAnnotationHandler(){
System.out.println("annotation...");
}
}
//下面编写适配器类
public class SimpleHandlerAdapter implements HandlerAdapter {
public void handle(Object handler) {
((SimpleController)handler).doSimplerHandler();
}
public boolean supports(Object handler) {
return (handler instanceof SimpleController);
}
}
public class HttpHandlerAdapter implements HandlerAdapter {
public void handle(Object handler) {
((HttpController)handler).doHttpHandler();
}
public boolean supports(Object handler) {
return (handler instanceof HttpController);
}
}
public class AnnotationHandlerAdapter implements HandlerAdapter {
public void handle(Object handler) {
((AnnotationController)handler).doAnnotationHandler();
}
public boolean supports(Object handler) {
return (handler instanceof AnnotationController);
}
}
//模拟一个DispatcherServlet
import java.util.ArrayList;
import java.util.List;
public class DispatchServlet {
public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();
public DispatchServlet(){
handlerAdapters.add(new AnnotationHandlerAdapter());
handlerAdapters.add(new HttpHandlerAdapter());
handlerAdapters.add(new SimpleHandlerAdapter());
}
public void doDispatch(){
//不论实现何种Controller,适配器总能经过适配以后得到想要的结果
// HttpController controller = new HttpController();
// AnnotationController controller = new AnnotationController();
SimpleController controller = new SimpleController();
//得到对应适配器
HandlerAdapter adapter = getHandler(controller);
//通过适配器执行对应的controller对应方法
adapter.handle(controller);
}
public HandlerAdapter getHandler(Controller controller){
for(HandlerAdapter adapter: this.handlerAdapters){
if(adapter.supports(controller)){
return adapter;
}
}
return null;
}
public static void main(String[] args){
new DispatchServlet().doDispatch();
}
}
HandlerAdapter在spring中的代码配置:
<!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
5.HandlerAdapter——>DispatcherServlet
HandlerAdapter把ModelAndView(包含模型数据、逻辑视图名)对象传递给DispatcherServlet
6.ModelAndView的逻辑视图名——>ViewResolver
ViewResolver会将逻辑视图名解析为具体的View。
7.View——>渲染
View根据传进来的Model数据模型进行渲染,此处的Model实际上是一个Map数据结构。
8.视图处理完毕
前端控制器DispatcherServlet将收回控制权,然后由DispatcherServlet返回响应给用户。