pom.xml
pom.xml
<?xml version="1.0" encoding="UTF-8"?><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>org.example</groupId><artifactId>wisefly-spring-test</artifactId><version>1.0-SNAPSHOT</version><properties><java.version>8</java.version></properties><dependencies><!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-compiler-plugin --><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>8</source><target>8</target></configuration></plugin></plugins></build></project>
web.xml
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"version="3.1"><display-name>wisefly spring framework</display-name><servlet><servlet-name>mvc</servlet-name><servlet-class>com.wisefly.spring.servlet.WiseflyDispatcherServlet</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>mvc</servlet-name><url-pattern>/*</url-pattern></servlet-mapping></web-app>
application.properties
scanPackage=com.wisefly.spring
java代码
WiseflyAutowired
package com.wisefly.spring.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface WiseflyAutowired {String value() default "";}
WiseflyController
package com.wisefly.spring.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface WiseflyController {String value() default "";}
WiseflyRequestMapping
package com.wisefly.spring.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface WiseflyRequestMapping {String value() default "";}
WiseflyRequestParam
package com.wisefly.spring.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface WiseflyRequestParam {String value() default "";}
WiseflyService
package com.wisefly.spring.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface WiseflyService {String value() default "";}

Handler
package com.wisefly.spring.handler;import com.wisefly.spring.annotation.WiseflyRequestParam;import java.lang.annotation.Annotation;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*** @author leon* @className Handler* @date 2021-08-20 20:03**/public class Handler {private Method method;private Object controller;private Map<String, Integer> paramIndexMapping;public void setMethod(Method method) {this.method = method;}public void setController(Object controller) {this.controller = controller;}public void setParamIndexMapping(Map<String, Integer> paramIndexMapping) {this.paramIndexMapping = paramIndexMapping;}public Method getMethod() {return method;}public Object getController() {return controller;}public Map<String, Integer> getParamIndexMapping() {return paramIndexMapping;}public Handler(Method method, Object controller) {this.controller = controller;this.method = method;paramIndexMapping = new HashMap<>();putParamIndexMapping(method);}/*** 提取方法中的参数并加入到索引map** @param method*/private void putParamIndexMapping(Method method) {// 提取方法中加了注解的参数Annotation[] [] annotations = method.getParameterAnnotations();for (int i = 0; i < annotations.length; i++) {// 二级遍历for (Annotation annotation : annotations[i]) {if (annotation instanceof WiseflyRequestParam) {String paramName = ((WiseflyRequestParam) annotation).value();// 自定义参数名不为空则加入索引否则用传入的paramMapif (!"".equals(paramName.trim())) {paramIndexMapping.put(paramName, i);}}}}// 提取参数里的request/response参数Class<?> [] paramTypes = method.getParameterTypes();for (int i = 0; i < paramTypes.length; i++) {Class<?> type = paramTypes[i];if (type == HttpServletRequest.class || type == HttpServletResponse.class) {paramIndexMapping.put(type.getName(), i);}}}}

WiseflyDispatcherServlet
package com.wisefly.spring.servlet;import com.wisefly.spring.annotation.WiseflyAutowired;import com.wisefly.spring.annotation.WiseflyController;import com.wisefly.spring.annotation.WiseflyRequestMapping;import com.wisefly.spring.annotation.WiseflyService;import com.wisefly.spring.handler.Handler;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.net.URL;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Properties;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*** @author leon* @className WiseflyDispatcherServlet* @date 2021-08-20 19:13**/public class WiseflyDispatcherServlet extends HttpServlet {private Properties properties = new Properties();private List<String> classNameList = new ArrayList<>();private Map<String, Object> iocMap;private Map<String, Handler> handlerMapping;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// MVC分发执行请求try {doDispatch(req, resp);}catch (Exception e) {resp.getWriter().write("500 Exception");e.printStackTrace();}}private void doDispatch(HttpServletRequest req, HttpServletResponse resp) {String url = req.getRequestURI();String contextPath = req.getContextPath();url = url.replace(contextPath, "").replaceAll("/+", "/");try {// 从handlerMapping获取对应的methodHandler handler = handlerMapping.get(url);if (handler == null) {resp.getWriter().write("404 NOT FOUND");return;}Object instance = handler.getController();// 获取执行方法的参数类型列表Class<?> [] paramTypes = handler.getMethod().getParameterTypes();// 保存所有需要自动赋值的参数的值Object [] paramValues = new Object[paramTypes.length];// 获取请求里的参数Map<String, String[]> params = req.getParameterMap();for (Map.Entry<String, String[]> entry : params.entrySet()) {String value = Arrays.toString(entry.getValue());// 过滤掉中括号value = value.replaceAll("\\[|\\]", "");String paramName = entry.getKey();int paramIndex = handler.getParamIndexMapping().get(paramName);paramValues[paramIndex] = value;}int requestIndex = handler.getParamIndexMapping().get(HttpServletRequest.class.getName());paramValues[requestIndex] = req;int responseIndex = handler.getParamIndexMapping().get(HttpServletResponse.class.getName());paramValues[responseIndex] = resp;// 反射执行handler.getMethod().invoke(handler.getController(), paramValues);// for debug doDispatchSystem.out.println("[doDispatch]:::" + handler.getMethod());} catch (IOException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}@Overridepublic void init(ServletConfig config) throws ServletException {// 1:加载spring配置文件doLoadConfig(config);// 2:初始化IOC容器iocMap = new HashMap<>();// 3:扫描指定的配置包加载到类名列表doScanner(properties.getProperty("scanPackage"));// 4:通过反射实例化我们的类doInstance();// 5:自动注入doAutowired();// ======================== spring初始化完成 ========================// 6:MVC内容初始化handlerMappinginitHandlerMapping();}private void initHandlerMapping() {if (iocMap.isEmpty()) {return;}// 要想通过url里的method那么获取到对应的method调用// 通过反射需要的数据支持// 1:instance调用对象实例// 2:params调用的参数列表handlerMapping = new HashMap<>();// 迭代遍历iocMapfor (Map.Entry<String, Object> entry : iocMap.entrySet()) {Class<?> clazz = entry.getValue().getClass();if (!clazz.isAnnotationPresent(WiseflyController.class)) {continue;}String baseUrl = "";// 如果是requestMapping则需要加入if (clazz.isAnnotationPresent(WiseflyRequestMapping.class)) {WiseflyRequestMapping requestMapping = clazz.getAnnotation(WiseflyRequestMapping.class);baseUrl += requestMapping.value();}// 扫描所有的公共方法,过滤掉不是requestMapping的方法for (Method method : clazz.getMethods()) {if (!method.isAnnotationPresent(WiseflyRequestMapping.class)) {continue;}// 获取方法上requestMapping的注解的值WiseflyRequestMapping requestMapping = method.getAnnotation(WiseflyRequestMapping.class);// 设置其对应的正则匹配,并取出多余的//String methodKey = ("/" + baseUrl + requestMapping.value()).replaceAll("/+", "/");// 加入handlerMappinghandlerMapping.put(methodKey, new Handler(method, entry.getValue()));// for debug infoSystem.out.println("Mapping:::" + methodKey + "------" + method);}}}private void doAutowired() {if (iocMap.isEmpty()) {return;}// 迭代遍历iocMapfor (Map.Entry<String, Object> entry : iocMap.entrySet()) {// 获取当前实例的成员属性列表Field[] fields = entry.getValue().getClass().getDeclaredFields();// 遍历fieldsfor (Field field : fields) {if (!field.isAnnotationPresent(WiseflyAutowired.class)) {continue;}WiseflyAutowired autowired = field.getAnnotation(WiseflyAutowired.class);String beanName = autowired.value().trim();// 没有自定义用默认名字if ("".equals(beanName)) {beanName = field.getType().getName();}// 暴力拆除field.setAccessible(true);try {field.set(entry.getValue(), iocMap.get(beanName));} catch (IllegalAccessException e) {e.printStackTrace();}}}}private void doInstance() {if (classNameList.isEmpty()) {return;}// 循环遍历开始通过反射实例化for (String className : classNameList) {try {Class<?> clazz = Class.forName(className);// 并不是所有的类都需要实例化,只实例化有注解的controller,serviceif (clazz.isAnnotationPresent(WiseflyController.class)) {// 获取对象的类名作为keyString beanName = clazz.getName();// 加入IOC容器iocMap.put(beanName, clazz.newInstance());}else if (clazz.isAnnotationPresent(WiseflyService.class)) {// 3:如果是个接口那就需要自己的实现类来实例化WiseflyService service = clazz.getAnnotation(WiseflyService.class);// 1:如果有自己的名字,那就用自己的String beanName = service.value();if ("".equals(beanName.trim())) {// 2:如果没有自己的名字,那就用默认的类名beanName = clazz.getName();}// 实例化Object instance = clazz.newInstance();// 加入IOC容器iocMap.put(beanName, instance);for (Class<?> inter : clazz.getInterfaces()) {// TODO 如果此处有重复的key需要做异常处理iocMap.put(inter.getName(), instance);}}else {continue;}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}}}private void doScanner(String scanPackage) {// 把包里的.替换成/返回一个urlURL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));File classDir = new File(url.getFile());for (File file : classDir.listFiles()) {// 如果是文件夹if (file.isDirectory()) {// 递归doScanner(scanPackage + "." + file.getName());}else {// 加入类名列表String className = scanPackage + "." + file.getName().replace(".class", "");classNameList.add(className);}}}private void doLoadConfig(ServletConfig config) {// 从配置文件获取文件流到propertiesString configPath = config.getInitParameter("contextConfigLocation");// 从文件读取application.propertiesInputStream is = this.getClass().getClassLoader().getResourceAsStream(configPath);try {properties.load(is);} catch (IOException e) {e.printStackTrace();} finally {try {is.close();} catch (IOException e) {e.printStackTrace();}}}}

DemoController
package com.wisefly.spring.demo.controller;import com.wisefly.spring.annotation.WiseflyAutowired;import com.wisefly.spring.annotation.WiseflyController;import com.wisefly.spring.annotation.WiseflyRequestMapping;import com.wisefly.spring.annotation.WiseflyRequestParam;import com.wisefly.spring.demo.service.IDemoService;import java.io.IOException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*** @author leon* @className DemoController* @date 2021-08-20 19:21**/@WiseflyController@WiseflyRequestMapping("/demo")public class DemoController {@WiseflyAutowiredIDemoService demoService;@WiseflyRequestMapping("/sayHello")public void sayHello(HttpServletRequest request, HttpServletResponse response,@WiseflyRequestParam("name") String name) {String result = demoService.sayHello(name);try {response.getWriter().write(result);} catch (IOException e) {e.printStackTrace();}}}
IDemoService
package com.wisefly.spring.demo.service;public interface IDemoService {String sayHello(String name);}
DemoServiceImpl
package com.wisefly.spring.demo.service.impl;import com.wisefly.spring.annotation.WiseflyService;import com.wisefly.spring.demo.service.IDemoService;/*** @author leon* @className DemoServiceImpl* @date 2021-08-20 19:25**/@WiseflyService("demoService")public class DemoServiceImpl implements IDemoService {@Overridepublic String sayHello(String name) {return "hello " + name;}}
