手写IOC

IOC原理(手写IOC)

Spring框架的IOC是基于反射机制实现的。

反射回顾

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

示例

实体类Car

package com.louis.reflect;

/**
 * @author XRY
 * @date 2023年06月26日8:59
 */
public class Car {

    private String bind;
    private int lifeTime;
    private String color;

    public Car() {
    }

    public Car(String bind, int lifeTime, String color) {
        this.bind = bind;
        this.lifeTime = lifeTime;
        this.color = color;
    }

    //普通方法
    private void use(){
        System.out.println("私有方法..........");
    }

    public String getBind() {
        return bind;
    }

    public void setBind(String bind) {
        this.bind = bind;
    }

    public int getLifeTime() {
        return lifeTime;
    }

    public void setLifeTime(int lifeTime) {
        this.lifeTime = lifeTime;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Car{" +
                "bind='" + bind + '\'' +
                ", lifeTime=" + lifeTime +
                ", color='" + color + '\'' +
                '}';
    }
}

1、获取class对象

@Test
public void testGetClass() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    //1、类名.class
    Class<Car> clazz01 = Car.class;
    //2、对象.getClass()
    Class<? extends Car> clazz02 = new Car().getClass();
    //3、Class.forName("全路径")
    Class<?> clazz03 = Class.forName("com.louis.reflect.Car");
    //实例化
    Car car = (Car)clazz03.getDeclaredConstructor().newInstance();
    logger.info("car" + car);
}

/*[2023-06-26 09:16:13:036] [INFO] - com.louis.reflect.TestCar.testGetClass(TestCar.java:28) - carcom.louis.reflect.Car@2445445a*/

2、获取构造方法

@Test
public void testCacheConstructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    Class<Car> clazz = Car.class;
    //获取所有构造
    //getConstructors针对public方法,如果是private则不能够使用这种方法获取,如果构造方法中包含私有的方法,则需要使用getDeclaredConstructors
    Constructor<?>[] constructors = clazz.getConstructors();
    for (Constructor<?> constructor : constructors) {
        logger.info("constructor" + constructor.getName() + "参数个数" + constructor.getParameterCount());
    /*
    * [2023-06-26 09:57:16:855] [INFO] - com.louis.reflect.TestCar.testCacheConstructor(TestCar.java:38) - constructorcom.louis.reflect.Car参数个数0
      [2023-06-26 09:57:16:858] [INFO] - com.louis.reflect.TestCar.testCacheConstructor(TestCar.java:38) - constructorcom.louis.reflect.Car参数个数3
    * */
    }
    //指定有参数的构造去创建对象
    //1、构造是public,如果目标对象是private则会报错
    /*Constructor<Car> haveParameterPub = clazz.getConstructor(String.class, int.class, String.class);
    Car car = haveParameterPub.newInstance("野马", 1, "blue");
    /*[2023-06-26 10:07:47:947] [INFO] - com.louis.reflect.TestCar.testCacheConstructor(TestCar.java:39) - constructorcom.louis.reflect.Car参数个数0
      [2023-06-26 10:07:47:950] [INFO] - com.louis.reflect.TestCar.testCacheConstructor(TestCar.java:39) - constructorcom.louis.reflect.Car参数个数3
      汽车Car{bind='野马', lifeTime=1, color='blue'}*/
    //2、构造是private
    Constructor<Car> haveParameterPri = clazz.getDeclaredConstructor(String.class, int.class, String.class);
    haveParameterPri.setAccessible(true);//设置访问权限,如果为false不能够访问
    Car car1 = haveParameterPri.newInstance("悍马", 2, "yellow");
    System.out.println("car1 = " + car1);
    /*
    [2023-06-26 10:13:58:492] [INFO] - com.louis.reflect.TestCar.testCacheConstructor(TestCar.java:39) - constructorcom.louis.reflect.Car参数个数0
    [2023-06-26 10:13:58:496] [INFO] - com.louis.reflect.TestCar.testCacheConstructor(TestCar.java:39) - constructorcom.louis.reflect.Car参数个数3
    car1 = Car{bind='悍马', lifeTime=2, color='yellow'}
    * */
}

3、获取属性

@Test
public void getAttribute() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    //获得类的字节码文件,类、对象和class.forName
    Class<?> carClass = Class.forName("com.louis.reflect.Car");
    //实例化
    Car car = (Car)carClass.getDeclaredConstructor().newInstance();
    //获取其中所有的public方法
    Field[] fields = carClass.getFields();
    //获取所有的属性,包括私有的属性
    Field[] declaredFields = carClass.getDeclaredFields();
    for (Field declaredField : declaredFields) {
        System.out.println("declaredField.getName() = " + declaredField.getName());
        //给属性赋值
        if(declaredField.getName().equals("bind")){
            //设置允许访问
            declaredField.setAccessible(true);
            //传入对象和属性值
            declaredField.set(car,"野马");
        }
        System.out.println("car" + car);
    }
    /*
    * declaredField.getName() = bind
      carCar{bind='野马', lifeTime=0, color='null'}
      declaredField.getName() = lifeTime
      carCar{bind='野马', lifeTime=0, color='null'}
      declaredField.getName() = color
      carCar{bind='野马', lifeTime=0, color='null'}

    * */
}

