参考原文链接:
https://blog.csdn.net/weixin_39651041/article/details/129674784
核心类图

顶层父类接口和类作用定义及详细类图
BeanFactory

SimpleJndiBeanFactory
ListableBeanFactory
HierarchicalBeanFactory
AutowireCapableBeanFactory
StaticListableBeanFactory
StubBeanFactory
ConfigurableBeanFactory
ConfigurableListableBeanFactory
ApplicationContext
WebApplicationContext
ConfigurableApplicationContext
AbstractApplicationContext
AbstractRefreshableApplicationContext
AbstractRefreshableConfigApplicationContext
AbstractXmlApplicationContext
FileSystemXmlApplicationContext
ClassPathXmlApplicationContext
AbstractRefreshableWebApplicationContext
AnnotationConfigWebApplicationContext
XmlWebApplicationContext
GroovyWebApplicationContext
GenericApplicationContext
GenericXmlApplicationContext
GenericGroovyApplicationContext
AnnotationConfigApplicationContext
ConfigurableWebApplicationContext
StaticApplicationContext
StubWebApplicationContext
Aware
LifeCycle
定义启动/停止生命周期控制方法的通用接口
/**
* Start this component.
*/
void start();
/**
* Stop this component, typically in a synchronous fashion, such that the component is
* fully stopped upon return of this method.
*/
void stop();
/**
* Check whether this component is currently running.
*/
boolean isRunning();
}
InitializingBean
Spring 提供的拓展性接口,InitializingBean 接口为 Bean 提供了属性初始化后的处理方法,它只有一个 afterPropertiesSet() 方法,凡是继承该接口的类,在 Bean 的属性初始化后都会执行该方法,进行其总体配置和最终初始化验证
/**
* Invoked by the containing {@code BeanFactory} after it has set all bean properties
* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
* <p>This method allows the bean instance to perform validation of its overall
* configuration and final initialization when all bean properties have been set.
* @throws Exception in the event of misconfiguration (such as failure to set an
* essential property) or if initialization fails for any other reason
*/
void afterPropertiesSet() throws Exception;
}
ResourceLoader
用于加载资源(例如,类路径或文件系统资源)的策略接口
Spring 中整合了获取资源的工具,就是使用 Resource 接口。此接口是 Spring 为了统一读取诸如本地文件、classpath 项目路径下的文件、url 互联网上的文件等不同类型渠道的资源,封装隐藏如打开流、关闭流、报错处理等大量重复模板代码,而专程设计提供的接口类
而 Spring 框架为了更方便的获取资源,尽量弱化程序员对各个 Resource 接口实现类的感知与分辨,降低学习与使用成本,定义了另一个接口,就是:ResourceLoader接口
/** Pseudo URL prefix for loading from the class path: "classpath:". */
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
/**
* Return a {@code Resource} handle for the specified resource location.
*/
Resource getResource(String location);
/**
* Expose the {@link ClassLoader} used by this {@code ResourceLoader}.
*/
@Nullable
ClassLoader getClassLoader();
}
ApplicationEventPublisher
封装事件发布功能的接口
函数式接口
public interface ApplicationEventPublisher {
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an application event. Events may be framework events
* (such as ContextRefreshedEvent) or application-specific events.
*/
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an event.
*/
void publishEvent(Object event);
}
AutoCloseable
当一个资源类实现了该接口 close 方法,在使用 try-with-resources 语法创建的资源抛出异常后,JVM 会自动调用 close 方法进行资源释放;当没有抛出异常正常退出 try 代码块时也会自动调用 close 方法。像数据库链接类 Connection,io 类 InputStream 或 OutputStream 都直接或者间接实现了该接口
/**
* Closes this resource, relinquishing any underlying resources.
* This method is invoked automatically on objects managed by the
* {@code try}-with-resources statement.
*/
void close() throws Exception;
}
配置文件加载Bean
加载配置文件
new ClassPathXmlApplicationContext(); 初始化
使用构造函数传入配置文件路径,初始化
setConfigLocations(configLocations); 按顺序、覆盖规则加载配置文件路径,需要对路径进行处理,调用的方法比较多
refresh(); refresh() 方法是 ApplicationContext 接口的一个核心方法,用于初始化和刷新 Spring 应用程序上下文
prepareRefresh(); 为上下文刷新做准备,包括设置Spring容器启动时间、活跃状态/关闭状态刷新、初始化context environment(上下文环境)中的占位符属性来源、验证必要属性
obtainFreshBeanFactory(); 重新创建一个Bean工厂
prepareBeanFactory(beanFactory); 为后续的bean注册和初始化过程做好准备,包括设置类加载器ClassLoader ,注册相关配置
postProcessBeanFactory(beanFactory); 上下文的子类可以对Bean工厂进行后置处理
invokeBeanFactoryPostProcessors(beanFactory); 实例化并调用所有已注册的bean
对不同类型的Bean分类添加到链表: BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor,作用时BeanDefinitionRegistryPostProcessor 允许在 bean 定义注册阶段动态添加 Bean 定义;而 BeanFactoryPostProcessor 则在所有 Bean 定义加载完成后、Bean 实例化之前执行,用于修改现有 Bean 定义的属性
BeanDefinitionRegistryPostProcessor 实现,查找Bean名称、遍历同时也是PriorityOrdered 接口的实例,对其根据PriorityOrdered接口的优先级值排序,然后执行
继续处理 BeanDefinitionRegistryPostProcessor 的实现,同理,不过按照 Ordered 接口查找和排序
调用所有剩余的 BeanDefinitionRegistryPostProcessor 实例,迭代处理,因为一个Bean可能会注册新的Bean,按Ordered 接口排序
递归调用
invokeBeanFactoryPostProcessors*(registryProcessors, beanFactory); invokeBeanFactoryPostProcessors*(regularPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory); 从Spring容器中找出的BeanPostProcessor接口的bean,并设置到BeanFactory的属性中,进行注册
beanPostProcess.end(); 空方法,表示后处理阶段已经完成,可自定义
initMessageSource(); 国际化
initApplicationEventMulticaster(); 在Spring容器中初始化事件广播器,事件广播器用于事件的发布
onRefresh(); 初始化特定上下文子类中的其他特殊bean
registerListeners(); 检查并注册监听器Bean
finishBeanFactoryInitialization(beanFactory); 实例化所有剩余非懒加载单例
finishRefresh() 发布,结束刷新
LiveBeansView.registerApplicationContext(this); 若非原生镜像,则在非原生镜像(native image)环境中注册应用程序上下文到LiveBeansView MBean,使其可以通过JMX(Java Management Extensions)进行监控和管理
resetCommonCaches(); 位于finally块中,用于清除缓存,清除用于加速反射操作缓存、加速注解处理缓存、处理泛型类型缓存、JavaBean属性和方法的内省结果的缓存
contextRefresh.end(); 标记上下文刷新结束
获取Bean
applicationContext.getBean("A"); 获取Bean
assertBeanFactoryActive(); 安全检查,检查Spring容器中的BeanFactory是否处于活动状态
getBeanFactory().getBean(name); 获取Bean,AbstractApplicationContext 的方法
doGetBean(name, null, null, false); AbstractBeanFactory 的泛型方法,获取Bean
接受四个参数:
name:要获取的bean的名称
requiredType:期望返回的bean的类型,可以为null
args:创建bean时需要的参数,可以为null
typeCheckOnly:如果为true,则只进行类型检查,不实际创建bean
可以调用方法或进行其他后续操作
配置文件加载Bean总结
为什么在Bean加载时要使用这么多的super关键字?
因为ApplicationContext 存在层级结构,在加载子类构造函数前必须先加载父类的构造函数,如果不使用super关键字默认会加载父类的无参构造函数,这可能不是我们想要的,所以需要显示的指定加载父类的那个构造方法,使父类加载某些特定的资源,确保从最顶层的父类开始,逐层向下初始化,直到当前子类,保证整个初始化过程完成
this()的作用是什么?
this()会加载本类中的其他构造方法,默认通过参数列表识别要掉的构造方法,不允许递归调用
Spring中的层级结构作用是什么?
Spring框架中的层级结构主要指的是ApplicationContext的层级结构,主要具有以下作用:
refresh()方法使用synchronized关键字的原因?
创建互斥锁,防止并发刷新导致容器状态不一致,避免加载出错,也避免Bean还没有加载完成就被调用
StartupStep的作用是什么?
StartupStep是一个用于记录和测量应用程序在启动过程中的各个阶段耗时的工具,对于性能调优和故障排查非常有用
为什么要使用这么多的预加载机制,比如prepareRefresh()?
为什么要使用许多contextRefresh.end()这样的空方法?
使用这些方法的原因是为了方便用户重写这些方法,便于自定义加载结束后的行为,比如记录日志、回调等
符合开放封闭原则,提供重写方法,用户不必要修改原有代码,对扩展开放,对修改封闭
注释
JNDI是Java平台中用于访问命名和目录服务的API,为Java应用程序提供了一种统一的方式来访问各种不同的命名和目录服务,如LDAP、DNS、RMI等,而不需要关心底层的具体实现细节 ↩︎
原型Bean在Spring框架中的应用场景通常涉及到需要每次使用时都创建一个新实例的情况,他们之间相互隔离,从而避免了由于实例之间的数据共享所带来的潜在冲突或安全问题,通常使用@Scope("prototype")定义原型Bean ↩︎
SPI是一种服务发现机制,它允许框架或应用程序在运行时动态加载服务的实现,是专门提供给服务提供者或扩展框架功能的开发者使用的一个接口。它通过接口定义服务行为,并允许多个服务提供者在运行时为该接口提供不同的实现。不同于API的是,API是提供一组标准化的接口,是被调用方依赖的,即应用程序需要引入API所在的库才能使用其功能。而SPI是调用方依赖的,即框架或库需要引入第三方实现类的库才能加载和调用。SPI允许在运行时动态加载和替换实现类,提供了一种灵活的扩展机制 ↩︎
框架内部即插即用(Plug-and-Play)是一种设计模式,它允许框架在运行时动态加载和卸载模块或组件,而无需停止和重新启动整个系统,框架设计时预留扩展点,如回调、钩子和事件,允许开发者在特定时机插入自定义代码 ↩︎ ↩︎
回调是一种将函数作为参数传递给另一个函数,以便在某个操作完成或特定事件发生时被调用的技术。在编程中,回调通常用于异步编程和事件驱动编程 ↩︎ ↩︎
钩子是一种允许用户或框架自定义或扩展某些操作的机制。在软件中,钩子通常用于拦截和修改系统或库的内部操作 ↩︎ ↩︎ ↩︎
事件是一种通知机制,用于在发生特定动作或状态改变时通知感兴趣的对象。事件驱动编程是一种编程范式,其中对象之间的交互是通过事件的产生和消费来实现的 ↩︎ ↩︎
bean的生命周期方法指的是在bean的创建、初始化、使用和销毁过程中,Spring容器会自动调用的一系列方法。这些方法允许开发者在bean的不同生命周期阶段插入自定义逻辑,其中关键方法包括构造函数、@PostConstruct注解方法(依赖注入完成后调用,通常用于初始化工作)、init-method属性(依赖注入完成后调用,可以在xml配置文件中指定一个方法作为初始化方法)、@PreDestroy注解方法(在bean销毁前调用,通常用于清理工作)、destroy-method属性(在bean销毁前调用,可以在xml配置文件中指定一个方法作为销毁方法)、DisposableBean接口(实现DisposableBean接口的destroy()方法也会在bean销毁时被调用)、BeanPostProcessor接口(BeanPostProcessor接口提供了两个方法:postProcessBeforeInitialization和postProcessAfterInitialization。这两个方法分别在bean的初始化前后被调用,允许开发者插入自定义逻辑) ↩︎

