【Spring源码解读!底层原理高级进阶】【上】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨

本文主要是介绍【Spring源码解读!底层原理高级进阶】【上】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 🎉🎉欢迎光临🎉🎉

🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀

🌟特别推荐给大家我的最新专栏《Spring 狂野之旅:底层原理高级进阶》 🚀

本专栏纯属为爱发电永久免费!!!

这是苏泽的个人主页可以看到我其他的内容哦👇👇

努力的苏泽icon-default.png?t=N7T8http://suzee.blog.csdn.net/

✨这篇文分了三部分来解释Spring--BeanFactory以及ApplicationContext内部的工作原理 本来想一文到底的 奈何太长了...于是拆成了两篇文  

本篇文章的目标,在于通过深入剖析Spring框架的源码,不仅让读者亲身体验到Spring设计大师们的卓越智慧,同时也分享我对其设计哲学所引发的思考与感悟。

如果 觉得阿泽写的还过得去的 观众老爷们可以给个免费的三连 作为一位纯粹的技术热爱者为爱发电的动力🌟

目录

🌼 引言

第一章:Spring框架概览

🌱 Spring框架的设计哲学

在日常工作中的好处

示例

🌿 核心组件与它们的协同工作方式

第二章:深入BeanFactory —— Spring的基石

BeanFactory的角色与职责

定义与类型

核心接口解析

Bean生命周期管理

Bean定义的解析过程

Bean的实例化与依赖注入

初始化与销毁回调

案例分析:BeanFactory如何管理Bean

Spring源码解析

实例化

依赖注入

初始化

测试代码

第三章:ApplicationContext —— 超越BeanFactory

ApplicationContext与BeanFactory的关系

ApplicationContext的核心功能

国际化消息处理

事件发布与监听机制

环境抽象与配置文件管理

实现原理揭秘

如何实现Bean的自动装配

AOP支持的背后机制

🌼 引言

欢迎来到Spring的世界:简介与动机

我很荣幸能与大家一起探索Spring框架的奇妙之处。本文将带领大家从BeanFactory到ApplicationContext,一步步揭示Spring框架的设计原理和核心组件之间的协同工作方式。在这个过程中,我将结合代码和源码解读,以及适当的测试代码来证明观点的正确性。

第一章:Spring框架概览

🌱 Spring框架的设计哲学

Spring框架的设计哲学体现了延迟加载和依赖注入的思想。通过延迟加载,Spring框架可以在应用程序运行时根据需要动态创建和加载Bean,而不是在启动时就创建所有的Bean。这种设计思想有助于提高应用程序的性能和资源利用率。

具体来说,当我们通过BeanFactory获取Bean的时候,Spring框架会检查该Bean是否已经被创建。如果该Bean尚未被创建,Spring框架会按照配置文件中的定义,使用合适的策略来实例化和初始化该Bean。这种延迟加载的设计思想使得应用程序能够更加灵活地管理和使用组件。

在日常工作中的好处

延迟加载和依赖注入的设计思想在日常工作中有许多好处,其中包括:

  1. 提高性能和资源利用率:由于Spring框架延迟加载的特性,只有在需要使用某个Bean时才会进行创建和加载。这可以减少启动时间、内存占用和网络传输等开销,从而提高应用程序的性能和资源利用率。

  2. 降低耦合度:Spring框架的依赖注入机制使得组件之间的依赖关系由外部容器来管理,而不是硬编码在代码中。这样可以降低组件之间的耦合度,使得代码更加灵活、可维护和可测试。

  3. 增强扩展性和可配置性:通过使用Spring框架,我们可以将应用程序的配置信息集中管理,而不是散落在各个组件中。这使得我们可以更方便地进行配置修改和扩展,而无需修改代码。

示例

以下是一个简单的示例,展示了延迟加载和依赖注入在实际业务场景中的提升:

