Spring源码分析(1)

本文详细解读了Spring框架的分层架构,重点介绍了Bean的编程理念、IoC容器的工作原理、核心组件如Bean组件和Context组件,以及Bean的生命周期管理和后置处理器。同时,展示了如何使用Gradle构建Spring源码环境并进行测试。
摘要由CSDN通过智能技术生成

1.Spring架构设计

Spring框架是一个分层架构,他包含一系列的功能要素,并被分为大约20个模块

image-20211007143024635

2. 设计理念

Spring是面向Bean的编程(BOP:Bean Oriented Programming),Bean在Spring中才是真正的主角。Bean在Spring中作用就像Object对OOP的意义一样,没有对象的概念就像没有面向对象编程,Spring中没有Bean也就没有Spring存在的意义。Spring提供了IoC 容器通过配置文件或者注解的方式来管理对象之间的依赖关系。

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。

3. 核心组件介绍

Bean组件

Bean组件定义在Spring的org.springframework.beans包下,解决了以下几个问题:

这个包下的所有类主要解决了三件事:

  • Bean的定义
  • Bean的创建
  • Bean的解析

Spring Bean的创建是典型的工厂模式,它的顶级接口是BeanFactory。

image-20211007145355908

BeanFactory有三个子类:ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory。目的是为了区分Spring内部对象处理和转化的数据限制

但是从图中可以发现最终的默认实现类是DefaultListableBeanFactory,它实现了所有的接口

Bean定义:BeanDefinition

这里的 BeanDefinition 就是我们所说的 Spring 的 Bean,我们自己定义的各个 Bean 其实会转换成一个个 BeanDefinition 存在于 Spring 的 BeanFactory 中

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); 
}  

BeanDefinition 中保存了我们的 Bean 信息,比如这个 Bean 指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean 等等。

image-20211007161031805

Context组件

Context在Spring的org.springframework.context包下

Context模块构建于Core和Beans模块基础之上,提供了一种类似于JNDI注册器的框架式的对象访问方法.Context模块继承了Beans的特性,为Spring核心提供了大量扩展,添加了对国际化(例如资源绑定)、事件传播、资源加载和对Context的透明创建的支持

ApplicationContext是Context的顶级父类

image-20211007165548928

ApplicationContext 的子类主要包含两个方面:

  1. ConfigurableApplicationContext 表示该 Context 是可修改的,也就是在构建 Context 中用户可以动态添加或修改已有的配置信息
  2. WebApplicationContext 顾名思义,就是为 web 准备的 Context 他可以直接访问到 ServletContext,通常情况下,这个接口使用少

再往下分就是按照构建 Context 的文件类型,接着就是访问 Context 的方式。这样一级一级构成了完整的 Context 等级层次。

总体来说 ApplicationContext 必须要完成以下几件事:

  • 标识一个应用环境
  • 利用 BeanFactory 创建 Bean 对象
  • 保存对象关系表
  • 能够捕获各种事件

面试题:简述Spring后置处理器

后置处理器是一种拓展机制,贯穿Spring Bean的生命周期

后置处理器分为两类:

BeanFactory后置处理器:BeanFactoryPostProcessor

实现该接口,可以在spring的bean创建之前,修改bean的定义属性

image-20211008102757203

public interface BeanFactoryPostProcessor {

    /*
     *  该接口只有一个方法postProcessBeanFactory,方法参数是ConfigurableListableBeanFactory,通过该
        参数,可以获取BeanDefinition
    */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

image-20211008101438194

Bean后置处理器:BeanPostProcessor

BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口

实现该接口,可以在spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些处理逻辑

image-20211105161715077

public interface BeanPostProcessor {
    //bean初始化方法调用前被调用
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    //bean初始化方法调用后被调用
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

运行顺序

=Spring IOC容器实例化Bean= =调用BeanPostProcessor的postProcessBeforeInitialization方法= =调用bean实例的初始化方法= =调用BeanPostProcessor的postProcessAfterInitialization方法=

4. IOC流程图

image-20211105165148155

5. Bean的生命周期

image-20211008142608762

image-20211008142650441

image-20211008144105946

Bean 生命周期的整个执行过程描述如下。

1)根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。

2)利用依赖注入完成 Bean 中所有属性值的配置注入。

3)如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。

4)如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。

5)如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。

6)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作

7)如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。

8)如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。

9)如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。

10)如果在 中指定了该 Bean 的作用范围为 scope=“singleton”,则将该 Bean 放入 Spring IoC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用范围为 scope=“prototype”,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。

11)如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法。

6. Spring源码环境构建

1. 自动化构建Gradle

引言:
从Sping5开始,官方就开始使用gradle来构建环境了
接下来,我们所有的环境都要基于gradle

1.1 什么是Gradle

Gradle是一个项目自动化构建工具。

是Apache的一个基于Ant 和Maven的软件,用于项目的依赖管理

image-20210928100038457

项目的构建经历了三个时代:

Apache Ant(2000 年左右)

Maven(2004年)

Gradle(2012 年左右)

Spring(5.0开始) 等优秀的开源项目都将自己的项目从 Maven 迁移到了 Gradle

1.2 安装Gradle

  • Gradle下载地址:https://gradle.org/releases/

    (注:需下载6.0以下版本,版本太高,会导致idea中编译时,部分spring组件无法下载,此处下载的是5.6.4版本,具体配置步骤自行百度)

image-20210928100144207

2. 下载Spring源码

2.1 下载

下载地址(GitHub): https://github.com/spring-projects/spring-framework

注意:对于源码要进行 git clone 拉取(如果直接下载zip,会报如下错误)

image-20210928100827693

2.2 源码环境编译

进入bin目录下,执行 gradlew.bat(建议命令行中执行)

3 源码导入IDEA

​ 直接open project (idea 2020)

​ 漫长的等待…

(注意:手动配置JDK及gradle)

image-20230813215913958

image-20230813215951379

构建完成后,模块会出现蓝色小点

image-20230813220443475

3. 构建源码测试模块

3.1 创建新Module

image-20230813220555807

image-20230813220833984

image-20230813220908866

image-20230813220935926

3.2 添加依赖

打开 build.gradle

dependencies {
    compile(project(':spring-context')) // 添加spring-context依赖
    compile(project(':spring-aop')) // 添加spring-aop依赖
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

3.3 编写测试代码

  1. 编写TestBean
@Component
public class TestBean {

    public void print(){
        System.err.println("testBean method...");
        System.err.println("spring源码环境构建完成...");
    }
}
  1. 创建applicationContext.xml,配置TestBean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


   <bean id="testBean" class="com.xc.config.TestBean"/>
   
</beans>
  1. 编写测试类IOCTest
public class IOCTest {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new       ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        TestBean testBean = (TestBean) applicationContext.getBean("testBean");
        testBean.print();
    }
}

image-20230813221530539

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值