基于注解手写Spring的IOC(上)

一、思路

先要从当前类出发找到对应包下的所有类文件,再从这些类中筛选出类上有@MyComponent注解的类;把它们都装入Map中,同时类属性完成@MyValue的赋值操作。

二、具体实现

测试类结构:

测试类:myse、mycontor、BigStar、MyAnneTest结构都一致

java 复制代码
@MyComponent("BigStar")
public class BigStar{

    @MyValue("张三")
    private String name;

    @Override
    public String toString() {
        return "BigStar{" +
                "name='" + name + '\'' +
                '}';
    }
}

自定义注解类(MyComponent--扫描类)

java 复制代码
@Target({ElementType.TYPE}) // 作用范围:类上
@Retention(RetentionPolicy.RUNTIME) // 运行时候生效
public @interface MyComponent {
    String value() default "";
}

数据注入(MyValue)

java 复制代码
@Target({ ElementType.FIELD}) // 使用的范围 字段上
@Retention(RetentionPolicy.RUNTIME) // 生效时候 运行时候
public @interface MyValue {
    String value() default "";
}

三、代码编写

首先处理获得项目的包路径:也是IOC启动方法

在junit4 中编写:

MyIOC()方法

javascript 复制代码
   private Map<Object,Object> IOC=new HashMap<>(); // 创建 IOC容器

    @Test
    public void MyIOC() throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {

        ClassLoader contextClassLoader =Thread.currentThread().getContextClassLoader(); //当前线程中获得类加载器
       // System.out.println("包路径:"+ BigStar.class.getPackage()); // 获得包数据
        // 获得包资源
        // BigStar.class.getPackage().getName()获得包 名字
        // contextClassLoader.getResources() 获得资源相关的路径
        Enumeration<URL> resources = contextClassLoader.getResources( BigStar.class.getPackage().getName());

        // 如果有存在没有被读取过的--包只有一个,所有数据只有一条
        while (resources.hasMoreElements()){
            // 获得数据
            URL url = resources.nextElement();
          
            String path = url.getPath(); // 获取包的绝对路径
            // 包的绝对地址:/C:/Users/kk/IdeaProjects/IOCTest/target/classes/bean
            System.out.println("包的绝对地址:"+ path);
          // 获得地址: /C:/Users/kk/IdeaProjects/IOCTest/target/classes/bean
            DirectoryToClass(path); // 把包路径传入
            System.out.println("容器中的数据:"+IOC);

        }
    }

对路径进行处理:

只需要 "包名.类名字" 即可

DirectoryToClass()方法

java 复制代码
    // 处理类路径--获得 包名字+类名字
    private  void DirectoryToClass(String Mypath) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        // 获得类路径
        //  String myclassPath=myclass.getPath();
        List<Object> list=new ArrayList<>();
        String dgtoPath=""; //递归路径
        File files=new File(Mypath); //打开文件
        if (files.isDirectory()) { //如果是目录

            for (File myclass : files.listFiles()) { // 遍历目录中的文件
              String  directoryPath=myclass.getPath(); //获得单个文件路径路径
                // 路径例如: C:\Users\kk\IdeaProjects\IOCTest\target\classes\bean\Star.class
              // System.out.println("类文件路径:" + directoryPath);
                dgtoPath=directoryPath;
                String path1 = directoryPath.replace("\\", "."); // 把 \替换成 .

                String path = path1.replace("/", "."); // 把 /替换成 .
                String[] split = path.split("classes\\."); // 根据classes 切割字符串
                String classpath = split[split.length - 1]; // 获得包路径路径 com.xx.cc.class

                if (classpath.contains(".class")) { //  是 .class后缀
                    String[] name = classpath.split("\\.class");//  根据.class切割 ---类加载器只需要包名字+类名字
                    //例如: bean.BigStar 或者bean.test.test2.myse 等
                    System.out.println("包名.类名字:"+name[0]);
                    getToClass(name[0]);  //参数传入:获得对象
                } // TODO 如果是目录的话?递归
                else {
                DirectoryToClass(dgtoPath); // 如果是目录就--递归
                }
            }
        }

    }

