首页 > 其他分享 >简单得实现IOC容器控制反转和依赖注入,并分析原理

简单得实现IOC容器控制反转和依赖注入,并分析原理

时间:2024-09-23 16:50:29浏览次数:10  
标签:容器 String 构造方法 反转 beanName bean IOC class beanDefinition

目录

参考文章链接: https://blog.csdn.net/heyl163_/article/details/132515809


IOC容器

Component注解:标记是否要创建bean,传入bean的名称

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {

    String value() default "";
}

ComponentScan注解:这个是spring启动类上要扫描的路径

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {

    String value();
}

创建SpringConfig类,添加注解@ComponentScan指定扫描包

@ComponentScan("org.example")
public class SpringConfig {
}

使用@Component标记需要IOC容器管理的对象

@Component("userMapper")
public class UserMapper {
}

在scan配置类springConfig上的注解@ComponentScan(“org.example”)时,遇到类有标记注解Component就会添加到IOC容器中管理

// 扫描组件 ComponentScan指定的包和Component标记的类
        scan(configClass);

//先放入Map中
if (loadClass.isAnnotationPresent(Component.class)) {
            // 获取@Component注解上配置的组件名
            Component component = loadClass.getAnnotation(Component.class);
            beanName = component.value();

            if ("".equals(beanName)) {
                beanName = getBeanName(loadClass);
            }


            // 是否懒加载
            boolean lazy = false;
            // bean的作用域
            String scope = "singleton";

            // 类上使用了@Scope注解
            if (loadClass.isAnnotationPresent(Scope.class)) {
                // 获取@Scope注解
                Scope annotation = loadClass.getAnnotation(Scope.class);

                // 单例
                if (isSingleton(annotation.value())) {
                    lazy = loadClass.isAnnotationPresent(Lazy.class);
                } else {
                    // 非单例
                    scope = annotation.value();
                }
            } else {
                // 类上没有使用@Scope注解,默认是单例的
                lazy = loadClass.isAnnotationPresent(Lazy.class);
            }

            // 保存bean的定义
            BeanDefinition beanDefinition = new BeanDefinition();

            beanDefinition.setType(loadClass);
            beanDefinition.setLazy(lazy);
            beanDefinition.setScope(scope);

            // BeanPostProcessor接口的实现类保存到list
            if (BeanPostProcessor.class.isAssignableFrom(loadClass)) {
                list.add((BeanPostProcessor) createBean(beanDefinition));
            } else {
                beanDefinitionMap.put(beanName, beanDefinition);
            }

            beanDefinitionMap.put(beanName, beanDefinition);

//之后遍历创建
// 把组件中非懒加载的单例bean保存到单例池
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            BeanDefinition beanDefinition = entry.getValue();

            if(isSingleton(beanDefinition.getScope()) && !beanDefinition.isLazy()) {
                Object bean = createBean(beanDefinition);
                String beanName = entry.getKey();

                singletonObjects.put(beanName, bean);
            }
        }

依赖反转/注入

依赖注入,在创建bean对象得时候,看bean的字段是否有Autowired.class注解

if (field.isAnnotationPresent(Autowired.class)) {

有的话就拿字段名字从IOC容器中获取bean,然后再注入

 Object autowiredBean = getBean(field.getName());

                   // 没有找到对应名称的bean,尝试通过bean类型查找,bean的类型就是该字段的类型
                   if (autowiredBean == null) {
                       // 获取字段类型
                       Class<?> type = field.getType();

                       autowiredBean = getBean((Class<T>) type);
                   }

                   // 并设置到@Autowired注入的属性中
                   field.setAccessible(true);
                   field.set(bean, autowiredBean);
               }

下面是创建bean的代码:

