【源码】手写SpringMVC框架源码(二)

mac2024-05-22  31

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"> <servlet> <servlet-name>dispatcher</servlet-name> <!--定义MyDispatcherServlet类--> <servlet-class>com.panda.servlet.MyDispatcherServlet</servlet-class> <!--设置为1后,httpServlet初始化调用init方法--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <!--拦截所有请求 /*--> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>

注解类

@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyAutowired { String value() default ""; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyController { String value() default ""; } @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyRequestMapping { String value() default ""; } @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyRequestParam { String value() default ""; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyService { String value() default ""; }

entity/service/controller类

public class User { private String id; private String username; private String password; public User(String id, String username, String password) { this.id = id; this.username = username; this.password = password; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id='" + id + '\'' + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } public interface UserService { public String get(String name); } @MyService("userService") public class UserServiceImpl implements UserService { @Override public String get(String name) { return "查询到姓名为:" + name; } } @MyController public class UserController { @MyAutowired private UserService userService; @MyRequestMapping("/index") public String index(HttpServletRequest request, HttpServletResponse response, @MyRequestParam("name") String name) throws IOException { String res = userService.get(name); System.out.println(name + "=>" + res); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write(res); return "index"; } }

DispathServlet

public class MyDispatcherServlet extends HttpServlet { //类名列表 private List<String> classNames = new ArrayList<String>(); //ioc容器,Map<类名,类实例> private Map<String, Object> ioc = new HashMap<String, Object>(); private List<Handler> handlerMapping = new ArrayList<Handler>(); @Override public void init(ServletConfig config) throws ServletException { System.out.println("init..."); //1.扫描包,将包内所有对象类名存储到list中 doScanner("com.panda.web"); System.out.println("========第一步:扫描文件包=========="); classNames.forEach(value -> System.out.println("保存类名:" + value)); //2.IOC实现,单例模式,new出对象,放入Map中 doInstance(); System.out.println("========第二步:IOC=========="); ioc.forEach((key, value) -> System.out.println("IOC名称:" + key + ":" + value)); //3.DI实现,依赖注入。实现注释MyAutowired的类,进行赋值 doAutoWired(); //4.将requestMapping注释的method方法,放入到Arraylist中 initHandlerMapping(); } private void doScanner(String packageName) { //1.获取当前class的文件路径下的com.panda.web下的文件路径, URL resource = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/")); File classDir = new File(resource.getFile()); for (File classFile : classDir.listFiles()) { if (classFile.isDirectory()) { //2.递归,如果遇到文件夹,递归扫描此文件夹下的class doScanner(packageName + "." + classFile.getName()); } else { //3.文件,直接获取文件名称,存放到List中,形式为com.panda.web.controller.UserController String className = (packageName + "." + classFile.getName()).replace(".class", ""); classNames.add(className); } } } private void doInstance() { if (classNames.isEmpty()) { return; } try { //循环所有扫描出来的类名,将其实例化,并放入ioc容器中 for (String className : classNames) { //类反射机制,获取clazz Class<?> clazz = Class.forName(className); //如果有MyController注解,说明为controller类,可初始化 if (clazz.isAnnotationPresent(MyController.class)) { //ioc的beanId的格式为类名,且首字母小写 String beanName = lowerFirstCase(clazz.getSimpleName()); ioc.put(beanName, clazz.newInstance()); //如果有MyService注解,说明为service类,可初始化 } else if (clazz.isAnnotationPresent(MyService.class)) { //1.如果自己起了名字,优先使用自己的 //2.如果没起名字,使用首字母小写 //3.如果自动注入的为接口,使用接口的全称 MyService service = clazz.getAnnotation(MyService.class); String beanName = service.value(); if ("".equals(beanName)) { beanName = lowerFirstCase(clazz.getSimpleName()); } Object instance = clazz.newInstance(); ioc.put(beanName, instance); //service注解的时候,如实现接口时,再put一次 Class<?>[] interfaces = clazz.getInterfaces(); for (Class<?> i : interfaces) { ioc.put(i.getName(), instance); } } else { //如无注解,无需初始化。 continue; } } } catch (Exception e) { e.printStackTrace(); } } private void doAutoWired() { if (ioc.isEmpty()) { return; } //注入就是对类中定义的一些属性,进行赋值 //不管是公有的还是私有的,都需要赋值 for (Map.Entry<String, Object> entry : ioc.entrySet()) { //getDeclaredFields获取类中,所有的属性值 Field[] fields = entry.getValue().getClass().getDeclaredFields(); for (Field field : fields) { //如果属性上,无注解,直接循环下一次。如有MyAutowired才进行操作 if (!field.isAnnotationPresent(MyAutowired.class)) { continue; } MyAutowired autowired = field.getAnnotation(MyAutowired.class); String beanName = autowired.value(); if ("".equals(beanName)) { //如果beanName是空,使用默认接口注入 beanName = field.getType().getName(); } //开始赋值,setAccessible - 强制访问 field.setAccessible(true); //通过反射机制,强制赋值。将ioc初始化实例后的对象赋值到MyAutowired属性值上 try { field.set(entry.getValue(), ioc.get(beanName)); } catch (IllegalAccessException e) { e.printStackTrace(); continue; } } } } private void initHandlerMapping() { if (ioc.isEmpty()) { return; } for (Map.Entry<String, Object> entry : ioc.entrySet()) { Class<?> clazz = entry.getValue().getClass(); //如果类的注解不是MyController,则继续循环,此方法只处理controller层 if (!clazz.isAnnotationPresent(MyController.class)) { continue; } String baseUrl = ""; //如果类注解有MyRequestMapping,说明定义了根路径,将此路径存储起来 if (clazz.isAnnotationPresent(MyRequestMapping.class)) { MyRequestMapping requestMapping = clazz.getAnnotation(MyRequestMapping.class); baseUrl = requestMapping.value(); } //获取controller类的所有方法,并变量 Method[] methods = clazz.getMethods(); for (Method method : methods) { //如方法无注解,则继续循环,目的获取到所有MyRequestMapping注解的方法 if (!method.isAnnotationPresent(MyRequestMapping.class)) { continue; } //获取MyRequestMapping注解的路径,并与根路径进行拼接 MyRequestMapping requestMapping = method.getAnnotation(MyRequestMapping.class); String url = (baseUrl + requestMapping.value()).replaceAll("/+", "/"); Pattern pattern = Pattern.compile(url); //url和method的方法,封装到handler类中 handlerMapping.add(new Handler(pattern, entry.getValue(), method)); System.out.println("mapped:" + url + "=>" + method); } } } private String lowerFirstCase(String str) { char[] chars = str.toCharArray(); chars[0] += 32; return String.valueOf(chars); } //内部类 private class Handler { protected Object controller;//保存controller的实例对象 protected Method method;//保存controller类的method方法 protected Pattern pattern;//url正则表达是 protected Map<String, Integer> paramIndexMapping;//param注解的map存储 protected Handler(Pattern pattern, Object controller, Method method) { this.pattern = pattern; this.controller = controller; this.method = method; paramIndexMapping = new HashMap<String, Integer>(); putParamIndexMapping(method); } private void putParamIndexMapping(Method method) { Annotation[][] pa = method.getParameterAnnotations(); for (int i = 0; i < pa.length; i++) { for (Annotation a : pa[i]) { if (a instanceof MyRequestParam) { String paramName = ((MyRequestParam) a).value(); if (!"".equals(paramName)) { paramIndexMapping.put(paramName, i); } } } } 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); } } } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { this.doPost(req, res); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { doDispatcher(req, res); } public void doDispatcher(HttpServletRequest req, HttpServletResponse res) { try { //获取request中的url访问路径和参数,从ArrayList的handlerMapping中查找。找到后,执行method方法 Handler handler = getHandler(req); if (handler == null) { res.getWriter().write("404 not found."); return; } Class<?>[] paramTypes = handler.method.getParameterTypes(); Object[] paramValues = new Object[paramTypes.length]; //获取访问链接中的params,并对其循环 Map<String, String[]> params = req.getParameterMap(); for (Map.Entry<String, String[]> param : params.entrySet()) { String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", ""); if (!handler.paramIndexMapping.containsKey(param.getKey())) { continue; } int index = handler.paramIndexMapping.get(param.getKey()); paramValues[index] = convert(paramTypes[index], value); } int reqIndex = handler.paramIndexMapping.get(HttpServletRequest.class.getName()); paramValues[reqIndex] = req; int resIndex = handler.paramIndexMapping.get(HttpServletResponse.class.getName()); paramValues[resIndex] = res; //method方法执行 handler.method.invoke(handler.controller, paramValues); } catch (Exception e) { e.printStackTrace(); } } //通过request的url链接,寻找handler对象中是否有对应的method private Handler getHandler(HttpServletRequest req) { if (handlerMapping.isEmpty()) { return null; } String url = req.getRequestURI(); String contextPath = req.getContextPath(); url = url.replace(contextPath, "").replaceAll("/+", "/"); for (Handler handler : handlerMapping) { Matcher matcher = handler.pattern.matcher(url); if (!matcher.matches()) { continue; } //url有对应的method,返回handler return handler; } //url无对应的method,返回null return null; } private Object convert(Class<?> type, String value) { if (Integer.class == type) { return Integer.valueOf(value); } return value; } }

码云地址:[https://gitee.com/xumiaofeng/springmvc]

最新回复(0)