我的编程空间,编程开发者的网络收藏夹
学习永远不晚

spring6-实现简易版IOC容器

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

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

spring6-实现简易版IOC容器

手写简易版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 + '\'' +                '}';    }}

编写测试类

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);            }        }    }}

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>

创建UserDao接口

package com.atguigu.spring6.test.dao;public interface UserDao {    public void print();}

创建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层执行结束");    }}

创建UserService接口

package com.atguigu.spring6.test.service;public interface UserService {    public void out();}

创建UserServiceImpl实现类

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

③定义注解

我们通过注解的形式加载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 {}

依赖注入注解

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 {}

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

④定义bean容器接口

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

⑤编写注解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);    }        public AnnotationApplicationContext(String basePackage) {            }}

⑥编写扫描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);    }        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 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");    }}

控制台打印测试

⑨依赖注入

只要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;@Beanpublic class UserServiceImpl implements UserService {    @Di    private UserDao userDao;    @Override    public void out() {        userDao.print();        System.out.println("Service层执行结束");    }}

执行第八步:报错了,说明当前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);    }        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/m0_62946761/article/details/133470213

免责声明:

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

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

spring6-实现简易版IOC容器

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C#简单实现IOC容器的示例代码

IOC容器是一种设计模式,用于管理对象创建和依赖关系,提升代码的可测试性、可维护性等。本文提供了一个使用C#简单实现IOC容器的示例代码,包括注册、解析等功能。此外,文章还讨论了IOC容器的扩展、优缺点等。
C#简单实现IOC容器的示例代码
2024-04-02

Linux模拟实现【简易版bash】

✨个人主页: Yohifo 🎉所属专栏: Linux学习之旅 🎊每篇一句: 图片来源 🎃操作环境: CentOS 7.6 阿里云远程服务器 Good judgment comes fro
2023-08-18

Python如何实现简易版音乐播放器

小编给大家分享一下Python如何实现简易版音乐播放器,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、前言今天我们将用Python来创建一个属于自己的音乐播放器。为此,我们将使用三个软件包:Tkinter:用于UIPyg
2023-06-15

C++简易版Tensor实现方法详解

这篇文章主要介绍了C++简易版Tensor的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
2022-11-13

Android Studio实现简易计算器App (Java语言版)

本文实例为大家分享了Android Studio实现简易计算器App的具体代码,供大家参考,具体内容如下 效果演示 布局文件
2022-06-07

html+css+js实现简易版ChatGPT聊天机器人

OpenAI的一款聊天机器人模型ChatGPT爆火,本篇文章用一百行html+css+js代码给大家制作一款简易的聊天机器人。
2023-02-25

如何使用TypeScript实现一个IoC容器

这篇文章主要介绍“如何使用TypeScript实现一个IoC容器”,在日常操作中,相信很多人在如何使用TypeScript实现一个IoC容器问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何使用TypeScr
2023-06-16

Java中的IoC容器是怎么实现的

本篇文章为大家展示了Java中的IoC容器是怎么实现的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。IoC的概念介绍控制反转(IOC)模式(又称DI:Dependency Injection)就是I
2023-05-31

python实现简易连点器

本文主要介绍了python实现简易连点器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-01-29

Android 简易版天气预报app的实现(改进版)

需要技术支持的可以联系我QQ:1990724437 最近总是有人来和我说我以前写的一个小app无法正常获取数据~Android简易版天气预报app 今天就又运行了下来查找问题,发现或许是接口有限制吧,不能在多台手机使用同个apikey 然后
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录