SpringMVC流程图
-
用户发送请求至前端控制器DispatcherServlet。
-
DispatcherServlet收到请求调用HandlerMapping处理器映射器。
-
处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
-
DispatcherServlet调用HandlerAdapter处理器适配器。
-
HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
-
Controller执行完成返回ModelAndView。
-
HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
-
DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
-
ViewReslover解析后返回具体View。
-
DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
-
DispatcherServlet响应用户。
SpringMVC核心组件
1、前端控制器DispatcherServlet
作用:接收请求,响应结果,相当于转发器,中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
2、处理器映射器HandlerMapping
作用:根据请求的url查找Handler
HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
4、处理器Handler
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler。
5、视图解析器View resolver(不需要工程师开发),由框架提供
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。
6、视图View
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
手写 SpringMVC 思路
处理器:
- 使用内嵌的tomcat作为servlet容器
注解方式(@Controller 定义处理器):
- 打开Spring Ioc 扫描,讲处理器放入容器,方便后面后置处理器从容器中取出,如果发现加了@Controller 则可以认为是一个处理器
- 实现SpringMVC 的@RequestMapping 注解,获取参数url,和处理器一起放入 Map<url,处理器>
- 获取请求传入的参数并处理参数,通过初始化好的handlerMapping中拿出url对应的方法名,反射调用
基于 servlet 定义处理器 调用 service()
接口方式(实现Controller接口 定义处理器)调用 handleRequest
接口方式(实现HttpRequestHandler 接口 定义处理器)调用 handleRequest
适配器(跟映射器一一对应):
- 统一的接口
- 判断适配是否成功 Object处理器 instanseOf Controller
- 执行处理逻辑 (Controller)处理器 调用 handleRequest
序列化返回:
- 第一种方式是spring2时代的产物,也就是每个json视图controller配置一个Jsoniew
- 第二种使用JSON工具将对象序列化成json,常用工具Jackson,fastjson,gson
- 注解@ResponseBody
参数绑定:
注解方式:@RequestParam(value)里面的参数值和我们的方法值进行匹配,匹配成功的则为该方法的参数
非注解方式:jdk7:asm字节码技术;jdk8:可以通过反射获取参数名
具体代码实现
内嵌的tomcat作为servlet容器,完成IOC注入,Servlet初始化工作
@ComponentScan("com.zy")
public class Start {
public static void main(String[] args) throws Exception {
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
Context appContext = tomcat.addWebapp("/", "D:\\workspace\\springmvc\\src\\main\\webapp");
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Start.class);
tomcat.addServlet(appContext,"dispatcherServlet",new DispatcherServlet(ac));
appContext.addServletMapping("/","dispatcherServlet");
tomcat.start();
tomcat.getServer().await();
}
}
映射器,基于注解和Controller接口实现
注解形式:
@Component
public class AnnotationHadlerMapping implements HandlerMapping,InstantiationAwareBeanPostProcessor {
public static Map<String,RequestMappingInfo> map = new HashMap<>();
@Override
//bean里面会有多个处理器
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
Method[] methods = bean.getClass().getDeclaredMethods();
for(Method method : methods){
RequestMappingInfo requestMappingInfo = createRequestMappingInfo(method,bean);
map.put(requestMappingInfo.getUri(),requestMappingInfo);
}
return true;
}
private RequestMappingInfo createRequestMappingInfo(Method method,Object bean) {
RequestMappingInfo requestMappingInfo = new RequestMappingInfo();
if(method.isAnnotationPresent(RequestMapping.class)){
requestMappingInfo.setMethod(method);
requestMappingInfo.setUri(method.getDeclaredAnnotation(RequestMapping.class).value());
requestMappingInfo.setObj(bean);
}
return requestMappingInfo;
}
@Override
public Object getHandlerMapping(String requestURI) {
return map.get(requestURI);
}
}
Controller接口形式:
@Component
public class BeanNameHandlerMapping implements HandlerMapping,InstantiationAwareBeanPostProcessor {
public static Map<String, Controller> map = new HashMap<>();
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if(beanName.startsWith("/")){
map.put(beanName,(Controller)bean);
}
return true;
}
@Override
public Object getHandlerMapping(String requestURI) {
return map.get(requestURI);
}
}
适配器
注解形式:
@Component
public class AnnotationHandlerAdapter implements HandlerAdapter{
@Override
public boolean supports(Object handler) {
//判断是否是RequestMapping子类
return (handler instanceof RequestMappingInfo);
}
@Override
//参数绑定
public Object handle(HttpServletRequest request, HttpServletResponse response, Object handler){
RequestMappingInfo requestMappingInfo = (RequestMappingInfo)handler;
Map<String, String[]> paramMap = request.getParameterMap();//请求携带的参数
Method method = requestMappingInfo.getMethod();//方法定义的参数
Parameter[] parameters = method.getParameters();
Object[] params = new Object[method.getParameterTypes().length];
for(int i=0; i<parameters.length; i++){
for(Map.Entry<String, String[]> entry : paramMap.entrySet()){
if(parameters[i].getAnnotation(RequestParam.class) != null && entry.getKey()!= null &&
entry.getKey().equals(parameters[i].getAnnotation(RequestParam.class).value())){
params[i] = entry.getValue()[0];
//jdk1.8实现反射获取方法名 1.8之前使用asm实现
}else if(entry.getKey().equals(parameters[i].getName())){
params[i] = entry.getValue()[0];
}
}
//传入request和response
if(ServletRequest.class.isAssignableFrom(parameters[i].getType())){
params[i] = request;
}else if(ServletResponse.class.isAssignableFrom(parameters[i].getType())){
params[i] = response;
}
}
try {
Object result = method.invoke(requestMappingInfo.getObj(),params);
if (result instanceof String) {
if ("forward".equals(((String) result).split(":")[0])) {
request.getRequestDispatcher(((String) result).split(":")[1]).forward(request, response);
} else {
response.sendRedirect(((String) result).split(":")[1]);
}
}else{
if(method.isAnnotationPresent(ResponseBody.class)){
return JSON.toJSONString(result);
}
}
return result;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
Controller接口方式
@Component
public class BeanNameHandlerAdapter implements HandlerAdapter{
@Override
// //判断hanlde是否适配当前适配器
public boolean supports(Object handler) {
//判断是否是RequestMapping子类
return (handler instanceof Controller);
}
@Override
public Object handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
return ((Controller)handler).handler(request, response);
}
}
控制器
public class DispatcherServlet extends HttpServlet {
static Collection<HandlerAdapter> handlerAdapters ;
static Collection<HandlerMapping> handlerMappings ;
public DispatcherServlet() {
}
//构造器
public DispatcherServlet(AnnotationConfigApplicationContext ac) {
//映射器
Map<String, HandlerMapping> handlerMappingMaps = ac.getBeansOfType(HandlerMapping.class);
handlerMappings = handlerMappingMaps.values();
//适配器
Map<String, HandlerAdapter> handlerAdapterMaps = ac.getBeansOfType(HandlerAdapter.class);
handlerAdapters = handlerAdapterMaps.values();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
Object handlerMapping = getHandlerMapping(req);
if(handlerMapping == null){
System.out.println("未匹配到handlerMapping");
return;
}
HandlerAdapter handlerAdapter = getHandlerAdapter(handlerMapping);
if(handlerAdapter == null){
System.out.println("未匹配到handlerAdapter");
return;
}
Object result = handlerAdapter.handle(req,resp,handlerMapping);
PrintWriter writer = resp.getWriter();
writer.println(result);
writer.flush();
writer.close();
}
protected Object getHandlerMapping(HttpServletRequest request) {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
Object handler = mapping.getHandlerMapping(request.getRequestURI());
if (handler != null) {
return handler;
}
}
}
return null;
}
protected HandlerAdapter getHandlerAdapter(Object handlerMapping) {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
boolean flag = adapter.supports(handlerMapping);
if (flag) {
return adapter;
}
}
}
return null;
}
}
lerMapping) {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
boolean flag = adapter.supports(handlerMapping);
if (flag) {
return adapter;
}
}
}
return null;
}
}