Spring IOC 源码分析之深入理解 IOC

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: Spring IOC 源码分析之深入理解 IOC

Spring IOC 源码分析之深入理解 IOC

如果你要学习,最好的时间是十年前,其次就是当下。

在Spring框架中,IOC(Inversion of Control,控制反转)是其中最重要的一个核心概念。它的实现方式是通过BeanFactory和ApplicationContext等容器来管理对象的创建、依赖注入、生命周期等等。


下面,我们将通过分析Spring的源码,来深入理解IOC的实现原理

BeanFactory接口

在Spring的IOC容器中,BeanFactory是最基本的容器接口。它定义了IOC容器的基本行为,包括获取Bean、销毁Bean等操作。

public interface BeanFactory {
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    boolean containsBean(String name);
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    String[] getAliases(String name);
}

上述接口中,最核心的方法是 getBean() 方法,它通过Bean的名称或类型,返回对应的Bean对象。在Spring IOC的实现中,getBean() 方法是通过BeanFactory实现的,我们来看一下BeanFactory的默认实现类:DefaultListableBeanFactory。

DefaultListableBeanFactory

DefaultListableBeanFactory是Spring IOC容器的默认实现类。它实现了BeanFactory接口,并提供了Bean的定义、注册、获取等操作。

在DefaultListableBeanFactory中,最核心的是BeanDefinition对象。它是Spring IOC容器中的核心数据结构,表示一个Bean的定义信息,包括Bean的类名、构造方法、属性、依赖等等。下面是BeanDefinition接口的定义:

public interface BeanDefinition {
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

    String getBeanClassName();
    void setBeanClassName(String beanClassName);
    String getScope();
    void setScope(String scope);
    boolean isSingleton();
    boolean isPrototype();
    String getFactoryMethodName();
    void setFactoryMethodName(String factoryMethodName);
    String getFactoryBeanName();
    void setFactoryBeanName(String factoryBeanName);
    String[] getDependsOn();
    void setDependsOn(String... dependsOn);
    boolean isLazyInit();
    void setLazyInit(boolean lazyInit);
    ConstructorArgumentValues getConstructorArgumentValues();
    MutablePropertyValues getPropertyValues();
    boolean isAutowireCandidate();
    void setAutowireCandidate(boolean autowireCandidate);
}

上述接口中,最核心的是 getBeanClassName() 和 getPropertyValues() 方法。 getBeanClassName() 返回Bean的类名,getPropertyValues() 返回Bean的属性值。在DefaultListableBeanFactory中,BeanDefinition是在DefaultListableBeanFactory中,BeanDefinition是通过Map来存储的,其中key是Bean的名称,value是对应的BeanDefinition对象。具体实现如下:

// 搜索 JavaPub,Spring 源码讲解。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    // 存储BeanDefinition的Map
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    // BeanDefinition注册接口的实现方法
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        synchronized (this.beanDefinitionMap) {
            BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
            if (existingDefinition != null) {
                if (!beanDefinition.equals(existingDefinition)) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(),
                            beanName, "Definition of bean '" + beanName + "' differs from existing " +
                            "definition for the same bean name. " + "Consider deleting or renaming the existing " +
                            "bean definition with the same name.");
                }
            }
            else {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.frozenBeanDefinitionNames = null;
            }
        }
    }

    // BeanDefinition获取接口的实现方法
    @Override
    public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
        Assert.hasText(beanName, "Bean name must not be empty");
        BeanDefinition bd = this.beanDefinitionMap.get(beanName);
        if (bd == null) {
            throw new NoSuchBeanDefinitionException(beanName);
        }
        return bd;
    }

    // 根据Bean名称获取Bean对象
    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    // 根据Bean类型获取Bean对象
    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return doGetBean(requiredType.getName(), requiredType, null, false);
    }

    // 根据Bean名称和类型获取Bean对象
    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return doGetBean(name, requiredType, null, false);
    }

    // 核心方法,通过Bean名称或类型获取Bean对象
    protected <T> T doGetBean(final String name, final Class<T> requiredType,
            final Object[] args, boolean typeCheckOnly) throws BeansException {

        // 根据名称或类型解析BeanDefinition对象
        final BeanDefinition beanDefinition = getBeanDefinition(name);

        // 根据BeanDefinition对象创建Bean实例
        Object bean = createBean(name, beanDefinition, args);

        // 对Bean实例进行依赖注入
        populateBean(beanName, beanDefinition, bean);

        // 对Bean实例进行初始化
        initializeBean(beanName, bean, beanDefinition);

        // 返回Bean实例
        return (T) bean;
    }
}

