专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

IOC容器初始化和循环依赖解决原理

SpringApplication 实例化

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 确定应用的类型,分为SERVLET、REACTIVE。关系到 ApplicationContext、Environment 实现类的实例化
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 从 spring.factories 加载 ApplicationContextInitializer 设置到 ApplicationContext 中
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 从 spring.factories 加载 ApplicationListener 设置到 ApplicationContext 中
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 识别启动类。根据执行栈中,调用方法为 main 来确定启动类
    this.mainApplicationClass = deduceMainApplicationClass();
}

private Class<?> deduceMainApplicationClass() {
    try {
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}

注册ApplicationContextInitializer

通过实例化 SpringApplication ,其构造器内部通过 SpringFactoriesLoader.loadFactoryNames 从 spring.factories 加载。

默认有:

  • DelegatingApplicationContextInitializer
  • SharedMetadataReaderFactoryContextInitializer
  • ContextIdApplicationContextInitializer
  • ConfigurationWarningsApplicationContextInitializer
  • ServerPortInfoApplicationContextInitializer
  • ConditionEvaluationReportLoggingListener

注册ApplicationListener

通过实例化 SpringApplication ,其构造器内部通过 SpringFactoriesLoader.loadFactoryNames 从 spring.factories 加载。

默认有:

  • ConfigFileApplicationListener
  • AnsiOutputApplicationListener
  • LoggingApplicationListener
  • ClasspathLoggingApplicationListener
  • BackgroundPreinitializer
  • DelegatingApplicationListener
  • ParentContextCloserApplicationListener
  • ClearCachesApplicationListener
  • FileEncodingApplicationListener
  • LiquibaseServiceLocatorApplicationListener

AnnotationConfigServletWebServerApplicationContext 实例化

注册BeanDefinitionRegistryPostProcessor

org.springframework.boot.SpringApplication#createApplicationContext,创建 AnnotationConfigServletWebServerApplicationContext 对象时,调用其构造器

public AnnotationConfigServletWebServerApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

在创建 AnnotatedBeanDefinitionReader 时,向 beanfactory 设置了 dependencyComparator = AnnotationAwareOrderComparator;autowireCandidateResolver = ContextAnnotationAutowireCandidateResolver。

默认有:

  • ConfigurationClassPostProcessor
  • AutowiredAnnotationBeanPostProcessor
  • CommonAnnotationBeanPostProcessor
  • EventListenerMethodProcessor
  • DefaultEventListenerFactory

回调ApplicationContextInitializer.initialize

在 org.springframework.boot.SpringApplication#applyInitializers 方法中进行回调。

作用:

  • DelegatingApplicationContextInitializer,通过获取环境变量 context.initializer.classes (逗号分隔)指定的ApplicationContextInitializer实现类,并触发回调
  • SharedMetadataReaderFactoryContextInitializer,注册了 CachingMetadataReaderFactoryPostProcessor
  • ContextIdApplicationContextInitializer,注册了 ContextId
  • ConfigurationWarningsApplicationContextInitializer注册了ConfigurationWarningsPostProcessor,输出警告
  • ServerPortInfoApplicationContextInitializer,自身实现了ApplicationListener,监听WebServerInitializedEvent事件,事件触发时将服务监听端口注入到环境变量中,可以使用 @Value(“${local.server.port}”) 获取到
  • ConditionEvaluationReportLoggingListener 注册了 ConditionEvaluationReportListener ,监听 ContextRefreshedEvent、ApplicationFailedEvent 事件。对容器初始化成功、失败做处理(打印日志提醒)

总结

通过默认的 ApplicationContextInitializer,向 ApplicationContext 注入了 BeanDefinitionRegistryPostProcessor:

  • CachingMetadataReaderFactoryPostProcessor
  • ConfigurationWarningsPostProcessor

向 ApplicationContext 设置了事件监听器:

  • ServerPortInfoApplicationContextInitializer,监听WebServerInitializedEvent事件
  • ConditionEvaluationReportListener,监听ContextRefreshedEvent、ApplicationFailedEvent事件

刷新ApplicationContext的主流程

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    // 应用启动各阶段事件的监听器。默认只有 spring.factories 配置的 EventPublishingRunListener
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 创建 Environment 实现类对象,Servlet 环境下为 StandardServletEnvironment
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        configureIgnoreBeanInfo(environment);
        Banner printedBanner = printBanner(environment);
        // 创建 ApplicationContext,其中注册了5个 BeanDefinitionRegistryPostProcessor
        context = createApplicationContext();
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                                                         new Class[] { ConfigurableApplicationContext.class }, context);
        // 设置类型转换器:ApplicationConversionService
        // 回调 ApplicationContextInitializer
        // 将primarySource,即主配置类注册到 BeanFactory 中
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 执行 ApplicationContext refresh 操作,进行一系列的初始化操作
        refreshContext(context);

        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }
        listeners.started(context);
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        // 设置ClassLoader、BeanExpressionResolver、PropertyEditorRegistrar;
        // 注册 BeanPostProcessor:ApplicationContextAwareProcessor、ApplicationListenerDetector
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            // 注册 BeanPostProcessor:WebApplicationContextServletContextAwareProcessor
            // 注册 Scope(向BeanFactory.scopes属性设值):RequestScope、SessionScope
            // 注册依赖:ServletRequest-RequestObjectFactory、ServletResponse-ResponseObjectFactory、HttpSession-SessionObjectFactory、WebRequest-WebRequestObjectFactory
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            // 调用BeanFactoryPostProcessor:
            // 1.先调用提前实例化过的BeanDefinitionRegistryPostProcessor:CachingMetadataReaderFactoryPostProcessor、ConfigurationWarningsPostProcessor、ConfigurationClassPostProcessor
            // 2.再调用注册到 BeanFactory 中的 BeanDefinitionRegistryPostProcessor(实现了 PriorityOrdered 接口的):ConfigurationClassPostProcessor,完成配置的导入,包括 spring.factories 定义的自动化配置类
            // 3.再调用注册到 BeanFactory 中的 BeanDefinitionRegistryPostProcessor(实现了 Ordered 接口的):默认没有
            // 4.再调用注册到 BeanFactory 中的其余的 BeanDefinitionRegistryPostProcessor:默认没有
            // 5.再调用注册到 BeanFactory 中的BeanDefinitionRegistryPostProcessor.postProcessBeanFactory 方法:CachingMetadataReaderFactoryPostProcessor、ConfigurationWarningsPostProcessor、ConfigurationClassPostProcessor
            // 6.再调用注册到 BeanFactory 中的BeanFactoryPostProcessor.postProcessBeanFactory 方法:PropertySourceOrderingPostProcessor
            // 7.依次执行实现了PriorityOrdered、Ordered、普通BeanFactoryPostProcessor 
            // PropertySourcesPlaceholderConfigurer(PriorityOrdered)、EventListenerMethodProcessor、ConfigurationBeanFactoryMetadata、PreserveErrorControllerTargetClassPostProcessor(no order)
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // BeanPostProcessor的实例化并注册到beanfactory。按照PriorityOrdered、Ordered、普通、MergedBeanDefinitionPostProcessor 的顺序注册;最后注册一个 ApplicationListenerDetector
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

            // 实例化剩余的单例的 bean 对象(重点)
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();
        }

        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
            }

            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();

            // Reset 'active' flag.
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }

