之前我分享过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 {
@RequestMapping
public 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) {
//如果文件是文件夹的形式,放入list
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
@Controller
@RequestMapping
public class IndexController {
@RequestMapping
public 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