• Java手写IOC


    视频教程连接

    点击进入
    本文实现的注解有

    • @Component
    • @Value
    • @Autowired
    • @Qualifier
      在这里插入图片描述

    实现的效果

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    实现这些IOC的思路

    在这里插入图片描述

    1. 获取到我们要管理的Class对象

    我们首先要扫描我们要用的包 然后获取到所有有我们定义的@myComponent注解的Class对象 然后把这些Class和他们的名字给封装到一个对象里面在这里插入图片描述
    然后我们把获取到的所有对象给放到一个Set集合里面提供给下面步骤的使用

    2.实例化要管理的对象 把初始化之后的对象给放到Map容器里面

    • 在第一步的时候我们获取到了所有要管理的MyBeanDefinition
      因为这个对象里面有Class 我们可以直接用反射去用
      clazz.newInstance();调用无参构造方法实例化
    • 然后我们通过反射获取@myValue注解里面的值 然后用反射调用set方法把值给赋进去
      这样我们的对象就能初始化了
    • 我们还需要把这个初始化之后的对象给设置一个名字 根据spring的习惯来说 默认命名都是类 的首字母小写 这一步我们直接把第一步获取到的BeanName处理一下就行了
    • 最后我们把初始化好的 还有他的名字给放到一个Map集合里面 这样一个容器就差不多快做成了

    3.依赖注入的实现

    1. 去遍历我们在第一步做好的那个Set 然后找到有@myAutowired这个注解标记的变量
      @myAutowired是根据类型自动注入 或者说就是根据类型的名字去第二部的那个Map容器里面去找名字(key)一样的对象然后赋值 @myQualifier是根据注解里面的value去Map容器里面找对象
    2. 我们获取到有@myAutowired注解的变量的时候还要检查他有没有被 @myQualifier标记
      如果有就根据value找第二步初始化之后的对象 没的话就自动注入就行了

    具体实现步骤

    注解

    这四个注解的使用位置不同 但是我让他们都保存到运行时了
    @myAutowired是自动根据类型名注入

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface myAutowired {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    @myComponent标记该类让他被我写的ioc管理

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface myComponent {
    String value() default "";
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    @myQualifier是根据value去注入

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface myQualifier {
        String value();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    @myValue是根据value的值给实例化对象赋值

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface myValue {
        String value();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    MyBeanDefinition 存放Class和ClassName

    public class MyBeanDefinition {
        private String BeanName;
        private Class beanClass;
    
        @Override
        public String toString() {
            return "MyBeanDefinition{" +
                    "BeanName='" + BeanName + '\'' +
                    ", beanClass=" + beanClass +
                    '}';
        }
    
        public String getBeanName() {
            return BeanName;
        }
    
        public void setBeanName(String beanName) {
            BeanName = beanName;
        }
    
        public Class getBeanClass() {
            return beanClass;
        }
    
        public void setBeanClass(Class beanClass) {
            this.beanClass = beanClass;
        }
    
        public MyBeanDefinition(String beanName, Class beanClass) {
            BeanName = beanName;
            this.beanClass = beanClass;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    MyAnnotationConfigApplicationContext(重点 IOC的核心)

    就和上面思路里面说的一样 分三步走就好了

    在这里插入图片描述

    第一步的实现 获取到我们要管理的Class对象的

    我们直接用工具就好了 获取到存放所有class的Set集合 然后通过迭代器遍历
    在这里插入图片描述
    在这里插入图片描述
    不处理的话名字是这样的 如果把这个当成Bean的名字太长了 就截取最后的类名就行
    在这里插入图片描述

    思路第二步的实现 实例化并且初始化把对象给放到Map容器里面

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

    在这里插入图片描述

    第三步 把我们的存入map的bean给赋值到需要的地方

    手动指定bean

    在这里插入图片描述

    自动注入

    在这里插入图片描述

    全部代码如下

    public class MyAnnotationConfigApplicationContext{
    
        private Map<String, Object> map = new HashMap();
    
        public MyAnnotationConfigApplicationContext(String pack) {
            //扫描包下所有的class 吧有mybean注解的都放到set里面
            Set<MyBeanDefinition> beanDefinitions = findBeanDefinitions(pack);
            //根据set里面的beanDefinitions来 创建对象放到map里面
                createObject(beanDefinitions);
            //把map里面的对像给自动装配
                autowireObject(beanDefinitions);
    
        }
        public Object getBean(String name){
            return map.get(name);
        }
    
        public void autowireObject(Set<MyBeanDefinition> beanDefinitions)  {
            Iterator<MyBeanDefinition> iterator = beanDefinitions.iterator();
            while(iterator.hasNext()){
                MyBeanDefinition next = iterator.next();
                Class beanClass = next.getBeanClass();
                for (Field declaredField : beanClass.getDeclaredFields()) {
                    myAutowired annotation = declaredField.getAnnotation(myAutowired.class);
                    if (annotation!=null){
                        //根据bean的name获取bean
                        myQualifier declaredannotation = declaredField.getAnnotation(myQualifier.class);
                        if (declaredannotation!=null){
                            try {
                            String beanName = declaredannotation.value();
                            Object bean = getBean(beanName);
                            String fieldName = declaredField.getName();
                            String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
                            Method method = null;
                            method = beanClass.getMethod(methodName, declaredField.getType());
                            Object object = getBean(next.getBeanName());
                            method.invoke(object, bean);
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (NoSuchMethodException e) {
                                e.printStackTrace();
                            }
                        }else{
                            //自动装配  获取到
                            try {
                                String name = declaredField.getType().getName();
                                String className =   name.replaceAll( beanClass.getPackage().getName() + ".", "");
                                String  beanName = className.substring(0, 1).toLowerCase()+className.substring(1);
                                Object bean = getBean(beanName);
                                String fieldName = declaredField.getName();
                                String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
                                Method method = null;
                                method = beanClass.getMethod(methodName, declaredField.getType());
                                Object object = getBean(next.getBeanName());
                                method.invoke(object, bean);
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (NoSuchMethodException e) {
                                e.printStackTrace();
                            }
                        }
                    }
    
                }
    
            }
        }
    
        public void createObject( Set<MyBeanDefinition> set){
            Iterator<MyBeanDefinition> iterator = set.iterator();
            while(iterator.hasNext()){
                MyBeanDefinition next = iterator.next();
                Class beanClass = next.getBeanClass();
                String beanName = next.getBeanName();
    
                try {
                    //根据findBeanDefinitions里面存入的 class对象来新建一个对象
                    Object o = beanClass.newInstance();
                    Field[] declaredFields = beanClass.getDeclaredFields();
                    for (Field declaredField : declaredFields) {
                        myValue myValueAnnotation = declaredField.getAnnotation(myValue.class);
                        if (myValueAnnotation!=null){
                            String value = myValueAnnotation.value();//获取value上面的值
                            String name = declaredField.getName();//获取方法名字
                            String methodName = "set"+name.substring(0, 1).toUpperCase()+name.substring(1);
    
                            try {
                                //获取get方法
                                System.out.println(methodName);
                                Method method = beanClass.getMethod(methodName,declaredField.getType());
                                try {
    
                                    //完成数据类型转换
                                    Object val = null;
                                    switch (declaredField.getType().getName()){
                                        case "java.lang.Integer":
                                            val = Integer.parseInt(value);
                                            break;
                                        case "java.lang.String":
                                            val = value;
                                            break;
                                        case "java.lang.Float":
                                            val = Float.parseFloat(value);
                                            break;
                                    }                               //使用 set方法
                                    method.invoke(o,val);
                                } catch (InvocationTargetException e) {
                                    e.printStackTrace();
                                }
    
                            } catch (NoSuchMethodException e) {
                                e.printStackTrace();
                            }
    
                        }
    
                        System.out.println(declaredField);
                    }
                    map.put(beanName,o);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
    
            }
    
        }
    
        public Set<MyBeanDefinition> findBeanDefinitions(String pack){
            Set<MyBeanDefinition> myset=new HashSet<>();
    
            //获取到包下所有的类
            Set<Class<?>> classes = MyTools.getClasses(pack);
            Iterator<Class<?>> iterator = classes.iterator();
            while(iterator.hasNext()){
                Class<?> next = iterator.next();
                myComponent annotation = next.getAnnotation( myComponent.class);
                if(annotation != null){
                    String packname = next.getPackage().getName();
                    String name = next.getName();
                    String beanName  = annotation.value();
                    if("".equals(beanName)){
                        String classname = name.replace(packname + ".", "");
                        String s = classname.substring(0, 1).toLowerCase();
                        beanName=s+classname.substring(1);
                    }
                    myset.add(new MyBeanDefinition(beanName,next));
    
    
                }
            }
            return myset;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161

    MyTools工具类

    这个工具类做的主要是遍历指定的包 然后获取包里面的class
    我的建议是 CV

    import java.io.File;
    import java.io.FileFilter;
    import java.io.IOException;
    import java.net.JarURLConnection;
    import java.net.URL;
    import java.net.URLDecoder;
    import java.util.Enumeration;
    import java.util.LinkedHashSet;
    import java.util.Set;
    import java.util.jar.JarEntry;
    import java.util.jar.JarFile;
    
    public class MyTools {
    
        public static Set<Class<?>> getClasses(String pack) {
    
            // 第一个class类的集合
            Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
            // 是否循环迭代
            boolean recursive = true;
            // 获取包的名字 并进行替换
            String packageName = pack;
            String packageDirName = packageName.replace('.', '/');
            // 定义一个枚举的集合 并进行循环来处理这个目录下的things
            Enumeration<URL> dirs;
            try {
                dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
                // 循环迭代下去
                while (dirs.hasMoreElements()) {
                    // 获取下一个元素
                    URL url = dirs.nextElement();
                    // 得到协议的名称
                    String protocol = url.getProtocol();
                    // 如果是以文件的形式保存在服务器上
                    if ("file".equals(protocol)) {
                        // 获取包的物理路径
                        String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                        // 以文件的方式扫描整个包下的文件 并添加到集合中
                        findClassesInPackageByFile(packageName, filePath, recursive, classes);
                    } else if ("jar".equals(protocol)) {
                        // 如果是jar包文件
                        // 定义一个JarFile
                        System.out.println("jar类型的扫描");
                        JarFile jar;
                        try {
                            // 获取jar
                            jar = ((JarURLConnection) url.openConnection()).getJarFile();
                            // 从此jar包 得到一个枚举类
                            Enumeration<JarEntry> entries = jar.entries();
                            findClassesInPackageByJar(packageName, entries, packageDirName, recursive, classes);
                        } catch (IOException e) {
                            // log.error("在扫描用户定义视图时从jar包获取文件出错");
                            e.printStackTrace();
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return classes;
        }
    
        private static void findClassesInPackageByJar(String packageName, Enumeration<JarEntry> entries, String packageDirName, final boolean recursive, Set<Class<?>> classes) {
            // 同样的进行循环迭代
            while (entries.hasMoreElements()) {
                // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
                JarEntry entry = entries.nextElement();
                String name = entry.getName();
                // 如果是以/开头的
                if (name.charAt(0) == '/') {
                    // 获取后面的字符串
                    name = name.substring(1);
                }
                // 如果前半部分和定义的包名相同
                if (name.startsWith(packageDirName)) {
                    int idx = name.lastIndexOf('/');
                    // 如果以"/"结尾 是一个包
                    if (idx != -1) {
                        // 获取包名 把"/"替换成"."
                        packageName = name.substring(0, idx).replace('/', '.');
                    }
                    // 如果可以迭代下去 并且是一个包
                    if ((idx != -1) || recursive) {
                        // 如果是一个.class文件 而且不是目录
                        if (name.endsWith(".class") && !entry.isDirectory()) {
                            // 去掉后面的".class" 获取真正的类名
                            String className = name.substring(packageName.length() + 1, name.length() - 6);
                            try {
                                // 添加到classes
                                classes.add(Class.forName(packageName + '.' + className));
                            } catch (ClassNotFoundException e) {
                                // .error("添加用户自定义视图类错误 找不到此类的.class文件");
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
    
        private static void findClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) {
            // 获取此包的目录 建立一个File
            File dir = new File(packagePath);
            // 如果不存在或者 也不是目录就直接返回
            if (!dir.exists() || !dir.isDirectory()) {
                // log.warn("用户定义包名 " + packageName + " 下没有任何文件");
                return;
            }
            // 如果存在 就获取包下的所有文件 包括目录
            File[] dirfiles = dir.listFiles(new FileFilter() {
                // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
                @Override
                public boolean accept(File file) {
                    return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
                }
            });
            // 循环所有文件
            for (File file : dirfiles) {
                // 如果是目录 则继续扫描
                if (file.isDirectory()) {
                    findClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
                } else {
                    // 如果是java类文件 去掉后面的.class 只留下类名
                    String className = file.getName().substring(0, file.getName().length() - 6);
                    try {
                        // 添加到集合中去
                        // classes.add(Class.forName(packageName + '.' +
                        // className));
                        // 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
                        classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
                    } catch (ClassNotFoundException e) {
                        // log.error("添加用户自定义视图类错误 找不到此类的.class文件");
                        e.printStackTrace();
                    }
                }
            }
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140

    测试方法

    public class run {
        public static void main(String[] args) {
            MyAnnotationConfigApplicationContext myAnnotationConfigApplicationContext = new MyAnnotationConfigApplicationContext("myioc.test");
            Object student = myAnnotationConfigApplicationContext.getBean("student");
            System.out.println(student.toString());
            Object at = myAnnotationConfigApplicationContext.getBean("at");
            At a=(At)at;
            System.out.println("================");
            System.out.println(a.student.toString());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    @myComponent()
    public class At {
      @myAutowired
      @myQualifier("student")
      public Student student;
    
      @Override
      public String toString() {
          return "At{" +
                  "student=" + student +
                  '}';
      }
    
      public Student getStudent() {
          return student;
      }
    
      public void setStudent(Student student) {
          this.student = student;
      }
    
      public At() {
      }
    
      public At(Student student) {
          this.student = student;
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    package myioc.test;
    
    import myioc.myAnnotation. myComponent;
    import myioc.myAnnotation.myValue;
    @myComponent()
    public class Student {
        @myValue("张三")
        String name;
        @myValue("25")
        Integer age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
  • 相关阅读:
    深度学习中的数据类型介绍:FP32, FP16, TF32, BF16, Int16, Int8 ...
    异步编程真的让程序更快了吗?
    Selenium原理深度解析
    七、【套索工具组】
    搭建SGC实现引文网络节点预测(PyTorch+PyG)
    vim插件管理器之Vundle的使用
    sock锁文件导致的MySQL启动失败
    2022年全国大学生数学建模竞赛E题目-小批量物料生产安排详解+思路+Python代码时序预测模型(三)
    代码随想录训练营day52
    2023-09-07工作心得:String 和 LocalDate 的比较
  • 原文地址:https://blog.csdn.net/qq_47431361/article/details/127565246