【Spring系列-02】IoC 容器与依赖注入源码剖析

95 阅读5分钟

【Spring系列-02】IoC 容器与依赖注入源码剖析

一、概念

Spring开发中,@Autowired自动注入依赖、循环依赖时成功与报错的差异,均与IoC容器和依赖注入机制相关。深入源码可帮助理解并解决这些问题。

二、BeanFactory与ApplicationContext的继承体系

(一)功能边界

核心接口BeanFactory职责ApplicationContext职责
ListableBeanFactory按类型或名称获取Bean定义列表,查询符合条件的Bean定义。继承该接口功能,新增国际化、事件发布等扩展功能。
HierarchicalBeanFactory支持父子BeanFactory结构,可获取父BeanFactory。继承该结构管理能力,增强上下文层次结构支持。

(二)ApplicationContext为何是BeanFactory的超集

Spring Framework 6.x中,AbstractApplicationContext封装BeanFactory,实现其接口并扩展资源加载、国际化等功能。核心源码显示其通过持有ConfigurableListableBeanFactory实例,在obtainFreshBeanFactory方法中创建管理,实现功能扩展。

// AbstractApplicationContext部分源码
public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    private ConfigurableListableBeanFactory beanFactory;
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }
}

(三)实战

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

public class BeanFactoryVsApplicationContext {
    public static void main(String[] args) {
        // BeanFactory获取Bean
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
        Object beanFromBeanFactory = beanFactory.getBean("exampleBean");
        
        // ApplicationContext获取Bean
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Object beanFromApplicationContext = applicationContext.getBean("exampleBean");
    }
}

两者均可获取exampleBean,但ApplicationContext提供自动装配、国际化等更丰富功能。

流程图(BeanFactory与ApplicationContext继承关系)

image.png

三、BeanDefinition加载与解析流程

(一)资源定位→解析→注册全流程

Spring 6.x中XmlBeanDefinitionReaderdoLoadBeanDefinitions是核心方法:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
        throws BeanDefinitionStoreException {
    try {
        Document doc = doLoadDocument(inputSource, resource);
        return registerBeanDefinitions(doc, resource);
    } catch (Exception ex) {
        // 异常处理
    }
}
  1. 资源定位:通过Resource接口(如ClassPathResource)定位配置文件。
  2. 解析DocumentLoader转换资源为Document,再由BeanDefinitionParserDelegate提取信息。
  3. 注册:解析后的BeanDefinition注册到BeanDefinitionRegistry(如DefaultListableBeanFactory)。

(二)关键数据解析

  1. propertyValues属性:解析<property>标签值,创建PropertyValue存入集合。
  2. scope属性:解析<bean>scope值(如singleton),设置到BeanDefinitionscope字段。

(三)协作时序图

image.png

四、循环依赖源码分析与解决方案

(一)复现循环依赖场景

  1. 构造器注入循环依赖
public class A { private B b; public A(B b) { this.b = b; } }
public class B { private A a; public B(A a) { this.a = a; } }
  1. setter注入循环依赖
public class C { private D d; public void setD(D d) { this.d = d; } }
public class D { private C c; public void setC(C c) { this.c = c; } }
  1. 多例Bean循环依赖scope="prototype"的Bean默认不支持循环依赖,会抛异常。

(二)Spring处理循环依赖的判定标准

DefaultSingletonBeanRegistrybeforeSingletonCreation方法检测循环依赖:

protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) &&!this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
}

Bean创建时加入singletonsCurrentlyInCreation集合,重复创建则抛异常。isDependent方法检查依赖关系。

(三)实战

通过自定义BeanPostProcessor验证循环依赖处理时机:

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化前检查循环依赖: " + beanName);
        return bean;
    }
}

断点可设在AbstractAutowireCapableBeanFactoryresolveCircularReference方法。

流程图(循环依赖检测流程)

image.png

五、三级缓存设计原理

(一)三级缓存源码定义与交互逻辑

