文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Spring6-IoC(Inversion of Control)控制反转和DI(Dependency Injection)依赖注入,手动实现IOC

2023-09-04 19:01

关注

文章目录

1、Java反射

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

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

相关文章:

自定义类

package org.example.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 + '\'' +                '}';    }}

编写测试类

package org.example.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("org.example.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);            }        }    }}

2、实现Spring的IOC

IoC(控制反转)和DI(依赖注入)是Spring里面核心的东西,如何实现Spring框架最核心的部分?

①搭建模块

搭建模块:ioc-spring

②准备测试需要的bean

添加依赖

<dependencies>        <dependency>        <groupId>org.junit.jupitergroupId>        <artifactId>junit-jupiter-apiartifactId>        <version>5.3.1version>    dependency>dependencies>

创建UserDao接口

package org.example.spring6.test.dao;public interface UserDao {    public void print();}

创建UserDaoImpl实现

package org.example.spring6.test.dao.impl;import org.example.spring.dao.UserDao;public class UserDaoImpl implements UserDao {    @Override    public void print() {        System.out.println("Dao层执行结束");    }}

创建UserService接口

package org.example.spring6.test.service;public interface UserService {    public void out();}

创建UserServiceImpl实现类

package org.example.spring.test.service.impl;import org.example.spring.core.annotation.Bean;import org.example.spring.service.UserService;@Beanpublic class UserServiceImpl implements UserService {//    private UserDao userDao;    @Override    public void out() {        //userDao.print();        System.out.println("Service层执行结束");    }}

③定义注解

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

bean注解

package org.example.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 {}

依赖注入注解

package org.example.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 {}

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

④定义bean容器接口

package org.example.spring.core;public interface ApplicationContext {    Object getBean(Class clazz);}

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

AnnotationApplicationContext基于注解扫描bean

package org.example.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);    }        public AnnotationApplicationContext(String basePackage) {            }}

⑥编写扫描bean逻辑

通过构造方法传入包的base路径,扫描被@Bean(自己定义的)注解的java对象,完整代码如下:

package org.example.spring.core;import org.example.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);    }        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();                        }                    }                }            }        }    }}

⑦java类标识Bean注解

@Beanpublic class UserServiceImpl implements UserService
@Beanpublic class UserDaoImpl implements UserDao 

⑧测试Bean加载

package org.example.spring;import org.example.spring.core.AnnotationApplicationContext;import org.example.spring.core.ApplicationContext;import org.example.spring.test.service.UserService;import org.junit.jupiter.api.Test;public class SpringIocTest {    @Test    public void testIoc() {        ApplicationContext applicationContext = new AnnotationApplicationContext("org.example.spring.test");        UserService userService = (UserService)applicationContext.getBean(UserService.class);        userService.out();        System.out.println("run success");    }}

控制台打印测试

⑨依赖注入

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

package org.example.spring.test.service.impl;import org.example.spring.core.annotation.Bean;import org.example.spring.core.annotation.Di;import org.example.spring.dao.UserDao;import org.example.spring.service.UserService;@Beanpublic class UserServiceImpl implements UserService {    @Di    private UserDao userDao;    @Override    public void out() {        userDao.print();        System.out.println("Service层执行结束");    }}

执行第八步:报错了,说明当前userDao是个空对象,还没有进行注入

⑩依赖注入实现

package org.example.spring.core;import org.example.spring.core.annotation.Bean;import org.example.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);    }        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();                    }                }            }        }    }}

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

来源地址:https://blog.csdn.net/weixin_43847283/article/details/131158742

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