private Object createBean(BeanDefinition beanDefinition) {
        Object bean = null;
        Class beanType = beanDefinition.getType();

        // 获取所有构造方法
        Constructor[] constructors = beanType.getConstructors();

        try {
            /*
             * 推断构造方法
             * 1、没有提供构造方法:调用默认的无参构造
             * 2、提供了构造方法:
             *   - 构造方法个数为1
             *     - 构造方法参数个数为0:无参构造
             *     - 构造方法参数个数不为0:传入多个为空的参数
             *   - 构造方法个数 > 1:
             *     - 提供了无参构造方法:调用无参构造方法实例化
             *     - 没有提供无参构造方法:推断失败,抛出异常
             */
            if (isEmpty(constructors)) { // 注意:这个分支永远不会执行,可以删除,但是为了方便理解代码,在此保留
                // 无参构造方法
                Constructor constructor = beanType.getConstructor();

                bean = constructor.newInstance();
            } else if (constructors.length == 1) {
                Constructor constructor = constructors[0];
                // 得到构造方法参数个数
                int parameterCount = constructor.getParameterCount();

                if (parameterCount == 0) {
                    // 无参构造方法
                    bean = constructor.newInstance();
                } else {
                    // 多个参数的构造方法
                    Object[] array = new Object[parameterCount];

                    bean = constructor.newInstance(array);
                }
            } else {
                boolean success = false;

                for (Constructor constructor : constructors) {
                    if (constructor.getParameterCount() == 0) {
                        bean = constructor.newInstance();
                        success = true;
                        break;
                    }
                }

                if (!success) {
                    throw new IllegalStateException("No default constructor found.");
                }
            }
            /*
             * 处理字段注入
             * 先AutowiredByName后AutowiredByType
             */
            // 获取bean的所有自定义属性
            Field[] fields = beanType.getDeclaredFields();

            for (Field field : fields) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    // 获取bean
                    // 通过bean名称获取bean
                    Object autowiredBean = getBean(field.getName());

                    // 没有找到对应名称的bean,尝试通过bean类型查找,bean的类型就是该字段的类型
                    if (autowiredBean == null) {
                        // 获取字段类型
                        Class<?> type = field.getType();

                        autowiredBean = getBean((Class<T>) type);
                    }

                    // 并设置到@Autowired注入的属性中
                    field.setAccessible(true);
                    field.set(bean, autowiredBean);
                }
            }
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }
        return bean;
    }

AnnotationConfigApplicationContext spring容器启动类(相当于spring容器)完整简单理解代码

package org.example.spring;

import org.example.spring.annotation.*;
import org.example.spring.exception.NoSuchBeanException;
import org.example.spring.exception.TooMuchBeanException;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author heyunlin
 * @version 1.0
 */
public class AnnotationConfigApplicationContext<T> implements ApplicationContext<T> {

    private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    /**
     * 单例对象池
     */
    private final Map<String, Object> singletonObjects = new HashMap<>();

    /**
     * 创建Spring容器时指定的配置类
     */
    public final Class<T> configClass;

