Spring Framework IOC 原理

发布于:2023-03-03 ⋅ 阅读:(289) ⋅ 点赞:(0)

缘由

Spring Framework 提供了除IOC之外的很多有意思的功能,深入研究其技术原理,可在项目技术选型上提供更多的思路和技术把控。Spring Framewrok 代码由大佬精心打磨,可以从功能实现上学习和模仿。另外Spring Framework是Java项目开发的基础,其他技术框架都会基于或者与Spring 兼容,研究其中的技术原理,可快速掌握其他技术框架的技术原理,比如 Spring boot \ Spring cloud...

简述

Spring Framework 出现的背景是,Java 对象之间调用关系复杂,为简化对象调用,Spring Framework 基于Dependency Injection,将对象的控制权转移到BeanFactory,由框架负责对象的生命周期,将对象与Bean进行映射,Bean的生命周期由完善的管理机制。

本文将会根据自己对Spring Framework的理解编辑。

正文

Spring Framework的核心技术非IOC莫属,BeanFactory接口可以将IOC的功能基本体现出来,子接口与子类实现各自的职责,层次清晰,职责明朗,可以作为面向对象的编程范文。

BeanFactory

注释中解释了Spring 的基本行为,基于Bean Definition创建Bean实例,由Bean Factory负责对象的创建、以及属性的赋值。

  1. 注释中提到一个说法,依赖 dependency injection 通常来说是比较好的。凭借 Dependency Injection 以推送的形式去配置应用对象通过setters 或者 constructors,而不是使用任何形式的拉去配置,比如BeanFactory lookup。
  2. BeanFactory会加载来自多种形式配置的 bean definition, 比如 xml 、配置bean的package ,bean definition 如何存储时无所谓的。鼓励支持bean之间引用的实现。
  3. 依赖注入功能是实现BeanFactory接口和子接口。

ListableBeanFactory

BeanFactory接口的扩展,可以列举所有的Bean实例,该接口的实现类要预加载所有单实例Bean.

HierarchicalBeanFactory

允许设置父容器,适用于web环境,Spring 有一个核心BeanFactory 还有一个Web BeanFactory.

ApplicationContext

BeanFactory定义了Spring Framework的基本思想和特性,解决了项目开发中核心痛点,另外还有其他的特性增加开发工作中的便利性,比如国际化、事件、资源加载等功能。

继承下列所有接口:

  1. EnvironmentCapable
  2. ListableBeanFactory
  3. HierarchicalBeanFactory
  4. MessageSource
  5. ApplicationEventPublisher
  6. ResourcePatternResolver

ConfigureableApplicationContext

BeanFactory接口的扩展,增加BeanFactory的配置能力,接口中的方法仅在容器启动或者销毁时使用,比如启动时需要的BeanFactoryPostProcessor, ApplicationListener, ResourceLoader ...


以上接口定义Spring Framework 框架的基本行为。

AbstractApplicationContext

ApplicationContext接口的抽象实现,已实现主要的Spring Frameword 特性,ApplicationContext接口定义的功能,都可以在此类中提供默认实现。

浏览源码,大致功能如下:

  1. 构造器中可设置 resourcePatternResolver 属性,创建PathMatchingResourcePatternResolver 对象。
  2. 构造器中可设置父容器,并融合父容器中的环境变量。
  3. 实现 ApplicationContext 中的接口,比如 publishEvent setStartupDate ...
  4. 实现 ConfigurationApplicationContext 中的接口,比如 addBeanFactoryPostProcessor addApplicationListener refresh() registerShutdownHook close ...

