7.手写spring
准备工作
<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 "";
}
@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获取值,然后返回。
- 因为方法上参数类型是有先后顺序的,返回的参数列表也是符合这个顺序的。