2、初始化阶段在前面我们提到DispatcherServlet的initStrategies方法会初始化9大组件,但是这里将实现一些SpringMVC的最基本的组件而不是全部,按顺序包括:
- 加载配置文件
- 扫描用户配置包下面所有的类
- 拿到扫描到的类,通过反射机制,实例化 。并且放到ioc容器中(Map的键值对 beanName-bean) beanName默认是首字母小写
- 初始化HandlerMapping,这里其实就是把url和method对应起来放在一个k-v的Map中,在运行阶段取出
3、运行阶段每一次请求将会调用doGet或doPost方法,所以统一运行阶段都放在doDispatch方法里处理,它会根据url请求去HandlerMapping中匹配到对应的Method,然后利用反射机制调用Controller中的url对应的方法,并得到结果返回 。按顺序包括以下功能:
- 异常的拦截
- 获取请求传入的参数并处理参数
- 通过初始化好的handlerMapping中拿出url对应的方法名,反射调用
三、实现自己的SpringMVC框架工程文件及目录:

文章插图
首先,新建一个maven项目,在pom.xml中导入以下依赖:
<project xmlns="http://maven.Apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.liugh</groupId><artifactId>liughMVC</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><java.version>1.8</java.version></properties><dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.0.1</version><scope>provided</scope></dependency></dependencies></project>接着,我们在WEB-INF下创建一个web.xml,如下配置:<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"version="3.0"><servlet><servlet-name>MySpringMVC</servlet-name><servlet-class>com.liugh.servlet.MyDispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>application.properties</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>MySpringMVC</servlet-name><url-pattern>/*</url-pattern></servlet-mapping></web-app>application.properties文件中只是配置要扫描的包到SpringMVC容器中 。scanPackage=com.liugh.core
创建自己的Controller注解,它只能标注在类上面:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MyController {/*** 表示给controller注册别名* @return*/String value default "";}RequestMapping注解,可以在类和方法上:@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MyRequestMapping {/*** 表示访问该方法的url* @return*/String value default "";}RequestParam注解,只能注解在参数上@Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MyRequestParam {/*** 表示参数的别名,必填* @return*/String value;}然后创建MyDispatcherServlet这个类,去继承HttpServlet,重写init方法、doGet、doPost方法,以及加上我们第二步分析时要实现的功能:public class MyDispatcherServlet extends HttpServlet{private Properties properties = new Properties;private List<String> classNames = new ArrayList<>;private Map<String, Object> ioc = new HashMap<>;private Map<String, Method> handlerMapping = new HashMap<>;private Map<String, Object> controllerMap =new HashMap<>;@Overridepublic void init(ServletConfig config) throws ServletException {//1.加载配置文件doLoadConfig(config.getInitParameter("contextConfigLocation"));//2.初始化所有相关联的类,扫描用户设定的包下面所有的类doScanner(properties.getProperty("scanPackage"));//3.拿到扫描到的类,通过反射机制,实例化,并且放到ioc容器中(k-v beanName-bean) beanName默认是首字母小写doInstance;//4.初始化HandlerMapping(将url和method对应上)initHandlerMapping;}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {try {//处理请求doDispatch(req,resp);} catch (Exception e) {resp.getWriter.write("500!! Server Exception");}}private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {if(handlerMapping.isEmpty){return;}String url =req.getRequestURI;String contextPath = req.getContextPath;url=url.replace(contextPath, "").replaceAll("/+", "/");if(!this.handlerMapping.containsKey(url)){resp.getWriter.write("404 NOT FOUND!");return;}Method method =this.handlerMapping.get(url);//获取方法的参数列表Class<?> parameterTypes = method.getParameterTypes;//获取请求的参数Map<String, String> parameterMap = req.getParameterMap;//保存参数值ObjectparamValues= new Object[parameterTypes.length];//方法的参数列表for (int i = 0; i<parameterTypes.length; i++){//根据参数名称,做某些处理String requestParam = parameterTypes[i].getSimpleName;if (requestParam.equals("HttpServletRequest")){//参数类型已明确,这边强转类型paramValues[i]=req;continue;}if (requestParam.equals("HttpServletResponse")){paramValues[i]=resp;continue;}if(requestParam.equals("String")){for (Entry<String, String> param : parameterMap.entrySet) {String value =https://www.isolves.com/it/cxkf/kj/2021-09-22/Arrays.toString(param.getValue).replaceAll("/[|/]", "").replaceAll(",/s", ",");paramValues[i]=value;}}}//利用反射机制来调用try {method.invoke(this.controllerMap.get(url), paramValues);//第一个参数是method所对应的实例 在ioc容器中} catch (Exception e) {e.printStackTrace;}}private void doLoadConfig(String location){//把web.xml中的contextConfigLocation对应value值的文件加载到流里面InputStream resourceAsStream = this.getClass.getClassLoader.getResourceAsStream(location);try {//用Properties文件加载文件里的内容properties.load(resourceAsStream);} catch (IOException e) {e.printStackTrace;}finally {//关流if(!=resourceAsStream){try {resourceAsStream.close;} catch (IOException e) {e.printStackTrace;}}}}private void doScanner(String packageName) {//把所有的.替换成/URL url =this.getClass.getClassLoader.getResource("/"+packageName.replaceAll("/.", "/"));File dir = new File(url.getFile);for (File file : dir.listFiles) {if(file.isDirectory){//递归读取包doScanner(packageName+"."+file.getName);}else{String className =packageName +"." +file.getName.replace(".class", "");classNames.add(className);}}}private void doInstance {if (classNames.isEmpty) {return;}for (String className : classNames) {try {//把类搞出来,反射来实例化(只有加@MyController需要实例化)Class
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 为什么项羽听到四面楚歌就认为自己败了-?项羽是四面楚歌吗
- 万历陵墓为什么被挖了?秦始皇墓为何一直无人敢挖
- 粉底液|刘畊宏翻车了?
- 侵权|李子柒斥300余账号恶意侵权:让背后花钱的人失望了 是不是有点气人?
- 亚马逊开店流程?新手做亚马逊需要了解的几点
- 如何挑选轮叶党参
- 如何挑选柳松菇
- 南非博士茶喝了上火,博士茶的功效
- |钓了几条鱼后就没动静了,新手要补窝,老钓友却这样做
- 一个连朋友圈都不让看的人还值得交往吗?不发朋友圈的人值得交往吗
