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)
@Documented
public @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)
@Documented
public @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)
@Documented
public @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)
@Documented
public @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)
@Documented
public @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();
// 自定义参数名不为空则加入索引否则用传入的paramMap
if (!"".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;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected 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获取对应的method
Handler 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 doDispatch
System.out.println("[doDispatch]:::" + handler.getMethod());
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
@Override
public 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内容初始化handlerMapping
initHandlerMapping();
}
private void initHandlerMapping() {
if (iocMap.isEmpty()) {
return;
}
// 要想通过url里的method那么获取到对应的method调用
// 通过反射需要的数据支持
// 1:instance调用对象实例
// 2:params调用的参数列表
handlerMapping = new HashMap<>();
// 迭代遍历iocMap
for (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("/+", "/");
// 加入handlerMapping
handlerMapping.put(methodKey, new Handler(method, entry.getValue()));
// for debug info
System.out.println("Mapping:::" + methodKey + "------" + method);
}
}
}
private void doAutowired() {
if (iocMap.isEmpty()) {
return;
}
// 迭代遍历iocMap
for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
// 获取当前实例的成员属性列表
Field[] fields = entry.getValue().getClass().getDeclaredFields();
// 遍历fields
for (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,service
if (clazz.isAnnotationPresent(WiseflyController.class)) {
// 获取对象的类名作为key
String 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) {
// 把包里的.替换成/返回一个url
URL 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) {
// 从配置文件获取文件流到properties
String configPath = config.getInitParameter("contextConfigLocation");
// 从文件读取application.properties
InputStream 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 {
@WiseflyAutowired
IDemoService 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 {
@Override
public String sayHello(String name) {
return "hello " + name;
}
}