注:本文纯手写实现MVC的实现原理,没有使用设计模式等,代码直接复制即可debug调试查看运行流程,相关解释放在文末
手写呈现MVC实现原理
- 1. 注解详解
- @Documented
- @Retention
- @Target
- 2. 文件内容
- Controller 注解文件(annotation.Controller)
- RequestMapping注解 (annotation.RequestMapping )
- TestController类 (Controller.TestController)
- StepMvc类 (mvc.StepMvc)
- IndexController类
- Main(启动类)
- 3.StepMvc详解
文章会用到的包以及类的分层
1. 注解详解
@Documented
@Documented 在自定义注解的时候可以使用@Documented来进行标注
@Retention
@Retention 用来说明该注解类的生命周期。它有以下三个参数:
- RetentionPolicy.SOURCE : 注解只保留在源文件中
- RetentionPolicy.CLASS : 注解保留在class文件中,在加载到JVM虚拟机时丢弃
- RetentionPolicy.RUNTIME : 注解保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解。
@Target
@Target注解的作用目标,8种类型
- @Target(ElementType.TYPE)——接口、类、枚举、注解
- @Target(ElementType.FIELD)——字段、枚举的常量
- @Target(ElementType.METHOD)——方法
- @Target(ElementType.PARAMETER)——方法参数
- @Target(ElementType.CONSTRUCTOR) ——构造函数
- @Target(ElementType.LOCAL_VARIABLE)——局部变量
- @Target(ElementType.ANNOTATION_TYPE)——注解
- @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!");
}
}
运行结果
3.StepMvc详解
StepMvc 中用到了两个map
private static HashMap<String, Map<String,Method>> map=new HashMap<>();
private static HashMap<String, Object> objMap=new HashMap<>();