spring源码|spring源码-生命周期

BeanFactory和ApplicationContext的区别 Spring 有两个核心的接口:BeanFactory 和 ApplicationContext,其中 ApplicationContext 是BeanFactory 的子接口/它们都可以代表 Spring 容器,Spring 容器时生成Bean 实例的工厂,并且管理容器中的 Bean。
如何生成类图?
idea:ctrl + atl + u
BeanFactory和ApplicationContext的作用和区别
作用:
1、BeanFactory 负责读取 bean 配置文档,管理 bean 的加载,实例化,维护 bean 之间的依赖关系,负责 bean 的生命周期。
2、ApplicationContext 除了提供上述 BeanFactory 所能提供的功能之外,还提供了更完整的框架功能。

  • 国际化支持
  • 资源访问:Resource rs = ctx.getResource("classpath:config.properties");
  • 事件传递:通过实现 ApplicationContextAware 接口。
  • 常用的获取 ApplicationContext 的方法。
FileSystemXmlApplicationContext:从文件系统或者 url 指定的 xml 配置文件创建,参数为配置文件名或文件名数组。
ClassPathXmlApplicationContext:从classpath 的xml 配置文件创建,可以从 jar 包中读取配置文件。
WebApplicationContextUtils:从 web 应用的跟目录读取配置文件,需要先在 web.xml 中配置,可以配置监听器或者 servlet 来实现。
AnnotationApplicationContext 是基于注解来使用的,它不需要配置文件,采用 java 配置类和各种注解来配置,是比较简单的方式。
AnnotationConfig启动流程源码分析 分析前须知:
1、配置文件类也会注入到IOC容器中。
2、通过Java的多态机制,子类的无参构造函数执行时,先执行父类的无参构造函数。
3、BeanDefinition 作用:bean的信息描述、获取api,AnnotatedGenericBeanDefinition 作用:表示注解方式启动注入配置类
spring源码|spring源码-生命周期
文章图片

源码流程分析:
1、基于注解启动,通过有参构造函数(参数为配置类方式)
java类MyConfig 中配置了扫包范围、【@Import注解注入的bean】等等。
//基于注解启动 ApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyConfig.class);

2、AnnotationConfigApplicationContext 调用自己的无参构造函数
有参构造函数
spring源码|spring源码-生命周期
文章图片
无参构造函数
spring源码|spring源码-生命周期
文章图片

调用父类 GenericApplicationContext 的无参构造函数
spring源码|spring源码-生命周期
文章图片

spring源码|spring源码-生命周期
文章图片

3、执行 register(componentClasses); 注册方法
spring源码|spring源码-生命周期
文章图片

spring源码|spring源码-生命周期
文章图片

for循环
spring源码|spring源码-生命周期
文章图片

4、通过 doRegisterBean 方法注册bean
spring源码|spring源码-生命周期
文章图片

【spring源码|spring源码-生命周期】5、doRegisterBean 方法介绍
该方法会注册bean到IOC容器中去。
private void doRegisterBean(Class beanClass,@Nullable String name, @Nullable Class[]qualifiers,@Nullable Supplier supplier, @Nullable BeanDefinitionCustomizer[]customizers){ //1、AnnotatedGenericBeanDefinition 注解方式启动的配置注入 ioc bean 信息 AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); //2、判断是否有使用 condition 条件注入 bean if(this.conditionEvaluator.shouldSkip(abd.getMetadata())){ return; } //3、设置回调方式 abd.setInstanceSupplier(supplier); //4、判断config 类上是否有加上 @Scope 作用域 ScopeMetadata scopeMetadata=https://www.it610.com/article/this.scopeMetadataResolver.resolveScopeMetadata(abd); //5、设置 scope abd.setScope(scopeMetadata.getScopeName()); //6、判断是否有传递 beanname,如果没有传递name的话,生成beanname 默认类名小写作为beanid String beanName=(name!=null?name:this.beanNameGenerator.generateBeanName(abd,this.registry)); //7、判断是否有其他注解:Lazy、Primary、DependsOn、Role、Description,有的话给 adb 对应属性赋值。 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if(qualifiers!=null){ for(Class qualifier:qualifiers){ if(Primary.class ==qualifier){ abd.setPrimary(true); } else if(Lazy.class ==qualifier){ abd.setLazyInit(true); } else{ abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } if(customizers!=null){ for(BeanDefinitionCustomizer customizer:customizers){ customizer.customize(abd); } } //封装 BeanDefinitionHolder 注册 BeanDefinition 到IOC容器中 BeanDefinitionHolder definitionHolder=new BeanDefinitionHolder(abd,beanName); definitionHolder=AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder,this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder,this.registry); }

执行完 registerBeanDefinition 方法后,Bean 的名称和对应的 BeanDefinition(Bean 的信息) 就被放入了容器中,
后续获取 Bean 也是从这个容器中获取。
单例和多例 单例:容器在创建的时候会初始化,默认是单例。
多例:从容器中获取对象的时候再初始化。
判断对象在什么时候初始化?
答:在类的无参构造函数里面输出内容就可以发现了。
对象的初始化与销毁 SpringBean 的生命周期: Bean的创建 --》初始化–》销毁过程。
可以自定义方法与销毁的方法。
配置bean的初始化、销毁方法的方式
方法一:通过 @Bean 指定 init-methed 和 destroy-method;
方法二:通过 Bean 实现 InitalizingBean (定义初始化逻辑),DisposableBean(定义销毁逻辑);
方法三:可以使用JSR250:
  • @PostConstruct:在bean 创建完成并且属性赋值完成,来执行初始化方法。
  • @PreDestroy:在容器销毁 bean 之前通知我们来进行清理工作。
如何判断对象是否初始化呢?
答:bean初始化,指的就是对象已经创建,里面的所有的set方法都已经执行完毕了;指定方法执行
@Bean 注解中可以指定bean的初始化后方法(initMethod():对象创建之后,构造函数执行之后,才执行这个初始化方法)和销毁后方法(destroyMethod():多例bean没有销毁方法)
spring源码|spring源码-生命周期
文章图片
spring源码|spring源码-生命周期
文章图片

spring源码|spring源码-生命周期
文章图片

什么时候bean执行销毁?
答:异常报错的时候、执行applicationContext的 close 方法
ApplicationContextAware接口 在servlet过滤器中不可以使用注解方式获取 bean 对象。需要自己单独获取上下文 applicationContext
spring源码|spring源码-生命周期
文章图片

后置处理器 BeanPostProcessor
作用:可以对初始化实现增强。
SpringBean的生命周期总结 spring源码|spring源码-生命周期
文章图片

    推荐阅读