手写简易版SpringIoc、SpringMvc

清疚 2022-12-18 13:55 295阅读 0赞

1 工程目录

在这里插入图片描述

2 pom

  1. <properties>
  2. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  3. </properties>
  4. <dependencies>
  5. <dependency>
  6. <groupId>javax.servlet</groupId>
  7. <artifactId>javax.servlet-api</artifactId>
  8. <version>3.1.0</version>
  9. <scope>provided</scope>
  10. </dependency>
  11. </dependencies>
  12. <build>
  13. <plugins>
  14. <plugin>
  15. <groupId>org.apache.maven.plugins</groupId>
  16. <artifactId>maven-compiler-plugin</artifactId>
  17. <version>3.1</version>
  18. <configuration>
  19. <source>1.8</source>
  20. <target>1.8</target>
  21. </configuration>
  22. </plugin>
  23. <plugin>
  24. <groupId>org.apache.tomcat.maven</groupId>
  25. <artifactId>tomcat7-maven-plugin</artifactId>
  26. <version>2.2</version>
  27. <configuration>
  28. <path>/</path>
  29. <port>8080</port>
  30. </configuration>
  31. </plugin>
  32. </plugins>
  33. </build>

3 web.xml

  1. <!DOCTYPE web-app PUBLIC
  2. "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  3. "http://java.sun.com/dtd/web-app_2_3.dtd" >
  4. <web-app>
  5. <display-name>Rosh Created Web Application</display-name>
  6. <servlet>
  7. <servlet-name>roshmvc</servlet-name>
  8. <servlet-class>com.rosh.mvcframework.servlet.RoshDispatcherServlet</servlet-class>
  9. <init-param>
  10. <param-name>contextConfigLocation</param-name>
  11. <param-value>application.properties</param-value>
  12. </init-param>
  13. <load-on-startup>1</load-on-startup>
  14. </servlet>
  15. <servlet-mapping>
  16. <servlet-name>roshmvc</servlet-name>
  17. <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>

4 application.properties

  1. scanPackage=com.rosh.demo