// 示例:订单服务
@Service
public class OrderService {@Autowiredprivate PaymentService paymentService;public void placeOrder() {// 业务逻辑省略// 调用支付服务完成支付paymentService.pay();// 业务逻辑省略}
}// 示例:支付服务
@Service
public class PaymentService {public void pay() {// 执行支付逻辑System.out.println("执行支付逻辑");}
}

在上述示例中,订单服务依赖于支付服务。通过使用Spring框架的依赖注入机制,我们可以将支付服务注入到订单服务中,而无需在订单服务中硬编码创建和管理支付服务的实例。

这样,当订单服务需要使用支付服务时,Spring框架会自动创建和注入支付服务实例。同时,由于延迟加载的特性,支付服务只会在需要时才会被创建和加载。这种设计使得代码更加灵活、可维护和可测试。

🌿 核心组件与它们的协同工作方式

Spring框架的核心组件就像大自然中的各种元素,它们相互配合、相互作用,才能构建出一个完整的生态系统。让我们通过代码和源码解读的方式来展示它们之间的协同工作方式。

// 核心组件的协同工作
public class SpringEcoSystem {public void coordinateWork() {// 创建ApplicationContext对象ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 从ApplicationContext中获取BeanFactoryBeanFactory beanFactory = context.getBeanFactory();// 使用BeanFactory创建和管理BeanComponentA componentA = beanFactory.getBean(ComponentA.class);ComponentB componentB = beanFactory.getBean(ComponentB.class);// 省略其他代码}
}

在上述代码中,我们使用了Spring的ApplicationContext来创建一个应用程序的上下文,并通过它获取了BeanFactory对象。BeanFactory是Spring框架中的一个核心组件,负责创建和管理Bean。

通过源码解读,我们可以发现BeanFactory的设计思想是延迟加载和依赖注入。它在需要使用Bean时才去创建它,而不是在应用程序启动时就创建所有的Bean。这种延迟加载的设计思想可以提高应用程序的性能和资源利用率。

接下来,我们通过测试代码来证明BeanFactory的延迟加载特性:

// 测试BeanFactory的延迟加载特性
public class BeanFactoryLazyLoadingTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 获取BeanFactory对象BeanFactory beanFactory = context.getBeanFactory();// 执行一些其他操作for (int i = 0; i < 10000; i++) {System.out.println("test");}// 获取ComponentA对象ComponentA componentA = beanFactory.getBean(ComponentA.class);System.out.println("获取ComponentA对象");// 执行一些其他操作for (int i = 0; i < 10000; i++) {System.out.println("test");}// 获取ComponentB对象ComponentB componentB = beanFactory.getBean(ComponentB.class);System.out.println("获取ComponentB对象");}
}
// 预期结果和执行时间估计
获取ComponentA对象
test
test
test
...
test
获取ComponentB对象

在上述测试代码中,我们先获取了BeanFactory对象,然后执行了一些其他操作。在需要使用ComponentA和ComponentB时,才去通过BeanFactory来获取它们。这样就实现了Bean的延迟加载。

结果是,在执行"获取ComponentA对象"和"获取ComponentB对象"之前,不会创建和加载这两个组件。只有当真正需要使用它们时,才会进行创建和加载。

通过以上的代码和测试,我们可以看到Spring框架中的BeanFactory的设计思想:

延迟加载和依赖注入。

  1. 延迟加载:通过先获取BeanFactory对象,然后执行其他操作的方式,实现了Bean的延迟加载。在需要使用ComponentA和ComponentB时,才去通过BeanFactory来获取它们。这意味着只有在真正需要使用这些组件时,才会进行创建和加载。延迟加载的特性可以提高应用程序的性能和资源利用率。

  2. 依赖注入:通过获取BeanFactory对象,并在需要使用ComponentA和ComponentB时通过BeanFactory来获取它们,实现了依赖注入。在示例中,ComponentA和ComponentB被注入到其他组件中,而不是在代码中硬编码创建和管理它们的实例。这种依赖注入的设计思想降低了组件之间的耦合度,使得代码更加灵活、可维护和可测试。

第二章:深入BeanFactory —— Spring的基石

在Spring框架中,BeanFactory是一个非常核心的接口,它为Spring容器的基础功能提供了定义。BeanFactory可以看作是一个高级的工厂模式实现,负责配置、创建和管理应用程序中的beans。这篇博客将深入探讨BeanFactory的角色、职责和关键实现细节。

BeanFactory的角色与职责

BeanFactory是Spring IoC容器的心脏,IoC(控制反转)是一种设计原则,用于实现依赖注入(DI)。通过BeanFactory,我们可以获得对Spring容器管理的对象(即Beans)的完全控制。它负责:

