决战圣地玛丽乔亚Day40---Spring容器的启动流程
Spring启动过程?
tips:
BeanDefinition的定义:
Spring是Bean的容器,Bean和普通的java实例的区别就在于bean在java的实例上加入了一些Spring封装的属性(作用域,加载模式,是否单例等...)
BeanDefinition就是用来实例化对应的bean。
BeanDefinitionReader定义:
从配置文件读取Bean解析成BeanDefinition
BeanDefinitionRegistry:
存储bean解析后的BeanDefinition
BeanFacotry:
根据BeanDefinition将Bean生产出来并保存。
BeanPostProcessor :
对Bean的生命周期进行干预
BeanFactoryPostProcessor:
对BeanFactory进行干预
在聊启动流程之前,放几张图:
1.初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中
如果是注解的方式,会调用AnnotationConfigApplicationContext
如果是使用xml方式,会调用ClassPathXmlApplicationContext
我们以AnnotationConfigApplicationContext 为例进行分析。
1. this():
调用自身构造器,主要是实例化两个对象,一个是
AnnotatedBeanDefinitionReader
INSTANCE:
所以这里的INSTANCE是一个空的。这里是在设置默认的Bean名称生成器
然后new 一个 AnnotationScopeMetadataResolver
这里的
ScopedProxyMode.NO代表不创建代理对象
ScopedProxyMode有三种类型:NO,INTERFACES,TARGET_CLASS.
NO是不创建代理对象,应用Bean的作用域,例如是多例则不需要创建代理对象。
INTERFACES使用JDK动态代理生成代理对象。
TARGET_CLASS使用CGLIB创建代理对象。
Bean的代理主要是由于作用于不同会产生线程安全问题,如果单例模式的Bean注入到多例的作用域可能会有污染,就可以使用代理模式来生成对应的bean。
紧接着是两个断言,进行非空判断。
next,初始化BeanDefinitionRegistry、Environment和ConditionEvaluator
这里是注解形式,所以ResouceLoader是null即可。ConditionEvaluator用于根据条件工具,可以根据不同的Condition注解对bean加载的时机等进行判断。
最重要一行代码:
registerAnnotationConfigProcessors的作用是注册一些注解处理器,以便能够处理不同的注解,并将其转化为对应的BeanDefinition对象,并将其注册到容器中,方便后续使用。
初始化的过程可以看到初始化beanFactory为DefaultListableBeanFactory
并且通过unwrapDefaultListableBeanFactory方法,从参数(BeanDefinitionRegistry)registry中获取DefaultListableBeanFactory对象。
然后为bean设置DependencyComparator(用来比较两个bean的依赖关系)和AutowireCandidateResolver(用于确定哪些Bean对象可以被自动注入到其他Bean对象中)
这两个方法是DefaultListableBeanFactory实现的,这也是为什么要使用DefaultListableBeanFactory的原因。
调用setDependencyComparator和setAutowireCandidateResolver等方法是为了设置BeanFactory的扩展点,以便在后续的Bean加载和依赖注入过程中,能够更好地控制Bean之间的依赖关系和注入行为。这些方法是BeanFactory接口的扩展点,只有DefaultListableBeanFactory实现了这些方法。因此,如果使用其他的BeanFactory对象替代DefaultListableBeanFactory,则可能无法使用这些扩展点,从而无法更好地控制Bean之间的依赖关系和注入行为,可能会导致程序的正确性和稳定性问题。
介绍完了AnnotatedBeanDefinitionReader,别忘了还有一个ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner这些操作都是为了在后续的扫描过程中能够更加准确地定位和注册BeanDefinition
this()总结: 主要初始化一些注册和生成BeanDefinition的工具和处理器。以便于把bean封装成BeanDefinition并注册。
2.this.register(conponentClasses)注册
1)
setBeanClass不用说,是设置AnnotatedGenericBeanDefinition对象对应的beanclass。
下面的metadata是从bean对象中获取的各种注解元数据。包括注解类型、注解属性、注解中定义的方法等
通过AnnotatedGenericBeanDefinition,可以把传入的bean作为BeanDefination的bean。
2)
判断注解是否满足可以被加载的条件,如果满足就执行if里面的语句。
abd.setInstanceSupplier(supplier) 提供bean实例的创建逻辑,会在bean实例化的时候调用。
它会根据Bean类上的@Scope注解来确定Bean的作用域,并返回一个ScopeMetadata对象,该对象包含了作用域名称、是否是单例等信息。然后将该作用域名称设置到BeanDefinition对象中。
生成bean的名称,如果没有指定名称则由generateBeanName生成一个唯一名称
这里的AnnotationConfigUtils是一个工具类,它会处理一些通用的定义注解,例如@Lazy、@Primary等。
具体来说,它会根据Bean类上的这些注解来设置BeanDefinition对象的相应属性,例如设置是否延迟初始化、是否为主要候选Bean等。
这里的qualifiers是一个Class类型的数组,用于指定自动装配的限定符。
具体来说,它会遍历数组中的每个限定符,根据限定符的类型设置BeanDefinition对象的相应属性,例如设置是否为主要候选Bean、是否延迟初始化等。
如果限定符不是@Primary或@Lazy,则会将其添加到BeanDefinition对象的限定符列表中,该列表用于在自动装配时进行匹配(懒匹配)
在这里,实现的是自定义修改BeanDefinition属性。
BeanDefinitionHolder就是一个BeanDefinition的持有者,这里就是简单的把BeanDefination封装为BeanDefinitionHolder
它会根据Bean定义的作用域以及@Bean注解的proxyMode属性,决定是否需要为该Bean创建作用域代理。
具体来说,它会根据传入的scopeMetadata和definitionHolder对象来判断是否需要创建作用域代理,并将新的Bean定义封装成DefinitionHolder对象返回。
在这个过程中,如果需要创建作用域代理,则AnnotationConfigUtils会调用ScopedProxyFactoryBean来创建代理对象,并将代理对象的Bean定义封装成DefinitionHolder对象返回。
最终,DefinitionHolder对象会被注册到BeanDefinitionRegistry中,成为一个正式的Bean定义。
下面是registerBeanDefinition方法在DefaultListableBeanFatory中的实现:
就是把BeanDefinition注册到spring中,其实就是找个Map容器存储起来,后面若要使用则直接从这个Map中获取。
总体来说,首先对BeanDefiniton 的校验,具体来说,是对AbstractBeanDefinition属性中的methodOverrides 效验; 效验methodOverrides 是否与工厂方法并存或者methodOverrides对应的方法根本不存在。
然后对容器中已经存在了一个同名bean的处理方法。如果对应beanName已经注册 并且beanName不能被覆盖,则抛出异常,否则后注册的覆盖先注册的。
正常情况会将beanName和beanDefinition放到beanDefinitionMap中,此时的beanDefinitionMap中已经存在了5个beanDefinition,前面一节调用无参构造 this()中放进去的5个处理器。
registerBeanDefinition方法之后,还有registry.registerAlias(beanName, alias)方法,这是给bean注册别名用的。其实就是spring上线文对bean名称和别名之间维护了映射关系。
到此注册结束。
register()总结:根据注解判断是否满足加载条件,bean封装到BeanDefinition,并且额外的信息也要封装到BeanDefinition(懒加载,作用域代理,是否主要等等属性),最后把BeanDefinition根据一定规则注册到Spring中。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!