spring(六):手写一个SimpleSpring

7.手写spring

准备工作

  • pom文件只引用servlet
  <dependencies>
  		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>3.0-alpha-1</version>
			<scope>provided</scope>
		</dependency>
  </dependencies>
  • 定义自己的注解
@Target({java.lang.annotation.ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyController {
	
	String value() default "";

}

@Target({java.lang.annotation.ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyQualifier {
	
	String value() default "";

}

@Target({java.lang.annotation.ElementType.TYPE,java.lang.annotation.ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
	String value() default "";
}

@Target({java.lang.annotation.ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestParam {
	
	String value() default "";

}

@Target({java.lang.annotation.ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyService {
	String value() default "";
}
  • 定义Controller层和service层
@MyController
@MyRequestMapping("/orderCon")
public class OrderController {
	
	@MyQualifier("orderServiceImpl")
	private OrderService orderServie;

	@MyRequestMapping("/query")
	public void query(HttpServletRequest req,HttpServletResponse res,
			@MyRequestParam("id") String id,@MyRequestParam("name")String name) {
		try {
			PrintWriter pw = res.getWriter();
			String result = orderServie.query(id, name);
			pw.write(result);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
}

@MyService("orderServiceImpl")
public class OrderServiceImpl implements OrderService {

	public String query(String id, String name) {
		
		return "name="+name+";id="+id;
	}

	public String insert(String id) {
		// TODO Auto-generated method stub
		return null;
	}

	public String update(String param) {
		// TODO Auto-generated method stub
		return null;
	}

}

MyDispacherServlet

public class MyDispatcherServlet extends HttpServlet {
	List<String> classNames = new ArrayList<String>();
	Map<String,Object> beans = new HashMap<String ,Object>();
	Map<String,Method> handMap = new HashMap<String, Method>();
	
	public MyDispatcherServlet() {};
	
	//容器的初始化
	public void init(ServletConfig servletConfig) {
		
		//1.扫描哪些类需要被实例化--找到class文件
		doScanPackage("com.machine");
		System.out.println("扫描完成。。。。。。。");
		for(String cname:classNames) {
			System.out.println(cname);
		}
		//2.将类实例化
		doInstance();
		System.out.println("实例化对象结束");
		for(Map.Entry<String, Object> entry : beans.entrySet()) {
			System.out.println(entry.getKey()+":"+entry.getValue());
		}
		//3.依赖注入 把service创建的对象依赖注入到反射里面
		iocDI();
		System.out.println("依赖注入完成。。。");
		
		//4.建立一个URL和类/方法之间的映射关系
		myHandMapper();
		System.out.println("建立好了URL和方法之间的映射关系。。。");
		for(Entry<String, Method> entry : handMap.entrySet()) {
			System.out.println(entry.getKey()+":"+entry.getValue());
		}
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String uri = req.getRequestURI();
		String context = req.getContextPath();
		String path = uri.replaceAll(context, "");
		System.out.println("请求路径:uri="+uri+";context="+context+";path="+path);
		Method method = (Method)handMap.get(path);//找到了要执行的方法,然后取将参数对应
		OrderController orderController = (OrderController)beans.get("/"+path.split("/")[1]);//拿到对应的controller
		//1.利用策略模式处理
		//2.处理这些参数的方法是 method.invoke(obj, args),实例、实例里面的处理方法都有了,就是要获取参数
		HandTools  hand = (HandTools)beans.get("myHandTool");
		Object[] args = hand.hand(req, resp, method, beans);
		
		try {
			method.invoke(orderController, args);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		
		
	}
	
	//扫描class类
	public void doScanPackage(String basePackage) {
		//扫描编译好的路径下所有的类
		URL url = this.getClass().getClassLoader().getResource("/"+basePackage.replaceAll("\\.", "/"));
		String fileStr = url.getFile();
		File file = new File(fileStr);
		String[] files = file.list();
		for(String path :files) {
			File filePath = new File(fileStr+path);
			if(filePath.isDirectory()) {
				doScanPackage(basePackage+"."+path);
			}else {
				classNames.add(basePackage+"."+filePath.getName());
			}
		}	
	}
	
	//根据className将类全部实例化
	public void doInstance() {
		if(classNames.size() <=0) {
			System.out.println("扫描失败。。。。");
			return;
		}
		
		//遍历扫描到的class全类名路径,通过反射创建对象
		for(String className:classNames) {
			String cn = className.replaceAll(".class", "");
			try {
				Class<?> clazz = Class.forName(cn);
				if(clazz.isAnnotationPresent(MyController.class)) {//判断使用mycontroller注解标注的,就进行实例化
					MyController con = clazz.getAnnotation(MyController.class);
					Object instance = clazz.newInstance();
					MyRequestMapping requestMapping = clazz.getAnnotation(MyRequestMapping.class);
					String key = requestMapping.value();
					beans.put(key, instance);
				}else if(clazz.isAnnotationPresent(MyService.class)) {
					Object instance = clazz.newInstance();
					MyService service = clazz.getAnnotation(MyService.class);
					beans.put(service.value(), instance);
				}else {
					continue;
				}
				
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public void iocDI() {
		if(beans.entrySet().size()<=0) {
			System.out.println("类没有被实例化");
			return;
		}
		for(Map.Entry<String, Object> entry : beans.entrySet()) {
			Object instance = entry.getValue();
			Class<?> clazz = instance.getClass();
			if(clazz.isAnnotationPresent(MyController.class)) {
				Field[] declaredFields = clazz.getDeclaredFields();//获取有哪些属性,或者说是参数
				for(Field field : declaredFields) {
					if(field.isAnnotationPresent(MyQualifier.class)) {//用MyQualifier声明,需要注入的
						MyQualifier myQualifier = field.getAnnotation(MyQualifier.class);
						String value = myQualifier.value();
						field.setAccessible(true);//放开反射设置参数值的权限
						try {
							field.set(instance, beans.get(value));//设置值:当前实例instance,要设置的参数field,注入的值beans.get(value)
						} catch (IllegalArgumentException e) {
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						}
					}else {
						continue;
					}
				}
				
			}else {
				continue;
			}
			
			
		}
	}
	
	//建立映射关系
	public void myHandMapper(){
		if(beans.entrySet().size()<=0) {
			System.out.println("类没有被实例化");
			return;
		}
		for(Map.Entry<String,Object> entry: beans.entrySet()) {
			Object instance = entry.getValue();
			//哪类类 声明了哪些注解
			Class<?> clazz = instance.getClass();
			if(clazz.isAnnotationPresent(MyController.class)) {//控制层才建立映射
				MyRequestMapping mrm = clazz.getAnnotation(MyRequestMapping.class);
				String classPath = mrm.value();
				Method[] methods = clazz.getMethods();
				for(Method method : methods) {
					if(method.isAnnotationPresent(MyRequestMapping.class)) {
						MyRequestMapping param2 = method.getAnnotation(MyRequestMapping.class);
						String methodUrl = param2.value();
						handMap.put(classPath+methodUrl,method);
					}
				}
			}
		}
	}
}

工具类

@MyService("myHandTool")
public class HandToolsImpl implements HandTools{

	public Object[] hand(HttpServletRequest req, HttpServletResponse resp, 
			Method method, Map<String, Object> beans) {
		Class<?>[] parameterTypes = method.getParameterTypes();//取到方法里面参数的类型
		Object[] args = new Object[parameterTypes.length];
		
		//1.拿到所有实现了ArgumentResolver的实例
		Map<String,Object> argResolvers = getInstanceType(beans,ArgumentResolver.class);
		int index = 0;
		int i=0;
		for(Class<?> paramClazz : parameterTypes) {
			//1.哪个参数对应哪个解析器,用策略模式来找
			for(Map.Entry<String, Object> entry : argResolvers.entrySet()) {
				ArgumentResolver resolver = (ArgumentResolver)entry.getValue();
				if(resolver.support(paramClazz, index, method)) {
					args[i++] = resolver.argumentReolver(req, resp, paramClazz, index, method);
				}
			}
			index++;
		}
		
		return args;
	}

	//1.拿到所有实现了ArgumentResolver的实例
	private Map<String, Object> getInstanceType(Map<String, Object> beans, Class<?> type) {
		Map<String,Object> resultBeans = new HashMap<String,Object>();
		for(Map.Entry<String, Object> entry :beans.entrySet()) {
			Class<?>[] interfaces = entry.getValue().getClass().getInterfaces();
			for(Class inf : interfaces) {
				if(inf.isAssignableFrom(type)) {
					resultBeans.put(entry.getKey(), entry.getValue());
				}
			}
		}
		
		return resultBeans;
	}
}


@MyService("myRequestParamResolver")
public class MyRequestParamResolver implements ArgumentResolver{

	public boolean support(Class<?> type, int index, Method method) {
		/*
		 *  1.传进来的是二维数组,类型和名字
		 */
		Annotation[][] anno = method.getParameterAnnotations();//返回的就是一个二维数组
		Annotation[] params = anno[index];
		for(Annotation an : params) {
			if(MyRequestParam.class.isAssignableFrom(an.getClass())) {
				return true;
			}
		}
		return false;
	}

	public Object argumentReolver(HttpServletRequest req, HttpServletResponse resp, Class<?> type, int index,
			Method method) {
		Annotation[][] anno = method.getParameterAnnotations();//返回的就是一个二维数组
		Annotation[] params = anno[index];
		for(Annotation an : params) {
			if(MyRequestParam.class.isAssignableFrom(an.getClass())) {
				MyRequestParam er = (MyRequestParam)an;//拿到方法上用MyRequestParam注解的参数的接收名字,然后从请求中获取
				String value = er.value();
				return req.getParameter(value);
				
			}
		}
		return null;
	}

}


@MyService("requestParamResolver")
public class RequestParamResolver implements ArgumentResolver {

	public boolean support(Class<?> type, int index, Method method) {
		
		return ServletRequest.class.isAssignableFrom(type);//判断是不是ServletRequest类型
	}

	public Object argumentReolver(HttpServletRequest req, HttpServletResponse resp, Class<?> type, int index,
			Method method) {
		// TODO Auto-generated method stub
		return req;
	}

}

总结

  • 内容:只引用servlet一个包,按照处理的大致流程,将简单的实现写出来
  • 创建项目:po依赖、web.xml
  • 自定义注解
  • 新建controller层、service层,使用自定义注解处理
  • 写自己的httpServlet ,进行初始化、doget doPost
  • 初始化的流程:
    • 扫描指定路径下面所有的类
    • 检查这些类里面使用自定义注解的标记的要实例化的bean,通过反射实例化放到BeanMap里面
    • 进行依赖注入,检查BeanMap里面所有类。获取里面的属性declaredFields,检查每个属性是不是需要依赖注入(以@MyQualifier标记),到BeanMap拿到要注入的bean,设置权限权限为true,通过反射进行依赖注入
    • 建立请求路径与方法映射关系。到每个@MyController标的bean里面(要求是每个Controller bean唯一),找到value;继续向下获取方法上的路径,加到 路径-method 的映射表MethodMap里面。
  • 请求处理的过程:
    • doget 转到doPost请求
    • 去掉项目名,获取请求的路径
    • 根据请求路径找到MethodMap里面对应的方法。
    • 将请求参数经过处理,用invoke方法进行处理。method.invoke(orderController, args);–底层是通过反射实现的。
  • 请求参数的处理过程:利用了策略模式。hand.hand(req, resp, method, beans); 请求、返回、方法、类
    • 先获取方法上所有参数类型;每个类型有对应的解析器
    • 遍历参数类型、第N个;
    • 每个解析器判断是否处理
      • 获取这个方法上所有的参数类型和索引
      • 获取这第N个参数所有的注解
      • 如果是MyRequestParam.class标记的话就能处理
    • 处理的时候根据MyRequestParam的value值取request获取值,然后返回。
    • 因为方法上参数类型是有先后顺序的,返回的参数列表也是符合这个顺序的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值