5 注解

  1. @Target({ ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface RoshService {
  5. String value() default "";
  6. }
  7. @Target({ ElementType.PARAMETER})
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Documented
  10. public @interface RoshRequestParam {
  11. String value() default "";
  12. }
  13. @Target({ ElementType.TYPE,ElementType.METHOD})
  14. @Retention(RetentionPolicy.RUNTIME)
  15. @Documented
  16. public @interface RoshRequestMapping {
  17. String value() default "";
  18. }
  19. @Target({ ElementType.TYPE})
  20. @Retention(RetentionPolicy.RUNTIME)
  21. @Documented
  22. public @interface RoshController {
  23. String value() default "";
  24. }
  25. @Target({ ElementType.FIELD})
  26. @Retention(RetentionPolicy.RUNTIME)
  27. @Documented
  28. public @interface RoshAutowired {
  29. String value() default "";
  30. }

6 RoshDispatcherServlet

  1. package com.rosh.mvcframework.servlet;
  2. import com.rosh.mvcframework.annotation.RoshAutowired;
  3. import com.rosh.mvcframework.annotation.RoshController;
  4. import com.rosh.mvcframework.annotation.RoshRequestMapping;
  5. import com.rosh.mvcframework.annotation.RoshService;
  6. import javax.servlet.ServletConfig;
  7. import javax.servlet.ServletException;
  8. import javax.servlet.http.HttpServlet;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.io.File;
  12. import java.io.IOException;
  13. import java.io.InputStream;
  14. import java.lang.reflect.Field;
  15. import java.lang.reflect.Method;
  16. import java.net.URL;
  17. import java.util.*;
  18. public class RoshDispatcherServlet extends HttpServlet {
  19. private Properties contextConfig = new Properties();
  20. private List<String> classNames = new ArrayList<>();
  21. private Map<String, Object> ioc = new HashMap<>();
  22. private Map<String, Method> handlerMapping = new HashMap<>();
  23. @Override
  24. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  25. this.doPost(req, resp);
  26. }
  27. @Override
  28. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  29. //调用
  30. try {
  31. doDispatch(req, resp);
  32. } catch (Exception e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
  37. //绝对路径
  38. String url = req.getRequestURI();
  39. //相对路径
  40. String contextPath = req.getContextPath();
  41. url = url.replaceAll(contextPath, "").replaceAll("/+", "/");
  42. if (this.handlerMapping.containsKey(url)) {
  43. Method method = this.handlerMapping.get(url);
  44. //beanname
  45. String beanName = toLowerFirstCase(method.getDeclaringClass().getSimpleName());
  46. //参数
  47. Map<String, String[]> parameterMap = req.getParameterMap();
  48. method.invoke(ioc.get(beanName), new Object[]{ req, resp, parameterMap.get("name")[0]});
  49. } else {
  50. resp.getWriter().write("404 Not Found!!!!");
  51. }
  52. }
  53. @Override
  54. public void init(ServletConfig config) throws ServletException {
  55. //1 加载配置文件
  56. doLoadConfig(config.getInitParameter("contextConfigLocation"));
  57. //2 扫描相关类
  58. doScanner(contextConfig.getProperty("scanPackage"));
  59. //3 初始化扫描到的类,并且将他们放入到IOC容器中
  60. doInstance();
  61. //4 完成依赖注入
  62. doAutowired();
  63. //5 初始化HandlerMapping
  64. initHandlerMapping();
  65. System.out.println("Rosh Spring framework is init.");
  66. }
  67. /** * 映射 */
  68. private void initHandlerMapping() {
  69. if (!ioc.isEmpty()) {
  70. for (Map.Entry<String, Object> entry : ioc.entrySet()) {
  71. Class<?> clazz = entry.getValue().getClass();
  72. if (clazz.isAnnotationPresent(RoshController.class)) {
  73. String baseUrl = "";
  74. if (clazz.isAnnotationPresent(RoshRequestMapping.class)) {
  75. RoshRequestMapping requestMapping = clazz.getAnnotation(RoshRequestMapping.class);
  76. baseUrl = requestMapping.value();
  77. }
  78. //获取所有public 方法
  79. Method[] methods = clazz.getMethods();
  80. for (Method method : methods) {
  81. if (method.isAnnotationPresent(RoshRequestMapping.class)) {
  82. RoshRequestMapping requestMapping = method.getAnnotation(RoshRequestMapping.class);
  83. String url = (baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");
  84. handlerMapping.put(url, method);
  85. }
  86. }
  87. }
  88. }
  89. }
  90. }
  91. /** * 自动注入 */
  92. private void doAutowired() {
  93. if (!ioc.isEmpty()) {
  94. for (Map.Entry<String, Object> entry : ioc.entrySet()) {
  95. //所有字段
  96. Field[] fields = entry.getValue().getClass().getDeclaredFields();
  97. for (Field field : fields) {
  98. if (field.isAnnotationPresent(RoshAutowired.class)) {
  99. RoshAutowired autowired = field.getAnnotation(RoshAutowired.class);
  100. String beanName = autowired.value();
  101. if ("".endsWith(beanName)) {
  102. beanName = field.getType().getName();
  103. }
  104. field.setAccessible(true);
  105. try {
  106. //反射机制,动态赋值
  107. field.set(entry.getValue(), ioc.get(beanName));
  108. } catch (IllegalAccessException e) {
  109. e.printStackTrace();
  110. }
  111. }
  112. }
  113. }
  114. }
  115. }
  116. /** * 初始化 */
  117. private void doInstance() {
  118. if (classNames.isEmpty()) {
  119. return;
  120. }
  121. try {
  122. for (String className : classNames) {
  123. Class<?> clazz = Class.forName(className);
  124. //判断注解
  125. if (clazz.isAnnotationPresent(RoshController.class)) {
  126. Object o = clazz.newInstance();
  127. String beanName = toLowerFirstCase(clazz.getSimpleName());
  128. ioc.put(beanName, o);
  129. } else if (clazz.isAnnotationPresent(RoshService.class)) {
  130. //1 默认beanName
  131. String beanName = toLowerFirstCase(clazz.getSimpleName());
  132. //2 自定义beanName
  133. RoshService roshService = clazz.getAnnotation(RoshService.class);
  134. if (!"".endsWith(roshService.value())) {
  135. beanName = roshService.value();
  136. }
  137. Object o = clazz.newInstance();
  138. ioc.put(beanName, o);
  139. //3 根据类型自动赋值
  140. for (Class<?> i : clazz.getInterfaces()) {
  141. if (!ioc.containsKey(i.getName())) {
  142. ioc.put(i.getName(), o);
  143. }
  144. }
  145. }
  146. }
  147. } catch (Exception e) {
  148. e.printStackTrace();
  149. }
  150. }
  151. private String toLowerFirstCase(String simpleName) {
  152. char[] chars = simpleName.toCharArray();
  153. chars[0] += 32;
  154. return String.valueOf(chars);
  155. }
  156. /** * 扫描出相关的类 */
  157. private void doScanner(String scanPackage) {
  158. //获取类文件url
  159. URL url = this.getClass().getClassLoader().getResource(scanPackage.replaceAll("\\.", "/"));
  160. //读取当前类文件
  161. File rootFile = new File(url.getFile());
  162. //遍历
  163. for (File file : rootFile.listFiles()) {
  164. if (file.isDirectory()) {
  165. doScanner(scanPackage + "." + file.getName());
  166. } else {
  167. if (!file.getName().endsWith(".class")) {
  168. continue;
  169. }
  170. //获取类名
  171. String className = scanPackage + "." + file.getName().replace(".class", "");
  172. classNames.add(className);
  173. }
  174. }
  175. }
  176. /** * 加载配置文件 */
  177. private void doLoadConfig(String contextConfigLocation) {
  178. InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
  179. try {
  180. contextConfig.load(is);
  181. } catch (IOException e) {
  182. e.printStackTrace();
  183. } finally {
  184. if (is != null) {
  185. try {
  186. is.close();
  187. } catch (IOException e) {
  188. e.printStackTrace();
  189. }
  190. }
  191. }
  192. }
  193. }

7 业务类

  1. @RoshController
  2. @RoshRequestMapping("/student")
  3. public class StudentController {
  4. @RoshAutowired
  5. private StudentService studentService;
  6. @RoshRequestMapping("/query")
  7. public void query(HttpServletRequest req, HttpServletResponse resp,
  8. @RoshRequestParam("name") String name) {
  9. String result = "<h1>My name is " + name + "</h1>";
  10. try {
  11. resp.getWriter().write(result);
  12. } catch (IOException e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. }
  17. public interface StudentService {
  18. }
  19. @RoshService
  20. public class StudentServiceImpl implements StudentService {
  21. }

8 测试

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,295人围观)

还没有评论,来说两句吧...

相关阅读

    相关 简易的Mybatis

    手写简易的Mybatis -------------------- 此篇文章用来记录今天花个五个小时写出来的简易版mybatis,主要实现了基于注解方式的增删查改,...