配置加载流程

由 invokeBeanFactoryPostProcessors 方法调用时,回调到ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry来完成配置的加载以及BeanDefinition的注册

// ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    int registryId = System.identityHashCode(registry);
    if (this.registriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
            "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
    }
    if (this.factoriesPostProcessed.contains(registryId)) {
        throw new IllegalStateException(
            "postProcessBeanFactory already called on this post-processor against " + registry);
    }
    this.registriesPostProcessed.add(registryId);

    // 处理所有配置类,包括 FullConfigure、LiteConfigure。使用 ConfigurationClassParser 进行解析。包括对 spring.factories 导入的自动化配置
    processConfigBeanDefinitions(registry);
}

// ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass
private void loadBeanDefinitionsForConfigurationClass(
            ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

    if (trackedConditionEvaluator.shouldSkip(configClass)) {
        String beanName = configClass.getBeanName();
        if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
            this.registry.removeBeanDefinition(beanName);
        }
        this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
        return;
    }

    // 以下步骤进行一系列的 BeanDefinition 注册
    if (configClass.isImported()) {
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }

    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

bean实例化

104_1.png

@Autowire注入流程

104_2.png

循环依赖

配置

@Component
public class Person {

    @Autowired
    private Cat cat;

}

@Component
public class Cat {

