【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 "";
}
注意:
- ElementType.TYPE表示定义的这个注解以后可以用在类上;
- 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
测试:
注意:
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字段的值;