在DefaultListableBeanFactory中,Bean的创建、依赖注入和初始化等操作都是在doGetBean()方法中完成的。接下来,我们将重点介绍Bean的创建和依赖注入过程。

Bean

Bean的创建过程

在DefaultListableBeanFactory中,Bean的创建是通过createBean()方法完成的,具体实现如下:

protected Object createBean(final String beanName, final BeanDefinition beanDefinition, final Object[] args) {
    // 创建Bean实例
    Object beanInstance = createBeanInstance(beanDefinition, beanName, args);

    // 设置Bean实例的Class属性
    Class<?> beanType = beanInstance.getClass();
    if (!beanType.equals(Object.class)) {
        beanDefinition.setBeanClass(beanType);
    }

    // 对Bean实例进行属性赋值和方法注入
    applyPropertyValues(beanName, beanDefinition, beanInstance);

    // 处理Aware接口的回调
    invokeAwareMethods(beanName, beanInstance);

    // Bean后处理器的前置处理
    Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(beanInstance, beanName);

    // 调用Bean实例的初始化方法
    try {
        invokeInitMethods(beanName, wrappedBean, beanDefinition);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Invocation of init method failed", ex);
    }

    // Bean后处理器的后置处理
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

    // 返回Bean实例
    return wrappedBean;
}

在createBean()方法中,首先通过createBeanInstance()方法创建Bean实例,然后设置Bean实例的Class属性、对Bean实例进行属性赋值和方法注入、处理Aware接口的回调、调用Bean实例的初始化方法,最后通过Bean后处理器进行前置处理和后置处理,最终返回Bean实例。

Bean的依赖注入过程

在DefaultListableBeanFactory中,Bean的依赖注入是通过applyPropertyValues()方法完成的,具体实现如下:

protected void applyPropertyValues(String beanName, BeanDefinition beanDefinition, Object bean) {
    try {
        // 对Bean实例进行属性赋值和方法注入
        PropertyValues pvs = beanDefinition.getPropertyValues();
        if (pvs != null) {
            for (PropertyValue pv : pvs.getPropertyValues()) {
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
                Object resolvedValue = resolveValueIfNecessary(beanName, beanDefinition, propertyName, originalValue);
                BeanWrapper bw = new BeanWrapperImpl(bean);
                bw.setPropertyValue(propertyName, resolvedValue);
            }
        }
    }
    catch (BeansException ex) {
        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    }
}

在applyPropertyValues()方法中,首先获取BeanDefinition对象的PropertyValues属性,然后遍历其中的PropertyValue对象,获取属性名称和属性值,并通过resolveValueIfNecessary()方法解析属性值,最后通过BeanWrapperImpl对Bean实例进行属性赋值。


在属性赋值过程中,如果属性值是一个引用类型,会尝试进行自动装配。具体实现如下:

protected Object resolveValueIfNecessary(String beanName, BeanDefinition beanDefinition, String propertyName,
        Object originalValue) {
    if (originalValue instanceof BeanDefinitionHolder) {
        // 如果属性值是一个BeanDefinitionHolder对象,说明属性是一个引用类型
        BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) originalValue;
        Object ref = resolveReference(bdHolder, beanName, propertyName);
        if (ref instanceof NullBean) {
            return null;
        }
        return ref;
    }
    else if (originalValue instanceof RuntimeBeanReference) {
        // 如果属性值是一个RuntimeBeanReference对象,说明属性是一个引用类型
        RuntimeBeanReference ref = (RuntimeBeanReference) originalValue;
        return resolveReference(ref, beanName, propertyName);
    }
    else if (originalValue instanceof ObjectFactory) {
        // 如果属性值是一个ObjectFactory对象,说明属性是一个懒加载类型
        ObjectFactory<?> objectFactory = (ObjectFactory<?>) originalValue;
        return objectFactory.getObject();
    }
    else if (originalValue instanceof ObjectProvider) {
        // 如果属性值是一个ObjectProvider对象,说明属性是一个懒加载类型
        ObjectProvider<?> objectProvider = (ObjectProvider<?>) originalValue;
        return objectProvider.getObject();
    }
    else {
        // 如果属性值不是一个引用类型,直接返回原始值
        return originalValue;
    }
}