// refresh 方法涉及到的方法。
prepareRefresh prepareBeanFactory postProcessBeanFactory registryBeanPostProcessors invokeBeanFactoryPostProcessors initMessageSource initApplicationEventMulticaster initLifecycleProcessor registerListeners finishBeanFactoryInitialization finishRefresh

  1. 实现 BeanFactory 中的接口,比如 getBean isSingleton isTypeMatch
  2. 实现 ListableBeanFactory 中的接口,比如 containsBeanDefinition getBeanDefinitionNames findAnnotationOnBean ..
  3. 实现 HierarchicalBeanFactory 中的接口,比如 getParentBeanFactory getInternalParentBeanFactory ...
  4. 实现 MessageSource 中的接口,比如 getMessage getMessageSource ...
  5. 实现 ResourcePatternResolver 中的接口,比如getResources
  6. 实现 Lifecycle 中的接口,比如start stop isRunning
  7. 抽象方法 refreshBeanFactory ...

GenericApplicationContext

完整的ApplicationContext实现,实现了BeanDefinitionRegistry接口的方法,拥有注册BeanDefinition的能力,可以覆盖一些BeanFactory的属性。

  1. 构造器中创建 DefaultListableBeanFactory。
  2. 配置BeanFactory allowBeanDefinitionOverriding bean定义覆盖的问题 allowEagerClassLoading 是否加载标记为懒加载的类。
  3. 实现 AbstractApplicationContext 中的虚拟方法 refreshBeanFactory getBeanFactory ...
  4. 实现 BeanDefinitionRegistry 接口,比如 registerBeanDefinition isBeanNameInUse
  5. 手动注册Bean registerBean.

AnnotationConfigApplicationContext

接收 component class 、Configuration annotated class,@Component JSR330 javax.inject annotation.
允许一个接一个使用register方法注册类,扫描class path。Bean annotation 可以被后续的覆盖。

构造器中初始化 AnnotatedBeanDefinitionReader ClassPathBeanDefinitionScanner。或者手动注册一个启动类,并启动容器启动操作 refresh.

DefaultListableBeanFactory

一个很核心的类,可以说是IOC功能的承载者。继承抽象类 AbstractAutowireCapableBeanFactory。

  1. 实现 BeanFactory 剩余的接口实现 getBean getBeanProvider resolveBean ...
  2. 实现 ListableBeanFactory 接口,比如 getBeanDefinitionNames containsBeanDefinition ...
  3. 实现 ConfigurableListableBeanFactory 接口,比如 registerResolvableDependency isAutowireCandidate preInstantiateSingletons
  4. 实现 BeanDefinitionRegistry 接口,比如 registerBeanDefinition registerSingleton
  5. 处理依赖的一些方法。resolveNamedBean resolveDependency doResolveDependency resolveMultipleBeans

AbstractAutowireCapableBeanFactory

实现默认的Bean创建,具有RootBeanDefinition指定的全部功能。
使用构造器解析提供bean创建,属性填充,wiring,初始化。
支持构造器注入、名字或类型注入。
没有任何的bean注册能力。


通过上述的接口和类的介绍,BeanFactory的子类和相关子接口有个了大致的了解,使用由上至下的顺序介绍了spring Ioc 容器的功能,其中还有一些类或者接口没有介绍到,可以在源码中进入详细了解。

Spring Framework 启动流程。

Spring的启动流程可以简单描述为启动框架的提供功能,加载并初始化开发人员定义的类。

Spring Framework 目前几乎所有开发人员都会采用基于注解的形式开发应用。首先会使用new AnnotationConfigApplicationContext() 启动一个Spring Application Context。

AnnotationConfigApplicationContext 是继承了 GenericApplicationContext 和 AbstractApplicationContext,加载子类时会先加载父类,并使用父类的无参构造或者指定的有参构造创建父类。GenericApplicationContext的无参构造器中会创建一个DefaultListableBeanFactory,对于DefaultListableBeanFactory的父类AbstractAutowireCapableBeanFactory 同样也会被加载到Jvm中,创建对应Class对象。AbstractApplicationContext是一个抽象类,不过其中静态属性和静态方法也会被初始化,创建 PathMatchingResourcePatternResolver 作为默认的 ResourcePatternResolver。