    @Value("${name:hehe}")
    private String name;

    @Autowired
    private Person person;
}

流程说明

前提:cat先于person进行实例化

1、 实例化cat时,先从singletonObjects获取cat实例,此时由于未进行过实例化,singletonObjects返回null,且singletonsCurrentlyInCreation中不存在cat;因此无法获取到早期bean,返回null
2、 进入到实例化阶段时,先调用beforeSingletonCreation方法将cat添加到singletonsCurrentlyInCreation中,表示实例化中
3、 通过InstantiationStrategy策略实现类,调用默认构造器实例化bean,默认支持循环依赖的情况下,添加一个绑定beanName(cat)的ObjectFactory到singletonFactories中,移出earlySingletonObjects,放入registeredSingletons
4、 之后在执行populate设置cat属性时,BeanPostProcessor实现类AutowiredAnnotationBeanPostProcessor执行属性注入解析依赖bean,重新触发了beanfactory.getBean(“person”),进入person的实例化
5、 同样的,先从singletonObjects获取person实例,此时由于未进行过实例化,singletonObjects返回null,且singletonsCurrentlyInCreation中不存在person;因此无法获取到早期bean,返回null
6、 进入到实例化阶段时,先调用beforeSingletonCreation方法将person添加到singletonsCurrentlyInCreation中,表示实例化中
7、 通过InstantiationStrategy策略实现类,调用默认构造器实例化bean,之后BeanPostProcessor实现类AutowiredAnnotationBeanPostProcessor执行属性注入时解析依赖bean,重新触发了beanfactory.getBean(“cat”),进入cat的实例化
8、 此时,先从singletonObjects获取cat实例,此时由于未进行过实例化,singletonObjects返回null;因为第一步已经将cat放入了singletonsCurrentlyInCreation,因此尝试从 earlySingletonObjects 获取cat,但此时早期的cat实例没有放入,返回null;又因为第三步放入了绑定beanName(cat)的ObjectFactory,因此调用 getEarlyBeanReference 获取到了第三步实例化后的cat, 将cat实例放入earlySingletonObjects,并移除绑定beanName(cat)的ObjectFactory
9、 由于能获取到cat的早期bean,此时调用 getObjectForBeanInstance ,返回调用FactoryBean.getObject的对象,或者是bean对象自身(取决于bean是否为FactoryBean)
10、 返回了cat的早期bean(即未经过属性设置、初始化方法调用、BeanPostProcessor处理的bean)给到person
11、 拿到cat实例后,AutowiredAnnotationBeanPostProcessor 将它注入到person对象中,完成cat属性的依赖注入
12、 之后对person执行剩余的初始化操作,比如:Aware方法回调、BeanPostProcessor 方法回调、初始化方法调用、注册销毁回调方法等等
13、 将person移出singletonsCurrentlyInCreation、将person实例放入singletonObjects、放入registeredSingletons
14、 调用 getObjectForBeanInstance ,返回调用FactoryBean.getObject的对象,或者是bean对象自身(取决于bean是否为FactoryBean)
15、 此时cat实例拿到了依赖类对象person,注入到属性中,完成person属性的依赖注入
16、 之后对cat执行剩余的初始化操作,比如:Aware方法回调、BeanPostProcessor 方法回调、初始化方法调用、注册销毁回调方法等等
17、 调用getSingleton方法,由于singletonsCurrentlyInCreation存在cat,尝试从earlySingletonObjects获取早期的cat对象,由于第8步将cat对象放入了earlySingletonObjects中,因此获取到早期的cat对象,用于检查是否需要抛出 BeanCurrentlyInCreationException 异常
18、 将cat从singletonsCurrentlyInCreation移除,放入singletonObjects、放入registeredSingletons、移除绑定beanName(cat)的ObjectFactory、移除earlySingletonObjects
19、 此时完成了cat的实例化,并且person在这个过程中也完成了实例化,并且两者都记录到了singletonObjects

未经允许不得转载:搜云库技术团队 » IOC容器初始化和循环依赖解决原理

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们