    public AnnotationConfigApplicationContext(Class<T> configClass) throws ClassNotFoundException {
        this.configClass = configClass;

        // 扫描组件
        scan(configClass);

        // 把组件中非懒加载的单例bean保存到单例池
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            BeanDefinition beanDefinition = entry.getValue();

            if(isSingleton(beanDefinition.getScope()) && !beanDefinition.isLazy()) {
                Object bean = createBean(beanDefinition);
                String beanName = entry.getKey();

                singletonObjects.put(beanName, bean);
            }
        }
    }

    /**
     * 扫描组件
     * @param clazz 配置类的类对象
     * @throws ClassNotFoundException 类找不到
     */
    private void scan(Class<T> clazz) throws ClassNotFoundException {
        // 如果类上使用了@ComponentScan注解
        if (clazz.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScan = clazz.getAnnotation(ComponentScan.class);
            String value = componentScan.value();

            if (!"".equals(value)) {
                String path = value;
                path = path.replace(".", "/");

                URL resource = clazz.getClassLoader().getResource(path);
                File file = new File(resource.getFile());

                loopFor(file);
            }
        }
    }

    /**
     * 递归遍历指定文件/文件夹
     * @param file 文件/文件夹
     * @throws ClassNotFoundException 类找不到
     */
    private void loopFor(File file) throws ClassNotFoundException {
        if (file.isDirectory()) {
            for (File listFile : file.listFiles()) {
                if (listFile.isDirectory()) {
                    loopFor(listFile);

                    continue;
                }

                toBeanDefinitionMap(listFile);
            }
        } else if (file.isFile()) {
            toBeanDefinitionMap(file);
        }
    }

    List<BeanPostProcessor> list = new ArrayList<>();
    /**
     * 解析bean,并保存到Map<String, BeanDefinition>
     * @param file 解析的class文件
     * @throws ClassNotFoundException 类找不到
     */
    private void toBeanDefinitionMap(File file) throws ClassNotFoundException {
        // 获取类的绝对路径
        String absolutePath = file.getAbsolutePath();
        // 处理得到类的全限定名
        absolutePath = absolutePath.substring(absolutePath.indexOf("org"), absolutePath.indexOf(".class"));
        absolutePath = absolutePath.replace("\\", ".");

        // 通过类加载器加载
        Class<?> loadClass = configClass.getClassLoader().loadClass(absolutePath);

        String beanName;

        if (loadClass.isAnnotationPresent(Component.class)) {
            // 获取@Component注解上配置的组件名
            Component component = loadClass.getAnnotation(Component.class);
            beanName = component.value();

            if ("".equals(beanName)) {
                beanName = getBeanName(loadClass);
            }


            // 是否懒加载
            boolean lazy = false;
            // bean的作用域
            String scope = "singleton";

            // 类上使用了@Scope注解
            if (loadClass.isAnnotationPresent(Scope.class)) {
                // 获取@Scope注解
                Scope annotation = loadClass.getAnnotation(Scope.class);

                // 单例
                if (isSingleton(annotation.value())) {
                    lazy = loadClass.isAnnotationPresent(Lazy.class);
                } else {
                    // 非单例
                    scope = annotation.value();
                }
            } else {
                // 类上没有使用@Scope注解,默认是单例的
                lazy = loadClass.isAnnotationPresent(Lazy.class);
            }

            // 保存bean的定义
            BeanDefinition beanDefinition = new BeanDefinition();

            beanDefinition.setType(loadClass);
            beanDefinition.setLazy(lazy);
            beanDefinition.setScope(scope);

            // BeanPostProcessor接口的实现类保存到list
            if (BeanPostProcessor.class.isAssignableFrom(loadClass)) {
                list.add((BeanPostProcessor) createBean(beanDefinition));
            } else {
                beanDefinitionMap.put(beanName, beanDefinition);
            }

            beanDefinitionMap.put(beanName, beanDefinition);
        } else if (loadClass.isAnnotationPresent(Configuration.class)) {
            Method[] methods = loadClass.getDeclaredMethods();

            for (Method method : methods) {
                if (method.isAnnotationPresent(Bean.class)) {
                    Bean annotation = method.getAnnotation(Bean.class);
                    beanName = annotation.value();

                    // 是否懒加载
                    boolean lazy = method.isAnnotationPresent(Lazy.class);
                    // 作用域
                    String scope = "singleton";

                    if ("".equals(beanName)) {
                        beanName = method.getName();
                    }

                    // 保存bean的定义
                    BeanDefinition beanDefinition = new BeanDefinition();

                    // 方法的返回值类型就是bean的类型
                    beanDefinition.setType(method.getReturnType()); // 方法的返回值类型就是bean的类型
                    beanDefinition.setLazy(lazy);
                    beanDefinition.setScope(scope);

                    // BeanPostProcessor接口的实现类保存到list
                    if (BeanPostProcessor.class.isAssignableFrom(loadClass)) {
                        list.add((BeanPostProcessor) createBean(beanDefinition));
                    } else {
                        beanDefinitionMap.put(beanName, beanDefinition);
                    }
                }
            }
        }
    }

    /**
     * 根据类对象获取beanName
     * @param clazz bean的Class对象
     * @return String bean名称
     */
    private String getBeanName(Class<?> clazz) {
        String beanName = clazz.getSimpleName();

        // 判断是否以双大写字母开头
        String className = beanName.replaceAll("([A-Z])([A-Z])", "$1_$2");

        // 正常的大驼峰命名:bean名称为类名首字母大写
        if (className.indexOf("_") != 1) {
            beanName = beanName.substring(0, 1).toLowerCase().concat(beanName.substring(1));
        } else { // 否则,bean名称为类名
            beanName = beanName;
        }

        return beanName;
    }

    /**
     * 判断作用域是否单例
     * @param scope bean的作用域
     * @return boolean 如果是单例,返回true,否则返回false
     */
    private boolean isSingleton(String scope) {
        return "singleton".equals(scope);
    }

    /**
     * 创建bean对象
     * @param beanDefinition bean的定义
     * @return Object 创建好的bean对象
     */
    private Object createBean(BeanDefinition beanDefinition) {
        Object bean = null;
        Class beanType = beanDefinition.getType();

        // 获取所有构造方法
        Constructor[] constructors = beanType.getConstructors();

        try {
            /*
             * 推断构造方法
             * 1、没有提供构造方法:调用默认的无参构造
             * 2、提供了构造方法:
             *   - 构造方法个数为1
             *     - 构造方法参数个数为0:无参构造
             *     - 构造方法参数个数不为0:传入多个为空的参数
             *   - 构造方法个数 > 1:
             *     - 提供了无参构造方法:调用无参构造方法实例化
             *     - 没有提供无参构造方法:推断失败,抛出异常
             */
            if (isEmpty(constructors)) { // 注意:这个分支永远不会执行,可以删除,但是为了方便理解代码,在此保留
                // 无参构造方法
                Constructor constructor = beanType.getConstructor();

                bean = constructor.newInstance();
            } else if (constructors.length == 1) {
                Constructor constructor = constructors[0];
                // 得到构造方法参数个数
                int parameterCount = constructor.getParameterCount();

                if (parameterCount == 0) {
                    // 无参构造方法
                    bean = constructor.newInstance();
                } else {
                    // 多个参数的构造方法
                    Object[] array = new Object[parameterCount];

                    bean = constructor.newInstance(array);
                }
            } else {
                boolean success = false;

                for (Constructor constructor : constructors) {
                    if (constructor.getParameterCount() == 0) {
                        bean = constructor.newInstance();
                        success = true;
                        break;
                    }
                }

                if (!success) {
                    throw new IllegalStateException("No default constructor found.");
                }
            }

            /*
             * 处理字段注入
             * 先AutowiredByName后AutowiredByType
             */
            // 获取bean的所有自定义属性
            Field[] fields = beanType.getDeclaredFields();

            for (Field field : fields) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    // 获取bean
                    // 通过bean名称获取bean
                    Object autowiredBean = getBean(field.getName());

                    // 没有找到对应名称的bean,尝试通过bean类型查找,bean的类型就是该字段的类型
                    if (autowiredBean == null) {
                        // 获取字段类型
                        Class<?> type = field.getType();

                        autowiredBean = getBean((Class<T>) type);
                    }

                    // 并设置到@Autowired注入的属性中
                    field.setAccessible(true);
                    field.set(bean, autowiredBean);
                }
            }

            // 调用InitializingBean的afterPropertiesSet()方法
