注:本文纯手写实现MVC的实现原理,没有使用设计模式等,代码直接复制即可debug调试查看运行流程,相关解释放在文末


手写呈现MVC实现原理

  • 1. 注解详解
  • @Documented
  • @Retention
  • @Target
  • 2. 文件内容
  • Controller 注解文件(annotation.Controller)
  • RequestMapping注解 (annotation.RequestMapping )
  • TestController类 (Controller.TestController)
  • StepMvc类 (mvc.StepMvc)
  • IndexController类
  • Main(启动类)
  • 3.StepMvc详解


文章会用到的包以及类的分层

springnative 反射 springmvc反射机制_mvc

1. 注解详解

@Documented

@Documented 在自定义注解的时候可以使用@Documented来进行标注

@Retention

@Retention 用来说明该注解类的生命周期。它有以下三个参数:

  1. RetentionPolicy.SOURCE : 注解只保留在源文件中
  2. RetentionPolicy.CLASS : 注解保留在class文件中,在加载到JVM虚拟机时丢弃
  3. RetentionPolicy.RUNTIME : 注解保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解。
@Target

@Target注解的作用目标,8种类型

  1. @Target(ElementType.TYPE)——接口、类、枚举、注解
  2. @Target(ElementType.FIELD)——字段、枚举的常量
  3. @Target(ElementType.METHOD)——方法
  4. @Target(ElementType.PARAMETER)——方法参数
  5. @Target(ElementType.CONSTRUCTOR) ——构造函数
  6. @Target(ElementType.LOCAL_VARIABLE)——局部变量
  7. @Target(ElementType.ANNOTATION_TYPE)——注解
  8. @Target(ElementType.PACKAGE)——包

2. 文件内容

Controller 注解文件(annotation.Controller)

定义一个Controller注解

package com.mystep.annotation;

import java.lang.annotation.*;

/**
 * heaboy 的controller声明
 * @author step
 * @date 2021/8/14 12:20
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @ interface Controller {
}

RequestMapping注解 (annotation.RequestMapping )

定义了一个RequestMapping 接口

package com.mystep.annotation;

import java.lang.annotation.*;

/**
 *
 * @author step
 * @date 2021/8/14 12:28
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface RequestMapping {
    /**
     *
     * @return
     */
    String value() default "";
}

TestController类 (Controller.TestController)

这里是一个测试的controller层,方法可以自定义,属性可以自定义,此处不能传参数

package com.mystep.Controller;

import com.mystep.annotation.Controller;
import com.mystep.annotation.RequestMapping;

@Controller
@RequestMapping("test")
public class TestController {
    @RequestMapping
    public  String index(){
        System.out.println("test->index");
        return "";
    }
    @RequestMapping("index1")
    public  String index1(){
        System.out.println("test->index1");
        return "";
    }
}

StepMvc类 (mvc.StepMvc)

package com.mystep.mvc;

import com.mystep.annotation.Controller;
import com.mystep.annotation.RequestMapping;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;

/**
 *
 * @author zxj
 * @date 2021/8/14 12:33
 * mvc类
 */
