• 项目实战:组件扫描(5)-解析带有GetMapping或PostMapping的方法最后封装成ControllerDefinition


     

    1、ControllerDefinition  

    1. package com.csdn.mymvc.core;
    2. import lombok.AllArgsConstructor;
    3. import lombok.Data;
    4. import lombok.NoArgsConstructor;
    5. import java.lang.reflect.Method;
    6. import java.util.HashMap;
    7. import java.util.Map;
    8. //假设有一个uri是:/fruit/index
    9. @Data
    10. @NoArgsConstructor
    11. @AllArgsConstructor
    12. public class ControllerDefinition {
    13. private String requestMapping;
    14. private Object controllerBean;
    15. private Map methodMappingMap = new HashMap<>();
    16. }

    2、ComponentScan

    1. package com.csdn.mymvc.core;
    2. import com.csdn.mymvc.annotation.*;
    3. import java.io.File;
    4. import java.lang.annotation.Annotation;
    5. import java.lang.reflect.Field;
    6. import java.lang.reflect.InvocationTargetException;
    7. import java.lang.reflect.Modifier;
    8. import java.util.*;
    9. public class ComponentScan {
    10. public static Map beanFactory = new HashMap<>();
    11. public static Map controllerBeanMap = new HashMap<>();
    12. static String path = null;
    13. static {
    14. //分析文件夹
    15. path = ComponentScan.class.getClassLoader().getResource("").getPath();
    16. // /F:/IdeaProjects/workspace/review/pro13-fruit-DispatcherServlet/target/
    17. // pro13-fruit-DispatcherServlet-1.0-SNAPSHOT/WEB-INF/classes/
    18. //计算机的硬盘根目录是 / ,不论是什么操作系统。只是微软人为的分出盘符的概念
    19. //System.out.println(path);
    20. path = path.substring(1);
    21. //System.out.println(path);
    22. // F:/IdeaProjects/workspace/review/pro13-fruit-DispatcherServlet/target
    23. // /pro13-fruit-DispatcherServlet-1.0-SNAPSHOT/WEB-INF/classes/
    24. File rootDir = new File(path);
    25. //开始解析文件夹 - 组件扫描工作开始
    26. try {
    27. //第 1 步:扫描类路径,解析出所有的bean实例,存放到IOC容器中(beanFactory)
    28. parseFile(rootDir);
    29. beanFactory.values().forEach(System.out::println);
    30. //第 2 步:经过第 1 步,所有的bean实例已经创建就绪,但是bean和bean之间的依赖关系没有注入(Injection)
    31. //本步骤实现 注入依赖关系
    32. beanFactory.values().forEach(bean -> {
    33. //获取bean内部所有的field
    34. Field[] fields = bean.getClass().getDeclaredFields();
    35. //获取每一个field上的注解信息
    36. Arrays.stream(fields)
    37. .filter(field -> field.getDeclaredAnnotation(Autowire.class) != null)
    38. .forEach(field -> {
    39. //获取这个字段的类型的名称
    40. String fieldTypeName = field.getType().getName();
    41. //System.out.println(fieldTypeName);
    42. Object filedValue = beanFactory.values().stream().filter(instance -> {
    43. return field.getType().isAssignableFrom(instance.getClass());
    44. }).findFirst().orElseThrow(() -> new RuntimeException(fieldTypeName + "装配失败!"));
    45. try {
    46. field.setAccessible(true);
    47. field.set(bean, filedValue);
    48. } catch (IllegalAccessException e) {
    49. throw new RuntimeException(e);
    50. }
    51. });
    52. });
    53. //第 3 步:经过前两个步骤:IOC容器中已经准备好了所有的bean实例。并且bean实例之间的依赖关系也注入完成
    54. //这一步需要实现的是:uri是:/fruit/index 我们需要实现的是将uri中的两个标识分别映射到具体的controller实例以及controller方法上去
    55. //简单讲,这一步需要完成将每一个Controller都要存放到controllerBeanMap中
    56. beanFactory.values().stream()
    57. .filter(bean -> bean.getClass().getDeclaredAnnotation(RequestMapping.class) != null)
    58. .forEach(bean->{
    59. ControllerDefinition controllerDefinition = new ControllerDefinition();
    60. String requestMapping = bean.getClass().getDeclaredAnnotation(RequestMapping.class).value();
    61. Object controllerBean = bean;
    62. controllerDefinition.setRequestMapping(requestMapping);
    63. controllerDefinition.setControllerBean(controllerBean);
    64. //开始分析bean中的每一个方法
    65. Arrays.stream(bean.getClass().getDeclaredMethods()).forEach(method -> {
    66. GetMapping getMappingAnnotation = method.getDeclaredAnnotation(GetMapping.class);
    67. String methodMapping = null;
    68. if (getMappingAnnotation != null) {
    69. methodMapping = getMappingAnnotation.value();
    70. methodMapping = "get_" + methodMapping;
    71. }
    72. PostMapping postMappingAnnotation = method.getDeclaredAnnotation(PostMapping.class);
    73. if (postMappingAnnotation != null) {
    74. methodMapping = postMappingAnnotation.value();
    75. methodMapping = "post_" + methodMapping;
    76. }
    77. if (methodMapping != null) {
    78. controllerDefinition.getMethodMappingMap().put(methodMapping, method);
    79. }
    80. });
    81. //将这个controllerDefinition存放到专门的Controller容器中
    82. controllerBeanMap.put(requestMapping, controllerDefinition);
    83. });
    84. System.out.println(beanFactory);
    85. } catch (ClassNotFoundException e) {
    86. throw new RuntimeException(e);
    87. } catch (InvocationTargetException e) {
    88. throw new RuntimeException(e);
    89. } catch (NoSuchMethodException e) {
    90. throw new RuntimeException(e);
    91. } catch (InstantiationException e) {
    92. throw new RuntimeException(e);
    93. } catch (IllegalAccessException e) {
    94. throw new RuntimeException(e);
    95. }
    96. }
    97. private static void parseFile(File file) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    98. if (file.exists()) {
    99. if (file.isDirectory()) {
    100. //获取所有的子目录
    101. File[] childFiles = file.listFiles();
    102. for (File childFile : childFiles) {
    103. parseFile(childFile);
    104. }
    105. } else {
    106. String absPath = file.getAbsolutePath();
    107. //System.out.println(absPath);
    108. String fullClassPath = absPath.substring(path.length());
    109. //System.out.println(fullClassPath);
    110. if (fullClassPath.endsWith(".class")) {
    111. String fullClassPathName = fullClassPath.substring(0, fullClassPath.length() - ".class".length());
    112. //System.out.println(fullClassPathName);
    113. String fullClassName = fullClassPathName.replaceAll("\\\\", ".");
    114. //System.out.println(fullClassName);
    115. Class clazz = Class.forName(fullClassName);
    116. //System.out.println(clazz.toString());
    117. if (clazz.toString().startsWith("class")) { //排除掉接口、注解....,只关心class
    118. if (!Modifier.isAbstract(clazz.getModifiers())) { //排除掉抽象类
    119. Optional optional = Arrays.stream(clazz.getDeclaredAnnotations()).filter(annotation -> {
    120. return (annotation instanceof Controller || annotation instanceof Service || annotation instanceof Repository);
    121. }).findFirst();
    122. if (!optional.isEmpty()) {
    123. Object bean = clazz.getDeclaredConstructor().newInstance();
    124. beanFactory.put(fullClassName, bean);
    125. }
    126. }
    127. }
    128. }
    129. }
    130. }
    131. }
    132. }

  • 相关阅读:
    C#开发的OpenRA游戏之金钱系统(1)
    前端HTML5+CSS3+移动Web全套教程
    Seata 环境搭建
    MySQL教程
    【Java 基础篇】深入理解Java HashMap:使用注意事项和性能优化
    2300. 咒语和药水的成功对数
    【LLM大模型】大模型也内卷,Vicuna训练及推理指南,效果碾压斯坦福羊驼
    数据预处理
    起风了,NCC 云原生项目孵化计划
    sysstat系列:pidstat
  • 原文地址:https://blog.csdn.net/m0_65152767/article/details/134292640