源码(码云):https://gitee.com/yin_zhipeng/implement-_springmvc_of_myself.git |
---|
文章目录
一、手写SpringMVC
思路分析 |
---|
所以我们需要搭建一个web骨架,来实现SpringMvc |
---|
- Maven项目和tomcat插件
- 相关依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope><!--tomcat如果有,不使用这个使用自己的,避免冲突-->
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
DispatchServlet,派发Servlet,这个是SpringMvc处理请求的核心,我们先把他搞出来 |
---|
- DispatchServlet类new出来,具体实现后面再说,他就是一个Servlet而已
- web.xml配置DispatchServlet默认拦截所有请求
1. 注解
接下来我们要开发注解 |
---|
- @MyController注解
- @MyService
- @RequestMapping
- @Autowired
2. 流程结构DispatchServlet
接下来按照流程,编写DispatchServlet,加载配置文件,扫描注解,IoC容器初始化Bean |
---|
基本上都是初始化的东西。在init方法完成 |
---|
3. 加载指定配置文件doLoadConfig
为了方便,我们不解析xml了,就用properties文件凑合吧 |
---|
- springmvc.properties文件配置,扫描注解包
- 配置文件配置到web.xml中
解析配置文件 |
---|
- 获取web.xml配置的内容,加载配置文件(操作都放在方法中),建立模板方法
- 编写doLoadConfig()
- 用到的变量
- doLoadConfig()解析
4. 扫描类,注解doScan()
扫描配置文件中指定的包,然后反射注解,进行相应处理 |
---|
- 获取到配置文件包名传给doScan()
- 声明全局(成员)变量,保存扫描到的全限定类名
- 编写doScan()
5. 实现IoC容器,实例化相关Bean,doInstance()
接下来基于注解,我们实现一个简易版Spring IoC容器,用一个map将根据全限定类名反射出来的对象,映射出来 |
---|
- 全局变量,ioc容器
- 工具方法,首字母小写
- doInstance,如果是MyController,就直接加入ioc容器,如果是@MyService,除了实体类加入IoC容器,还需要将接口加入IoC,方便后面依赖注入
6. 注入相关依赖,doAutowired()
接下来判断刚刚实例化到IoC的实例,是否有@Autowired注解,进行实例注入 |
---|
- 注入时,先获取bean所有属性,然后判断属性是否有@Autowired注解,有的话,就寻找ioc容器中,是否有相应实例,有的话,通过反射进行注入
7. 实现initHandlerMapping
最后,就是处理url和Methods的映射了,前面的东西都不重要(都是基础),这个理解了就完事了,SpringMvC的核心 |
---|
先看有缺陷的版本 |
---|
- 保存url和Method的全局变量,容器
- 编写initHandlerMapping(),获取类和方法的@MyRequestMapping注解的value值,进行拼接,然后将url和方法进行映射
而反射玩的溜得小伙伴应该已经发现,我们虽然存储了反射的method,但是没有存储对象,和参数,所以我们需要进行一个封装,封装成一个Handler |
---|
- 假设我们的controller方法参数是这样的
- 封装需要的方法信息
改造initHandlerMapping(),我们封装时,需要封装参数位置,然后将相应的参数传递。而request和response对象,需要特殊处理。因为我们直接把doPost()方法的res和resp直接传输过去 |
---|
- 改造全局变量,不用map了,而是封装成Handler容器
- 改造initHandlerMapping方法
8. 处理请求
有了映射关系,接下来进行请求的处理 |
---|
- 封装一个功能方法,根据req,利用url获取MyHandler
- doPost()
9. 测试
首先,编译器会自动将方法参数,编译成arg0,rag1这种,所以我们的方法参数名,没法存储到map中,需要通过maven指定编译级别 |
---|
<packaging>war</packaging>
<name>implement_springmvc Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope><!--tomcat如果有,不使用这个使用自己的,避免冲突-->
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
<build>
<plugins>
<!--指定编译级别-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId><!--加个插件-->
<version>3.1</version>
<configuration>
<source>8</source><!--JDK-->
<target>8</target><!--编译-->
<encoding>utf-8</encoding><!--编码-->
<compilerArgs>
<arg>-parameters</arg><!--告诉编译器,编译时,记录形参的真实名称-->
</compilerArgs>
</configuration>
</plugin>
<!--tomcat 7插件-->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
</configuration>
</plugin>
</plugins>
</build>
测试 |
---|
- 注意包名,和配置文件中配置要相同
- Service
- controller
启动服务器,访问http://localhost:8080/demo/method?name=zhangsan |
---|
二、SpringMVC高级应用
篇幅原因,我将其放在这篇文章https://blog.csdn.net/grd_java/article/details/123000873 |
---|
三、SpringMVC源码
篇幅原因,我将其放在这篇文章https://blog.csdn.net/grd_java/article/details/123000880 |
---|