模拟实现Spring IoC
Posted sakura1027
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模拟实现Spring IoC相关的知识,希望对你有一定的参考价值。
项目结构
直接上代码
1 package com.sakura.annotion; 2 3 import java.lang.annotation.*; 4 5 @Target(ElementType.TYPE) 6 @Retention(RetentionPolicy.RUNTIME) 7 @Documented 8 public @interface Controller { 9 String value() default ""; 10 }
1 package com.sakura.annotion; 2 3 import java.lang.annotation.*; 4 5 @Target(ElementType.FIELD) 6 @Retention(RetentionPolicy.RUNTIME) 7 @Documented 8 public @interface Qualifier { 9 String value() default ""; 10 }
1 package com.sakura.annotion; 2 3 import java.lang.annotation.*; 4 5 @Target(ElementType.METHOD) 6 @Retention(RetentionPolicy.RUNTIME) 7 @Documented 8 public @interface RequestMapping { 9 String value() default ""; 10 }
1 package com.sakura.annotion; 2 3 import java.lang.annotation.*; 4 5 @Target(ElementType.TYPE) 6 @Retention(RetentionPolicy.RUNTIME) 7 @Documented 8 public @interface Service { 9 String value() default ""; 10 }
1 package com.sakura.controller; 2 3 import com.sakura.annotion.Controller; 4 import com.sakura.annotion.Qualifier; 5 import com.sakura.annotion.RequestMapping; 6 import com.sakura.service.FishService; 7 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 @Controller("fish") 12 public class FishController { 13 @Qualifier("fishServiceImpl") 14 FishService fishService; 15 16 @RequestMapping("get") 17 public void get(HttpServletRequest request, HttpServletResponse response) { 18 System.out.println(fishService.get()); 19 } 20 21 }
1 package com.sakura.service.impl; 2 3 import com.sakura.annotion.Service; 4 import com.sakura.service.FishService; 5 6 @Service("fishServiceImpl") 7 public class FishServiceImpl implements FishService { 8 @Override 9 public String get() { 10 return "shark"; 11 } 12 }
1 package com.sakura.service; 2 3 public interface FishService { 4 String get(); 5 }
1 package com.sakura.servlet; 2 3 import com.sakura.annotion.Controller; 4 import com.sakura.annotion.Qualifier; 5 import com.sakura.annotion.RequestMapping; 6 import com.sakura.annotion.Service; 7 import com.sakura.controller.FishController; 8 9 import javax.servlet.ServletException; 10 import javax.servlet.annotation.WebServlet; 11 import javax.servlet.http.HttpServlet; 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 import java.io.File; 15 import java.io.IOException; 16 import java.lang.reflect.Field; 17 import java.lang.reflect.Method; 18 import java.net.URL; 19 import java.util.ArrayList; 20 import java.util.HashMap; 21 import java.util.List; 22 import java.util.Map; 23 24 @WebServlet("/") 25 public class DispatcherServlet extends HttpServlet { 26 private List<String> classNames = new ArrayList<>(); 27 private Map<String, Object> instanceMap = new HashMap<>(); 28 private Map<String, Method> methodMap = new HashMap<>(); 29 30 @Override 31 public void init() throws ServletException { 32 // 找到bean 33 scanBase("com.sakura"); 34 try { 35 // 生成并注册bean 36 registerBean(); 37 // 注入bean 38 springDi(); 39 mvc(); 40 } catch (Exception e) { 41 e.printStackTrace(); 42 } 43 } 44 45 private void mvc() { 46 if (instanceMap.size() == 0) return; 47 for (Map.Entry<String, Object> entry : instanceMap.entrySet()) { 48 if (entry.getValue().getClass().isAnnotationPresent(Controller.class)) { 49 String ctlUrl = entry.getValue().getClass().getAnnotation(Controller.class).value(); 50 Method[] methods = entry.getValue().getClass().getMethods(); 51 for (Method method : methods) { 52 if (method.isAnnotationPresent(RequestMapping.class)) { 53 String reqUrl = method.getAnnotation(RequestMapping.class).value(); 54 String dispatchUrl = "/spring/" + ctlUrl + "/" + reqUrl; 55 methodMap.put(dispatchUrl, method); 56 } 57 } 58 } 59 } 60 } 61 62 private void springDi() throws Exception { 63 if (instanceMap.size() == 0) return; 64 for (Map.Entry<String, Object> entry : instanceMap.entrySet()) { 65 Field[] fields = entry.getValue().getClass().getDeclaredFields(); 66 for (Field field : fields) { 67 if (field.isAnnotationPresent(Qualifier.class)) { 68 String key = field.getAnnotation(Qualifier.class).value(); 69 field.setAccessible(true); 70 field.set(entry.getValue(), instanceMap.get(key)); 71 } 72 } 73 } 74 } 75 76 private void registerBean() throws Exception { 77 if (classNames.size() == 0) return; 78 for (String className : classNames) { 79 Class clazz = Class.forName(className.replace(".class", "")); 80 if (clazz.isAnnotationPresent(Controller.class)) { 81 Object instance = clazz.newInstance(); 82 String key = ((Controller) clazz.getAnnotation(Controller.class)).value(); 83 // bean交付给ioc容器 84 instanceMap.put(key, instance); 85 } else if (clazz.isAnnotationPresent(Service.class)) { 86 Object instance = clazz.newInstance(); 87 String key = ((Service) clazz.getAnnotation(Service.class)).value(); 88 // bean交付给ioc容器 89 instanceMap.put(key, instance); 90 } 91 } 92 } 93 94 private void scanBase(String basePackage) { 95 URL url = this.getClass().getClassLoader().getResource("/" + basePackage.replaceAll("\\\\.", "/")); 96 String path = url.getFile(); 97 File file = new File(path); 98 String[] strFiles = file.list(); 99 for (String strFile : strFiles) { 100 File eachFile = new File(path + strFile); 101 if (eachFile.isDirectory()) { 102 scanBase(basePackage + "." + eachFile.getName()); 103 } else { 104 System.out.println("class name:" + eachFile.getName()); 105 classNames.add(basePackage + "." + eachFile.getName()); 106 } 107 } 108 } 109 110 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 111 // localhost:8080/spring/fish/get 112 String uri = request.getRequestURI(); 113 Method method = methodMap.get(uri); 114 String className = uri.split("/")[2]; 115 FishController fishController = (FishController) instanceMap.get(className); 116 try { 117 method.invoke(fishController, new Object[]{request, response}); 118 } catch (Exception e) { 119 e.printStackTrace(); 120 } 121 122 } 123 }
运行结果
实现思路
1. 通过scanBase方法获取com.sakura包下的classNames
2. 通过registerBean方法注册bean,需要注意还未完成依赖注入
3. 通过springDi方法完成依赖注入
4. 通过mvc方法绑定url到methodMap
5. 反射调用
以上是关于模拟实现Spring IoC的主要内容,如果未能解决你的问题,请参考以下文章
javaSpring 自己模拟 Spring 实现 IOC依赖注入 并且 解决 循环依赖