• spring6-实现简易版IOC容器


    我们都知道,Spring框架的IOC是基于Java反射机制实现的,下面我们先回顾一下java反射。

    1、回顾Java反射

    Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。

    要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关API**(1)java.lang.Class(2)java.lang.reflect**,所以,Class对象是反射的根源

    自定义类

    package com.atguigu.reflect;
    
    public class Car {
    
        //属性
        private String name;
        private int age;
        private String color;
    
        //无参数构造
        public Car() {
        }
    
        //有参数构造
        public Car(String name, int age, String color) {
            this.name = name;
            this.age = age;
            this.color = color;
        }
    
        //普通方法
        private void run() {
            System.out.println("私有方法-run.....");
        }
    
        //get和set方法
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getColor() {
            return color;
        }
        public void setColor(String color) {
            this.color = color;
        }
    
        @Override
        public String toString() {
            return "Car{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", color='" + color + '\'' +
                    '}';
        }
    }
    
    • 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

    编写测试类

    package com.atguigu.reflect;
    
    import org.junit.jupiter.api.Test;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class TestCar {
    
        //1、获取Class对象多种方式
        @Test
        public void test01() throws Exception {
            //1 类名.class
            Class clazz1 = Car.class;
    
            //2 对象.getClass()
            Class clazz2 = new Car().getClass();
    
            //3 Class.forName("全路径")
            Class clazz3 = Class.forName("com.atguigu.reflect.Car");
    
            //实例化
            Car car = (Car)clazz3.getConstructor().newInstance();
            System.out.println(car);
        }
    
        //2、获取构造方法
        @Test
        public void test02() throws Exception {
            Class clazz = Car.class;
            //获取所有构造
            // getConstructors()获取所有public的构造方法
    //        Constructor[] constructors = clazz.getConstructors();
            // getDeclaredConstructors()获取所有的构造方法public  private
            Constructor[] constructors = clazz.getDeclaredConstructors();
            for (Constructor c:constructors) {
                System.out.println("方法名称:"+c.getName()+" 参数个数:"+c.getParameterCount());
            }
    
            //指定有参数构造创建对象
            //1 构造public
    //        Constructor c1 = clazz.getConstructor(String.class, int.class, String.class);
    //        Car car1 = (Car)c1.newInstance("夏利", 10, "红色");
    //        System.out.println(car1);
            
            //2 构造private
            Constructor c2 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
            c2.setAccessible(true);
            Car car2 = (Car)c2.newInstance("捷达", 15, "白色");
            System.out.println(car2);
        }
    
        //3、获取属性
        @Test
        public void test03() throws Exception {
            Class clazz = Car.class;
            Car car = (Car)clazz.getDeclaredConstructor().newInstance();
            //获取所有public属性
            //Field[] fields = clazz.getFields();
            //获取所有属性(包含私有属性)
            Field[] fields = clazz.getDeclaredFields();
            for (Field field:fields) {
                if(field.getName().equals("name")) {
                    //设置允许访问
                    field.setAccessible(true);
                    field.set(car,"五菱宏光");
                    System.out.println(car);
                }
                System.out.println(field.getName());
            }
        }
    
        //4、获取方法
        @Test
        public void test04() throws Exception {
            Car car = new Car("奔驰",10,"黑色");
            Class clazz = car.getClass();
            //1 public方法
            Method[] methods = clazz.getMethods();
            for (Method m1:methods) {
                //System.out.println(m1.getName());
                //执行方法 toString
                if(m1.getName().equals("toString")) {
                    String invoke = (String)m1.invoke(car);
                    //System.out.println("toString执行了:"+invoke);
                }
            }
    
            //2 private方法
            Method[] methodsAll = clazz.getDeclaredMethods();
            for (Method m:methodsAll) {
                //执行方法 run
                if(m.getName().equals("run")) {
                    m.setAccessible(true);
                    m.invoke(car);
                }
            }
        }
    }
    
    • 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

    2、实现Spring的IoC

    我们知道,IoC(控制反转)和DI(依赖注入)是Spring里面核心的东西,那么,我们如何自己手写出这样的代码呢?下面我们就一步一步写出Spring框架最核心的部分。

    ①搭建子模块

    搭建模块:guigu-spring,搭建方式如其他spring子模块

    ②准备测试需要的bean

    添加依赖

    <dependencies>
        
        <dependency>
            <groupId>org.junit.jupitergroupId>
            <artifactId>junit-jupiter-apiartifactId>
            <version>5.3.1version>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    创建UserDao接口

    package com.atguigu.spring6.test.dao;
    
    public interface UserDao {
    
        public void print();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    创建UserDaoImpl实现

    package com.atguigu.spring6.test.dao.impl;
    
    import com.atguigu.spring.dao.UserDao;
    
    public class UserDaoImpl implements UserDao {
    
        @Override
        public void print() {
            System.out.println("Dao层执行结束");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    创建UserService接口

    package com.atguigu.spring6.test.service;
    
    public interface UserService {
    
        public void out();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    创建UserServiceImpl实现类

    package com.atguigu.spring.test.service.impl;
    
    import com.atguigu.spring.core.annotation.Bean;
    import com.atguigu.spring.service.UserService;
    
    @Bean
    public class UserServiceImpl implements UserService {
    
    //    private UserDao userDao;
    
        @Override
        public void out() {
            //userDao.print();
            System.out.println("Service层执行结束");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    ③定义注解

    我们通过注解的形式加载bean与实现依赖注入

    bean注解

    package com.atguigu.spring.core.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Bean {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    依赖注入注解

    package com.atguigu.spring.core.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Di {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    说明:上面两个注解可以随意取名

    ④定义bean容器接口

    package com.atguigu.spring.core;
    
    public interface ApplicationContext {
    
        Object getBean(Class clazz);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ⑤编写注解bean容器接口实现

    AnnotationApplicationContext基于注解扫描bean

    package com.atguigu.spring.core;
    
    import java.util.HashMap;
    
    public class AnnotationApplicationContext implements ApplicationContext {
    
        //存储bean的容器
        private HashMap<Class, Object> beanFactory = new HashMap<>();
    
        @Override
        public Object getBean(Class clazz) {
            return beanFactory.get(clazz);
        }
    
        /**
         * 根据包扫描加载bean
         * @param basePackage
         */
        public AnnotationApplicationContext(String basePackage) {
            
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ⑥编写扫描bean逻辑

    我们通过构造方法传入包的base路径,扫描被@Bean注解的java对象,完整代码如下:

    package com.atguigu.spring.core;
    
    import com.atguigu.spring.core.annotation.Bean;
    
    import java.io.File;
    import java.util.HashMap;
    
    public class AnnotationApplicationContext implements ApplicationContext {
    
        //存储bean的容器
        private HashMap<Class, Object> beanFactory = new HashMap<>();
        private static String rootPath;
    
        @Override
        public Object getBean(Class clazz) {
            return beanFactory.get(clazz);
        }
    
        /**
         * 根据包扫描加载bean
         * @param basePackage
         */
        public AnnotationApplicationContext(String basePackage) {
           try {
                String packageDirName = basePackage.replaceAll("\\.", "\\\\");
                Enumeration<URL> dirs =Thread.currentThread().getContextClassLoader().getResources(packageDirName);
                while (dirs.hasMoreElements()) {
                    URL url = dirs.nextElement();
                    String filePath = URLDecoder.decode(url.getFile(),"utf-8");
                    rootPath = filePath.substring(0, filePath.length()-packageDirName.length());
                    loadBean(new File(filePath));
                }
    
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        private  void loadBean(File fileParent) {
            if (fileParent.isDirectory()) {
                File[] childrenFiles = fileParent.listFiles();
                if(childrenFiles == null || childrenFiles.length == 0){
                    return;
                }
                for (File child : childrenFiles) {
                    if (child.isDirectory()) {
                        //如果是个文件夹就继续调用该方法,使用了递归
                        loadBean(child);
                    } else {
                        //通过文件路径转变成全类名,第一步把绝对路径部分去掉
                        String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                        //选中class文件
                        if (pathWithClass.contains(".class")) {
                            //    com.xinzhi.dao.UserDao
                            //去掉.class后缀,并且把 \ 替换成 .
                            String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
                            try {
                                Class<?> aClass = Class.forName(fullName);
                                //把非接口的类实例化放在map中
                                if(!aClass.isInterface()){
                                    Bean annotation = aClass.getAnnotation(Bean.class);
                                    if(annotation != null){
                                        Object instance = aClass.newInstance();
                                        //判断一下有没有接口
                                        if(aClass.getInterfaces().length > 0) {
                                            //如果有接口把接口的class当成key,实例对象当成value
                                            System.out.println("正在加载【"+ aClass.getInterfaces()[0] +"】,实例对象是:" + instance.getClass().getName());
                                            beanFactory.put(aClass.getInterfaces()[0], instance);
                                        }else{
                                            //如果有接口把自己的class当成key,实例对象当成value
                                            System.out.println("正在加载【"+ aClass.getName() +"】,实例对象是:" + instance.getClass().getName());
                                            beanFactory.put(aClass, instance);
                                        }
                                    }
                                }
                            } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
                                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

    ⑦java类标识Bean注解

    @Bean
    public class UserServiceImpl implements UserService
    
    • 1
    • 2
    @Bean
    public class UserDaoImpl implements UserDao 
    
    • 1
    • 2

    ⑧测试Bean加载

    package com.atguigu.spring;
    
    import com.atguigu.spring.core.AnnotationApplicationContext;
    import com.atguigu.spring.core.ApplicationContext;
    import com.atguigu.spring.test.service.UserService;
    import org.junit.jupiter.api.Test;
    
    public class SpringIocTest {
    
        @Test
        public void testIoc() {
            ApplicationContext applicationContext = new AnnotationApplicationContext("com.atguigu.spring.test");
            UserService userService = (UserService)applicationContext.getBean(UserService.class);
            userService.out();
            System.out.println("run success");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    控制台打印测试

    ⑨依赖注入

    只要userDao.print();调用成功,说明就注入成功

    package com.atguigu.spring.test.service.impl;
    
    import com.atguigu.spring.core.annotation.Bean;
    import com.atguigu.spring.core.annotation.Di;
    import com.atguigu.spring.dao.UserDao;
    import com.atguigu.spring.service.UserService;
    
    @Bean
    public class UserServiceImpl implements UserService {
    
        @Di
        private UserDao userDao;
    
        @Override
        public void out() {
            userDao.print();
            System.out.println("Service层执行结束");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    执行第八步:报错了,说明当前userDao是个空对象

    ⑩依赖注入实现

    package com.atguigu.spring.core;
    
    import com.atguigu.spring.core.annotation.Bean;
    import com.atguigu.spring.core.annotation.Di;
    
    import java.io.File;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.Map;
    
    public class AnnotationApplicationContext implements ApplicationContext {
    
        //存储bean的容器
        private HashMap<Class, Object> beanFactory = new HashMap<>();
        private static String rootPath;
    
        @Override
        public Object getBean(Class clazz) {
            return beanFactory.get(clazz);
        }
    
        /**
         * 根据包扫描加载bean
         * @param basePackage
         */
        public AnnotationApplicationContext(String basePackage) {
            try {
                String packageDirName = basePackage.replaceAll("\\.", "\\\\");
                Enumeration<URL> dirs =Thread.currentThread().getContextClassLoader().getResources(packageDirName);
                while (dirs.hasMoreElements()) {
                    URL url = dirs.nextElement();
                    String filePath = URLDecoder.decode(url.getFile(),"utf-8");
                    rootPath = filePath.substring(0, filePath.length()-packageDirName.length());
                    loadBean(new File(filePath));
                }
    
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            
            //依赖注入
            loadDi();
        }
        
        private  void loadBean(File fileParent) {
            if (fileParent.isDirectory()) {
                File[] childrenFiles = fileParent.listFiles();
                if(childrenFiles == null || childrenFiles.length == 0){
                    return;
                }
                for (File child : childrenFiles) {
                    if (child.isDirectory()) {
                        //如果是个文件夹就继续调用该方法,使用了递归
                        loadBean(child);
                    } else {
                        //通过文件路径转变成全类名,第一步把绝对路径部分去掉
                        String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                        //选中class文件
                        if (pathWithClass.contains(".class")) {
                            //    com.xinzhi.dao.UserDao
                            //去掉.class后缀,并且把 \ 替换成 .
                            String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
                            try {
                                Class<?> aClass = Class.forName(fullName);
                                //把非接口的类实例化放在map中
                                if(!aClass.isInterface()){
                                    Bean annotation = aClass.getAnnotation(Bean.class);
                                    if(annotation != null){
                                        Object instance = aClass.newInstance();
                                        //判断一下有没有接口
                                        if(aClass.getInterfaces().length > 0) {
                                            //如果有接口把接口的class当成key,实例对象当成value
                                            System.out.println("正在加载【"+ aClass.getInterfaces()[0] +"】,实例对象是:" + instance.getClass().getName());
                                            beanFactory.put(aClass.getInterfaces()[0], instance);
                                        }else{
                                            //如果有接口把自己的class当成key,实例对象当成value
                                            System.out.println("正在加载【"+ aClass.getName() +"】,实例对象是:" + instance.getClass().getName());
                                            beanFactory.put(aClass, instance);
                                        }
                                    }
                                }
                            } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
    
        private void loadDi() {
            for(Map.Entry<Class,Object> entry : beanFactory.entrySet()){
                //就是咱们放在容器的对象
                Object obj = entry.getValue();
                Class<?> aClass = obj.getClass();
                Field[] declaredFields = aClass.getDeclaredFields();
                for (Field field : declaredFields){
                    Di annotation = field.getAnnotation(Di.class);
                    if( annotation != null ){
                        field.setAccessible(true);
                        try {
                            System.out.println("正在给【"+obj.getClass().getName()+"】属性【" + field.getName() + "】注入值【"+ beanFactory.get(field.getType()).getClass().getName() +"】");
                            field.set(obj,beanFactory.get(field.getType()));
                        } catch (IllegalAccessException e) {
                            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

    执行第八步:执行成功,依赖注入成功

  • 相关阅读:
    大学生抗击疫情感动人物最美逆行者网页设计作业 html抗疫专题网页设计 最美逆行者网页模板 致敬疫情感动人物网页设计制作
    T113-S3-LCD-RGB显示屏调试
    C++ iostream、ostream、istream等标准库都是什么?看完这篇就知道了
    Cesium快速上手4-Polylines图元使用讲解
    【SpringCloud】Gateway网关入门
    设计模式13-行为型设计模式-策略设计模式
    Spring学习第6篇: 基于注解使用IOC
    FutureTask源码阅读
    Revit中墙体的连接方式创建,快速改变墙连接状态
    Redis之SDS底层原理解读
  • 原文地址:https://blog.csdn.net/m0_62946761/article/details/133470213