SpringMVC简单源码实现

SpringMVC简单源码实现
源码下载地址

程序架构
在这里插入图片描述
web.xml配置
这里一点要注意中要让所有的请求通过,所以设置为/,以及设置,让程序加载时就启动servlet在这里插入图片描述

pom.xml中仅引入servlet的jar包
在这里插入图片描述
注解类:仿照springmvc注解做简单模仿,五个注解均仅有一个value方法,除定义的注解位置不同,无其他区别
在这里插入图片描述

Controller类的源码以及控制类中的自定义注解使用

@MyController
@MyRequestMapping("/my")
public class TestController{
	@MyAutowired(value = "testService")
	private TestService testService;

	@MyRequestMapping("/ok")
	public void updateUser(HttpServletRequest request,HttpServletResponse response,
						@MyRequestParam("name") String name,
						@MyRequestParam("password") String password){
		String user = testService.updateUser(name,password);
		try {
			response.getWriter().write(user);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	@MyRequestMapping("/no")
	public void noUser(HttpServletRequest request,HttpServletResponse response,
						@MyRequestParam("name") String name,
						@MyRequestParam("password") String password){
		String user = testService.updateUser(name,password);
		try {
			response.getWriter().write(user);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

Service类的源码以及类中的自定义注解使用

import com.ys.annotation.MyService;

@MyService("testService")
public class TestService {
	public String updateUser(String name, String password){
		return "name:"+name+"password:"+password;
	}
}


Servlet类核心功能

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ys.annotation.MyAutowired;
import com.ys.annotation.MyController;
import com.ys.annotation.MyRequestMapping;
import com.ys.annotation.MyRequestParam;
import com.ys.annotation.MyService;
import com.ys.controller.TestController;


public class TestServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	//用来存储class文件路径
	List<String> classNames = new ArrayList<String>();
	//用来存储controller类对象
	Map<String,Object> beans = new HashMap<String,Object>();
	//创建一个存储autowire的集合
	Map<String,Object> handlerMap = new HashMap<String,Object>();
	
	//tomcat启动扫描controller,service
	//通过反射实例化对象
	//处理autowired
	//path-method
	@Override
	public void init() throws ServletException {
		//扫描包
		scanPackage("com.ys");
		//实例化类对象
		instance();
		//扫描MyAutowired
		doAutowired();
		//处理requestMapping
		UrlHanding();
		test();
	}
	
	
	private void test() {
		System.out.println("---------------------------");
		for (String name : classNames) {
			System.out.println(name);
		}
		
		System.out.println("beans-------------------------------------");
		
		for (String key : beans.keySet()) {
			System.out.println("key:"+key+"\t"+"value:"+beans.get(key));
		}
		System.out.println("handlerMap--------------------------------");
		for (String key : handlerMap.keySet()) {
			System.out.println("key:"+key+"\t"+"value:"+handlerMap.get(key));
		}
	}


	private void UrlHanding() {
		// 遍历容器里的bean
		for (Map.Entry<String, Object> entry : beans.entrySet()) {
			// 获取到map中的对象
			Object instance = entry.getValue();
			// 获取到当前类的路径,可以利用反射对对象进行实例化
			Class<?> clazz = instance.getClass();
			// 注意:在controller下使用autowired注解
			if (clazz.isAnnotationPresent(MyController.class)) {
				//MyController类上会存在MyRequestMapping注解
				MyRequestMapping map1 = clazz.getAnnotation(MyRequestMapping.class);
				//获取类路径,类上的值,需要和方法上的进行拼接
				String classPath = map1.value();
				//获取对象所有的方法
				Method[] methods = clazz.getMethods();
				//遍历方法
				for (Method method : methods) {
					//判断方法上是否有注解
					if(method.isAnnotationPresent(MyRequestMapping.class)){
						//获取方法上的注解值
						MyRequestMapping map2 = method.getAnnotation(MyRequestMapping.class);
						//获取注解上的value
						String methodPath = map2.value();
						//拼接,并以路径为key,方法名为value存到map中
						handlerMap.put(classPath+methodPath, method);
					}else{
						continue;
					}
				}
			}else{
				continue;
			}
		}
	}

	private void doAutowired() {
		//遍历容器里的bean
		for (Map.Entry<String, Object> entry: beans.entrySet()) {
			//获取到map中的value值
			Object instance = entry.getValue();
			//获取到当前类的路径,可以利用反射对对象进行实例化
			Class<?> clazz = instance.getClass();
			//注意:在controller下使用autowired注解
			if(clazz.isAnnotationPresent(MyController.class)){
				//获取控制层中所有的属性
				Field[] fields = clazz.getDeclaredFields();
				//遍历属性
				for (Field field : fields) {
					//判断属性上是否有Autowired注解
					if(field.isAnnotationPresent(MyAutowired.class)){
						//获取属性上的注解
						MyAutowired ea = field.getAnnotation(MyAutowired.class);
						//获取注解值
						String key = ea.value();
						//根据注解值,获取bean的类路径
						//service上的值和autowired的值相同
						Object ins = beans.get(key);
						//暴力破解获取私有值
						field.setAccessible(true);
						
						
						//
						try {
							field.set(instance, ins);
						} catch (IllegalArgumentException e) {
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						}
					}else{//如果有dao层,加一个else if
						continue;
					}
				}
			}
		}
	}


	private void instance() {
		for (String className : classNames) {
			//com.ys.xxx.xxx.class
			//截取掉当前的.class后缀
			String cn = className.replace(".class", "");
			try {
				//获取到当前类的路径,可以利用反射对对象进行实例化
				Class<?> clazz = Class.forName(cn);
				//判断当前类里是否声明了类上注解
				if(clazz.isAnnotationPresent(MyController.class)){
					//控制类
					Object instance = clazz.newInstance();
					//获取类上的requestmapping注解
					MyRequestMapping map1 = clazz.getAnnotation(MyRequestMapping.class);
					//获取注解的值
					String key = map1.value();
					//将注解上的值作为key值存入到map集合中
					beans.put(key, instance);
				}else if(clazz.isAnnotationPresent(MyService.class)){
					//业务类
					Object instance = clazz.newInstance();
					//获取类上的Myservice注解
					MyService map2 = clazz.getAnnotation(MyService.class);
					//获取注解的值
					String key = map2.value();
					//将注解上的值作为key值存入到map集合中
					beans.put(key, instance);
				}else{
					continue;
				}
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}


	//扫描所有的基础包下的文件,将所有的类路径存在list集合下
	private void scanPackage(String basepackage) {
		//将路径中的.换成java认识的/
		URL url = this.getClass().getClassLoader().getResource("/"+basepackage.replaceAll("\\.", "/"));
		
		
		//E:workpace/abc
		String fileStr = url.getFile();
		//找到基础包路径
		File file = new File(fileStr);
		//获取该文件下所有的文件
		String[] fileNames = file.list();
		//只需要文件,所以遍历
		for (String path : fileNames) {
			//fileStr+filename  基础包路径拼接上对应路径名
			File filePath = new File(fileStr+path);
			//判断是否是文件
			if(filePath.isDirectory()){
				//是文件的话递归直到是文件为止
				scanPackage(basepackage+"."+path);
			}else{
				//com.ys.xxx.xxx.class
				classNames.add(basepackage+"."+filePath.getName());
			}
		}
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doPost(request, response);
	}
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//  http://ip+端口/项目名/请求路径
		//  uri获取得是            /项目名/请求路径
		String uri = request.getRequestURI();
		System.out.println("uri:"+uri);
		//获取工程名
		String contextPath = request.getContextPath();
		System.out.println("contextPath:"+contextPath);
		//剪切   /请求路径
		String path = uri.replace(contextPath, ""); 
		System.out.println("path:"+path);
		//获取handlerMap中的方法
		Method method = (Method)handlerMap.get(path);
		System.out.println("method:"+method);
		//不足:进行了强转:因为只有一个controller类,所以,多个情况使用Object类型,具体使用时进行强转
		TestController instance = (TestController)beans.get("/"+path.split("/")[1]);
		System.out.println(instance);
		//参数处理
		Object[] args = hand(request, response, method);
//		调用方法
		try {
			method.invoke(instance, args);
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//获取方法中的参数
	private static Object[] hand(HttpServletRequest request, HttpServletResponse response,Method method){
		//拿到当前执行方法有哪些参数
		Class<?>[] paramClazzs = method.getParameterTypes();
		//根据参数个数,new一个参数的数组,将方法里的所有参数赋值大agrs中
		Object[] args = new Object[paramClazzs.length];
		
		int args_i = 0;
		int index = 0;
		for (Class<?>  paramClazz : paramClazzs) {
			if(ServletRequest.class.isAssignableFrom(paramClazz)){
				args[args_i++] = request;
			}
			if(ServletResponse.class.isAssignableFrom(paramClazz)){
				args[args_i++] = response;
			}
			
			Annotation[] paramAns = method.getParameterAnnotations()[index];
			if(paramAns.length>0){
				for (Annotation paramAn : paramAns) {
					if(MyRequestParam.class.isAssignableFrom(paramAn.getClass())){
						MyRequestParam mp = (MyRequestParam) paramAn;
						//找到注解里的name和password
						args[args_i++] = request.getParameter(mp.value());
					}
				}
			}
			index++;
		}
		return args;
	}
}



servlet中的init方法中test测试 :遍历已经完成存储的容器结果
在这里插入图片描述
最终运行结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/yang134679/article/details/88866926