//            if (bean instanceof InitializingBean) {
                Method afterPropertiesSet = beanType.getDeclaredMethod("afterPropertiesSet");
                afterPropertiesSet.invoke(bean);
//                ((InitializingBean) bean).afterPropertiesSet();
//            }

            /*
             * 初始化前
             */
            String beanName = getBeanName(beanDefinition.getType());

            if (!list.isEmpty()) {
                for (BeanPostProcessor beanPostProcessor : list) {
                    bean = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
                }
            }

            // 调用InitializingBean的afterPropertiesSet()方法
            if (bean instanceof InitializingBean) {
                ((InitializingBean) bean).afterPropertiesSet();
            }

            /*
             * 初始化后
             */
            if (list.size() > 0) {
                for (BeanPostProcessor beanPostProcessor : list) {
                    bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
                }
            }
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }

        return bean;
    }

    private boolean isEmpty(Object[] array) {
        return array.length == 0;
    }

    @Override
    public Object getBean(String beanName) {
        if (!beanDefinitionMap.containsKey(beanName)) {
            return null;
        }

        return getBean(beanName, beanDefinitionMap.get(beanName));
    }

    @Override
    public T getBean(Class<T> type) {
        if (type == null) {
            throw new IllegalStateException("bean类型不能为空!");
        }

        // 保存指定类型的bean的个数
        AtomicInteger count = new AtomicInteger();
        // 保存同一类型的bean
        Map<String, BeanDefinition> objectMap = new HashMap<>();

        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            BeanDefinition beanDefinition = entry.getValue();
            Class beanType = beanDefinition.getType();
            String beanName = entry.getKey();

            if (beanType.equals(type)) {
                count.addAndGet(1);
                objectMap.put(beanName, beanDefinition);
            }
        }

        if (count.get() == 0) {
            throw new NoSuchBeanException();
        } else if (count.get() > 1) {
            throw new TooMuchBeanException();
        } else {
            return (T) getBean((String) objectMap.keySet().toArray()[0], (BeanDefinition) objectMap.values().toArray()[0]);
        }
    }

    @Override
    public T getBean(String beanName, Class<T> type) {
        if (type == null) {
            throw new IllegalStateException("bean类型不能为空!");
        }
        if (beanDefinitionMap.containsKey(beanName)) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

            if (type.equals(beanDefinition.getType())) {
                return (T) getBean(beanName, beanDefinition);
            }
        }

        throw new NoSuchBeanException();
    }

    /**
     * 统一获取bean的方法
     * @param beanName bean名称
     * @param beanDefinition BeanDefinition
     * @return Object 符合条件的bean对象
     */
    private Object getBean(String beanName, BeanDefinition beanDefinition) {
        String scope = beanDefinition.getScope();

        // bean的作用域是单例
        if (isSingleton(scope)) {
            Object object = singletonObjects.get(beanName);

            // 懒加载的单例bean
            if (object == null) {
                Object bean = createBean(beanDefinition);

                singletonObjects.put(beanName, bean);
            }

            return singletonObjects.get(beanName);
        }

        return createBean(beanDefinition);
    }
}

