当前位置: 首页 > article >正文

简单实现Spring容器(一)

阶段1:

 编写自己的Spring容器,实现扫描包,得到bean的class对象.

思路:

使用 ElfSpringConfig.java 替代beans.xml文件作为配置文件,从中获取到:
1.扫描包,得到bean的class对象.
2.排除包下不是bean的

在这里插入图片描述
在这里插入图片描述

1.容器文件 ElfSpringApplicationContext.java 核心!!!

package com.elf.spring.ioc;

import com.elf.spring.annotation.*;

import java.io.File;
import java.net.URL;


/**
 * @author 45~
 * @version 1.0
 */
public class ElfSpringApplicationContext {
    //第一步,扫描包,得到bean的class对象,排除包下不是bean的,因此还没有放到容器中
    //因为现在写的spring容器比原先的基于注解的,要更加完善,所以不会直接把它放在ConcurrentHashMap
    private Class configClass;

    //构造器
    public ElfSpringApplicationContext(Class configClass) {
        this.configClass = configClass;

        /**获取要扫描的包:
         1.先得到ElfSpringConfig配置的 @ComponentScan(value= "com.elf.spring.component")
         2.通过 @ComponentScan的value => 即要扫描的包 **/
        ComponentScan componentScan =
                (ComponentScan) this.configClass.getDeclaredAnnotation(ComponentScan.class);
        String path = componentScan.value();
        System.out.println("要扫描的包path=" + path);

        /**
         * 得到要扫描包下的所有资源(类.class)
         * 1.得到类的加载器 -> APP类加载器是可以拿到 target目录下的classes所有文件的
         * 2.通过类的加载器获取到要扫描的包的资源url => 类似一个路径
         * 3.将要加载的资源(.class)路径下的文件进行遍历 => io
         */
        ClassLoader classLoader = ElfSpringApplicationContext.class.getClassLoader();
        path = path.replace(".", "/"); // 把.替换成 /
        URL resource = classLoader.getResource(path);
        System.out.println("resource=" + resource);

        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) { //把所有的文件都取出来
                System.out.println("============================");
                System.out.println("f.getAbsolutePath()=" + f.getAbsolutePath());
                String fileAbsolutePath = f.getAbsolutePath();//到target的classes目录下了

                //这里只处理.class文件
                if (fileAbsolutePath.endsWith(".class")) {
                    //1.获取类名
                    String className = fileAbsolutePath.substring(fileAbsolutePath.lastIndexOf("\\") + 1,
                            fileAbsolutePath.indexOf(".class"));
                    //2.获取类的完整路径(全类名)
                    String classFullName = path.replace("/", ".") + "." + className;
                    System.out.println("classFullName=" + classFullName);
                    //3.判断该类是否需要注入,就看是不是有注解@Component @Service @Contoller @Re....
                    try {
                        Class<?> clazz = classLoader.loadClass(classFullName);
                        if (clazz.isAnnotationPresent(Component.class) ||
                                clazz.isAnnotationPresent(Controller.class) ||
                                clazz.isAnnotationPresent(Service.class) ||
                                clazz.isAnnotationPresent(Repository.class)) {
                            //演示机制
                            //如果该类使用了@Component注解,说明是一个Spring bean
                            System.out.println("这是一个Spring bean=" + clazz + " 类名=" + className);
                        }
//                                Component component = clazz.getDeclaredAnnotation(Component.class);
//                                String id = component.value();
//                                if (!"".endsWith(id)) {
//                                    className = id;//替换
//                                }
                        else {
                            //如果该类没有使用了@Component注解,说明是一个Spring bean
                            System.out.println("这不是一个Spring bean" + clazz + " 类名=" + className);
                        }
//                            Class<?> Class = Class.forName(classFullName);
//                            Object instance = Class.newInstance();
//                            ioc.put(StringUtils.uncapitalize(className), instance);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }//遍历文件for循环结束
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        }

    }//构造器结束

    //编写放法返回容器中的对象
    public Object getBean(String name) {
        return null;
    }
}

2.AppMain.java

package com.elf.spring;
import com.elf.spring.ioc.ElfSpringApplicationContext;
import com.elf.spring.ioc.ElfSpringConfig;

/**
 * @author 45~
 * @version 1.0
 */
public class AppMain {
    public static void main(String[] args) {
        //把容器创建起来,在创建的时候传入了配置类的class类型/class对象
        //传进去后会根据自己写的容器机制 进行解析
        ElfSpringApplicationContext elfSpringApplicationContext =
                new ElfSpringApplicationContext(ElfSpringConfig.class);

    }
}

3.配置文件 ElfSpringConfig.java

package com.elf.spring.ioc;
import com.elf.spring.annotation.ComponentScan;

/**
 * @author 45~
 * @version 1.0
 * 这是一个配置类,作用类似于原生spring的beans.xml容器配置文件
 */
@ComponentScan(value= "com.elf.spring.component")
public class ElfSpringConfig {

}

4.component包下的类car / monsterDao / monsterService

package com.elf.spring.component;

/**
 * @author 45~
 * @version 1.0
 */
public class car {
}

package com.elf.spring.component;
import com.elf.spring.annotation.Component;
/**
 * @author 45~
 * @version 1.0
 * 写第二个类是因为要有两个类才能做依赖注入
 */
@Component(value = "monsterDao")
public class MonsterDao {
}

package com.elf.spring.component;
import com.elf.spring.annotation.Component;
/**
 * @author 45~
 * @version 1.0
 * 说明 MonsterService 是一个Servic
 */
@Component //把MonsterService注入到我们自己的spring容器中
public class MonsterService {

}

5.annotation包下的一堆自定义注解 ComponentScan + 经典4

package com.elf.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 45~
 * @version 1.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
    String value() default "";
}