初始化完父类后,就会执行 AnnotationConfigApplicationContext 无参构造器,创建 AnnotatedBeanDefinitionReader 和 ClassPathBeanDefininationScanner。

AnnotatedBeanDefinitionReader的构造器中,除了一些赋值外,会执行 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); 这行代码对基于注解的应用尤为的至关重要。其中会将一批框架提供的配置类包装为Bean Definition放入BeanFactory,其中包括:

  • ConfigurationClassPostProcessor
  • AutowiredAnnotationBeanPostProcessor
  • CommonAnnotationBeanPostProcessor
  • EventListenerMethodProcessor
  • DefaultEventListenerFactory
  • AnnotationAwareOrderComparator
  • ContextAnnotationAutowireCandidateResolver
    大多是一些后置处理器和工具类。

ClassPathBeanDefininationScanner主要是用来扫描classpath路径下类,继承 ClassPathScanningCandidateComponentProvider 提供扫描过程中的一些配置。


以上就是AnnotationConfigApplicationContext对象创建的流程,即将进入 AbstractApplicationContext.refresh() 方法。

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

            // 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.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();

                // 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();

                // 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();
                contextRefresh.end();
            }
        }
    }

这是一个Spring context的启动流程,有些context可以启动多次,有些只能启动一次,另外也会提供取消启动和重新启动的API.

prepareRefresh()

准备启动Spring context

  1. 设置启动时间
  2. 激活工作标识
  3. 初始化context中所有的 placeholder property sources
  4. 验证启动比如设置的变量
  5. 保存重新启动前的ApplicationListener

obtainFreshBeanFactory()

通知子类刷新内部的BeanFactory,其中子类比较关注 GenericApplicationContext。

  1. 原子更新刷新标识。
  2. 设置BeanFactory的唯一标识。

prepareBeanFactory()

准备上下文中的BeanFactory,配置标准context中的classLoader 和一些 PostProcessors

  1. 若要使用SPEL,则配置StandardBeanExpressionResolver。
  2. 增加ResourceEditorRegistrar 到 propertyEditorRegistrar。
  3. 配置分析依赖时需要忽略的接口 EnvironmentAware EmbeddedValueResolverAware ResourceLoaderAware
  4. 配置 ApplicationContextAwareProcessor ApplicationListenerDetector ApplicationEventPublisherAware MessageSourceAware ApplicationContextAware ApplicationStartupAware,这些接口需要框架提供支持,不需要在依赖注入时处理。
  5. 若要使用加载时创建代理,则配置LoadTimeWeaverAwareProcessor ContextTypeMatchClassLoader
  6. 配置处理依赖注入时需要注入的对象,比如Bean需要一个 ApplicationContext,在进行注入时会将配置的对象注入到Bean当中。
  7. 注册几个环境变量相关的Bean,systemProperties systemEnvironment。

postProcessBeanFactory()

处理 postProcessBeanFactory,暂未发现有效调用,是个空方法。

invokeBeanFactoryPostProcessors()

调用已注册的postProcessBeanFactory。

使用委托模式将PostProcessor的注册工作放置到 PostProcessorRegistrationDelegate中,调用 invokeBeanFactoryPostProcessors(),处理context中的BeanFactoryPostProcessor。
判断BeanFactory是否继承BeanDefinitionRegistry接口,没有继承就会直接调用 invokeBeanFactoryPostProcessors处理context中的beanFactoryPostProcessors。若继承BeanDefinitionRegistry

  1. 对context中的beanFactoryPostProcessors,进行分类,属于BeanDefinitionRegistryPostProcessor的 postProcessor 执行 postProcessBeanDefinitionRegistry()。
  2. 获取BeanFactory中的 BeanDefinitionRegistryPostProcessor.class 类型的BeanName数组,接下来就会遍历BeanName数组。
  3. 若bean实现了 PriorityOrdered \ Ordered 类,就会调用 invokeBeanDefinitionRegistryPostProcessors 处理BeanDefinition的注册工作。逻辑较多,独立在后续说明。
  4. 接着会调用 invokeBeanFactoryPostProcessors 执行 postProcessBeanFactory().
  5. 对@Configuration的类创建代理,并注册 ImportAwareBeanPostProcessor 到 BeanPostProcessor 的 BeanPostProcessor.
  6. 对BeanFactoryPostProcessors进行分类和排序 invokeBeanFactoryPostProcessors.

