GPDispatcherServlet.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. package cn.nosum.framework.mvc.v3.servlet;
  2. import cn.nosum.framework.annotation.*;
  3. import java.util.regex.Matcher;
  4. import java.util.regex.Pattern;
  5. import javax.servlet.ServletConfig;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.http.HttpServlet;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.File;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. import java.lang.annotation.Annotation;
  14. import java.lang.reflect.Field;
  15. import java.lang.reflect.Method;
  16. import java.net.URL;
  17. import java.util.*;
  18. public class GPDispatcherServlet extends HttpServlet {
  19. //保存application.properties配置文件中的内容
  20. private Properties contextConfig = new Properties();
  21. //保存扫描的所有的类名
  22. private List<String> classNames = new ArrayList<String>();
  23. // IOC容器
  24. private Map<String, Object> ioc = new HashMap<String, Object>();
  25. // 保存url和Method的对应关系
  26. private List<Handler> handlerMapping = new ArrayList<Handler>();
  27. @Override
  28. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  29. this.doPost(req, resp);
  30. }
  31. @Override
  32. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  33. //6、调用,运行阶段
  34. try {
  35. doDispatch(req, resp);
  36. } catch (Exception e) {
  37. e.printStackTrace();
  38. resp.getWriter().write("500 Exection,Detail : " + Arrays.toString(e.getStackTrace()));
  39. }
  40. }
  41. private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
  42. Handler handler = getHandler(req);
  43. if (handler == null) {
  44. resp.getWriter().write("404 Not Found!!!");
  45. return;
  46. }
  47. //获得方法的形参列表
  48. Class<?>[] paramTypes = handler.getParamTypes();
  49. Object[] paramValues = new Object[paramTypes.length];
  50. Map<String, String[]> params = req.getParameterMap();
  51. for (Map.Entry<String, String[]> parm : params.entrySet()) {
  52. String value = Arrays.toString(parm.getValue())
  53. .replaceAll("\\[|\\]", "")
  54. .replaceAll("\\s", ",");
  55. if (!handler.paramIndexMapping.containsKey(parm.getKey())) {
  56. continue;
  57. }
  58. int index = handler.paramIndexMapping.get(parm.getKey());
  59. paramValues[index] = convert(paramTypes[index], value);
  60. }
  61. if (handler.paramIndexMapping.containsKey(HttpServletRequest.class.getName())) {
  62. int reqIndex = handler.paramIndexMapping.get(HttpServletRequest.class.getName());
  63. paramValues[reqIndex] = req;
  64. }
  65. if (handler.paramIndexMapping.containsKey(HttpServletResponse.class.getName())) {
  66. int respIndex = handler.paramIndexMapping.get(HttpServletResponse.class.getName());
  67. paramValues[respIndex] = resp;
  68. }
  69. Object returnValue = handler.method.invoke(handler.controller, paramValues);
  70. if (returnValue == null || returnValue instanceof Void) {
  71. return;
  72. }
  73. resp.getWriter().write(returnValue.toString());
  74. }
  75. private Handler getHandler(HttpServletRequest req) {
  76. if (handlerMapping.isEmpty()) {
  77. return null;
  78. }
  79. // 绝对路径
  80. String url = req.getRequestURI();
  81. // 处理成相对路径
  82. String contextPath = req.getContextPath();
  83. url = url.replaceAll(contextPath, "").replaceAll("/+", "/");
  84. for (Handler handler : this.handlerMapping) {
  85. Matcher matcher = handler.getPattern().matcher(url);
  86. if (!matcher.matches()) {
  87. continue;
  88. }
  89. return handler;
  90. }
  91. return null;
  92. }
  93. //url传过来的参数都是String类型的,HTTP是基于字符串协议
  94. //只需要把String转换为任意类型就好
  95. private Object convert(Class<?> type, String value) {
  96. //如果是int
  97. if (Integer.class == type) {
  98. return Integer.valueOf(value);
  99. } else if (Double.class == type) {
  100. return Double.valueOf(value);
  101. }
  102. //如果还有double或者其他类型,继续加if
  103. //这时候,我们应该想到策略模式了
  104. //在这里暂时不实现,希望小伙伴自己来实现
  105. return value;
  106. }
  107. //初始化阶段
  108. @Override
  109. public void init(ServletConfig config) throws ServletException {
  110. //1、加载配置文件
  111. doLoadConfig(config.getInitParameter("contextConfigLocation"));
  112. //2、扫描相关的类
  113. doScanner(contextConfig.getProperty("scanPackage"));
  114. //3、初始化扫描到的类,并且将它们放入到ICO容器之中
  115. doInstance();
  116. //4、完成依赖注入
  117. doAutowired();
  118. //5、初始化HandlerMapping
  119. initHandlerMapping();
  120. System.out.println("Spring framework is init.");
  121. }
  122. //初始化url和Method的一对一对应关系
  123. private void initHandlerMapping() {
  124. if (ioc.isEmpty()) {
  125. return;
  126. }
  127. for (Map.Entry<String, Object> entry : ioc.entrySet()) {
  128. Class<?> clazz = entry.getValue().getClass();
  129. if (!clazz.isAnnotationPresent(Controller.class)) {
  130. continue;
  131. }
  132. //保存写在类上面的@GPRequestMapping("/demo")
  133. String baseUrl = "";
  134. if (clazz.isAnnotationPresent(RequestMapping.class)) {
  135. RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
  136. baseUrl = requestMapping.value();
  137. }
  138. //默认获取所有的 public方法
  139. for (Method method : clazz.getMethods()) {
  140. if (!method.isAnnotationPresent(RequestMapping.class)) {
  141. continue;
  142. }
  143. RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
  144. //优化
  145. String regex = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");
  146. Pattern pattern = Pattern.compile(regex);
  147. this.handlerMapping.add(new Handler(pattern, entry.getValue(), method));
  148. System.out.println("Mapped :" + pattern + "," + method);
  149. }
  150. }
  151. }
  152. //自动依赖注入
  153. private void doAutowired() {
  154. if (ioc.isEmpty()) {
  155. return;
  156. }
  157. for (Map.Entry<String, Object> entry : ioc.entrySet()) {
  158. //Declared 所有的,特定的 字段,包括 private/protected/default
  159. //正常来说,普通的OOP编程只能拿到public的属性
  160. Field[] fields = entry.getValue().getClass().getDeclaredFields();
  161. for (Field field : fields) {
  162. if (!field.isAnnotationPresent(Autowired.class)) {
  163. continue;
  164. }
  165. Autowired autowired = field.getAnnotation(Autowired.class);
  166. //如果用户没有自定义beanName,默认就根据类型注入
  167. //这个地方省去了对类名首字母小写的情况的判断,这个作为课后作业
  168. //小伙伴们自己去完善
  169. String beanName = autowired.value().trim();
  170. if ("".equals(beanName)) {
  171. //获得接口的类型,作为key待会拿这个key到ioc容器中去取值
  172. beanName = field.getType().getName();
  173. }
  174. //如果是public以外的修饰符,只要加了@Autowired注解,都要强制赋值
  175. //反射中叫做暴力访问, 强吻
  176. field.setAccessible(true);
  177. try {
  178. //用反射机制,动态给字段赋值
  179. field.set(entry.getValue(), ioc.get(beanName));
  180. } catch (IllegalAccessException e) {
  181. e.printStackTrace();
  182. }
  183. }
  184. }
  185. }
  186. private void doInstance() {
  187. //初始化,为DI做准备
  188. if (classNames.isEmpty()) {
  189. return;
  190. }
  191. try {
  192. for (String className : classNames) {
  193. Class<?> clazz = Class.forName(className);
  194. if (clazz.isAnnotationPresent(Controller.class)) {
  195. Object instance = clazz.newInstance();
  196. String beanName = toLowerFirstCase(clazz.getSimpleName());
  197. ioc.put(beanName, instance);
  198. } else if (clazz.isAnnotationPresent(Service.class)) {
  199. Service service = clazz.getAnnotation(Service.class);
  200. String beanName = service.value();
  201. if ("".equals(beanName.trim())) {
  202. beanName = toLowerFirstCase(clazz.getSimpleName());
  203. }
  204. Object instance = clazz.newInstance();
  205. ioc.put(beanName, instance);
  206. for (Class<?> i : clazz.getInterfaces()) {
  207. if (ioc.containsKey(i.getName())) {
  208. throw new Exception("The “" + i.getName() + "” is exists!!");
  209. }
  210. ioc.put(i.getName(), instance);
  211. }
  212. } else {
  213. continue;
  214. }
  215. }
  216. } catch (Exception e) {
  217. e.printStackTrace();
  218. }
  219. }
  220. //扫描出相关的类
  221. private void doScanner(String scanPackage) {
  222. URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
  223. File classPath = new File(url.getFile());
  224. for (File file : classPath.listFiles()) {
  225. if (file.isDirectory()) {
  226. doScanner(scanPackage + "." + file.getName());
  227. } else {
  228. if (!file.getName().endsWith(".class")) {
  229. continue;
  230. }
  231. String className = (scanPackage + "." + file.getName().replace(".class", ""));
  232. classNames.add(className);
  233. }
  234. }
  235. }
  236. //加载配置文件
  237. private void doLoadConfig(String contextConfigLocation) {
  238. // 直接从类路径下找到Spring主配置文件所在的路径
  239. // 并且将其读取出来放到Properties对象中
  240. // 相对于scanPackage=cn.nosum.demo 从文件中保存到了内存中
  241. InputStream fis = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
  242. try {
  243. contextConfig.load(fis);
  244. } catch (IOException e) {
  245. e.printStackTrace();
  246. } finally {
  247. if (null != fis) {
  248. try {
  249. fis.close();
  250. } catch (IOException e) {
  251. e.printStackTrace();
  252. }
  253. }
  254. }
  255. }
  256. public class Handler {
  257. private Pattern pattern; //正则
  258. private Method method;
  259. private Object controller;
  260. private Class<?>[] paramTypes;
  261. // 形参列表
  262. // 参数的名字作为key,参数的顺序,位置作为值
  263. private Map<String, Integer> paramIndexMapping;
  264. public Handler(Pattern pattern, Object controller, Method method) {
  265. this.pattern = pattern;
  266. this.method = method;
  267. this.controller = controller;
  268. paramTypes = method.getParameterTypes();
  269. paramIndexMapping = new HashMap<String, Integer>();
  270. putParamIndexMapping(method);
  271. }
  272. /**
  273. * 提取方法中加了注解的参数并且保存
  274. */
  275. private void putParamIndexMapping(Method method) {
  276. // 取得方法中参数的注解,得到的是一个二维数组
  277. // 一个方法有多个参数,一个参数可以有多个注解
  278. Annotation[][] pa = method.getParameterAnnotations();
  279. for (int i = 0; i < pa.length; i++) {
  280. for (Annotation annotation : pa[i]) {
  281. if (annotation instanceof RequestParam) {
  282. String paramName = ((RequestParam) annotation).value();
  283. if (!"".equals(paramName.trim())) {
  284. paramIndexMapping.put(paramName, i);
  285. }
  286. }
  287. }
  288. }
  289. // 提取方法中的request和response参数
  290. Class<?>[] paramsTypes = method.getParameterTypes();
  291. for (int i = 0; i < paramsTypes.length; i++) {
  292. Class<?> type = paramsTypes[i];
  293. if (type == HttpServletRequest.class || type == HttpServletResponse.class) {
  294. paramIndexMapping.put(type.getName(), i);
  295. }
  296. }
  297. }
  298. public Pattern getPattern() { return pattern; }
  299. public Method getMethod() { return method; }
  300. public Object getController() { return controller; }
  301. public Class<?>[] getParamTypes() { return paramTypes; }
  302. }
  303. private String toLowerFirstCase(String simpleName) {
  304. char[] chars = simpleName.toCharArray();
  305. chars[0] += 32;
  306. return String.valueOf(chars);
  307. }
  308. }