protected Object resolveReference(Object ref, String beanName, String propertyName) {
    if (ref instanceof RuntimeBeanReference) {
        // 如果引用类型是一个RuntimeBeanReference对象,说明需要进行自动装配
        RuntimeBeanReference reference = (RuntimeBeanReference) ref;
        String refName = reference.getBeanName();
        Object bean;
        try {
            bean = getBean(refName);
        }
        catch (BeansException ex) {
            throw new BeanCreationException(beanName, "Could not resolve reference to bean '" + refName + "' in property '" + propertyName + "'", ex);
        }
        if (bean instanceof NullBean) {
            return null;
        }
        return bean;
    }
    else if (ref instanceof BeanDefinitionHolder) {
        // 如果引用类型是一个BeanDefinitionHolder对象,说明需要进行自动装配
        BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) ref;
        return resolveReference(bdHolder.getBeanDefinition(), beanName, propertyName);
    }
    else {
        // 如果引用类型不是一个RuntimeBeanReference或者BeanDefinitionHolder对象,直接返回引用类型
        return ref;
    }
}

在resolveValueIfNecessary()方法中,如果属性值是一个BeanDefinitionHolder对象或者RuntimeBeanReference对象,说明属性是一个引用类型,需要进行自动装配。此时会调用resolveReference()方法进行引用的解析和自动装配。


在resolveReference()方法中,如果引用类型是一个RuntimeBeanReference对象或者BeanDefinitionHolder对象,说明需要进行自动装配。此时会通过getBean()方法获取引用类型对应的Bean实例,并返回该实例。如果获取不到Bean实例,则会抛出异常。


在自动装配的过程中,Spring会先根据属性的类型进行匹配,如果找到一个唯一的Bean实例,则使用该实例进行自动装配。如果还是找不到唯一的Bean实例,则会抛出异常。


除了自动装配外,Spring还支持手动装配,即通过配置元素来显式地指定属性值。例如:

<bean id="foo" class="com.example.Foo">
    <property name="bar" value="hello"/>
</bean>

上述配置表示创建一个名为foo的Bean实例,该实例的class属性为com.example.Foo,bar属性的值为字符串hello。


在手动装配的过程中,Spring会将配置的属性值解析为一个String类型的值,并将其转换为目标属性类型,最终将转换后的值设置到目标属性中。


以上就是Spring IOC源码分析的基本内容,通过阅读源码,我们可以深入理解Spring IOC的实现原理,为使用和定制Spring提供了很好的基础。

47bcb716c5fb4c125253a206d527ac9c.png

目录
相关文章
|
1月前
|
监控 Java 应用服务中间件
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
61 1
|
3天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
2天前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
23天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
44 2
|
1月前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
38 1
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
35 1
|
2月前
|
缓存 JavaScript Java
Spring之FactoryBean的处理底层源码分析
本文介绍了Spring框架中FactoryBean的重要作用及其使用方法。通过一个简单的示例展示了如何通过FactoryBean返回一个User对象,并解释了在调用`getBean()`方法时,传入名称前添加`&`符号会改变返回对象类型的原因。进一步深入源码分析,详细说明了`getBean()`方法内部对FactoryBean的处理逻辑,解释了为何添加`&`符号会导致不同的行为。最后,通过具体代码片段展示了这一过程的关键步骤。
Spring之FactoryBean的处理底层源码分析
|
3月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
264 18
|
3月前
|
XML Java 测试技术
spring复习01,IOC的思想和第一个spring程序helloWorld
Spring框架中IOC(控制反转)的思想和实现,通过一个简单的例子展示了如何通过IOC容器管理对象依赖,从而提高代码的灵活性和可维护性。
spring复习01,IOC的思想和第一个spring程序helloWorld