DefaultSingletonBeanRegistry中定义三级缓存:

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 完全初始化Bean
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 提前暴露Bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 单例Bean工厂

获取Bean时依次从三级缓存查询:先singletonObjects,再earlySingletonObjects,最后通过singletonFactories创建提前暴露Bean。

(二)为什么需要三级缓存而非两级

两级缓存缺少singletonFactories时,提前暴露的Bean无法经BeanPostProcessor处理。singletonFactories缓存工厂对象,通过getObject方法获取SmartInstantiationAwareBeanPostProcessorgetEarlyBeanReference处理后的Bean,解决循环依赖。

(三)状态流转图

image.png

六、Bean创建流程的关键扩展点

(一)按Bean生命周期顺序列出扩展点

  1. 实例化阶段InstantiationAwareBeanPostProcessorpostProcessBeforeInstantiation,实例化前调用,可返回代理对象。
  2. 初始化阶段BeanPostProcessorpostProcessAfterInitialization,初始化后调用,可增强Bean(如AOP代理)。

(二)源码定位

  1. 实例化阶段:AbstractAutowireCapableBeanFactorycreateBean调用applyBeanPostProcessorsBeforeInstantiation
  2. 初始化阶段:AbstractAutowireCapableBeanFactoryinitializeBean调用applyBeanPostProcessorsAfterInitialization

(三)实战

自定义BeanPostProcessor处理属性加密解密:

@Component
public class EncryptionBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if (bean instanceof EncryptableBean) {
            ((EncryptableBean) bean).setEncryptedProperty(decrypt(((EncryptableBean) bean).getEncryptedProperty()));
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean instanceof EncryptableBean) {
            ((EncryptableBean) bean).setEncryptedProperty(encrypt(((EncryptableBean) bean).getEncryptedProperty()));
        }
        return bean;
    }
    // 加密解密方法省略
}

七、源码级定制化

(一)自定义BeanDefinitionReader解析JSON配置

继承AbstractBeanDefinitionReader实现JSON解析:

public class JsonBeanDefinitionReader extends AbstractBeanDefinitionReader {
    public JsonBeanDefinitionReader(DefaultListableBeanFactory beanFactory) { super(beanFactory); }

    @Override
    public int loadBeanDefinitions(Resource... resources) {
        int count = 0;
        for (Resource resource : resources) {
            count += loadBeanDefinitions(resource);
        }
        return count;
    }

    public int loadBeanDefinitions(Resource resource) {
        // 解析JSON并注册BeanDefinition,逻辑省略
        return 1;
    }
}

注册到容器:

public class JsonConfigApp {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        JsonBeanDefinitionReader reader = new JsonBeanDefinitionReader(beanFactory);
        reader.loadBeanDefinitions(new ClassPathResource("config.json"));
        ApplicationContext context = new GenericApplicationContext(beanFactory);
    }
}

(二)扩展DefaultListableBeanFactory实现超时控制

public class TimeoutAwareBeanFactory extends DefaultListableBeanFactory {
    private long timeout = 1000;
    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws Exception {
        long startTime = System.nanoTime();
        try {
            return super.createBean(beanName, mbd, args);
        } finally {
            long elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);
            if (elapsed > timeout) {
                throw new RuntimeException("Bean创建超时: " + beanName);
            }
        }
    }
}

八、推荐源码学习路线图

  1. 基础入手:从BeanFactoryDefaultListableBeanFactory开始,掌握Bean注册与获取逻辑。
  2. 加载流程:研究BeanDefinition加载解析,重点关注XmlBeanDefinitionReaderAnnotationConfigApplicationContext
  3. 循环依赖与缓存:学习循环依赖处理及三级缓存原理,研读DefaultSingletonBeanRegistry相关方法。
  4. 扩展点与生命周期:探究BeanPostProcessor等扩展点及调用时机,梳理Bean完整生命周期对应源码。
  5. 高级定制:尝试自定义BeanDefinitionReader、扩展DefaultListableBeanFactory,深化对容器扩展性的理解。