【javaweb】自己动手实现简易的springmvc

 

【javaweb】自己动手实现简易的springmvc

 

自定义注解

MyController.java

package cn.huangyan.spring.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface MyController {
	String value() default "";
}

MyService.java

package cn.huangyan.spring.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface MyService {
	String value() default "";
}

MyAutowired.java

package cn.huangyan.spring.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

MyRequestMapping.java

package cn.huangyan.spring.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

注意:

  1. ElementType.TYPE表示定义的这个注解以后可以用在类上;
  2. ElementType.METHOD表示这个注解可以用在方法上;

测试类

TestService.java

package cn.huangyan.spring.pack;

import cn.huangyan.spring.annotation.MyService;

@MyService("/testService")
public class TestService {
		
	public String testService() {
		return "testService";
	}
}

TestController.java

package cn.huangyan.spring.pack;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.huangyan.spring.annotation.MyAutowired;
import cn.huangyan.spring.annotation.MyController;
import cn.huangyan.spring.annotation.MyRequestMapping;

@MyController
@MyRequestMapping("/test")
public class TestController {
	
	@MyAutowired("/testService")
	private TestService testService;
	
	@MyRequestMapping("/index")
	public void testController(HttpServletRequest request, HttpServletResponse response) {
		String returnString = "testController:" + testService.testService();
		System.out.println("returnString ="+returnString);
		try {
			PrintWriter writer = response.getWriter();
			writer.write(returnString);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

中央控制器DispatcherServlet

package cn.huangyan.spring.pack;

import java.io.File;
import java.io.IOException;
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 java.util.Map.Entry;

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

import cn.huangyan.spring.annotation.MyAutowired;
import cn.huangyan.spring.annotation.MyController;
import cn.huangyan.spring.annotation.MyRequestMapping;
import cn.huangyan.spring.annotation.MyService;

/**
 * Servlet implementation class MyDispatcherServlet
 */
public class MyDispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	// 存在当前加载的所有的类
	List<String> classNames = new ArrayList<String>();
	
	// 存储IOC容器的MAP
	Map<String,Object> beans = new HashMap<>();
	
	// 存储请求路径和方法的映射关系
	Map<String,Object> handlerMethd = new HashMap<>();

	public void init() throws ServletException{
		System.out.println("进来了");

		String basePackage = "cn.huangyan.spring";

		scanPackage(basePackage);

		classInstance();

		autoInject();

		handlerMapping();

		for(Entry<String,Object> entry : beans.entrySet()) {
			System.out.println(entry.getKey() + " = " + entry.getValue());
		}
		System.out.println("----------------------------------------------------------------------");
		for(Entry<String,Object> entry : handlerMethd.entrySet()) {
			System.out.println(entry.getKey() + " = " + entry.getValue());
		}
	}


	// 第1步:springmvc的包扫描
	private void scanPackage(String basePackage) {
		String path = basePackage.replaceAll("\\.", "/"); // path = cn/huangyan/spring

		// file:/D:/ecli_space/workspace/myday06/target/classes/cn/huangyan/spring
		URL url = getClass().getClassLoader().getResource(path); //  注意path最前面没有/
		String filePath = url.getFile(); // /D:/ecli_space/workspace/myday06/target/classes/cn/itcast/cn/huangyan/spring
		File[] files = new File(filePath).listFiles();

		for(File file : files) {
			if(file.isDirectory()) {
				scanPackage(basePackage + "." + file.getName());
			}else {
				classNames.add(basePackage + "." + file.getName());
			}
		}
	}

	// 第2步:类实例化
	private void classInstance() {
		if(classNames.isEmpty()) {
			System.out.println("没有扫描到任何.class文件");
			return;
		}

		for(String className : classNames) {
			String realClassName = className.replace(".class", "");
			try {
				Class clazz = Class.forName(realClassName);
				
				// 判断此类有没有MyController注解
				if(clazz.isAnnotationPresent(MyController.class)) {
					//获得此clazz上的MyController注解
					MyController myController = (MyController) clazz.getAnnotation(MyController.class);
					Object instance = clazz.newInstance();
					//获得此clazz上的MyRequestMapping注解
					MyRequestMapping myRequestMapping = (MyRequestMapping) clazz.getAnnotation(MyRequestMapping.class);
					String mappingValue = myRequestMapping.value();
					beans.put(mappingValue, instance);
				}

				// 判断此类有没有MyService注解
				if(clazz.isAnnotationPresent(MyService.class)) {
					//获得此clazz上的MyService注解
					MyService myService = (MyService) clazz.getAnnotation(MyService.class);
					String serviceName = myService.value();
					Object instance = clazz.newInstance();
					beans.put(serviceName, instance);
				}

			} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

	
	// 第3步:依赖注入(自动装配)
	private void autoInject() {
		if(beans.isEmpty()) {
			System.out.println("没有扫描到任何bean");
			return;
		}

		for(Entry<String,Object> entry : beans.entrySet()) {
			Object instance = entry.getValue();

			Field[] fields = instance.getClass().getDeclaredFields();
			for(Field field : fields) {
				if(field.isAnnotationPresent(MyAutowired.class)) {
					MyAutowired myAutowired = field.getAnnotation(MyAutowired.class);
					String valueOfInject = myAutowired.value();
					Object instanceOfInject = beans.get(valueOfInject);

					field.setAccessible(true);

					try {
						// 最关键的,完成依赖注入
						field.set(instance, instanceOfInject);
					} catch (IllegalArgumentException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}
				}
			}
		}

	}

	// 第4步:处理器映射处理
	private void handlerMapping() {
		if(beans.isEmpty()) {
			System.out.println("没有扫描到任何bean");
			return;
		}

		for(Entry<String,Object> entry : beans.entrySet()) {
			Object instance = entry.getValue();

			if(instance.getClass().isAnnotationPresent(MyController.class)) {
				MyRequestMapping myRequestMappingOfLevel1 = instance.getClass().getAnnotation(MyRequestMapping.class);
				// 获得类上的请求路径
				String mappingOfLevel1 = myRequestMappingOfLevel1.value();

				// 获得此实例对象的所有method
				Method[] methods = instance.getClass().getDeclaredMethods();
				for(Method method : methods) {
					if(method.isAnnotationPresent(MyRequestMapping.class)) {
						MyRequestMapping myRequestMappingOfLevel2 = method.getAnnotation(MyRequestMapping.class);
						// 获得方法上的请求路径
						String mappingOfLevel2 = myRequestMappingOfLevel2.value();

						String allMappingValue = mappingOfLevel1 + mappingOfLevel2;
						System.out.println(allMappingValue);
						handlerMethd.put(allMappingValue, method);
					}
				}
			}
		}
	}

	public MyDispatcherServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		System.out.println("doGet()............");

		String uri = request.getRequestURI(); // “/test/index”
		String ctxPath = request.getContextPath(); // 什么都没有
		String path = uri.replace(ctxPath, ""); // “/test/index”
		System.out.println("path.split(\"/\")[0] = " + path.split("/")[0]);
		System.out.println("path.split(\"/\")[1] = " + path.split("/")[1]); // path.split("/")[1] = test

		Method method = (Method) handlerMethd.get(path);
		Object controllerInstance = beans.get("/" + path.split("/")[1]);  // 这里最前面,还要加上一个/
		try {
			Object object = method.invoke(controllerInstance, request,response); // 传入了request和response对象;
		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
			e.printStackTrace();
		}

	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		System.out.println("doPost()............");		
	}

}

小结:

a)String realClassName = className.replace(".class", "");
            try {
                Class clazz = Class.forName(realClassName);

     Class.forName() 只能作用于cn.itcast.web.Servlet.MyDispatcherServlet这样的全路径名,

     不能作用于:cn.itcast.web.Servlet.MyDispatcherServlet.class

测试:

【javaweb】自己动手实现简易的springmvc

注意:

a)如果通过chrome浏览器发送请求,中央控制器中代码会发生空指针异常,因为chrome浏览器中有个关于html的插件,导致发送了两次请求;换了IE浏览器测试就好了;

小结:

1)   URL url = getClass().getClassLoader().getResource(path); //  注意path最前面没有/,path = cn/huangyan/spring
        String filePath = url.getFile();
        File[] files = new File(filePath).listFiles();

2)通过反射操作对象,获取Field,Method,set字段的值;