public class StepMvc {
    private static HashMap<String, Map<String,Method>> map=new HashMap<>();
    private static HashMap<String, Object> objMap=new HashMap<>();
    public static void exec(String classPath,String methodPath){
        if(objMap.get(classPath)==null){
            System.out.println("没有这个类 404");
        }else {
            if(map.get(classPath).get(methodPath)==null){
                System.out.println("没有这个方法 404");
            }else {
                try {
                    map.get(classPath).get(methodPath).invoke(objMap.get(classPath));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }

    }
    public static void scanner(String path,String packageName){
        List<String> paths = traverseFolder2(path);
        for (String p : paths) {
            System.out.println("哈哈哈");
            System.out.println(p);
            System.out.println(path.length());
            System.out.println(path);
            System.out.println(path.length()-1);
            p=p.substring(path.length()-1);
            System.out.println("这是p:::"+p);
            try {
                String className=packageName+"."+p.replaceAll( Matcher.quoteReplacement(File.separator),".");
                String replace = className.replace(".class", "");//去掉.class
                Class<?> cl = ClassLoader.getSystemClassLoader().loadClass(replace);
                if(isController(cl)){
                    if(isRequestMapping(cl)){
                    //根据类信息获得
                        RequestMapping requestMapping = getRequestMapping(cl);
                        //获得requestMapping 去取他的值,
                        if(map.containsKey(requestMapping.value())){
                            throw  new RuntimeException("类多注解值:"+requestMapping.value());
                        }else {
                       		//放入k,v k-括号内自定义的值 v-hashMap
                            map.put(requestMapping.value(),new HashMap<>());
                            //k-括号内自定义的值  v-Controller对象
                            objMap.put(requestMapping.value(),cl.newInstance());
                        }
                        //获得所有方法
                        Method[] declaredMethods = cl.getDeclaredMethods();
                        for (Method declaredMethod : declaredMethods) {
                            if(isRequestMapping(declaredMethod)){
                                RequestMapping mapping = getRequestMapping(declaredMethod);
                                //判断map的里面的hashmap是否包含这个值————方法的值
                                if(map.get(requestMapping.value()).containsKey(mapping.value())){
                                    throw  new RuntimeException("方法多注解值:"+requestMapping.value());
                                }else {
                                	//	获得类对应的hashmap put一个它对应的注解值,以及我们声明的方法
                                    map.get(requestMapping.value()).put(mapping.value(),declaredMethod);
                                }
                            }
                        }
                    }else {
                        throw  new RuntimeException("类无requestMapping");
                    }
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }


    }

    private static boolean isController(Class cl){
    //从他的类信息里面获得他的声明
        Annotation annotation = cl.getAnnotation(Controller.class);
        if(annotation!=null){
            return  true;
        }
        return false;
    }
    private static boolean isRequestMapping(Class cl){
    	//判断类信息是否有RequestMapping注解
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        if(annotation!=null){
            return  true;
        }
        return false;
    }
    private  static boolean isRequestMapping(Method method){
    	//方法重载,传入方法,方法也有可能有RequestMapping注解
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        if(annotation!=null){
            return  true;
        }
        return false;
    }
    private static RequestMapping getRequestMapping(Class cl){
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        if(annotation instanceof  RequestMapping){
            return  (RequestMapping) annotation;
        }
        return null;
    }
    private static RequestMapping getRequestMapping(Method method){
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        if(annotation instanceof  RequestMapping){
            return  (RequestMapping) annotation;
        }
        return null;
    }
    private static List<String> traverseFolder2(String path) {
        File file = new File(path);
        List<String> classFiles=new ArrayList<>();
        if (file.exists()) {
            LinkedList<File> list = new LinkedList<File>();
            File[] files = file.listFiles();
            for (File file2 : files) {
                if (file2.isDirectory()) {
                    list.add(file2);
                } else {
                    classFiles.add(file2.getAbsolutePath());
                }
            }
            File temp_file;
            while (!list.isEmpty()) {
                temp_file = list.removeFirst();
                files = temp_file.listFiles();
                for (File file2 : files) {
                    if (file2.isDirectory()) {
                        list.add(file2);
                    } else {
                        classFiles.add(file2.getAbsolutePath());
                    }
                }
            }
        } else {

        }

        return classFiles;
    }
}

IndexController类

package com.mystep;

import com.mystep.annotation.Controller;
import com.mystep.annotation.RequestMapping;

@Controller
@RequestMapping
public class IndexController {
    @RequestMapping
    public  void index(){
        System.out.println("index -> index");
    }
//    @RequestMapping
//    public  void index1(){
//        System.out.println("index -> index");
//    }
}

Main(启动类)

static块优先于main执行,static块中获得了main所在的路径,以及他的包的名字,然后扫描这个路径这个包下的所有信息

package com.mystep;

import com.mystep.mvc.StepMvc;

public class Main {
    static {
        String path = Main.class.getResource("").getPath();
        String packageName = Main.class.getPackage().getName();
        StepMvc.scanner(path,packageName);
    }

    public static void main(String[] args) {
        StepMvc.exec("","");//exec执行什么什么
        StepMvc.exec("test","index1");
        StepMvc.exec("test","");
        System.out.println("Hello World!");
    }
}

运行结果

springnative 反射 springmvc反射机制_System_02

3.StepMvc详解

StepMvc 中用到了两个map

private static HashMap<String, Map<String,Method>> map=new HashMap<>();
private static HashMap<String, Object> objMap=new HashMap<>();

springnative 反射 springmvc反射机制_反射_03


springnative 反射 springmvc反射机制_反射_04


springnative 反射 springmvc反射机制_System_05