手写注解实现SpringMVC底层原理
鄙人小白一个,还没毕业,就个人而言,搞IT这块,讲究思路。若对此文疑虑,评论来战。(本人->无期)
1.首先我们来搭建架构,就建一个普通的javaweb项目就OK了,具体目录如下:
对于小白来说可以细看后面web.xml的配置,对javaweb有点研究可以忽略而过后面的web.xml配置。
2.先上代码,运行起整个项目。再来聊聊思路。
(1).Controller注解
packagecom.wuqi.annotation;import java.lang.annotation.*;/*** Created by wuqi on 2017/3/22.*/@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documentedpublic @interfaceController {
String value()default "";
}
Controller
(2).Quatifier注解
packagecom.wuqi.annotation;import java.lang.annotation.*;/*** Created by wuqi on 2017/3/25.*/@Target({ ElementType.FIELD })//代表注解的注解
@Retention(RetentionPolicy.RUNTIME)
@Documentedpublic @interfaceQuatifier {
String value()default "";
}
Quatifier
(3).RequestMapping注解
packagecom.wuqi.annotation;importjava.lang.annotation.Documented;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;/*** Created by Shock on 2017/3/22.*/@Target({ ElementType.METHOD })//在方法上的注解
@Retention(RetentionPolicy.RUNTIME)
@Documentedpublic @interfaceRequestMapping {
String value()default "";
}
RequestMapping
(4).Service注解
packagecom.wuqi.annotation;importjava.lang.annotation.Documented;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;/*** Created by Shock on 2017/3/22.*/@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documentedpublic @interfaceService {
String value()default "";
}
Service
--------------------------------------------------------------------------------------------------------------------------
(1).MyService接口
packagecom.wuqi.service.impl;importjava.util.Map;/*** Created by wuqi on 2017/3/23.*/
public interfaceMyService {intinsert(Map map);intdelete(Map map);intupdate(Map map);intselect(Map map);
}
MyService
(2).MyServiceImpl类
packagecom.wuqi.service.impl;importcom.wuqi.annotation.Service;importjava.util.Map;/*** Created by wuqi on 2017/3/23.*/@Service("MyServiceImpl")public class MyServiceImpl implementsMyService {
@Overridepublic intinsert(Map map) {
System.out.println("MyServiceImpl:" + "insert");return 0;
}
@Overridepublic intdelete(Map map) {
System.out.println("MyServiceImpl:" + "delete");return 0;
}
@Overridepublic intupdate(Map map) {
System.out.println("MyServiceImpl:" + "update");return 0;
}
@Overridepublic intselect(Map map) {
System.out.println("MyServiceImpl:" + "select");return 0;
}
}
MyServiceImpl
(3).SpringmvcService接口
packagecom.wuqi.service.impl;importjava.util.Map;/*** Created by wuqi on 2017/3/23.*/
public interfaceSpringmvcService {intinsert(Map map);intdelete(Map map);intupdate(Map map);intselect(Map map);
}
SpringmvcService
(4).MyServiceImpl类
packagecom.wuqi.service.impl;importcom.wuqi.annotation.Service;importjava.util.Map;/*** Created by wuqi on 2017/3/23.*/@Service("SpringmvcServiceImpl")public class SpringmvcServiceImpl implementsSpringmvcService{
@Overridepublic intinsert(Map map) {
System.out.println("SpringmvcServiceImpl:" + "insert");return 0;
}
@Overridepublic intdelete(Map map) {
System.out.println("SpringmvcServiceImpl:" + "delete");return 0;
}
@Overridepublic intupdate(Map map) {
System.out.println("SpringmvcServiceImpl:" + "update");return 0;
}
@Overridepublic intselect(Map map) {
System.out.println("SpringmvcServiceImpl:" + "select");return 0;
}
}
SpringmvcServiceImpl
--------------------------------------------------------------------------------------------------------------------------
(1).SpringmvcController类
packagecom.wuqi.controller;import com.wuqi.annotation.*;importcom.wuqi.service.impl.MyService;importcom.wuqi.service.impl.SpringmvcService;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;/*** Created by wuqi on 2017/3/23.*/@Controller("wuqi")public classSpringmvcController {
@Quatifier("MyServiceImpl")
MyService myService;
@Quatifier("SpringmvcServiceImpl")
SpringmvcService smService;
@RequestMapping("insert")publicString insert(HttpServletRequest request, HttpServletResponse response, String param) {
myService.insert(null);
smService.insert(null);return null;
}
@RequestMapping("delete")publicString delete(HttpServletRequest request, HttpServletResponse response, String param) {
myService.delete(null);
smService.delete(null);return null;
}
@RequestMapping("update")publicString update(HttpServletRequest request, HttpServletResponse response, String param) {
myService.update(null);
smService.update(null);return null;
}
@RequestMapping("select")publicString select(HttpServletRequest request, HttpServletResponse response, String param) {
myService.select(null);
smService.select(null);return null;
}
}
SpringmvcController
--------------------------------------------------------------------------------------------------------------------------
(1).DispatcherServlet类继承 javax.servlet.http.HttpServlet类
packagecom.wuqi.servlet;import com.wuqi.annotation.*;importcom.wuqi.controller.SpringmvcController;importjava.io.File;importjava.io.IOException;importjava.lang.reflect.Field;importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;importjava.net.URL;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.List;importjava.util.Map;importjavax.servlet.ServletConfig;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;/*** Created by Shock on 2017/3/23.*/
public class DispatcherServlet extendsHttpServlet{private static final long serialVersionUID = 1L;
List packageNames = new ArrayList();//所有类的实例,key是注解的value,value是所有类的实例
Map instanceMap = new HashMap();
Map handerMap = new HashMap();publicDispatcherServlet() {super();
}public void init(ServletConfig config) throwsServletException {//包扫描,获取包中的文件
scanPackage("com.wuqi");try{
filterAndInstance();
}catch(Exception e) {
e.printStackTrace();
}//建立映射关系
handerMap();//实现注入
ioc();
}private void filterAndInstance() throwsException {if (packageNames.size() <= 0) {return;
}for(String className : packageNames) {
Class> cName = Class.forName(className.replace(".class", "").trim());if (cName.isAnnotationPresent(Controller.class)) {
Object instance=cName.newInstance();
Controller controller= (Controller) cName.getAnnotation(Controller.class);
String key=controller.value();
instanceMap.put(key, instance);
}else if (cName.isAnnotationPresent(Service.class)) {
Object instance=cName.newInstance();
Service service= (Service) cName.getAnnotation(Service.class);
String key=service.value();
instanceMap.put(key, instance);
}else{continue;
}
}
}private voidioc() {if(instanceMap.isEmpty())return;for (Map.Entryentry : instanceMap.entrySet()) {//拿到里面的所有属性
Field fields[] =entry.getValue().getClass().getDeclaredFields();for(Field field : fields) {
field.setAccessible(true);//可访问私有属性
if (field.isAnnotationPresent(Quatifier.class));
Quatifier quatifier= field.getAnnotation(Quatifier.class);
String value=quatifier.value();
field.setAccessible(true);try{
field.set(entry.getValue(), instanceMap.get(value));
}catch(IllegalArgumentException e) {
e.printStackTrace();
}catch(IllegalAccessException e) {
e.printStackTrace();
}
}
}
SpringmvcController wuqi= (SpringmvcController) instanceMap.get("wuqi");
System.out.print(wuqi);
}/*** 扫描包下的所有文件
*
*@paramPackage*/
private voidscanPackage(String Package) {
URL url= this.getClass().getClassLoader().getResource("/" + replaceTo(Package));//将所有的.转义获取对应的路径
String pathFile =url.getFile();
File file= newFile(pathFile);
String fileList[]=file.list();for(String path : fileList) {
File eachFile= new File(pathFile +path);if(eachFile.isDirectory()) {
scanPackage(Package+ "." +eachFile.getName());
}else{
packageNames.add(Package+ "." +eachFile.getName());
}
}
}/*** 建立映射关系*/
private voidhanderMap() {if (instanceMap.size() <= 0)return;for (Map.Entryentry : instanceMap.entrySet()) {if (entry.getValue().getClass().isAnnotationPresent(Controller.class)) {
Controller controller= (Controller) entry.getValue().getClass().getAnnotation(Controller.class);
String ctvalue=controller.value();
Method[] methods=entry.getValue().getClass().getMethods();for(Method method : methods) {if (method.isAnnotationPresent(RequestMapping.class)) {
RequestMapping rm= (RequestMapping) method.getAnnotation(RequestMapping.class);
String rmvalue=rm.value();
handerMap.put("/" + ctvalue + "/" +rmvalue, method);
}else{continue;
}
}
}else{continue;
}
}
}privateString replaceTo(String path) {return path.replaceAll("\\.", "/");
}
@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {this.doPost(req, resp);
}
@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
String url=req.getRequestURI();
String context=req.getContextPath();
String path= url.replace(context, "");
Method method=(Method) handerMap.get(path);
SpringmvcController controller= (SpringmvcController) instanceMap.get(path.split("/")[1]);try{
method.invoke(controller,new Object[] { req, resp, null});
}catch(IllegalAccessException e) {
e.printStackTrace();
}catch(IllegalArgumentException e) {
e.printStackTrace();
}catch(InvocationTargetException e) {
e.printStackTrace();
}
}
}
DispatcherServlet
所有的代码已经贴上,还有个web.xml
version="3.1">
testServlet
com.wuqi.servlet.DispatcherServlet
testServlet
/*
web.xml
3.好了代码已经贴上了,现在需要来说说思路,因为有代码了,所以用代码来将思路,这样更容易理解代码的含义。之后可以根据自己的程度去试着写。
首先我们需要扫描包中的所有文件(DispatcherServlet -> init(ServletConfig config) -> scanPackage("com.wuqi")),也就是含有注解的文件。然后将该包下的所有文件都存入packageNames集合中。
这时我们拿到了包下所有的文件,但我们只需要含有我们指定注解的那部分文件,因此需要过滤出我们想要的文件即可,并且在过滤的过程中,我们可以将过滤出来的类通过Class.forName来直接实例化并储存起来。存放到instanceMap集合中,并为其设置对应的key值,该key值就是类注解的value。
然后遍历instanceMap集合中的所有对象,获取指定注解的对象,并通过反射获取该对象的所有的方法,遍历所有的方法,将指定注解的方法存入handerMap,key为拼接字符串("/" + 对象变量名 + "/" + 方法名),value为方法(Method)。
然后我们可以遍历instanceMap集合中的所有对象,通过反射获取对象的所有属性值(字段)集合,然后遍历属性值集合,将属性值含有指定注解的,通过Field的set方法为该属性值赋值,这时就将对象注入了。(也就是往Controller中注入Service对象)
最后就可以通过反射的invoke方法调用某个对象的某个方法。(此时对象存于instanceMap,而方法都存于handerMap)
借鉴 -> http://blog.csdn.net/chaoyueygw/article/details/53393952该博文