项目实战:组件扫描(4)-筛选带有RequestMapping注解的bean实例

1、ControllerDefinition

java 复制代码
package com.csdn.mymvc.core;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
//假设有一个uri是:/fruit/index
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ControllerDefinition {
    private String requestMapping;
    private Object controllerBean;
    private Map<String, Method> methodMappingMap = new HashMap<>();
}

2、 ComponentScan

java 复制代码
package com.csdn.mymvc.core;
import com.csdn.mymvc.annotation.*;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.*;
public class ComponentScan {
    public static Map<String, Object> beanFactory = new HashMap<>();
    public static Map<String, ControllerDefinition> controllerBeanMap = new HashMap<>();
    static String path = null;
    static {
        //分析文件夹
        path = ComponentScan.class.getClassLoader().getResource("").getPath();
        //  /F:/IdeaProjects/workspace/review/pro13-fruit-DispatcherServlet/target/
        //  pro13-fruit-DispatcherServlet-1.0-SNAPSHOT/WEB-INF/classes/
        //计算机的硬盘根目录是 / ,不论是什么操作系统。只是微软人为的分出盘符的概念
        //System.out.println(path);
        path = path.substring(1);
        //System.out.println(path);
        //   F:/IdeaProjects/workspace/review/pro13-fruit-DispatcherServlet/target
        //   /pro13-fruit-DispatcherServlet-1.0-SNAPSHOT/WEB-INF/classes/
        File rootDir = new File(path);
        //开始解析文件夹 - 组件扫描工作开始
        try {
            //第 1 步:扫描类路径,解析出所有的bean实例,存放到IOC容器中(beanFactory)
            parseFile(rootDir);
            beanFactory.values().forEach(System.out::println);
            //第 2 步:经过第 1 步,所有的bean实例已经创建就绪,但是bean和bean之间的依赖关系没有注入(Injection)
            //本步骤实现 注入依赖关系
            beanFactory.values().forEach(bean -> {
                //获取bean内部所有的field
                Field[] fields = bean.getClass().getDeclaredFields();
                //获取每一个field上的注解信息
                Arrays.stream(fields)
                        .filter(field -> field.getDeclaredAnnotation(Autowire.class) != null)
                        .forEach(field -> {
                            //获取这个字段的类型的名称
                            String fieldTypeName = field.getType().getName();
                            //System.out.println(fieldTypeName);
                            Object filedValue = beanFactory.values().stream().filter(instance -> {
                                return field.getType().isAssignableFrom(instance.getClass());
                            }).findFirst().orElseThrow(() -> new RuntimeException(fieldTypeName + "装配失败!"));

                            try {
                                field.setAccessible(true);
                                field.set(bean, filedValue);
                            } catch (IllegalAccessException e) {
                                throw new RuntimeException(e);
                            }
                        });
            });

            //第 3 步:经过前两个步骤:IOC容器中已经准备好了所有的bean实例。并且bean实例之间的依赖关系也注入完成
            //这一步需要实现的是:uri是:/fruit/index    我们需要实现的是将uri中的两个标识分别映射到具体的controller实例以及controller方法上去
            //简单讲,这一步需要完成将每一个Controller都要存放到controllerBeanMap中
            beanFactory.values().stream()
                    .filter(bean -> bean.getClass().getDeclaredAnnotation(RequestMapping.class) != null)
                    .forEach(bean->{
                        String requestMapping = bean.getClass().getDeclaredAnnotation(RequestMapping.class).value();
                        Object controllerBean = bean;
                        //开始分析bean中的每一个方法
                    });

            //System.out.println(beanFactory);


        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
    private static void parseFile(File file) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        if (file.exists()) {
            if (file.isDirectory()) {
                //获取所有的子目录
                File[] childFiles = file.listFiles();
                for (File childFile : childFiles) {
                      parseFile(childFile);
                }
            } else {
                String absPath = file.getAbsolutePath();
                //System.out.println(absPath);
                String fullClassPath = absPath.substring(path.length());
                //System.out.println(fullClassPath);
                if (fullClassPath.endsWith(".class")) {
                    String fullClassPathName = fullClassPath.substring(0, fullClassPath.length() - ".class".length());
                    //System.out.println(fullClassPathName);
                    String fullClassName = fullClassPathName.replaceAll("\\\\", ".");
                    //System.out.println(fullClassName);
                    Class<?> clazz = Class.forName(fullClassName);
                    //System.out.println(clazz.toString());
                    if (clazz.toString().startsWith("class")) {  //排除掉接口、注解....,只关心class

                        if (!Modifier.isAbstract(clazz.getModifiers())) {   //排除掉抽象类

                            Optional<Annotation> optional = Arrays.stream(clazz.getDeclaredAnnotations()).filter(annotation -> {
                                return (annotation instanceof Controller || annotation instanceof Service || annotation instanceof Repository);
                            }).findFirst();

                            if (!optional.isEmpty()) {
                                Object bean = clazz.getDeclaredConstructor().newInstance();
                                beanFactory.put(fullClassName, bean);
                            }
                        }
                    }
                }
            }
        }
    }
}
相关推荐
拿破轮5 分钟前
使用通义灵码解决复杂正则表达式替换字符串的问题.
java·服务器·前端
j***51895 分钟前
Java进阶,时间与日期,包装类,正则表达式
java·mysql·正则表达式
WZTTMoon42 分钟前
Spring Boot 启动全解析:4 大关键动作 + 底层逻辑
java·spring boot·后端
章鱼哥73043 分钟前
[特殊字符] SpringBoot 自定义系统健康检测:数据库、Redis、表统计、更新时长、系统性能全链路监控
java·数据库·redis
深圳佛手1 小时前
Sharding-JDBC 和 Sharding-Proxy 区别
java
kk哥88991 小时前
inout参数传递机制的底层原理是什么?
java·开发语言
小二·2 小时前
Spring框架入门:深入理解Spring DI的注入方式
java·后端·spring
避避风港2 小时前
转发与重定向
java·servlet
毕设源码-钟学长2 小时前
【开题答辩全过程】以 基于springboot和协同过滤算法的线上点餐系统为例,包含答辩的问题和答案
java·spring boot·后端