  • 创建和管理应用程序中的bean
  • 解决bean之间的依赖
  • 管理bean的生命周期
定义与类型

在Spring中,BeanFactory以及其子类如ApplicationContext提供了丰富的功能来支持不同的需求。ApplicationContextBeanFactory的子接口,提供了更多高级特性,如事件发布、国际化支持等。

核心接口解析

BeanFactory提供了几个核心方法,如getBean(String name),用于根据bean的名称获取一个bean实例。此外,containsBean(String name)检查容器中是否包含指定名称的bean。

Bean生命周期管理

Bean的生命周期由创建、初始化、使用到销毁几个阶段组成。BeanFactory负责整个生命周期的管理。其中,初始化和销毁回调是两个重要的生命周期事件。

Bean定义的解析过程

Spring容器启动时,会解析配置文件或注解,构建每个bean定义的BeanDefinition对象。这个过程涉及到读取配置元数据并转换成容器内部结构。

Bean的实例化与依赖注入

Bean的实例化主要有两种方式:构造函数实例化和静态工厂方法实例化。依赖注入(DI)是Spring实现IoC的手段之一,主要有构造器注入和setter方法注入。

初始化与销毁回调

Spring允许在bean的生命周期的特定点执行自定义逻辑,比如通过实现InitializingBeanDisposableBean接口。

案例分析:BeanFactory如何管理Bean

让我们通过一个简单的例子来看看BeanFactory是如何管理Bean的。考虑一个简单的UserService类,我们将展示如何通过XML配置来声明这个Bean,并通过BeanFactory来获取和使用这个Bean。

<bean id="userService" class="com.example.UserService"/>
public class UserService {public void getUser() {System.out.println("Fetching user...");}
}ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.getUser();

预期输出:

Fetching user...

这个例子展示了BeanFactory如何通过配置文件解析、实例化Bean,并进行依赖注入。

Spring源码解析

让我们深入Spring的DefaultListableBeanFactory类,看看Spring是如何实现这些原理的。DefaultListableBeanFactoryBeanFactory接口的一个核心实现类,它管理着容器中的bean定义(BeanDefinition)和bean实例。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {// 存储bean定义的映射private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// 实例化bean的核心逻辑}
}

让我们更深入地探讨DefaultListableBeanFactory类中的createBean方法,以及Spring是如何处理bean的实例化、依赖注入和初始化的。这将帮助我们更好地理解Spring框架的内部工作原理。

实例化

DefaultListableBeanFactory中,实例化bean的过程主要是通过其父类AbstractAutowireCapableBeanFactorycreateBeanInstance方法完成的。这个方法首先会尝试使用构造函数来创建bean实例,如果找到合适的构造函数,它会通过反射来实例化对象。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {// 确定构造函数并实例化bean
}

在这个过程中,Spring会考虑到构造函数的参数匹配,确保能够找到与配置相匹配的最适合的构造函数进行实例化。

依赖注入

一旦bean被实例化,Spring接下来会进行依赖注入。这一步是通过populateBean方法完成的。在这个方法中,Spring会检查bean定义中的依赖关系,并通过反射来设置bean的属性值或者通过方法注入依赖的对象。

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {// 获取bean的属性值并注入
}

这里,Spring处理了两种类型的依赖注入:基于属性的注入和基于构造函数的注入。对于基于属性的注入,Spring会解析属性值(可能是另一个bean的引用或简单类型的值)并通过setter方法或直接字段访问来注入这些值。对于基于构造函数的注入,这一步骤实际上已经在实例化阶段处理完毕。

初始化

最后,一旦bean被成功实例化并注入所需的依赖,Spring会调用initializeBean方法来处理bean的初始化。这个方法会按顺序执行BeanPostProcessor前置处理、调用自定义的初始化方法(比如实现InitializingBean接口或通过init-method指定的方法),以及BeanPostProcessor后置处理。

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {// 执行BeanPostProcessors的前置处理// 调用bean的初始化方法// 执行BeanPostProcessors的后置处理
}

在这个阶段,Spring提供了强大的扩展点,允许开发者通过实现BeanPostProcessor接口来在bean的初始化前后执行自定义逻辑。

通过以上解析,我们可以看到DefaultListableBeanFactory类中的createBean方法涵盖了bean生命周期的关键阶段:实例化、依赖注入和初始化。每个阶段都有其详细的处理逻辑,保证了bean的正确创建和配置。

测试代码

为了验证我们的理解,我们可以编写一个简单的测试用例来模拟BeanFactory的使用场景。

public class BeanFactoryTest {@Testpublic void testBeanLifecycle() {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = context.getBean("userService", UserService.class);userService.getUser();}
}

预期结果应该与前面的示例相同,显示"Fetching user...",证明我们通过BeanFactory成功地管理了UserService的生命周期。

第三章:ApplicationContext —— 超越BeanFactory

在Spring的世界里,ApplicationContext是一个闪耀的星辰,它不仅继承了BeanFactory的能力,更在此基础上提供了更加丰富和高级的功能。让我们一步步揭开ApplicationContext的神秘面纱,探索它超越BeanFactory的奥秘。

ApplicationContext与BeanFactory的关系

首先,我们需要明确ApplicationContextBeanFactory之间的关系。简单来说,ApplicationContextBeanFactory的子接口,它提供了更加全面的功能。如果说BeanFactory是基础的Spring容器,那么ApplicationContext就是提供了额外增强功能的高级容器。🌱 ➡️ 🌳

ApplicationContext的核心功能

ApplicationContext的核心功能可以说是非常强大,包括但不限于:

