• 手写ioc


    回顾反射

    1.建立car类

    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

    2.写测试类

    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

    总结(获取class对象的三种方法):
    1 类名.class
    Class clazz1 = Car.class;
    2.对象.getClass()
    Class clazz2 = new Car().getClass();
    3 Class.forName(“全路径”)
    Class clazz3 = Class.forName("com.test.Car");

    获取构造方法:(clazz是获取的类对象

    clazz.getConstructors(); 获取所有的public的构造方法
    clazz.getDeclaredConstructors()获取所有的构造方法public private
    clazz.getConstructor(String.class, int.class, String.class);指定有参数构造创建对象(public的)
    clazz.getDeclaredConstructor(String.class, int.class, String.class);:指定参数构造创造对象(私有公开的都可)但是设置.setAccessible(true);

    • 返回是list

    获取属性 (clazz 是获取类的对象)
    clazz.getFields();获取所有public属性
    clazz.getDeclaredFields()获取所有属性(包含私有属性)

    • 返回是list

    获取方法
    clazz.getMethods(); 获取public方法
    clazz.getDeclaredMethods(); private,public方法

    实现Spring的IoC

    ①准备测试需要的bean**
    创建UserDao接口

    public interface UserDao {
    
        public void print();
    }
    
    • 1
    • 2
    • 3
    • 4

    创建UserDaoImpl实现

    public class UserDaoImpl implements UserDao {
    
        @Override
        public void print() {
            System.out.println("Dao层执行结束");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    创建UserService接口

    public interface UserService {
    
        public void out();
    }
    
    • 1
    • 2
    • 3
    • 4

    创建UserServiceImpl实现类

    @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

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

    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

    依赖注入注解

    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

    ④定义bean容器接口

    public interface ApplicationContext {
    
        Object getBean(Class clazz);
    }
    
    • 1
    • 2
    • 3
    • 4

    ④编写注解bean容器接口实现
    AnnotationApplicationContext基于注解扫描bean

    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

    ⑤编写扫描bean逻辑
    我们通过构造方法传入包的base路径,扫描被@Bean注解的java对象,完整代码如下:
    == 注意路径问题 ==

    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

    ⑥java类标识Bean注解

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

    ⑦写测试类

    @Test
        public void testIoc() {
            ApplicationContext applicationContext = new AnnotationApplicationContext("com.test");
            UserService userService = (UserService)applicationContext.getBean(UserService.class);
            userService.out();
            System.out.println("run success");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ⑧依赖注入

    之前的serviceImpl 下得dao的实现类被注释掉了,是因为还没有被注入进这个包,现在来写注入的实现

    先把之前的注释的userDao.print(); 不注释
    加上@Di

    @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

    ⑨实现依赖注入

    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

    在运行之前的测试类看dao 是否被注入

    注意就是操作系统不一样估计路径也不一样这个需要注意一下。

  • 相关阅读:
    医疗项目的环境搭建
    后台返回前端 is....开头字段被屏蔽
    AnyLink 安装教程(docker)
    contos7 设置mongodb需账号密码访问
    重新认识一下@Async,开启异步之路
    MATLAB向量的运算
    pyTorch——基础学习笔记
    MySQL字符串拼接函数
    分享三款免费好用的远程控制软件!
    JVM——一些零散的概念(后续学习深入了再补充)
  • 原文地址:https://blog.csdn.net/Don_t_always_ail/article/details/133868385