• 手写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)对注解的理解及使用加深

  • 相关阅读:
    单例模式
    工厂模式
    代理模式
    网络问题
    java中System.getProperty()方法详解
    配置logback.xml文件来实现日志文件输出
    Spring MVC 文件上传与下载快速学习
    SpringMVC中的视图和视图解析器
    JSON的概述和简单的操作
    BeanValidate中的注解
  • 原文地址:https://www.cnblogs.com/hunt1coder/p/12642541.html
Copyright © 2020-2023  润新知