  • 国际化消息处理:支持不同语言环境的消息访问和管理。
  • 事件发布与监听机制:允许应用内部各个组件之间进行松耦合的通信。
  • 环境抽象与配置文件管理:提供了一种抽象的方式来处理配置信息,支持不同环境下的配置变更。
国际化消息处理

ApplicationContext中,国际化是通过MessageSource接口来实现的。这使得我们能够很方便地在不同语言环境下获取消息。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
String message = context.getMessage("hello.message", null, Locale.US);
System.out.println(message);

假设我们有一个messages_en_US.properties文件,其中包含以下内容:

hello.message=Hello, World!

上述代码将会输出:

Hello, World!
事件发布与监听机制

ApplicationContext提供了一个基于观察者模式的事件发布与监听机制。这使得应用内部的组件可以发布和监听事件,从而实现松耦合的交互。

public class MyEvent extends ApplicationEvent {public MyEvent(Object source) {super(source);}
}public class MyListener implements ApplicationListener<MyEvent> {@Overridepublic void onApplicationEvent(MyEvent event) {System.out.println("Received event: " + event);}
}ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
context.publishEvent(new MyEvent("Some event"));

这段代码定义了一个自定义事件MyEvent和一个事件监听器MyListener。当事件被发布时,监听器会捕获到这个事件并执行相应的处理逻辑。

环境抽象与配置文件管理

ApplicationContext通过Environment接口提供了一种强大的环境抽象机制,允许我们灵活地管理和访问配置信息。

Environment env = context.getEnvironment();
String property = env.getProperty("some.property");
System.out.println(property);

这使得我们可以根据当前的运行环境(开发、测试、生产等)动态地调整配置信息。

实现原理揭秘

深入到ApplicationContext的实现原理,我们会发现它是通过一系列复杂但精妙的设计模式来实现上述功能的。以事件发布与监听机制为例,其背后是观察者模式的运用。

public class AbstractApplicationContext extends DefaultResourceLoaderimplements ConfigurableApplicationContext {private final ApplicationEventMulticaster applicationEventMulticaster = new SimpleApplicationEventMulticaster();// 其他实现细节...
}

AbstractApplicationContext中持有一个ApplicationEventMulticaster,负责管理事件的发布和监听。当事件发布时,ApplicationEventMulticaster会通知所有注册的监听器。

如何实现Bean的自动装配

ApplicationContext通过@Autowired注解和@ComponentScan注解等提供了强大的自动装配能力。这背后是Spring的依赖注入(DI)机制。

@Component
public class MyComponent {@Autowiredprivate MyDependency dependency;// 类体...
}

Spring容器会自动寻找类型匹配的bean,并注入到MyComponentdependency字段中。

AOP支持的背后机制

最后,ApplicationContext对AOP(面向切面编程)的支持也是其核心功能之一。Spring AOP是通过代理模式实现的,它允许开发者在不修改源码的情况下增强方法的行为。

@Aspect
public class MyAspect {@Before("execution(* com.example.MyComponent.myMethod(..))")public void beforeAdvice(JoinPoint joinPoint) {System.out.println("Before method: " + joinPoint.getSignature().getName());}
}

在这个例子中,MyAspect定义了一个前置通知,它会在MyComponentmyMethod方法执行前被调用。

本文未完待续....

下篇传送门点这里       

下章预告:

第四章:深挖ApplicationContext的高级特性

