pom.xml
    pom.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <modelVersion>4.0.0</modelVersion>
    6. <groupId>org.example</groupId>
    7. <artifactId>wisefly-spring-test</artifactId>
    8. <version>1.0-SNAPSHOT</version>
    9. <properties>
    10. <java.version>8</java.version>
    11. </properties>
    12. <dependencies>
    13. <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    14. <dependency>
    15. <groupId>javax.servlet</groupId>
    16. <artifactId>javax.servlet-api</artifactId>
    17. <version>4.0.1</version>
    18. <scope>provided</scope>
    19. </dependency>
    20. </dependencies>
    21. <build>
    22. <plugins>
    23. <plugin>
    24. <groupId>org.springframework.boot</groupId>
    25. <artifactId>spring-boot-maven-plugin</artifactId>
    26. </plugin>
    27. <plugin>
    28. <!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-compiler-plugin -->
    29. <groupId>org.apache.maven.plugins</groupId>
    30. <artifactId>maven-compiler-plugin</artifactId>
    31. <version>2.3.2</version>
    32. <configuration>
    33. <source>8</source>
    34. <target>8</target>
    35. </configuration>
    36. </plugin>
    37. </plugins>
    38. </build>
    39. </project>

    web.xml
    image.png

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    5. version="3.1">
    6. <display-name>wisefly spring framework</display-name>
    7. <servlet>
    8. <servlet-name>mvc</servlet-name>
    9. <servlet-class>com.wisefly.spring.servlet.WiseflyDispatcherServlet</servlet-class>
    10. <init-param>
    11. <param-name>contextConfigLocation</param-name>
    12. <param-value>application.properties</param-value>
    13. </init-param>
    14. <load-on-startup>1</load-on-startup>
    15. </servlet>
    16. <servlet-mapping>
    17. <servlet-name>mvc</servlet-name>
    18. <url-pattern>/*</url-pattern>
    19. </servlet-mapping>
    20. </web-app>

    application.properties
    image.png

    1. scanPackage=com.wisefly.spring

    java代码
    image.png

    WiseflyAutowired

    1. package com.wisefly.spring.annotation;
    2. import java.lang.annotation.Documented;
    3. import java.lang.annotation.ElementType;
    4. import java.lang.annotation.Retention;
    5. import java.lang.annotation.RetentionPolicy;
    6. import java.lang.annotation.Target;
    7. @Target({ElementType.FIELD})
    8. @Retention(RetentionPolicy.RUNTIME)
    9. @Documented
    10. public @interface WiseflyAutowired {
    11. String value() default "";
    12. }

    WiseflyController

    1. package com.wisefly.spring.annotation;
    2. import java.lang.annotation.Documented;
    3. import java.lang.annotation.ElementType;
    4. import java.lang.annotation.Retention;
    5. import java.lang.annotation.RetentionPolicy;
    6. import java.lang.annotation.Target;
    7. @Target({ElementType.TYPE})
    8. @Retention(RetentionPolicy.RUNTIME)
    9. @Documented
    10. public @interface WiseflyController {
    11. String value() default "";
    12. }

    WiseflyRequestMapping

    1. package com.wisefly.spring.annotation;
    2. import java.lang.annotation.Documented;
    3. import java.lang.annotation.ElementType;
    4. import java.lang.annotation.Retention;
    5. import java.lang.annotation.RetentionPolicy;
    6. import java.lang.annotation.Target;
    7. @Target({ElementType.TYPE, ElementType.METHOD})
    8. @Retention(RetentionPolicy.RUNTIME)
    9. @Documented
    10. public @interface WiseflyRequestMapping {
    11. String value() default "";
    12. }

    WiseflyRequestParam

    1. package com.wisefly.spring.annotation;
    2. import java.lang.annotation.Documented;
    3. import java.lang.annotation.ElementType;
    4. import java.lang.annotation.Retention;
    5. import java.lang.annotation.RetentionPolicy;
    6. import java.lang.annotation.Target;
    7. @Target({ElementType.PARAMETER})
    8. @Retention(RetentionPolicy.RUNTIME)
    9. @Documented
    10. public @interface WiseflyRequestParam {
    11. String value() default "";
    12. }

    WiseflyService

    1. package com.wisefly.spring.annotation;
    2. import java.lang.annotation.Documented;
    3. import java.lang.annotation.ElementType;
    4. import java.lang.annotation.Retention;
    5. import java.lang.annotation.RetentionPolicy;
    6. import java.lang.annotation.Target;
    7. @Target({ElementType.TYPE})
    8. @Retention(RetentionPolicy.RUNTIME)
    9. @Documented
    10. public @interface WiseflyService {
    11. String value() default "";
    12. }

    image.png
    Handler

    1. package com.wisefly.spring.handler;
    2. import com.wisefly.spring.annotation.WiseflyRequestParam;
    3. import java.lang.annotation.Annotation;
    4. import java.lang.reflect.Method;
    5. import java.util.HashMap;
    6. import java.util.Map;
    7. import javax.servlet.http.HttpServletRequest;
    8. import javax.servlet.http.HttpServletResponse;
    9. /**
    10. * @author leon
    11. * @className Handler
    12. * @date 2021-08-20 20:03
    13. **/
    14. public class Handler {
    15. private Method method;
    16. private Object controller;
    17. private Map<String, Integer> paramIndexMapping;
    18. public void setMethod(Method method) {
    19. this.method = method;
    20. }
    21. public void setController(Object controller) {
    22. this.controller = controller;
    23. }
    24. public void setParamIndexMapping(Map<String, Integer> paramIndexMapping) {
    25. this.paramIndexMapping = paramIndexMapping;
    26. }
    27. public Method getMethod() {
    28. return method;
    29. }
    30. public Object getController() {
    31. return controller;
    32. }
    33. public Map<String, Integer> getParamIndexMapping() {
    34. return paramIndexMapping;
    35. }
    36. public Handler(Method method, Object controller) {
    37. this.controller = controller;
    38. this.method = method;
    39. paramIndexMapping = new HashMap<>();
    40. putParamIndexMapping(method);
    41. }
    42. /**
    43. * 提取方法中的参数并加入到索引map
    44. *
    45. * @param method
    46. */
    47. private void putParamIndexMapping(Method method) {
    48. // 提取方法中加了注解的参数
    49. Annotation[] [] annotations = method.getParameterAnnotations();
    50. for (int i = 0; i < annotations.length; i++) {
    51. // 二级遍历
    52. for (Annotation annotation : annotations[i]) {
    53. if (annotation instanceof WiseflyRequestParam) {
    54. String paramName = ((WiseflyRequestParam) annotation).value();
    55. // 自定义参数名不为空则加入索引否则用传入的paramMap
    56. if (!"".equals(paramName.trim())) {
    57. paramIndexMapping.put(paramName, i);
    58. }
    59. }
    60. }
    61. }
    62. // 提取参数里的request/response参数
    63. Class<?> [] paramTypes = method.getParameterTypes();
    64. for (int i = 0; i < paramTypes.length; i++) {
    65. Class<?> type = paramTypes[i];
    66. if (type == HttpServletRequest.class || type == HttpServletResponse.class) {
    67. paramIndexMapping.put(type.getName(), i);
    68. }
    69. }
    70. }
    71. }

    image.png
    WiseflyDispatcherServlet

    1. package com.wisefly.spring.servlet;
    2. import com.wisefly.spring.annotation.WiseflyAutowired;
    3. import com.wisefly.spring.annotation.WiseflyController;
    4. import com.wisefly.spring.annotation.WiseflyRequestMapping;
    5. import com.wisefly.spring.annotation.WiseflyService;
    6. import com.wisefly.spring.handler.Handler;
    7. import java.io.File;
    8. import java.io.IOException;
    9. import java.io.InputStream;
    10. import java.lang.reflect.Field;
    11. import java.lang.reflect.InvocationTargetException;
    12. import java.lang.reflect.Method;
    13. import java.net.URL;
    14. import java.util.ArrayList;
    15. import java.util.Arrays;
    16. import java.util.HashMap;
    17. import java.util.List;
    18. import java.util.Map;
    19. import java.util.Properties;
    20. import javax.servlet.ServletConfig;
    21. import javax.servlet.ServletException;
    22. import javax.servlet.http.HttpServlet;
    23. import javax.servlet.http.HttpServletRequest;
    24. import javax.servlet.http.HttpServletResponse;
    25. /**
    26. * @author leon
    27. * @className WiseflyDispatcherServlet
    28. * @date 2021-08-20 19:13
    29. **/
    30. public class WiseflyDispatcherServlet extends HttpServlet {
    31. private Properties properties = new Properties();
    32. private List<String> classNameList = new ArrayList<>();
    33. private Map<String, Object> iocMap;
    34. private Map<String, Handler> handlerMapping;
    35. @Override
    36. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    37. doPost(req, resp);
    38. }
    39. @Override
    40. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    41. // MVC分发执行请求
    42. try {
    43. doDispatch(req, resp);
    44. }
    45. catch (Exception e) {
    46. resp.getWriter().write("500 Exception");
    47. e.printStackTrace();
    48. }
    49. }
    50. private void doDispatch(HttpServletRequest req, HttpServletResponse resp) {
    51. String url = req.getRequestURI();
    52. String contextPath = req.getContextPath();
    53. url = url.replace(contextPath, "").replaceAll("/+", "/");
    54. try {
    55. // 从handlerMapping获取对应的method
    56. Handler handler = handlerMapping.get(url);
    57. if (handler == null) {
    58. resp.getWriter().write("404 NOT FOUND");
    59. return;
    60. }
    61. Object instance = handler.getController();
    62. // 获取执行方法的参数类型列表
    63. Class<?> [] paramTypes = handler.getMethod().getParameterTypes();
    64. // 保存所有需要自动赋值的参数的值
    65. Object [] paramValues = new Object[paramTypes.length];
    66. // 获取请求里的参数
    67. Map<String, String[]> params = req.getParameterMap();
    68. for (Map.Entry<String, String[]> entry : params.entrySet()) {
    69. String value = Arrays.toString(entry.getValue());
    70. // 过滤掉中括号
    71. value = value.replaceAll("\\[|\\]", "");
    72. String paramName = entry.getKey();
    73. int paramIndex = handler.getParamIndexMapping().get(paramName);
    74. paramValues[paramIndex] = value;
    75. }
    76. int requestIndex = handler.getParamIndexMapping().get(HttpServletRequest.class.getName());
    77. paramValues[requestIndex] = req;
    78. int responseIndex = handler.getParamIndexMapping().get(HttpServletResponse.class.getName());
    79. paramValues[responseIndex] = resp;
    80. // 反射执行
    81. handler.getMethod().invoke(handler.getController(), paramValues);
    82. // for debug doDispatch
    83. System.out.println("[doDispatch]:::" + handler.getMethod());
    84. } catch (IOException e) {
    85. e.printStackTrace();
    86. } catch (IllegalAccessException e) {
    87. e.printStackTrace();
    88. } catch (InvocationTargetException e) {
    89. e.printStackTrace();
    90. }
    91. }
    92. @Override
    93. public void init(ServletConfig config) throws ServletException {
    94. // 1:加载spring配置文件
    95. doLoadConfig(config);
    96. // 2:初始化IOC容器
    97. iocMap = new HashMap<>();
    98. // 3:扫描指定的配置包加载到类名列表
    99. doScanner(properties.getProperty("scanPackage"));
    100. // 4:通过反射实例化我们的类
    101. doInstance();
    102. // 5:自动注入
    103. doAutowired();
    104. // ======================== spring初始化完成 ========================
    105. // 6:MVC内容初始化handlerMapping
    106. initHandlerMapping();
    107. }
    108. private void initHandlerMapping() {
    109. if (iocMap.isEmpty()) {
    110. return;
    111. }
    112. // 要想通过url里的method那么获取到对应的method调用
    113. // 通过反射需要的数据支持
    114. // 1:instance调用对象实例
    115. // 2:params调用的参数列表
    116. handlerMapping = new HashMap<>();
    117. // 迭代遍历iocMap
    118. for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
    119. Class<?> clazz = entry.getValue().getClass();
    120. if (!clazz.isAnnotationPresent(WiseflyController.class)) {
    121. continue;
    122. }
    123. String baseUrl = "";
    124. // 如果是requestMapping则需要加入
    125. if (clazz.isAnnotationPresent(WiseflyRequestMapping.class)) {
    126. WiseflyRequestMapping requestMapping = clazz.getAnnotation(WiseflyRequestMapping.class);
    127. baseUrl += requestMapping.value();
    128. }
    129. // 扫描所有的公共方法,过滤掉不是requestMapping的方法
    130. for (Method method : clazz.getMethods()) {
    131. if (!method.isAnnotationPresent(WiseflyRequestMapping.class)) {
    132. continue;
    133. }
    134. // 获取方法上requestMapping的注解的值
    135. WiseflyRequestMapping requestMapping = method.getAnnotation(WiseflyRequestMapping.class);
    136. // 设置其对应的正则匹配,并取出多余的//
    137. String methodKey = ("/" + baseUrl + requestMapping.value()).replaceAll("/+", "/");
    138. // 加入handlerMapping
    139. handlerMapping.put(methodKey, new Handler(method, entry.getValue()));
    140. // for debug info
    141. System.out.println("Mapping:::" + methodKey + "------" + method);
    142. }
    143. }
    144. }
    145. private void doAutowired() {
    146. if (iocMap.isEmpty()) {
    147. return;
    148. }
    149. // 迭代遍历iocMap
    150. for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
    151. // 获取当前实例的成员属性列表
    152. Field[] fields = entry.getValue().getClass().getDeclaredFields();
    153. // 遍历fields
    154. for (Field field : fields) {
    155. if (!field.isAnnotationPresent(WiseflyAutowired.class)) {
    156. continue;
    157. }
    158. WiseflyAutowired autowired = field.getAnnotation(WiseflyAutowired.class);
    159. String beanName = autowired.value().trim();
    160. // 没有自定义用默认名字
    161. if ("".equals(beanName)) {
    162. beanName = field.getType().getName();
    163. }
    164. // 暴力拆除
    165. field.setAccessible(true);
    166. try {
    167. field.set(entry.getValue(), iocMap.get(beanName));
    168. } catch (IllegalAccessException e) {
    169. e.printStackTrace();
    170. }
    171. }
    172. }
    173. }
    174. private void doInstance() {
    175. if (classNameList.isEmpty()) {
    176. return;
    177. }
    178. // 循环遍历开始通过反射实例化
    179. for (String className : classNameList) {
    180. try {
    181. Class<?> clazz = Class.forName(className);
    182. // 并不是所有的类都需要实例化,只实例化有注解的controller,service
    183. if (clazz.isAnnotationPresent(WiseflyController.class)) {
    184. // 获取对象的类名作为key
    185. String beanName = clazz.getName();
    186. // 加入IOC容器
    187. iocMap.put(beanName, clazz.newInstance());
    188. }
    189. else if (clazz.isAnnotationPresent(WiseflyService.class)) {
    190. // 3:如果是个接口那就需要自己的实现类来实例化
    191. WiseflyService service = clazz.getAnnotation(WiseflyService.class);
    192. // 1:如果有自己的名字,那就用自己的
    193. String beanName = service.value();
    194. if ("".equals(beanName.trim())) {
    195. // 2:如果没有自己的名字,那就用默认的类名
    196. beanName = clazz.getName();
    197. }
    198. // 实例化
    199. Object instance = clazz.newInstance();
    200. // 加入IOC容器
    201. iocMap.put(beanName, instance);
    202. for (Class<?> inter : clazz.getInterfaces()) {
    203. // TODO 如果此处有重复的key需要做异常处理
    204. iocMap.put(inter.getName(), instance);
    205. }
    206. }
    207. else {
    208. continue;
    209. }
    210. } catch (ClassNotFoundException e) {
    211. e.printStackTrace();
    212. } catch (IllegalAccessException e) {
    213. e.printStackTrace();
    214. } catch (InstantiationException e) {
    215. e.printStackTrace();
    216. }
    217. }
    218. }
    219. private void doScanner(String scanPackage) {
    220. // 把包里的.替换成/返回一个url
    221. URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
    222. File classDir = new File(url.getFile());
    223. for (File file : classDir.listFiles()) {
    224. // 如果是文件夹
    225. if (file.isDirectory()) {
    226. // 递归
    227. doScanner(scanPackage + "." + file.getName());
    228. }
    229. else {
    230. // 加入类名列表
    231. String className = scanPackage + "." + file.getName().replace(".class", "");
    232. classNameList.add(className);
    233. }
    234. }
    235. }
    236. private void doLoadConfig(ServletConfig config) {
    237. // 从配置文件获取文件流到properties
    238. String configPath = config.getInitParameter("contextConfigLocation");
    239. // 从文件读取application.properties
    240. InputStream is = this.getClass().getClassLoader().getResourceAsStream(configPath);
    241. try {
    242. properties.load(is);
    243. } catch (IOException e) {
    244. e.printStackTrace();
    245. } finally {
    246. try {
    247. is.close();
    248. } catch (IOException e) {
    249. e.printStackTrace();
    250. }
    251. }
    252. }
    253. }

    image.png
    DemoController

    1. package com.wisefly.spring.demo.controller;
    2. import com.wisefly.spring.annotation.WiseflyAutowired;
    3. import com.wisefly.spring.annotation.WiseflyController;
    4. import com.wisefly.spring.annotation.WiseflyRequestMapping;
    5. import com.wisefly.spring.annotation.WiseflyRequestParam;
    6. import com.wisefly.spring.demo.service.IDemoService;
    7. import java.io.IOException;
    8. import javax.servlet.http.HttpServletRequest;
    9. import javax.servlet.http.HttpServletResponse;
    10. /**
    11. * @author leon
    12. * @className DemoController
    13. * @date 2021-08-20 19:21
    14. **/
    15. @WiseflyController
    16. @WiseflyRequestMapping("/demo")
    17. public class DemoController {
    18. @WiseflyAutowired
    19. IDemoService demoService;
    20. @WiseflyRequestMapping("/sayHello")
    21. public void sayHello(HttpServletRequest request, HttpServletResponse response,
    22. @WiseflyRequestParam("name") String name) {
    23. String result = demoService.sayHello(name);
    24. try {
    25. response.getWriter().write(result);
    26. } catch (IOException e) {
    27. e.printStackTrace();
    28. }
    29. }
    30. }

    IDemoService

    1. package com.wisefly.spring.demo.service;
    2. public interface IDemoService {
    3. String sayHello(String name);
    4. }

    DemoServiceImpl

    1. package com.wisefly.spring.demo.service.impl;
    2. import com.wisefly.spring.annotation.WiseflyService;
    3. import com.wisefly.spring.demo.service.IDemoService;
    4. /**
    5. * @author leon
    6. * @className DemoServiceImpl
    7. * @date 2021-08-20 19:25
    8. **/
    9. @WiseflyService("demoService")
    10. public class DemoServiceImpl implements IDemoService {
    11. @Override
    12. public String sayHello(String name) {
    13. return "hello " + name;
    14. }
    15. }