4、获取方法

@Test
public void getMethod() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
    Car car = new Car("Benz", 10, "black");
    Class<? extends Car> clazz = car.getClass();
    //1、public方法,不会取到私有
    Method[] methods = clazz.getMethods();
    for (Method method : methods) {
//            System.out.println(method.getName());
        //执行方法toString
        if(method.getName().equals("toString")){
            String invoke = (String)method.invoke(car);
            System.out.println("toString执行了" + invoke);
            /*toString执行了Car{bind='Benz', lifeTime=10, color='black'}*/
        }
    }
    //2、private方法
    Method[] methodsAll = clazz.getDeclaredMethods();
    for (Method methodA : methodsAll) {
        //执行私有方法
        if(methodA.getName().equals("use")){
            methodA.setAccessible(true);
            methodA.invoke(car);
        }
    }
    /*私有方法..........*/
}

实现Spring的IoC

实现过程

1、创建模块spring-ioc

在这里插入图片描述

2、创建测试类service、dao

在这里插入图片描述

接口实现

@Bean
public class UserServiceImpl implements UserService {
    @Di
    private UserDao userDao;
    public void add(){
        System.out.println("service......");
        //调用dao的方法
        userDao.show();
    }
}

3、创建两个注解@Bean(创建对象)、 @Di(属性注入)

@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 {
    //用于创建对象
}

@Di

package com.louis.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 {
    //用于注入属性
}

4、创建bean容器接口ApplicationContext,定义方法、返回对象

public interface ApplicationContext {
    //在IOC中BeanFactory返回的是一个工厂
    Object getBean(Class clazz);
}

5、实现bean容器接口,创建实现类

(1)返回对象
(2)根据包规则加载bean(扫描路径下包含@Bean注解的类,并将这些类通过反射实例化)

package com.louis.bean.impl;

import com.louis.annotation.Bean;
import com.louis.annotation.Di;
import com.louis.bean.ApplicationContext;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author XRY
 * @date 2023年06月26日16:39
 */
public class AnnotationApplicationContext implements ApplicationContext {
    //模拟IOC,创建map集合,放置bean对象
    private Map<Class, Object> beanFactory = new HashMap<>();
    private static String rootPath;

