1.1 执行流程图
复制代码
1.2 执行过程
复制代码
读取配置文件前端
SpringMVC本质上是一个Servlet,为了读取web.xml配置,这里用到了ServletConfig 这个类,它表明当前Servlet在web.xml中的配置信息,经过 [^ config.getInitParameter("contextConfigLocation");//读取启动参数],读取application.properties。java
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>application.properties</param-value>
</init-param>
复制代码
初始化阶段git
@Override
public 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对应上)
iniHandlerMapping();
}
复制代码
运行阶段github
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 No Found");
return;
}
Method method = this.handlerMapping.get(url);
//获取方法的参数列表
Class<?>[] parameterTypes = method.getParameterTypes();
//获取请求的参数
Map<String, String[]> parameterMap = req.getParameterMap();
//保存参数值
Object [] paramValues = new Object[parameterTypes.length];
//方法的参数列表
for (int i = 0; i < parameterTypes.length; i++) {
//根据参数名称,作某些处理
String requestParam = parameterTypes[i].getSimpleName();
if("HttpServletRequest".equals(requestParam)){
//参数类型已明确,强转类型是
paramValues[i] = req;
continue;
}
if("HttpServletResponse".equals(requestParam)){
paramValues[i] = resp;
continue;
}
if("String".equals(requestParam)){
for (Entry<String, String[]> param : parameterMap.entrySet()) {
String valuse = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");
paramValues[i] = valuse;
}
}
}
//利用反射机制调用
try {
method.invoke(this.controllerMap.get(url),paramValues);//第一个参数为method所对应的实例,在IOC容器中
}catch (Exception e){
e.printStackTrace();
}
复制代码
Maven的依赖范围provided后端
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<!-- <scope>xxx</scope>依赖范围 * compile,缺省值,适用于全部阶段,会随着项目一块儿发布。 * provided,相似compile,指望JDK、容器或使用者会提供这个依赖。如servlet.jar。 * runtime,只在运行时使用,如JDBC驱动,适用运行和测试阶段。 * test,只在测试时使用,用于编译和运行测试代码。不会随项目发布。 * system,相似provided,须要显式提供包含依赖的jar,Maven不会在Repository中查找它。 -->
<scope>provided</scope>
</dependency>
</dependencies>
复制代码
Java元注解api
/** * java中元注解有四个: @Retention @Target @Document @Inherited; *   @Retention:注解的保留位置 *     @Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含 *     @Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时没法得到, *     @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时能够经过反射获取到 * *   @Target:注解的做用目标 *     @Target(ElementType.TYPE) //接口、类、枚举、注解 *     @Target(ElementType.FIELD) //字段、枚举的常量 *     @Target(ElementType.METHOD) //方法 *     @Target(ElementType.PARAMETER) //方法参数 *     @Target(ElementType.CONSTRUCTOR) //构造函数 *     @Target(ElementType.LOCAL_VARIABLE)//局部变量 *     @Target(ElementType.ANNOTATION_TYPE)//注解 *     @Target(ElementType.PACKAGE) ///包 * * @Document:说明该注解将被包含在javadoc中 * *   @Inherited:说明子类能够继承父类中的该注解 */
复制代码