registerBeanPostProcessors()

注册BeanPostProcessors 去拦截Bean的创建。

  1. PostProcessorRegistrationDelegate.registerBeanPostProcessors();
  2. 将BeanFactory中的 BeanPostProcessor BeanDefinition 转换为 BeanFactory的 BeanPostProcessor.

initMessageSource()

初始化context中的国际化。

initApplicationEventMulticaster()

初始化context中的事件机制。

onRefresh()

初始化在特定的子context中的特定Bean。

registerListeners()

检查context中的所有Listener,并注册他们。

finishBeanFactoryInitialization()

实例化所有非懒加载的单实例Bean。

finishRefresh()

发布事件。

ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()

  1. 检查是否已执行过,不能重复执行。
  2. 进入 processConfigBeanDefinitions()。
  3. 获取Context中被@Configuration标注的类。

    1. 判断BeanDefinition是否拥有属性 ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE,作为已处理的标识。
    2. 借助工具类判断 ConfigurationClassUtils.checkConfigurationClassCandidate()

      1. BeanDefinition中有BeanClassName属性的,没有FactoryMethodName的。
      2. 获取BeanDefinition中的AnnotationMetadata,可通过AnnotationMetadata.introspect(beanClass) metadataReaderFactory.getMetadataReader(className) 获取。
      3. AnnotationMetadata 中有设置 @Configuration注解的并且注解的属性 proxyBeanMethods为TRUE的。可以作为 full configuration 进行后续的 parse处理。
      4. 那些有 AnnotationMetadata 或者有 Component ComponentScan Import ImportResource 的注解 或者 有类中有方法使用@Bean BeanDefinition 就是一个 lite configuration 类。可会进行后续的 parse处理。
      5. 若AnnotationMetadata中有Order注解,会设置到BeanDefinition中。
      1. 将符合条件的BeanDefinition收集起来。
  4. 对获取到的BeanDefinition进行排序。
  5. 获取并支持定制 componentScanBeanNameGenerator importBeanNameGenerator
  6. 检查并设置 StandardEnvironment
  7. 开始 parse @Configuration标识的类(BeanDefinition)

    1. 创建 ConfigurationClassParser 对象。
    2. 进入 processConfigurationClass() 开始进行解析工作。
    3. 进入 ConditionEvaluator.shouldSkip(),会对@Condition注解进行解析判断是否需要解析此Bean。
    4. 使用反射技术根据 className 转化为 SourceClass.
    5. 递归调用 doProcessConfiguration(SourceClass)。
    6. processMemberClasses() 处理标有 @Component 注解的内部类。

      1. 解析内部类是否有被@Configuration的,会直接调用 processConfigurationClass 进行解析。
    7. processPropertySource() 处理标有 @PropertySource 注解的类。

      1. AnnotationConfigUtils.attributesForRepeatable() 解析出类上的@PropertySource数组,逐个处理。
      2. 当前 environment 必须是 ConfigurableEnvironment 的子类。
      3. 获取注解中的 name \ encoding \ value \ ignoreResourceNotFound \ factory。
      4. 将加载到的信息放到当前环境当中。
    8. ComponentScanAnnotationParser.parse() 处理标有 @ComponentScan 注解的类。

      1. 创建 ClassPathBeanDefinitionScanner 对象。
      2. 设置 BeanNameGenerator \ ScopedProxyMode \ ScopeMetadataResolver \ ResourcePattern \ IncludeFilter \ ExcludeFilter \ BeanDefinitionDefaults .
      3. 解析注解中的 basePackages \ basePackageClasses .
      4. 进入 doScan().
      5. 加载每个 package,将获取到的 metadataReader 作为创建 ScannedGenericBeanDefinition 的参数。
      6. 判断 ScannedGenericBeanDefinition 是否有被@Component注解,符合的放入方法结果集中。
      7. 遍历结果集。
      8. 判断是否实现 AbstractBeanDefinition,调用postProcessBeanDefinition进行处理。
      9. 判断是否实现 AnnotatedBeanDefinition,调用AnnotationConfigUtils.processCommonDefinitionAnnotations()进行处理。
      10. 根据BeanDefinition的冲突处理结果注册BeanDefinition.
      11. 从加载到BeanDefinition中过滤是否有@Configuration标注的类,有的话直接调用parse().
    9. processImports() 处理标有 @Import 注解的类。

      1. 判断是否有循环导入的问题
      2. 处理导入的类实现ImportSelector 接口

        1. 加载被导入的类。
        2. ParserStrategyUtils.instantiateClass() 将注解解析为 ImportSelector 对象 selector。
        3. 若 selector 实现了 DeferredImportSelector,直接放入deferredImportSelectorHandler。
        4. 递归处理导入类上的@Import。
      3. 处理导入的类实现ImportBeanDefinitionRegistrar 接口

        1. 加载被导入的类。
        2. ParserStrategyUtils.instantiateClass() 将注解解析为 ImportBeanDefinitionRegistrar 对象 registrar。
        3. 添加到 ImportBeanDefinitionRegistrar 中,在@Configuration注解解析完成后再进行加载。
      4. 处理导入的其他类

        1. 直接使用 processConfigurationClass 处理。
    10. addImportedResource() 处理标有 @ImportResource 注解的类。

      1. AnnotationConfigUtils.attributesFor() 解析出 AnnotationAttributes importResource 。
      2. 将解析出的resource 放入 ImportedResource 中。
    11. addBeanMethod() 处理标有 @Bean 注解的方法。

      1. 获取类中使用@Bean的方法 使用Java反射和ASM获取两遍,并进行比较方法数量和方法名字的比较。
      2. 比较通过的方法放入结果集中。
      3. 将结果集逐个放入BeanMethod
    12. processInterfaces() 处理接口的默认方法。

      1. 处理继承的抽象类非抽象方法或者接口的默认方法
      2. 将父类或者实现的接口中的@Bean标注的方法放入 BeanMethod
      3. 循环处理父类或者父接口.
    13. 解析 superclass.

      1. 处理父类,直接返回循环处理.
  8. this.deferredImportSelectorHandler.process() 开始处理延迟导入队列.

    1. 将队列中的ImportSelector逐个放入 DeferredImportSelectorGroupingHandler.registry()
    2. 实现逻辑较复杂,后续会继续分析.
  9. ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()

    1. registerBeanDefinitionForImportedConfigurationClass

      1. new AnnotatedGenericBeanDefinition(metadata) 构建 BeanDefinition 对象.
      2. 获取 BeanDefinition 中的 scopeMetadata, 经 scopeMetadataResolver.resolveScopeMetadata()处理 设置BeanDefinition的scope
      3. importBeanNameGenerator.generateBeanName() 生成BeanName.
      4. AnnotationConfigUtils.processCommonDefinitionAnnotations()
      5. 注册BeanDefinition.
    2. loadBeanDefinitionsForBeanMethod
    3. loadBeanDefinitionsFromImportedResources
    4. loadBeanDefinitionsFromRegistrars
  10. 对比parse前后的registry中的BeanDefinition数量,将未处理的BeanDefiniton继续处理.
  11. Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到