package com.elf.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 45~
 * @version 1.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
    //通过value可以给注入的bean/对象指定名字
    String value() default "";
}

package com.elf.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 45~
 * @version 1.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
    //通过value可以给注入的bean/对象指定名字
    String value() default "";
}
package com.elf.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 45~
 * @version 1.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Repository {
    //通过value可以给注入的bean/对象指定名字
    String value() default "";
}

package com.elf.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 45~
 * @version 1.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
    //通过value可以给注入的bean/对象指定名字
    String value() default "";
}


http://www.kler.cn/news/161132.html

相关文章:

  • shell命令学习(1)——(待完善)
  • pycharm使用Anaconda中的虚拟环境【我的入门困惑二】
  • ros来保存图像和保存记录视频的方法---gmsl相机保存视频和图片
  • java--枚举
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • 关于优雅的使用SQL多行转多列的记录(doris)
  • 如何使用phpStudy本地快速搭建网站并内网穿透远程访问
  • 如何使用内网穿透工具实现公网访问GeoServe Web管理界面
  • LeetCode刷题--- 计算布尔二叉树的值
  • 这些Java并发容器,你都了解吗?
  • 手写VUE后台管理系统7 - 整合Less样式
  • Inno Setup使用
  • supervisor杀死不掉程序的问题分析
  • (动手学习深度学习)第13章 实战kaggle竞赛:树叶分类
  • 4G基站BBU、RRU、核心网设备
  • VUE+THREE.JS 点击模型相机缓入查看模型相关信息
  • 云计算生成式 -给你不一样的音乐推荐新体验
  • 英伟达显卡系列与架构、代表产品
  • 基于JavaScript的jimp库处理图片,添加绘制点
  • 【华为od】存在一个m*n的二维数组,其成员取值范围为0,1。其中值为1的元素具备扩散性,每经过1S,将上下左右值为0的元素同化为1。
  • 要求CHATGPT高质量回答的艺术:提示工程技术的完整指南—第 23 章:命名实体识别提示
  • 《QDebug 2023年11月》
  • 要求CHATGPT高质量回答的艺术:提示工程技术的完整指南—第 7 章:让我们想一想 提示语
  • 背包问题学习
  • 数据结构与算法编程题50
  • NC 比telnet 强大网络命令
  • 我有才打造知识付费小程序
  • simulink trigger模块使用——多种调用案例分析
  • 出海电商中的技术护航:Socks5代理与代理IP的应用
  • 第16关 革新云计算:如何利用弹性容器与托管K8S实现极速服务POD扩缩容