DispatcherServlet.java 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. package cn.nosum.framework.mvc.v2.servlet;
  2. import cn.nosum.framework.annotation.*;
  3. import javax.servlet.ServletConfig;
  4. import javax.servlet.ServletException;
  5. import javax.servlet.http.HttpServlet;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8. import java.io.IOException;
  9. import java.io.InputStream;
  10. import java.lang.annotation.Annotation;
  11. import java.lang.reflect.Field;
  12. import java.lang.reflect.Method;
  13. import java.net.URL;
  14. import java.util.*;
  15. import java.io.File;
  16. public class DispatcherServlet extends HttpServlet {
  17. private Properties contextConfig = new Properties();
  18. //享元模式,缓存
  19. private List<String> classNames = new ArrayList<String>();
  20. //IoC容器,key默认是类名首字母小写,value就是对应的实例对象
  21. private Map<String,Object> ioc = new HashMap<String,Object>();
  22. // 保存 URL 与对应执行方法的映射
  23. private Map<String,Method> handlerMapping = new HashMap<String, Method>();
  24. @Override
  25. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  26. this.doPost(req,resp);
  27. }
  28. @Override
  29. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  30. try {
  31. //6、委派,根据URL去找到一个对应的Method并通过response返回
  32. doDispatch(req,resp);
  33. } catch (Exception e) {
  34. e.printStackTrace();
  35. resp.getWriter().write("500 Exception,Detail : " + Arrays.toString(e.getStackTrace()));
  36. }
  37. }
  38. private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
  39. String url = req.getRequestURI();
  40. String contextPath = req.getContextPath();
  41. url = url.replaceAll(contextPath,"").replaceAll("/+","/");
  42. if(!this.handlerMapping.containsKey(url)){
  43. resp.getWriter().write("404 Not Found!!!");
  44. return;
  45. }
  46. Map<String,String[]> params = req.getParameterMap();
  47. Method method = this.handlerMapping.get(url);
  48. //获取形参列表
  49. Class<?> [] parameterTypes = method.getParameterTypes();
  50. Object [] paramValues = new Object[parameterTypes.length];
  51. for (int i = 0; i < parameterTypes.length; i++) {
  52. Class parameterType = parameterTypes[i];
  53. if(parameterType == HttpServletRequest.class){
  54. paramValues[i] = req;
  55. }else if(parameterType == HttpServletResponse.class){
  56. paramValues[i] = resp;
  57. }else if(parameterType == String.class){
  58. // 需要通过运行时的状态才可以拿到
  59. Annotation[] [] pa = method.getParameterAnnotations();
  60. for (int j = 0; j < pa.length ; j ++) {
  61. for(Annotation annotation : pa[i]){
  62. if(annotation instanceof RequestParam){
  63. String paramName = ((RequestParam) annotation).value();
  64. if(!"".equals(paramName.trim())){
  65. String value = Arrays.toString(params.get(paramName))
  66. .replaceAll("\\[|\\]","")
  67. .replaceAll("\\s+",",");
  68. paramValues[i] = value;
  69. }
  70. }
  71. }
  72. }
  73. }
  74. }
  75. // 通过 method 获取对应的类
  76. String beanName = toLowerFirstCase(method.getDeclaringClass().getSimpleName());
  77. // 从 ioc 中获取对应的类并且执行
  78. method.invoke(ioc.get(beanName),paramValues);
  79. }
  80. @Override
  81. public void init(ServletConfig config) throws ServletException {
  82. //1、加载配置文件
  83. doLoadConfig(config.getInitParameter("contextConfigLocation"));
  84. //2、扫描相关的类
  85. doScanner(contextConfig.getProperty("scanPackage"));
  86. //==============IoC部分==============
  87. //3、初始化IoC容器,将扫描到的相关的类实例化,保存到IcC容器中
  88. doInstance();
  89. //AOP,新生成的代理对象
  90. //==============DI部分==============
  91. //4、完成依赖注入
  92. doAutowired();
  93. //==============MVC部分==============
  94. //5、初始化HandlerMapping
  95. doInitHandlerMapping();
  96. System.out.println("Spring framework is init.");
  97. }
  98. private void doInitHandlerMapping() {
  99. if(ioc.isEmpty()){ return;}
  100. for (Map.Entry<String,Object> entry : ioc.entrySet()) {
  101. Class<?> clazz = entry.getValue().getClass();
  102. if(!clazz.isAnnotationPresent(Controller.class)){ continue; }
  103. String baseUrl = "";
  104. if(clazz.isAnnotationPresent(RequestMapping.class)){
  105. // 取得类配置的 url
  106. RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
  107. baseUrl = requestMapping.value();
  108. }
  109. // 只获取 public 的方法
  110. for (Method method : clazz.getMethods()) {
  111. if(!method.isAnnotationPresent(RequestMapping.class)){continue;}
  112. // 提取每个方法配置的 url
  113. RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
  114. String url = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+","/");
  115. handlerMapping.put(url,method);
  116. System.out.println("Mapped : " + url + "," + method);
  117. }
  118. }
  119. }
  120. private void doAutowired() {
  121. if(ioc.isEmpty()){return;}
  122. for (Map.Entry<String,Object> entry : ioc.entrySet()) {
  123. // 把所有 private/protected/default/public 修饰字段都取出来
  124. for (Field field : entry.getValue().getClass().getDeclaredFields()) {
  125. if(!field.isAnnotationPresent(Autowired.class)){ continue; }
  126. Autowired autowired = field.getAnnotation(Autowired.class);
  127. // 没有自定义的beanName,根据类型注入
  128. String beanName = autowired.value().trim();
  129. if("".equals(beanName)){
  130. beanName = field.getType().getName();
  131. }
  132. // 赋值
  133. try {
  134. field.setAccessible(true);
  135. field.set(entry.getValue(),ioc.get(beanName));
  136. } catch (IllegalAccessException e) {
  137. e.printStackTrace();
  138. }
  139. }
  140. }
  141. }
  142. private void doInstance() {
  143. if(classNames.isEmpty()){return;}
  144. try {
  145. for (String className : classNames) {
  146. Class<?> clazz = Class.forName(className);
  147. if(clazz.isAnnotationPresent(Controller.class)) {
  148. String beanName = toLowerFirstCase(clazz.getSimpleName());
  149. Object instance = clazz.newInstance();
  150. ioc.put(beanName, instance);
  151. }else if(clazz.isAnnotationPresent(Service.class)){
  152. // 获取自定义的名称
  153. String beanName = clazz.getAnnotation(Service.class).value();
  154. if("".equals(beanName.trim())){
  155. beanName = toLowerFirstCase(clazz.getSimpleName());
  156. }
  157. Object instance = clazz.newInstance();
  158. ioc.put(beanName, instance);
  159. // 如果是接口,只能有一个实现,否则抛出异常
  160. for (Class<?> i : clazz.getInterfaces()) {
  161. if(ioc.containsKey(i.getName())){
  162. throw new Exception("The " + i.getName() + " is exists!!");
  163. }
  164. ioc.put(i.getName(),instance);
  165. }
  166. }else{
  167. continue;
  168. }
  169. }
  170. }catch (Exception e){
  171. e.printStackTrace();
  172. }
  173. }
  174. private void doScanner(String scanPackage) {
  175. URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.","/"));
  176. File classPath = new File(url.getFile());
  177. //当成是一个 ClassPath 文件夹
  178. for (File file : classPath.listFiles()) {
  179. if(file.isDirectory()){
  180. doScanner(scanPackage + "." + file.getName());
  181. }else {
  182. if(!file.getName().endsWith(".class")){continue;}
  183. // 全类名 = 包名.类名
  184. String className = (scanPackage + "." + file.getName().replace(".class", ""));
  185. classNames.add(className);
  186. }
  187. }
  188. }
  189. private void doLoadConfig(String contextConfigLocation) {
  190. InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
  191. try {
  192. contextConfig.load(is);
  193. } catch (IOException e) {
  194. e.printStackTrace();
  195. }finally {
  196. if(null != is){
  197. try {
  198. is.close();
  199. } catch (IOException e) {
  200. e.printStackTrace();
  201. }
  202. }
  203. }
  204. }
  205. private String toLowerFirstCase(String simpleName) {
  206. char [] chars = simpleName.toCharArray();
  207. chars[0] += 32;
  208. return String.valueOf(chars);
  209. }
  210. }