美文网首页
唰唰的手撕一个简单的Spring Mvc 框架

唰唰的手撕一个简单的Spring Mvc 框架

作者: 喊我小王吧 | 来源:发表于2020-12-05 20:56 被阅读0次

    @[TOC]

    自定义实现Spring Mvc框架

    前言

    在使用Spring Mvc时候我们需要配置一个中央处理器DispatcherServlet用于分发请求,根据url查找处理器,然后再根据处理器去处理不同的Url去执行不同的方法,最后到处理完数据,再返回给前端;这一过程都是在DispatcherServlet处理器中去执行的;

    可以看到下图是SpringMvc的请求流程图


    在这里插入图片描述

    当url进来的时候我们就应该去加载完成url和一些方法的对应关系,以及注册和处理好bean的依赖关系;

    如需要自己去实现一个这个框架:

    可以思考一下:

    1 需要提供一个路径去扫描包下的所有类
    2 然后解析处理类,注册bean 维护依赖关系
    3 处理好url和方法的对应关系
    4 在DispatcherServlet中取根据前端请求的url去查找到具体的处理器,然后再根据url去找到具的执行方法,去执行反方,返回给前端;

    具体操作:

    步骤

    • 1 启动tomcat
      DisPatcherServlet 加载配置文件SpringMvc.xml

    • 2 指定包扫描,扫描注解

      @Controllelr
      @Service
      @Autowired
      @RequestMapping 维护url映射

    • 3 加入IOC容器
      初始化对象,维护依赖关系,维护url映射

    • 4 SpringMVC相关组件初始化

      简历Url和method之间的映射关系---> 映射器 HanderMappping

    • 5 请求处理

    代码实现

    环境搭建

    JDK8 ,IDEA 2019 03

    依赖

     <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
                <scope>provided</scope>
            </dependency>
    
    
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.9</version>
            </dependency>
    

    插件

    
            <plugins>
    
                <!-- 配置Maven的JDK编译级别 -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>8</source>
                        <target>8</target>
                        <encoding>UTF-8</encoding>
                        <!--告诉编译器,编译的时候记录下形参的真实名称-->
                        <compilerArgs>
                            <arg>-parameters</arg>
                        </compilerArgs>
                    </configuration>
                </plugin>
    
                <!-- tomcat7插件 -->
                <!-- 注意:目前来说,maven中央仓库还没有tomcat8的插件 -->
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.2</version>
                    <configuration>
                        <port>8080</port>
                        <path>/</path>
                    </configuration>
                </plugin>
    
            </plugins>
    

    自定义注解

    Autowired

    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Autowired {
        String name() default "";
    
    }
    

    Controller

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Controller {
    }
    
    

    RequestMapping

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestMapping {
        String value() default "";
    }
    

    Service

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Service {
        String value() default "";
    }
    
    

    定义service 和 controller代码

    Test控制层

    @RequestMapping("/api")
    @Controller
    public class Test {
    
        @Autowired
        private TestService testService;
    
        @RequestMapping("/test")
        public String test(HttpServletRequest request, HttpServletResponse response, String name) {
    
            return testService.test(name);
        }
    }
    
    

    TestService 接口

    public interface TestService {
    
        String test(String name);
    }
    
    

    TestServiceImpl实现类

    @Service(value = "testServiceImpl")
    public class TestServiceImpl implements TestService {
    
        @Override
        public String test(String name) {
            System.out.println("-------------------- name = " + name);
            return "--------- " + name;
        }
    
    }
    

    定义DisPatcherServlet处理器

    处理前端所有的请求都走DisPatcherServlet处理器

        <!--    处理请求 -->
        <servlet-mapping>
            <servlet-name>mvc-servlte</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
        
    

    DisPatcherServlet 继承 HttpServlet 接口,重写init get post方法

    public class DisPatcherServlet extends HttpServlet {
        @Override
        public void init() throws ServletException {
        // 初始化参数 加载配置文件,bean实例化 以及依赖维护
                //1 加载配置文件
                doLoadConfigFile(resourceAsStream);
                // 2 扫描包
                doScanPackage();
                // 3  bean实例化和依赖维护
                doInitBean();
                // 4 维护url和method之间的映射关系
                doHandlerMapping();
                
    }
       @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 {
    
     // 处理请求 
    }
    }
    

    初始化反方里 需要我们去加载bean 实例化和依赖维护,,以及封装好url对应的方法handler

    定义方法

        //1 加载配置文件
                doLoadConfigFile(resourceAsStream);
                // 2 扫描包
                doScanPackage();
                // 3  bean实例化和依赖维护
                doInitBean();
                // 4 维护url和method之间的映射关系
                doHandlerMapping();
    

    加载配置文件

    对应到springmvc中就是包扫描配置扫描那些包
    这儿配置一个properties文件 mvc.properties配置需要扫描的包路径

    mvc.path=com.udem.edu
    

    通过类加载器去加载配置文件获取到流

      //加载流
            InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("mvc.properties");
    
    

    然后获取包路径封装文件到 Properties中

        /**
         * 加载配置文件
         *
         * @param resourceAsStream
         */
        private void doLoadConfigFile(InputStream resourceAsStream) {
            try {
                properties.load(resourceAsStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    包扫描

    包路径转换成文件路径然后去扫描,判断是否文件夹或文件,然后保存类的全限定命名到集合中,这个没得说;

    
        /**
         * 包扫描获取字节码对象
         *
         * @throws UnsupportedEncodingException
         */
        private void doScanPackage() throws UnsupportedEncodingException {
            //获取mvc包路径
            String packName = properties.getProperty("mvc.path");
            if (Objects.isNull(packName) || packName.length() == 0) {
                throw new RuntimeException("无效的包路径");
            }
            packName = packName.replace(".", File.separator);
            URL resource = this.getClass().getClassLoader().getResource(packName);
            String path = resource.getPath();
            //解析中文
            String filePath = URLDecoder.decode(path, "UTF-8");
    
            //解析包成java权限定命名com
            parseFilePackName(packName, stringSet, filePath);
    
        }
    

    bean实例化和依赖维护

    判断类上的注解以及封装到IOC 依赖维护赋值值给含有 Autowired 注解的成员变量

      /**
         * bean实例化和bean依赖注入关系维护
         *
         * @throws ClassNotFoundException
         * @throws IllegalAccessException
         * @throws InstantiationException
         */
        private void doInitBean() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            for (String className : stringSet) {
                //反射创建对象
                Class<?> aClass = Class.forName(className);
                //查找 Controller 注解
                Controller annotation = aClass.getAnnotation(Controller.class);
                if (Objects.nonNull(annotation)) {
                    //实例化存入ioc
                    IOC_MAP.put(aClass.getSimpleName(), aClass.newInstance());
                }
                //查找 service 注解
                Service service = aClass.getAnnotation(Service.class);
                if (Objects.nonNull(service)) {
                    //实例化存入ioc
                    IOC_MAP.put(aClass.getSimpleName(), aClass.newInstance());
                    //如果实现类接口 按照接口实例化
                    Class<?>[] interfaces = aClass.getInterfaces();
                    if (Objects.nonNull(interfaces) && interfaces.length > 0) {
                        for (Class<?> anInterface : interfaces) {
                            //按照接口名进行实例化
                            IOC_MAP.put(anInterface.getSimpleName(), aClass.newInstance());
                        }
    
                    }
                }
            }
    
    
            //依赖注入
            for (Map.Entry<String, Object> stringObjectEntry : IOC_MAP.entrySet()) {
    
                Class aClass = stringObjectEntry.getValue().getClass();
                //获取所有字段
                Field[] declaredFields = aClass.getDeclaredFields();
    
                if (Objects.isNull(declaredFields) && declaredFields.length == 0) {
                    continue;
                }
    
                for (Field field : declaredFields) {
                    //field.get
                    //字段含有 Autowired 注解的需要被自动装配对象
                    Autowired autowired = field.getAnnotation(Autowired.class);
    
                    if (Objects.nonNull(autowired)) {
                        //根据当前key获取需要注入示例对象
                        //先根据名字注入,如果名字获取不到,再根据类型去注入
                        String beanName = autowired.name();
    
                        if (Objects.isNull(beanName) || beanName.length() == 0) {
                            beanName = field.getType().getSimpleName();
                        }
    
                        //反射设置值
                        try {
                            field.setAccessible(true);
                            //自动装配 线程不安全,Spring中默认单例
                            field.set(stringObjectEntry.getValue(), IOC_MAP.get(beanName));
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
    
        }
    

    handlerMapper 处理映射器

    维护url和method之间的映射关系
    这儿需要处理控制层的参数方法,也就是控制层方法的参数顺序,需要和之后 DisPatcherServlet中请求处理传递进来的参数保持一致

    在 DisPatcherServlet 中根据请求url获取到这里封装的 handle 然后传递请求的参数与原方法需要的参数保持一致,反射调用;

    封装 handle 对象用于保存参数位置,以及那个方法,那个控制器!

    /**
     * 封装handler方法相关的信息
     * <p>
     * handler参数相关信息
     */
    public class Handle {
    
    
        /**
         * method.invoke(obj 需要执行得对象
         */
        private Object controller;
    
        /**
         * url正则匹配对象
         */
        private Pattern pattern;
    
        /**
         * 需要调用得url对应得方法
         */
        private Method method;
    
        /**
         * 存储参数顺序,为了进行参数绑定  Integer 第几个参数
         */
        private Map<String, Integer> map;
    
    
        public Handle(Object controller, Pattern pattern, Method method) {
            this.controller = controller;
            this.pattern = pattern;
            this.method = method;
            map = new HashMap<>();
        }
    
       // get  set省略
    }
    
    

    封装handler方法相关的信息

    这儿我们目前只处理String类型的传参,其他对象之类的暂时不涉及到...

        private void doHandlerMapping() {
    
            if (IOC_MAP.isEmpty()) {
                return;
            }
    
            //只处理controller层
            for (Map.Entry<String, Object> stringObjectEntry : IOC_MAP.entrySet()) {
    
                Class<?> objectEntryValue = stringObjectEntry.getValue().getClass();
                //没有包含 注解 跳过
                if (!objectEntryValue.isAnnotationPresent(Controller.class)) {
                    continue;
                }
    
                String url = "";
                //包含 RequestMapping 注解 就获取url
                if (objectEntryValue.isAnnotationPresent(RequestMapping.class)) {
                    RequestMapping requestMapping = objectEntryValue.getAnnotation(RequestMapping.class);
                    url = requestMapping.value();
                }
    
    
                //获取方法
                Method[] methods = objectEntryValue.getMethods();
                if (methods.length <= 0 || Objects.isNull(methods)) {
                    continue;
                }
    
                for (Method method : methods) {
                    //如果不包含就跳过
                    if (!method.isAnnotationPresent(RequestMapping.class)) {
                        continue;
                    }
                    //获取当前方法上 RequestMapping 的注解
                    RequestMapping requestMapping = method.getDeclaredAnnotation(RequestMapping.class);
                    //构建url
                    String urls = url + requestMapping.value();
    
                    //封装handler
                    Handle handle = new Handle(stringObjectEntry.getValue(), Pattern.compile(urls), method);
    
                    //处理计算参数位置
                    Parameter[] parameters = method.getParameters();
                    if (parameters != null && parameters.length > 0) {
                        for (int i = 0; i < parameters.length; i++) {
                            Parameter parameter = parameters[i];
                            if (parameter.getType() == HttpServletRequest.class || parameter.getType() == HttpServletResponse.class) {
                                //如果是 参数名称存本身
                                handle.getMap().put(parameter.getType().getSimpleName(), i);
                            }
                            //如果是tring类型
                            else {
                                //String类型存储name
                                handle.getMap().put(parameter.getName(), i);
                            }
                            //其他类型暂时不做判断
                        }
                        HANDLE_MAPPING.add(handle);
                    }
    
    
                }
    
            }
    
    
        }
    

    doPost中 处理请求

    根据HttpServletRequest 获取到请求参数以及url

     
            String requestURI = req.getRequestURI();
            //遍历请求中得参数顺序
            Map<String, String[]> reqParameterMaps = req.getParameterMap();
    
            System.out.println("------- 当前请求的url是 : " +  requestURI);
            if (Objects.isNull(requestURI) || requestURI.length() == 0) {
                return;
            }
    

    获取这个请求url的处理器handler ,如果不存在返回404

      //5.1 获取handle
            Handle handler = getHandler(req);
       if (Objects.isNull(handler)){
                resp.getWriter().println("404....");
                return;
            }
    

    获取到具体的执行方法以及方法中的参数顺序 也就是封装handler时候封装的map

     //获取执行方法
            Method method = handler.getMethod();
    
            Parameter[] parameters = handler.getMethod().getParameters();
            //5.2 获取型参数
            Map<String, Integer> map1 = handler.getMap();
    
    

    设置请求的url中的请求参数 与 method中的方法参数一致

      //设置传递参数 
            Object[] objects = new Object[parameters.length];
    
    
          //遍历除reqest 和 response之外的参数 并且填充到参数数组里
            for (Map.Entry<String, String[]> stringEntry : reqParameterMaps.entrySet()) {
                //判断请求参数和形参是否参数匹配
                //多个参数直接 , 拼接
                String value = StringUtils.join(stringEntry.getValue(), ",");  // 如同 1,2
                if (!map1.containsKey(stringEntry.getKey())) {
                   continue;
                }
                //获取型参数索引
                Integer index = map1.get(stringEntry.getKey());
    
                //赋值参数
                objects[index] = value;
            }
    
      int index1 = map1.get(HttpServletRequest.class.getSimpleName());
            int index2 = map1.get(HttpServletResponse.class.getSimpleName());
            //获取ret对象参数
            objects[index1] = req;
            //获取resp对象参数
            objects[index2] = resp;
    

    反射执行方法

    
            try {
               String result = (String) method.invoke(handler.getController(), objects);
               resp.getWriter().println(result);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
    
    

    完整的DisPatcherServlet代码

    package com.udem.mvcframework.servlet;
    
    import com.udem.mvcframework.annotation.Autowired;
    import com.udem.mvcframework.annotation.Controller;
    import com.udem.mvcframework.annotation.RequestMapping;
    import com.udem.mvcframework.annotation.Service;
    import org.apache.commons.lang3.StringUtils;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.UnsupportedEncodingException;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Parameter;
    import java.net.URL;
    import java.net.URLDecoder;
    import java.util.*;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    
    /**
     * 前端请求中央处理器
     */
    public class DisPatcherServlet extends HttpServlet {
    
        /**
         * 封装配置文件属性
         */
        private final static Properties properties = new Properties();
    
        /**
         * 存放扫描类的全限定命名
         */
        private final static Set<String> stringSet = new HashSet<>();
    
        /**
         * .class
         */
        public static final String CLASS_STR = ".class";
    
    
        /**
         * 存储bean单例
         */
        public final static Map<String, Object> IOC_MAP = new HashMap<>();
    
    
        /**
         * 构建映射信息
         */
        public final static List<Handle> HANDLE_MAPPING = new ArrayList<>();
    
    
        @Override
        public void init() throws ServletException {
            //加载流
            InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("mvc.properties");
    
            System.out.println("----------------- 初始化 -------------------");
            super.init();
    
    
            try {
                //1 加载配置文件
                doLoadConfigFile(resourceAsStream);
                // 2 扫描包
                doScanPackage();
                // 3  bean实例化和依赖维护
                doInitBean();
                // 4 维护url和method之间的映射关系
                doHandlerMapping();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
            System.out.println("------------  ioc容器bean \n " + IOC_MAP);
    
            System.out.println("----------------- 初始化完成 -------------------");
        }
    
    
        @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 {
    
            //5 判断请求Url和方法url 执行相应方法
            String requestURI = req.getRequestURI();
            //遍历请求中得参数顺序
            Map<String, String[]> reqParameterMaps = req.getParameterMap();
    
            System.out.println("------- 当前请求的url是 : " +  requestURI);
            if (Objects.isNull(requestURI) || requestURI.length() == 0) {
                return;
            }
            //5.1 获取handle
            Handle handler = getHandler(req);
    
            if (Objects.isNull(handler)){
                resp.getWriter().println("404....");
                return;
            }
            //获取执行方法
            Method method = handler.getMethod();
    
            Parameter[] parameters = handler.getMethod().getParameters();
            //5.2 获取型参数
            Map<String, Integer> map1 = handler.getMap();
            //5.3 获取参数长度
            //设置传递参数
            Object[] objects = new Object[parameters.length];
    
            //保证参数顺序和方法中的型参数顺序一致
    
            //遍历除reqest 和 response之外的参数 并且填充到参数数组里
            for (Map.Entry<String, String[]> stringEntry : reqParameterMaps.entrySet()) {
                //判断请求参数和形参是否参数匹配
                //多个参数直接 , 拼接
                String value = StringUtils.join(stringEntry.getValue(), ",");  // 如同 1,2
                if (!map1.containsKey(stringEntry.getKey())) {
                   continue;
                }
                //获取型参数索引
                Integer index = map1.get(stringEntry.getKey());
    
                //赋值参数
                objects[index] = value;
            }
    
            int index1 = map1.get(HttpServletRequest.class.getSimpleName());
            int index2 = map1.get(HttpServletResponse.class.getSimpleName());
            //获取ret对象参数
            objects[index1] = req;
            //获取resp对象参数
            objects[index2] = resp;
    
            try {
               String result = (String) method.invoke(handler.getController(), objects);
               resp.getWriter().println(result);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
    
        }
    
        private Handle getHandler(HttpServletRequest req) {
    
            // 根据url找到对应得method方法 并且执行调用
            for (Handle handle : HANDLE_MAPPING) {
    
    
                Matcher matcher = handle.getPattern().matcher(req.getRequestURI());
                if (matcher.find()) {
                    return handle;
                }
    
    
            }
    
            return null;
        }
    
        /**
         * 加载配置文件
         *
         * @param resourceAsStream
         */
        private void doLoadConfigFile(InputStream resourceAsStream) {
            try {
                properties.load(resourceAsStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * handlerMapper 处理映射器
         * 建立url和方法一致
         */
        private void doHandlerMapping() {
    
            if (IOC_MAP.isEmpty()) {
                return;
            }
    
            //只处理controller层
            for (Map.Entry<String, Object> stringObjectEntry : IOC_MAP.entrySet()) {
    
                Class<?> objectEntryValue = stringObjectEntry.getValue().getClass();
                //没有包含 注解 跳过
                if (!objectEntryValue.isAnnotationPresent(Controller.class)) {
                    continue;
                }
    
                String url = "";
                //包含 RequestMapping 注解 就获取url
                if (objectEntryValue.isAnnotationPresent(RequestMapping.class)) {
                    RequestMapping requestMapping = objectEntryValue.getAnnotation(RequestMapping.class);
                    url = requestMapping.value();
                }
    
    
                //获取方法
                Method[] methods = objectEntryValue.getMethods();
                if (methods.length <= 0 || Objects.isNull(methods)) {
                    continue;
                }
    
                for (Method method : methods) {
                    //如果不包含就跳过
                    if (!method.isAnnotationPresent(RequestMapping.class)) {
                        continue;
                    }
                    //获取当前方法上 RequestMapping 的注解
                    RequestMapping requestMapping = method.getDeclaredAnnotation(RequestMapping.class);
                    //构建url
                    String urls = url + requestMapping.value();
    
                    //封装handler
                    Handle handle = new Handle(stringObjectEntry.getValue(), Pattern.compile(urls), method);
    
                    //处理计算参数位置
                    Parameter[] parameters = method.getParameters();
                    if (parameters != null && parameters.length > 0) {
                        for (int i = 0; i < parameters.length; i++) {
                            Parameter parameter = parameters[i];
                            if (parameter.getType() == HttpServletRequest.class || parameter.getType() == HttpServletResponse.class) {
                                //如果是 参数名称存本身
                                handle.getMap().put(parameter.getType().getSimpleName(), i);
                            }
                            //如果是tring类型
                            else {
                                //String类型存储name
                                handle.getMap().put(parameter.getName(), i);
                            }
                            //其他类型暂时不做判断
                        }
                        HANDLE_MAPPING.add(handle);
                    }
    
    
                }
    
            }
    
    
        }
    
    
        /**
         * bean实例化和bean依赖注入关系维护
         *
         * @throws ClassNotFoundException
         * @throws IllegalAccessException
         * @throws InstantiationException
         */
        private void doInitBean() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            for (String className : stringSet) {
                //反射创建对象
                Class<?> aClass = Class.forName(className);
                //查找 Controller 注解
                Controller annotation = aClass.getAnnotation(Controller.class);
                if (Objects.nonNull(annotation)) {
                    //实例化存入ioc
                    IOC_MAP.put(aClass.getSimpleName(), aClass.newInstance());
                }
                //查找 service 注解
                Service service = aClass.getAnnotation(Service.class);
                if (Objects.nonNull(service)) {
                    //实例化存入ioc
                    IOC_MAP.put(aClass.getSimpleName(), aClass.newInstance());
                    //如果实现类接口 按照接口实例化
                    Class<?>[] interfaces = aClass.getInterfaces();
                    if (Objects.nonNull(interfaces) && interfaces.length > 0) {
                        for (Class<?> anInterface : interfaces) {
                            //按照接口名进行实例化
                            IOC_MAP.put(anInterface.getSimpleName(), aClass.newInstance());
                        }
    
                    }
                }
            }
    
    
            //依赖注入
            for (Map.Entry<String, Object> stringObjectEntry : IOC_MAP.entrySet()) {
    
                Class aClass = stringObjectEntry.getValue().getClass();
                //获取所有字段
                Field[] declaredFields = aClass.getDeclaredFields();
    
                if (Objects.isNull(declaredFields) && declaredFields.length == 0) {
                    continue;
                }
    
                for (Field field : declaredFields) {
                    //field.get
                    //字段含有 Autowired 注解的需要被自动装配对象
                    Autowired autowired = field.getAnnotation(Autowired.class);
    
                    if (Objects.nonNull(autowired)) {
                        //根据当前key获取需要注入示例对象
                        //先根据名字注入,如果名字获取不到,再根据类型去注入
                        String beanName = autowired.name();
    
                        if (Objects.isNull(beanName) || beanName.length() == 0) {
                            beanName = field.getType().getSimpleName();
                        }
    
                        //反射设置值
                        try {
                            field.setAccessible(true);
                            //自动装配 线程不安全,Spring中默认单例
                            field.set(stringObjectEntry.getValue(), IOC_MAP.get(beanName));
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
    
        }
    
    
        /**
         * 包扫描获取字节码对象
         *
         * @throws UnsupportedEncodingException
         */
        private void doScanPackage() throws UnsupportedEncodingException {
            //获取mvc包路径
            String packName = properties.getProperty("mvc.path");
            if (Objects.isNull(packName) || packName.length() == 0) {
                throw new RuntimeException("无效的包路径");
            }
            packName = packName.replace(".", File.separator);
            URL resource = this.getClass().getClassLoader().getResource(packName);
            String path = resource.getPath();
            //解析中文
            String filePath = URLDecoder.decode(path, "UTF-8");
    
            //解析包成java权限定命名com
            parseFilePackName(packName, stringSet, filePath);
    
        }
    
    
        /**
         * 递归处理路径下文件夹是否包含文件夹,如不包含则获取当前类的权限定命名存入set中
         *
         * @param packName
         * @param classNameSet
         * @param path
         */
        public static void parseFilePackName(String packName, Set<String> classNameSet, String path) {
    
            File packNamePath = new File(path);
    
            if (!packNamePath.isDirectory() || !packNamePath.exists()) {
                return;
            }
            //递归路径下所有文件和文件夹
            for (File file : packNamePath.listFiles()) {
                boolean directory = file.isDirectory();
                String classNamePath = packName + File.separator + file.getName().replace(File.separator, ".");
                if (directory) {
                    parseFilePackName(classNamePath, classNameSet, file.getPath());
                } else if (file.isFile() && file.getName().endsWith(CLASS_STR)) {
                    //存入set
                    classNameSet.add(classNamePath.replace(File.separator, ".").replace(CLASS_STR, ""));
                }
            }
    
        }
    }
    
    

    测试

    启动tomcat

    首先输入http://localhost:8080/kkkkk 可以看到首次请求容器初始化完成 各种bean实例化以及依赖维护.handler封装完成

    请求的这个地址不存在,返回 404....

    在这里插入图片描述

    然后我们再输入自己的地址 http://localhost:8080/api/test?name=123&name=000 可以看到

    在这里插入图片描述

    代码地址

    gir地址

    相关文章

      网友评论

          本文标题:唰唰的手撕一个简单的Spring Mvc 框架

          本文链接:https://www.haomeiwen.com/subject/sqqnwktx.html