  • 环境与配置文件的灵活管理
    • Profile的工作原理
    • 使用PropertySources优雅地管理配置
  • 数据访问与事务管理的抽象
    • 数据访问异常的统一处理
    • 声明式事务管理的实现机制

第五章:Spring表达式语言(SpEL)

  • SpEL的设计目的与应用场景
  • SpEL的核心语法与功能
  • 如何通过SpEL实现动态配置

这篇关于【Spring源码解读!底层原理高级进阶】【上】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/694921

相关文章

Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码

《Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码》:本文主要介绍Java中日期时间转换的多种方法,包括将Date转换为LocalD... 目录一、Date转LocalDateTime二、Date转LocalDate三、LocalDateTim

如何配置Spring Boot中的Jackson序列化

《如何配置SpringBoot中的Jackson序列化》在开发基于SpringBoot的应用程序时,Jackson是默认的JSON序列化和反序列化工具,本文将详细介绍如何在SpringBoot中配置... 目录配置Spring Boot中的Jackson序列化1. 为什么需要自定义Jackson配置?2.

Java中使用Hutool进行AES加密解密的方法举例

《Java中使用Hutool进行AES加密解密的方法举例》AES是一种对称加密,所谓对称加密就是加密与解密使用的秘钥是一个,下面:本文主要介绍Java中使用Hutool进行AES加密解密的相关资料... 目录前言一、Hutool简介与引入1.1 Hutool简介1.2 引入Hutool二、AES加密解密基础

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

Spring Boot项目部署命令java -jar的各种参数及作用详解

《SpringBoot项目部署命令java-jar的各种参数及作用详解》:本文主要介绍SpringBoot项目部署命令java-jar的各种参数及作用的相关资料,包括设置内存大小、垃圾回收... 目录前言一、基础命令结构二、常见的 Java 命令参数1. 设置内存大小2. 配置垃圾回收器3. 配置线程栈大小

SpringBoot实现微信小程序支付功能

《SpringBoot实现微信小程序支付功能》小程序支付功能已成为众多应用的核心需求之一,本文主要介绍了SpringBoot实现微信小程序支付功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作... 目录一、引言二、准备工作(一)微信支付商户平台配置(二)Spring Boot项目搭建(三)配置文件

解决SpringBoot启动报错:Failed to load property source from location 'classpath:/application.yml'

《解决SpringBoot启动报错:Failedtoloadpropertysourcefromlocationclasspath:/application.yml问题》这篇文章主要介绍... 目录在启动SpringBoot项目时报如下错误原因可能是1.yml中语法错误2.yml文件格式是GBK总结在启动S

鸿蒙中@State的原理使用详解(HarmonyOS 5)

《鸿蒙中@State的原理使用详解(HarmonyOS5)》@State是HarmonyOSArkTS框架中用于管理组件状态的核心装饰器,其核心作用是实现数据驱动UI的响应式编程模式,本文给大家介绍... 目录一、@State在鸿蒙中是做什么的?二、@Spythontate的基本原理1. 依赖关系的收集2.

Spring中配置ContextLoaderListener方式

《Spring中配置ContextLoaderListener方式》:本文主要介绍Spring中配置ContextLoaderListener方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录Spring中配置ContextLoaderLishttp://www.chinasem.cntene

基于Python实现高效PPT转图片工具

《基于Python实现高效PPT转图片工具》在日常工作中,PPT是我们常用的演示工具,但有时候我们需要将PPT的内容提取为图片格式以便于展示或保存,所以本文将用Python实现PPT转PNG工具,希望... 目录1. 概述2. 功能使用2.1 安装依赖2.2 使用步骤2.3 代码实现2.4 GUI界面3.效