    //返回对象
    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    //设置包扫描规则
    //当前包及其子包,将带有@Bean注解的类通过反射实现实例化
    public AnnotationApplicationContext(String basePackage){
        //扫描路径
        //1、将.替换成\
        String packagePath = basePackage.replaceAll("\\.", "\\\\");
        //2、获取包的绝对路径,编译之后的路径
        try {
            Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);
            while(urls.hasMoreElements()){
                URL url = urls.nextElement();
                //转码
                String filePath = URLDecoder.decode(url.getFile(), "utf-8");
                //获取包前面路劲部分,字符串截取
                rootPath = filePath.substring(0, filePath.length() - packagePath.length());
//                System.out.println("filePath = " + filePath);
                //根据获得的路径进行包扫描
                loadBean(new File(filePath));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        //属性注入
        loadDi();
    }

    /**
     * 包扫描过程,进行实例化
     * @param file
     */
    private void loadBean(File file) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1、判断当前路径下的东西是否是文件夹,如果不是就不需要继续往下查找
        if(file.isDirectory()){
            //2、获取文件夹里面所有内容
            File[] childFiles = file.listFiles();
            //3、判断文件夹里面为空,直接返回
            if(childFiles == null || childFiles.length == 0){
                return;
            }
            //4、如果文件夹里面不为空,遍历文件夹中所有内容
            for(File child:childFiles){
                //4.1遍历得到每个File对象,继续判断,如果是文件夹,递归
                if(child.isDirectory()){
                    //递归
                    loadBean(child);
                }else{
                    //4.2遍历得到的File对象不是文件夹
                    //4.3得到包路径+类名称部分
                    String packagePath = child.getAbsolutePath().substring(rootPath.length() - 1);
                    //4.4判断当前文件类型是否为.class,如果是,将路径中的\替换为.并将.class文件去掉
                    if(packagePath.contains(".class")){
                        String allName = packagePath.replaceAll("\\\\", "\\.").replaceAll(".class", "");
                        //4.5判断类上面是否有注解@Bean,如果有进行实例化过程
                        //4.5.1获取类的class
                        Class<?> clazz = Class.forName(allName);
                        //4.5.2判断不是interface
                        if(!clazz.isInterface()){
                            Bean annotation = clazz.getAnnotation(Bean.class);
                            if(annotation != null){
                                //4.5.3实例化
                                Object instance = clazz.getConstructor().newInstance();
                                //4.7把对象实例化之后,放到map集合beanFactory
                                //4.7.1判断当前类如果有接口,让接口class作为map的key,如果没有接口将自己的class作为key
                                if(clazz.getInterfaces().length > 0){
                                    beanFactory.put(clazz.getInterfaces()[0], instance);
                                }else{
                                    beanFactory.put(clazz,instance);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

//    public static void main(String[] args) {
//        new AnnotationApplicationContext("com.louis");
//    }

    //属性注入
    private void loadDi(){
        //实例化的对象都在beanFactory的map集合里
        //1、遍历beanFactory的map集合,entrySet()用来获取到对象的集合
        Set<Map.Entry<Class, Object>> entries = beanFactory.entrySet();
        for (Map.Entry<Class, Object> entry : entries) {
            //2、获取map集合中每个对象(value),每个对象获取到属性
            Object value = entry.getValue();
            //获取对象Class
            Class<?> clazz = value.getClass();
            //获取每个对象中的属性
            Field[] declaredFields = clazz.getDeclaredFields();
            //3、遍历得到的每个对象属性的数组,得到每个属性
            for (Field field : declaredFields) {
                //4、判断属性上是否有@Di注解,
                Di annotation = field.getAnnotation(Di.class);
                if(annotation != null){
                    //如果是私有属性可以设置一个值
                    field.setAccessible(true);
                    //有Di注解就把对象进行设置(注入)
                    try {
                        field.set(value, beanFactory.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }
}

6、测试

public class TestBean {
  public static void main(String[] args){
      ApplicationContext context = new AnnotationApplicationContext("com.louis");
      UserService userService = (UserService) context.getBean(UserService.class);
//      UserService userService1 = new UserServiceImpl();
      userService.add();
  }
}

/*
* service......
UserDao................
* */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/42245.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在Linux下做性能分析1:基本模型

介绍 本Blog开始介绍一下在Linux分析性能瓶颈的基本方法。主要围绕一个基本的分析模型&#xff0c;介绍perf和ftrace的使用技巧&#xff0c;然后东一扒子&#xff0c;西一扒子&#xff0c;逮到什么说什么&#xff0c;也不一定会严谨。主要是把这个领域的一些思路和技巧串起来。…

解码 LangChain|用 LangChain 和 Milvus 从零搭建 LLM 应用

如何从零搭建一个 LLM 应用&#xff1f;不妨试试 LangChain Milvus 的组合拳。 作为开发 LLM 应用的框架&#xff0c;LangChain 内部不仅包含诸多模块&#xff0c;而且支持外部集成&#xff1b;Milvus 同样可以支持诸多 LLM 集成&#xff0c;二者结合除了可以轻松搭建一个 LLM…

计算机科学与技术专业课程内容汇总

大学课程结束了&#xff0c;真的好快。昨天把专业课程涉及到的内容汇总了下&#xff0c;还是挺多的&#xff0c;存到网盘里也不会丢&#xff0c;电脑存储空间还能扩大。 把网盘链接放在这里&#xff0c;希望大家共勉。图片中所涉内容仅为部分课程。 链接&#xff1a;https://…

7.kafka+ELK连接

文章目录 kafkaELK连接部署Kafkakafka操作命令kafka架构深入FilebeatKafkaELK连接 kafkaELK连接 部署Kafka ###关闭防火墙systemctl stop firewalld systemctl disable firewalldsetenforce 0vim /etc/selinux/configSELINUXdisabled###下载安装包官方下载地址&#xff1a;ht…

js小写金额转大写 自动转换

// 小写转为大写convertCurrency(money) {var cnNums [零, 壹, 贰, 叁, 肆, 伍, 陆, 柒, 捌, 玖]var cnIntRadice [, 拾, 佰, 仟]var cnIntUnits [, 万, 亿, 兆]var cnDecUnits [角, 分, 毫, 厘]// var cnInteger 整var cnIntLast 元var maxNum 999999999999999.9999var…

船舶中压配电板应用弧光保护,可解决母排故障短路问题,对于提高船舶电站的安全性、稳定性,降低经济损失具有重要意义。-安科瑞黄安南

摘要&#xff1a;船舶中压配电板弧光故障导致的设备损坏和停电事故&#xff0c;不仅会造成较大的经济损失&#xff0c;而且严重影响船舶电站的安全稳定运行&#xff0c;威胁船舶电站操作人员的安全。弧光保护是基于电力系统开关柜发生弧光故障时而设计的一套母线保护系统&#…

使用testify包辅助Go测试指南

我虽然算不上Go标准库的“清教徒”&#xff0c;但在测试方面还多是基于标准库testing包以及go test框架的&#xff0c;除了需要mock的时候&#xff0c;基本上没有用过第三方的Go测试框架。我在《Go语言精进之路》[2]一书中对Go测试组织的讲解也是基于Go testing包和go test框架…

如何使用MATLAB软件完成生态碳汇涡度相关监测与通量数据分析

MATLAB MATLAB是美国MathWorks公司出品的商业数学软件&#xff0c;用于数据分析、无线通信、深度学习、图像处理与计算机视觉、信号处理、量化金融与风险管理、机器人&#xff0c;控制系统等领域。 [1] MATLAB是matrix&laboratory两个词的组合&#xff0c;意为矩阵工厂&a…

力扣206. 反转链表

给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例 3&#xff1a; 输入&am…

stm32(SPI读写W25Q18)

SPI 是什么&#xff1f; SPI是串行外设接口&#xff08;Serial Peripheral Interface&#xff09;的缩写&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总 线&#xff0c;并且在芯片的管脚上只占用四根线&#xff0c;节约了芯片的管脚&#xff0c;同时为PC…

electron+vue3全家桶+vite项目搭建【23】url唤醒应用,并传递参数

文章目录 引入实现效果实现步骤测试代码 引入 demo项目地址 很多场景下我们都希望通过url快速唤醒应用&#xff0c;例如百度网盘&#xff0c;在网页中唤醒应用&#xff0c;并传递下载链接&#xff0c;在electron中要实现这样的效果&#xff0c;就需要针对不同的平台做对应的处…

Stable Diffusion Webui 之 ControlNet使用

一、安装 1.1、插件安装 1.2、模型安装 模型安装分为预处理模型和 controlnet所需要的模型。 先安装预处理模型&#xff0c;打开AI所在的安装目录\extensions\sd-webui-controlnet\annotator,将对应的预处理模型放进对应的文件夹中即可&#xff0c; 而controlnet所需模型则…

vmware-ubuntu 出现的奇怪问题

虚拟机突然连不上网 参考博文-CSDN-卍一十二画卍&#xff08;作者&#xff09;-Vmware虚拟机突然连接不上网络【方案集合】 sudo vim /var/lib/NetworkManager/NetworkManager.statesudo service network-manager stop sudo vim /var/lib/NetworkManager/NetworkManager.stat…

初识react

初识react 第一步就给我出个问题版本太低 https://www.cnblogs.com/gslgb/p/16585233.html https://blog.csdn.net/xiangshiyufengzhong/article/details/124193898 第二个问题 便利生成dom 需要绑定key 不要总想着加冒号这不是vue 第三个问题 我p标签包裹 MapList组件 MapLis…

最小二乘拟合平面——直接求解法

目录 一、算法原理二、代码实现1、python2、matlab 三、算法效果 一、算法原理 平面方程的一般表达式为&#xff1a; A x B y C z D 0 ( C ≠ 0 ) (1) AxByCzD0(C\neq0)\tag{1} AxByCzD0(C0)(1) 即&#xff1a; z − A C x − B C y − D C (2) z-\frac{A}{C}x-\frac{…

相机图像质量研究(1)Camera成像流程介绍

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

Principle Component Analysis

简述PCA的计算过程 输入&#xff1a;数据集X{x1&#xff0c;x2&#xff0c;...&#xff0c;xn}&#xff0c;需降到k维 ① 去中心化&#xff08;去均值&#xff0c;即每个特征减去各自的均值&#xff09; ② 计算协方差矩阵1/nX*X^T&#xff08;1/n不影响特征向量&#xff09…

高效出报表的工具有哪些?奥威BI报表工具怎样?

随着企业精细化数据分析的展开&#xff0c;数据分析报表的制作压力也随之增加。对企业而言&#xff0c;拥有一个高效出报表的工具十分重要。高效出报表的工具有哪些&#xff1f;奥威BI报表工具的效率够不够高&#xff1f; 高效出报表的工具有很多&#xff0c;奥威BI报表工具就…

mybatis 基础2

查询所有 数据库字段与JavaBean属性保持一致 数据库字段与JavaBean属性不一致 使用resultMap标签 多表查询 association【引入JavaBean实体类】 通过tprice&#xff0c;address_name模糊查询

「数字化制造」 是如何让制造过程信息化的?

「数字化制造」 是如何让制造过程信息化的&#xff1f; 数字化制造是指利用数字技术和信息化手段来实现制造过程的智能化、自动化和高效化。 它通过将传感器、物联网、云计算、大数据分析、人工智能等先进技术与制造业相结合&#xff0c;实现生产过程的数字化、网络化和智能化…