之前我分享过SpringMVC的基本原理与配置(原文链接:https://blog.csdn.net/L170311/article/details/129339120),为了更深层次的学习,精益求精,手动仿写了一个MVC原理实现demo,一起学习一下吧
结构目录:
两个自定义注解,两个Controller,核心ImitateSpringMVC,以及测试Main
@Controller和@RequestMapping
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Controller {}@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface RequestMapping {String value() default "";
}
@Documented
该注解的作用就是在生产文档的时候,保留自定义注解的存在,例如:
-d doc Test.java ; 如果Test.java中有自定义的注解,然后该注解上面有@Documented,那么生成的文档中就会包含自定义注解部分,反之就没有。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
target英文有目标、目的的意思。 @Target在java中是注释类。@Target作用于修饰的注释可以修饰的类型范围
@Target包含一个ElementType[]元素类型的数组。ElementType[]数组值value,表明Target修饰的注释可以修饰的类型范围。ElementType枚举值包含方法、属性、类等等。
ANNOTATION_TYPE: 注解只能修饰注解,不能修饰其他的东西
CONSTRUCTOR: 注解只能修饰构造方法
FIELD: 注解只能修饰属性(成员变量) 字段加解密注解标记拦截
LOCAL_VARIABLE: 注解只能修饰局部变量
METHOD: 注解只能修饰方法 对应的方法进行拦截
PACKAGE: 注解只能修饰包
PARAMETER: 注解只能修饰方法的参数
TYPE: 注解只能修饰类、接口、枚举
TestController
@Controller
@RequestMapping("test")
public class TestController {@RequestMappingpublic String index(){System.out.println("test->index");return "";}@RequestMapping("index1")public String index1(){System.out.println("test->index1");return "";}
}
核心:ImitateSpringMVC
public class ImitateSpringMVC {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) {p=p.substring(path.length()-1);try {String className=packageName+"."+p.replaceAll( Matcher.quoteReplacement(File.separator),".");String replace = className.replace(".class", "");//通过类加载器加载类信息Class<?> cl = ClassLoader.getSystemClassLoader().loadClass(replace);if(isController(cl)){if(isRequestMapping(cl)){//获得我们设置在@RequestMapping里的值RequestMapping requestMapping = getRequestMapping(cl);//如果注解值重复,抛异常if(map.containsKey(requestMapping.value())){throw new RuntimeException("类多注解值:"+requestMapping.value());}else {map.put(requestMapping.value(),new HashMap<>());objMap.put(requestMapping.value(),cl.newInstance());}//获得当前类对象声明的所有方法Method[] declaredMethods = cl.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {//遍历,判定方法是否带有@RequestMapping注解if(isRequestMapping(declaredMethod)){RequestMapping mapping = getRequestMapping(declaredMethod);//判定方法的注解值是否重复if(map.get(requestMapping.value()).containsKey(mapping.value())){throw new RuntimeException("方法多注解值:"+requestMapping.value());}else {map.get(requestMapping.value()).put(mapping.value(),declaredMethod);//现在的map<K,V>中k是我们获取到类对象的@RequestMapping的值,V是类对象方法的@RequestMapping的值,组成的一个集合}}}}else {throw new RuntimeException("类无requestMapping");}}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}}}//判定类文件是否带有@Controller注解private static boolean isController(Class cl){Annotation annotation = cl.getAnnotation(Controller.class);if(annotation!=null){return true;}return false;}//判定类文件是否带有@RequestMapping注解private static boolean isRequestMapping(Class cl){Annotation annotation = cl.getAnnotation(RequestMapping.class);if(annotation!=null){return true;}return false;}private static boolean isRequestMapping(Method method){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) {//如果文件是文件夹的形式,放入listif (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
@Controller
@RequestMapping
public class IndexController {@RequestMappingpublic void index(){System.out.println("index -> index");}}
Main
public class Main {static {//获得当前类的路径String path = Main.class.getResource("").getPath();//获得当前类的包名String packageName = Main.class.getPackage().getName();//传入到MVC的方法中ImitateSpringMVC.scanner(path,packageName);}public static void main(String[] args) {ImitateSpringMVC.exec("","");ImitateSpringMVC.exec("test","index1");ImitateSpringMVC.exec("test","");System.out.println("SpringMVC!");}}
demo已上传gitee平台:https://gitee.com/dont-live-in-the-past/spring-mvc-simple-imitation