【手写一个spring】spring源码的简单实现--容器启动

文章目录

前言

今天开启一个新的章节,手写一个简易版的spring,帮助大家对spring能有一个更深层次的理解.

我将分为以下几个章节进行学习:

今天先开启我们的第一个章节:容器启动.

applicationContext初始化的前置操作

我们在日常使用spring的时候,一般会向容器传入一个配置类或者配置文件 ,在配置类或者配置文件中,存放扫描路径 .在这里我们使用配置类的方式进行设计.

  1. 自定义启动类BaiLuApplicationContext:

    public BaiLuApplicationContext(Class configClass) {
    //....
    }

  2. 自定义配置类

    @ComponentScan("com.fbl.service")
    public class AppConfig {
    //.....
    }

在配置类中需要进行扫描路径的确定,我们采用注解(@ComponentScan)的方式设置一个扫描路径

  1. 自定义@ComponentScan

    @Retention(RetentionPolicy.RUNTIME)//注解生效时机
    @Target(ElementType.TYPE) //写在类上面的注解
    public @interface ComponentScan {
    String value() default "";//存放扫描路径
    }

  2. 自定义Component

    @Retention(RetentionPolicy.RUNTIME)//生效时间
    @Target(ElementType.TYPE) //写在类上面的注解
    public @interface Component {
    String value() default ""; //这里是beanName
    }

获取扫描路径

容器启动的第一步,先要通过配置类,获取到扫描路径 .也就是获取到配置类上的注解 @ComponentScan的value()

复制代码
 public BaiLuApplicationContext(Class configClass) {
        this.configClass = configClass;

        //1.扫描
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan annotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            String path = annotation.value();//扫描路径:com.fbl.service
    //...
    }        
  • isAnnotationPresent:类中是否存在某个注解
  • getAnnotation:获取到类的某个注解类

这里,我们获取到路径com.fbl.service,该路径就是我们真正需要的路径吗?

答案是否定 的.因为我们真正想要扫描的是字节码文件 ,所以我们需要编译之后的字节码文件的路径,那么我们应该如何获取到这个路径呢?

复制代码
			String path = annotation.value();   //扫描路径:com.fbl.service
            path=path.replace(".","/");    //com/fbl/service
            ClassLoader classLoader = BaiLuApplicationContext.class.getClassLoader();//获取到类加载器
            URL resource = classLoader.getResource(path);   //通过相对路径(com/fbl/service)获取资源
            File file = new File(resource.getFile()); //转化成文件
            System.out.println(file); //D:\develop\MyGit\BaiLuSpring\out\production\BaiLuSpring\com\fbl\service
  • 通过配置类的注解@@ComponentScan("com.fbl.service")获取到扫描的包路径;
  • 将扫描的包路径转换成扫描路径:com.fbl.service->com/fbl/service
  • 获取到类加载器,通过相对路径获取到该资源D:\develop\MyGit\BaiLuSpring\out\production\BaiLuSpring\com\fbl\service,这里获取到的就是存放.class文件的文件夹

判断是否是bean对象

我们刚才已经获取到了字节码文件存放的文件夹 ,接下来,我们要开始判断,该文件夹下,有哪些是需要交给spring来管理的bean对象.

这里采用的方法是判断是否存在@Component注解:

复制代码
if(file.isDirectory()){
                File[] files = file.listFiles();
                for (File f : files) {
                    String fileName = f.getAbsolutePath();
                    System.out.println(fileName);
                    //判断是不是一个类
                    if(fileName.endsWith(".class")){
                        String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                        className=className.replace("\\",".");

                        //获取对象
                        try {
                            Class<?> clazz = classLoader.loadClass(className);//传入全限定类名
                            //说明当前存在@Component注解,是一个需要交给spring管理的bean对象
                            if (clazz.isAnnotationPresent(Component.class)) {
                        
                    		}
                }
            }
  • 遍历 获取到的资源文件夹,判断是否是.class文件;
  • 如果是.class文件(是一个类),接下来通过反射的方式获取到当前的类
  • 再来判断是否存在@Component注解.

这样,整个容器的启动大致就完成了,其实我们主要完成了扫描和判断是否是bean对象的工作 .那么bean对象是在什么时候被创建的?什么是单例?什么是多例?这些问题将会在接下来的博客文章里进行总结.

相关推荐
a努力。3 分钟前
Context-State-Memory三重信息架构揭秘
java·服务器·前端
lizhongxuan6 分钟前
让 AI 提效转化为团队交付
后端
桃西西呀21 分钟前
Spring AI Alibaba 之二:Spring AI 底座与原子抽象一笔带过,看清 SAA 在之上加了什么编排
人工智能·spring·llm
颜进强24 分钟前
23 · NestJs ModuleRef 模块引用:容器递给你的"取货窗口",四个 API 四种语义
前端·后端·ai编程
captain37626 分钟前
Maven
java·后端·idea
hsfxuebao27 分钟前
Loop Engineering 已死? 一文带你了解Graph Engineering
人工智能·后端
liangshanbo12151 小时前
主系统登录后,子系统怎么实现自动登录?
java·网络·数据库
颜进强1 小时前
22 · NestJs InjectionScopes 注入作用域:默认单例不是偷懒,是最优——以及何时才该打破
前端·后端·ai编程
ShineWinsu1 小时前
对于Redis:缓存的解析
java·redis·缓存·缓存穿透·缓存击穿·缓存雪崩·缓存预热
rannn_1111 小时前
【Java面试题】高频面试题1|Java 后端、MySQL、Redis 与 RAG 面试整理
java·jvm·数据库·后端·面试