手写SpringMvc

1,SpringMvc的实现,依托于Tomcat的Servlet,新建一个Maven工程,把工程修改成war包、并且引入Servlet包

2,回忆Tomcat启动时所作之事,会加载servlet程序,并且会马上执行init()方法,那么便可以把整个SpringMvc执行过程写在此方法中,分析,SpringMVC整个过程,首先其实是Spring的启动注入过程,

1,扫描路径 =====》2,实例化(将所有被@component或者@service等等注解标记的放入Spring容器)=====》3,注入(所有被@autowried注解标记的属性赋值)=====》4,访问路径和执行方法相对应 ====》5,执行方法

 第五步执行方法放在doPost()方法中,

3,具体执行步骤

整个过程包含三个容器

整个项目结构

自定义的servlet继承HttpServlet

 

以及JavaWeb项目的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_4_0.xsd"
         version="4.0">
    
    <servlet>
        <servlet-name>MyDispatcherServlet</servlet-name>
        <servlet-class>com.jy.servlet.MyDispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyDispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

1)在类加载时利用反射获取其所在的路径,然后遍历判断所有的文件夹和.class文件,然后利用反射,并且放入 类名容器

private void packageScan(String basePackage) {
        //获取到此类所在路径,
        URL url = this.getClass().getClassLoader().getResource(basePackage.replaceAll("\.", "/"));
        //文件路径  /D:/D:/java/com/jy
        //项目部署到tomcat上时,文件夹变为D:/Tomcat 8.5/******,此时将Tomcat和8.5之间的空格替换掉
        String urlFile = url.getPath().replace("%20"," ");
        File file = new File(urlFile);
        //路径下所有的文件及目录
        String[] list = file.list();
        //遍历所有文件及目录
        for (String fileStr : list) {
            File filepath = new File(urlFile + fileStr + "/");
            if (filepath.isDirectory()) {
                packageScan(basePackage + "." + fileStr);
            } else {
                //说明是com.jy.xxx.xxx.class
                classNames.add(basePackage + "." + fileStr);
            }
        }
    }

2)实例化类名容器中的所有的类

//实例化对象
    private void instance() {
        for (String className : classNames) {
            try {
                Class<?> clazz = Class.forName(className.replace(".class", ""));
                if (clazz.isAnnotationPresent(MyService.class)) {
                    //创建对象
                    Object object = clazz.newInstance();
                    //获取注解中写入的bean的名字
                    String beanName = clazz.getAnnotation(MyService.class).value();
                    beans.put(beanName, object);
                } else if (clazz.isAnnotationPresent(MyController.class)) {
                    //创建对象
                    Object object = clazz.newInstance();
                    //获取注解中写入的bean的名字
                    String beanName = clazz.getAnnotation(MyController.class).value();
                    beans.put(beanName, object);
                } else {
                    continue;
                }

                //将new出来的对象放入spring容器
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

3)依赖注入

private void doAutowied() {
        //遍历容器
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            //获取容器中的对象
            Object instance = entry.getValue();

            Class<?> clazz = instance.getClass();
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(MyAutowired.class)) {
                        //打开权限
                        field.setAccessible(true);
                        String fieldName = field.getName();
                        try {
                            field.set(instance,beans.get(fieldName) );
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }else {
                        continue;
                    }
                }


        }
    }

4)将访问路径和所执行的方法对应起来

private void urlMappring() {
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            Object instance = entry.getValue();
            Class<?> clazz = instance.getClass();
            if (clazz.isAnnotationPresent(MyController.class)) {
                //获取到类上的MyRequestMapping对象
                MyRequestMapping mapping1 = clazz.getAnnotation(MyRequestMapping.class);
                //获取到类上MyRequestMapping的value值
                String requestMapping1 = mapping1.value();
                //获取所有的方法
                Method[] methods = clazz.getDeclaredMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(MyRequestMapping.class)) {
                        MyRequestMapping mapping2 = method.getAnnotation(MyRequestMapping.class);
                        //方法上的requestMapping注解的value值
                        String requestMapping2 = mapping2.value();
                        //将方法存入容器中
                        handleMap.put(requestMapping1 + requestMapping2, method);
                    } else {
                        continue;
                    }
                }
            }

        }
    }

5)利用反射执行方法

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //  工程名/com/jy
        String uri = req.getRequestURI();
        //  获取到工程名
        String contextPath = req.getContextPath();
        //uri去掉工程名
        String path = uri.replace(contextPath, "");
        Method method = (Method) handleMap.get(path);
        //获取到所有的属性值并且遍历
        Field[] fields = this.getClass().getFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(MyAutowired.class)){

            }
        }
        //获取到方法所在类的类名
        String simpleName = method.getDeclaringClass().getSimpleName();
        //将类名转小写
        String sb = simpleName.substring(0,1).toLowerCase()+simpleName.substring(1);
        //根据类名获取到容器中的对象
        Object bean = beans.get(sb);

        try {
            //执行方法
            method.invoke(bean,"哈哈哈");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }


    }

4,收获

1)对反射等基础知识理解更加深刻

2)进一步理解Spring容器以及SpringMvc整个执行过程

3)对注解的理解及使用加深

原文地址:https://www.cnblogs.com/hunt1coder/p/12642541.html