标签:容器,String,构造方法,反转,beanName,bean,IOC,class,beanDefinition
From: https://blog.csdn.net/LSP20020926/article/details/142446207

相关文章

  • 滚雪球学SpringCloud[9.1讲]:Docker与容器化详解
    全文目录:前言9.1Docker与容器化Docker的基本概念与SpringBoot应用的容器化1.Docker的核心概念2.将SpringBoot应用容器化DockerCompose与微服务编排1.DockerCompose的核心概念2.使用DockerCompose编排微服务使用Kubernetes部署SpringCloud应用1.Kubernetes......
  • 20年架构师用一文带你彻底搞懂SpringBoot嵌入式Web容器原理
    ContainerLess理念微服务把应用和它所依赖的组件包、配置文件及附带的运行脚本打包成一个单一、独立、可执行的jar包文件。在实现Web服务器时,几乎不需要任何配置就可以启动Tomcat。你只需要使用java-jar命令就可以让Tomcat成为SpringBoot的一个自包含的可运行组件和单元。同时,这......
  • Dockerfile全面指南:从基础到进阶,掌握容器化构建的核心工具
    目录Dockerfile全面指南:从基础到进阶,掌握容器化构建的核心工具引言一、什么是Dockerfile二、Dockerfile的基本结构三、Dockerfile的常见配置项1、多阶段构建(Multi-stageBuilds)2、缓存优化3、合并RUN命令四、Dockerfile使用须知五、一个完整的Dockerfile实......
  • 计算机低能儿从0刷leetcode | 11.盛最多水的容器
    题目:11.盛最多水的容器解答:不想暴力遍历,于是让右端点j从最右侧开始遍历,每次寻找离j最远、且高度不小于height[j]的左端点i,结果发现错误,比如[1,2]的情况。于是又打补丁,按同样思路左端点i从0开始遍历,每次寻找离i最远、且高度不小于height[i]的右端点j,结果正确,然而时间复杂度......
  • Docker进入容器运行命令实例讲解
    Docker进入容器运行命令实例讲解在Docker中,要进入正在运行的容器并执行命令,主要使用dockerexec命令。这个命令允许你在运行中的容器内执行一个新的命令,这对于调试、运行附加的进程或在容器内部进行管理操作非常有用。基本语法dockerexec[OPTIONS]CONTAINERCOMMAND[ARG......
  • C++容器list底层迭代器的实现逻辑~list相关函数模拟实现
    目录1.两个基本的结构体搭建2.实现push_back函数3.关于list现状的分析(对于我们如何实现这个迭代器很重要)3.1和string,vector的比较3.2对于list的分析3.3总结4.迭代器类的封装5.list容器里面其他函数的实现6.个人总结7.代码附录1.两个基本的结构体搭建首先就是我......
  • 鸿蒙开发-Swiper(轮播图容器组件)
    Swiper组件提供滑动轮播显示的能力。Swiper本身是一个容器组件,当设置了多个子组件后,可以对这些子组件进行轮播显示。通常,在一些应用首页显示推荐的内容时,需要用到轮播显示的能力。针对复杂页面场景,可以使用Swiper组件的预加载机制,利用主线程的空闲时间来提前构建和布局绘制......
  • 远程访问本地基于Debian Linux用于运行虚拟机和容器的Proxmox VE
    文章目录前言1.局域网访问PVE2.安装Cpolar工具3.创建PVE公网地址4.远程访问PVE5.设置固定域名6.固定地址访问前言本文主要介绍如何在Windows环境安装内网穿透工具,实现公网环境远程访问本地局域网中的ProxmoxVE平台WEB管理界面。ProxmoxVE是一个完全开源......
  • docker阶段03 docker容器内hosts文件, DNS, 查docker空间占用, 部署自动化运维平台spu
    容器内部的hosts文件容器会自动将容器的ID加入自已的/etc/hosts文件中,并解析成容器的IP范例:修改容器的hosts文件[root@ubuntu1804~]#dockerrun-it--rm--add-hostwww.wangxiaochun.com:6.6.6.6--add-hostwww.wang.org:8.8.8.8busybox/#cat/etc/hosts127.0.0......
  • Docker 与 GitHub:完美结合实现容器化部署与持续集成
    Docker与GitHub:完美结合实现容器化部署与持续集成使用Docker和GitHub,开发者可以将代码构建、测试和部署流程自动化,从而提高开发效率,确保应用程序的一致性与可靠性。本文将介绍如何使用Docker和GitHubActions实现容器化部署与持续集成。目录概述Docker基础知识Docker镜......