项目实战:组件扫描(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);
                            }
                        }
                    }
                }
            }
        }
    }
}
相关推荐
CV_J1 天前
安装kibana
java·elasticsearch·spring cloud·docker·容器
码农水水1 天前
国家电网Java面试被问:TCP的BBR拥塞控制算法原理
java·开发语言·网络·分布式·面试·wpf
qq_336313931 天前
java基础-网络编程-TCP
java·网络·tcp/ip
咕噜咕噜啦啦1 天前
Java期末习题速通
java·开发语言
盐真卿1 天前
python2
java·前端·javascript
一嘴一个橘子1 天前
mybatis - 动态语句、批量注册mapper、分页插件
java
组合缺一1 天前
Json Dom 怎么玩转?
java·json·dom·snack4
危险、1 天前
一套提升 Spring Boot 项目的高并发、高可用能力的 Cursor 专用提示词
java·spring boot·提示词
kaico20181 天前
JDK11新特性
java
钊兵1 天前
java实现GeoJSON地理信息对经纬度点的匹配
java·开发语言