难点已经解决了,剩下的就是根据"包名.类名"使用反射创建对象。

getToClass()方法

java 复制代码
 // 获得类对象属性
    private void getToClass(String classPath) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        Class<?> clazz = Class.forName(classPath); // 获得类加载器
       // System.out.println("创建成功的类:"+clazz);

        try { // 异常处理 即使clazz.getDeclaredConstructor().newInstance(); 遇到接口不能创建对象--程序也不会停止
            Object bean = clazz.getDeclaredConstructor().newInstance(); // 创建对象--暴力创建

            MyComponent beanName = clazz.getAnnotation(MyComponent.class); // 获得类上注解
            if(!Objects.isNull(beanName)){ // 类上有注解的时候
                String key=beanName.value(); // 获得注解中的value值--类名字
            //    System.out.println("key名字:"+key);
                Field[] declaredFields = clazz.getDeclaredFields(); // 获得字段
                for (Field field:declaredFields){  // 遍历字段
                    MyValue value = field.getAnnotation(MyValue.class); // 获得字段上的注解
                    field.setAccessible(true); // 打开权限 暴力注入 狠狠地注入
                    field.set(bean,value.value()); // 设置当前bean对象的字段
                }
                IOC.put(key,bean); // 存储到IOC中
            }
        }catch (Exception e){
            System.out.println("不是类:"+e); // 如果遇到其他类型文件、接口等
        }

    }

四、运行结果

java 复制代码
包的绝对地址:/C:/Users/kk/IdeaProjects/IOCTest/target/classes/bean
包名.类名字:bean.BigStar
包名.类名字:bean.MyAnneTest
包名.类名字:bean.MyComponent
不是类:java.lang.NoSuchMethodException: bean.MyComponent.<init>()
包名.类名字:bean.MyValue
不是类:java.lang.NoSuchMethodException: bean.MyValue.<init>()
包名.类名字:bean.test.mycontor
包名.类名字:bean.test.test2.myse
容器中的数据:{mycontor=mycontor{hobb='李四'}, MyAnneTest=MyAnneTest{name='张三', hobby='打篮球'}, BigStar=BigStar{name='张三'}, myse=myse{name='后悔'}}

五、后言

大多少自之定义注解都需要扫描包这一步,把getToClass()方法换一下就是其他的功能。ioc真正关键的还是@Autowired注解的实现,我放到下篇讲解。

相关推荐
一条咸鱼_SaltyFish2 分钟前
远程鉴权中心设计:HTTP 与 gRPC 的技术决策与实践
开发语言·网络·网络协议·程序人生·http·开源软件·个人开发
我即将远走丶或许也能高飞14 分钟前
vuex 和 pinia 的学习使用
开发语言·前端·javascript
沐知全栈开发21 分钟前
SQL LEN() 函数详解
开发语言
剑锋所指,所向披靡!33 分钟前
C++之类模版
java·jvm·c++
钟离墨笺35 分钟前
Go语言--2go基础-->基本数据类型
开发语言·前端·后端·golang
Coder_Boy_1 小时前
基于SpringAI的在线考试系统-0到1全流程研发:DDD、TDD与CICD协同实践
java·人工智能·spring boot·架构·ddd·tdd
sheji34161 小时前
【开题答辩全过程】以 面向高校校园的物物交换系统设计与实现为例,包含答辩的问题和答案
java·eclipse
小郭团队1 小时前
1_7_五段式SVPWM (传统算法反正切+DPWM3)算法理论与 MATLAB 实现详解
开发语言·嵌入式硬件·算法·matlab·dsp开发
卓怡学长1 小时前
m115乐购游戏商城系统
java·前端·数据库·spring boot·spring·游戏
2501_944526421 小时前
Flutter for OpenHarmony 万能游戏库App实战 - 蜘蛛纸牌游戏实现
android·java·python·flutter·游戏