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

《JavaPub源码》

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提供了很好的基础。

硬核源码刨析 · Spring · JavaPub

硬核源码刨析 · SpringMVC · JavaPub

硬核源码刨析 · MyBatis · JavaPub

硬核源码刨析 · Dubbo · JavaPub

硬核源码刨析 · Netty · JavaPub

硬核源码刨析 · Elastic-Job · JavaPub

硬核源码刨析 · GoLang · JavaPub

猜你喜欢

转载自blog.csdn.net/qq_40374604/article/details/129760962