SpringMVC简单源码实现
源码下载地址
程序架构
web.xml配置
这里一点要注意中要让所有的请求通过,所以设置为/,以及设置,让程序加载时就启动servlet
pom.xml中仅引入servlet的jar包
注解类:仿照springmvc注解做简单模仿,五个注解均仅有一个value方法,除定义的注解位置不同,无其他区别
@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();
}
}
}
import com.ys.annotation.MyService;
@MyService("testService")
public class TestService {
public String updateUser(String name, String password){
return "name:"+name+"password:"+password;
}
}
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 classNames = new ArrayList();
//用来存储controller类对象
Map beans = new HashMap();
//创建一个存储autowire的集合
Map handlerMap = new HashMap();
//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 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 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;
}
}