当前位置: 首页 > article >正文

Spring的底层原理

文章目录

  • 1. Bean的生命周期
  • 2. 推断构造方法
  • 3. 依赖注入
  • 4. 初始化前
  • 5. 初始化
  • 6. 初始化后
  • 7. AOP
  • 8. Spring事务
  • 9. Spring事务失效
  • 10. @Configuration
  • 11. 循环依赖
  • 12. @Lazy

在这里插入图片描述

在这里插入图片描述

1. Bean的生命周期

UserService.class --> 推断构造方法 --> 普通对象 --> 依赖注入 --> 初始化前 --> 初始化 --> 初始化后(AOP)--> 代理对象 --> 放入Map(单例池)--> Bean对象

2. 推断构造方法

  • 对于bean类中定义了一个构造器(带参数或不带参数),或者不手动定义构造器(此时java默认会隐式的创建一个空参构造器),Spring在创建该bean时使用唯一的构造器。
  • 对于bean类中定义了多个构造器,Spring在创建该bean时会默认去找空参构造器,若没有则报错;
  • 对于bean类中定义了多个构造器,可以 为指定的构造器添加 @Autowire 注解,此时Spring在创建该bean时会使用指定的构造器。
  • 特别的:当Spring使用带参数的构造器创建bean时会在IOC容器中找形参对应的bean(先类型匹配,再名称匹配)并传入,找不到或不是bean则会报错
    • 对应找到过程,首先如果形参对应的bean是单例的则会先在 单例池 中寻找,找到则传入(先类型匹配,若有多个该类型的bean则再通过名称匹配,此时名称唯一匹配上则注入,没有则报错;若类型匹配只有一个时则直接注入无需匹配名称);若找不到则直接通过反射创建形参对应的bean(可能有多个),将其保存至 单例池,再查找。(在这个创建过程中可能出现循环依赖问题)
    • 如果形参对应的bean是多例的,则直接创建一个新的bean实例并注入
@Component
public class UserService{
    OrderService orderService;
    

    public UserService(){
    }

    @Autowire
    public UserService(OrderService orderService){
    }
}

3. 依赖注入

  • 对于bean的类中使用 @Autowire 等注解标注的属性,通过与构造器参数注入相同的方法进行依赖注入
  • @Autowire是先按类型匹配,再按名称。只匹配到一个该类型的对象则直接注入,对于匹配到多个该类型的对象再通过名称匹配,有则注入,没有则报错

4. 初始化前

  • 执行 @PostConstruct 所标注的方法
  • 执行 实现了 BeanPostPocessor 接口的bean 中的 前置处理方法

5. 初始化

  • 若当前创建的 bean 实现了 initializationBean 接口的 afterPropertiesSet 方法,则会执行

6. 初始化后

  • 执行 实现了 BeanPostPocessor 接口的bean 中的 后置处理方法

7. AOP

  • Spring的AOP基于Cglib的动态代理实现,其原理如下
    在这里插入图片描述

8. Spring事务

在这里插入图片描述

9. Spring事务失效

在这里插入图片描述

  • 可以自己注入自己,使用代理对象的a()方法,使得事务生效
    在这里插入图片描述

10. @Configuration

  • 对于自定义的配置类中 @Configuration 为当前配置类对象创建动态代理类(注意:是基于动态代理实现,不是基于AOP实现)其动态代理实现是基于继承
  • 由于 Spring 的事务中,需要使 transactionManagerjdbcTemplate 均使用一个dataSource(同一个对象),才能使得 ThreadLocal 中的 Map 中顺利传递,以保证事务的顺利执行
class AppConfigProxy extends AppConfig{
    public JDBCTemplate jdbcTemplate(){
        // 1. 此处会有代理逻辑代码,会先去 IOC 容器中其找是否已存在当前名(方法名)的bean,如果有则终止创建

        // 2. 使用被代理类的实现创建jdbcTemplate对象
        /**
        注意:super.jdbcTemplate()中所包含的 dataSource() 由于动态绑定机制,在调用时是使用当前代理类中的dataSource()方法,则该方法的逻辑是会先去 IOC 容器中去找对应的 Bean 没有再创建,对应多个方法中都使用 dataSource() 其实质是使用了同一个 dataSource 对象(单例的情况下)
        */
        JDBCTemplate jt = super.jdbcTemplate();

        // 3. 将新创建的 JDBCTemplate 加入 IOC 容器
        ....
    }

    public DataSource dataSource(){
        // 1. ...
        // 2. ...
        DataSource ds = super.dataSource()
        // 3. ...
    }
}
// 扫描组件
@ComponentScan("com.gyh")

// 开启事务
@EnableTransactionManagement

// 为当前对象创建动态代理类(注意:是基于动态代理实现,不是基于AOP实现)
@Configuration
public class AppConfig{
    @Bean
    public JdbcTemplate jdbcTemplate(){
        return enw JdbcTemplate(dataSource()); // 使用动态代理后的dataSource()
    }

    @Bean
    public PlatformTransactionManager transactionManager(){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource());  // 使用动态代理后的dataSource()
    }

    @Bean
    public DataSource dataSource(){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl("...");
        dataSource.setUsername("...");
        dataSource.setPassword("...");
        return dataSource;
    }

}

11. 循环依赖

  • 一个循环依赖问题
    在这里插入图片描述
// 循环依赖的场景
@Component
public class AService{
    @Autowire
    private BService bService;

    @Autowire
    private CService cService;
}


@Component
public class BService{
    @Autowire
    private AService aService;
}

@Component
public class CService{
    @Autowire
    private AService aService;
}

在这里插入图片描述

  • 利用三级缓存解决循环依赖
    • 第一级缓存:singletonObjects ---- 在依赖注入时会首先在单例池中查找是否有经完整周期创建的bean,有则直接注入
    • 第二级缓存:earlySingletonObjects — 如果单例池中没有则判断是否存在循环依赖,若存在循环依赖,则会在二级缓存中查找是否有还未经完成创建的bean,有则直接获取并注入;没有则进入下一级缓存(二级缓存可以保证多个循环依赖中的单例情况)
    • 第三级缓存:singletonFactories — 该缓存会在所有 bean 创建对象(普通bean对象)后进行保存,待到某个bean经过二级缓存后需要,则从中寻找该beanName对应的普通对象,若需要提前AOP则进行动态代理,生成该普通对象的代理对象后保存至二级缓存;若没有AOP过程直接将普通bean对象保存至二级缓存。

12. @Lazy

  • 对延迟对指定的属性或构造器参数的注入,在 bean 的属性设置等环节中直接构造它的代理对象并赋值(不执行循环注入逻辑),而在实际使用它的时候再去创建该@Lazy标注的属性或构造器参数的bean二级缓存;若没有AOP过程直接将普通bean对象保存至二级缓存。

http://www.kler.cn/news/361679.html

相关文章:

  • 鸿蒙网络编程系列25-TCP回声服务器的实现
  • R语言笔记(一)
  • 群晖通过 Docker 安装 MySQL
  • Wordpress GutenKit 插件 远程文件写入致RCE漏洞复现(CVE-2024-9234)
  • 【PHP小课堂】一起学习PHP中的反射(一)
  • JavaScript 中String.repeat() 的用法
  • Linux:Linux中第一个小程序_进度条
  • Springboot 使用EasyExcel导出Excel文件
  • 英语写作中“有前景的”promising的用法
  • Python 第七节 魔法圆阵
  • PCL 最小点数约束的体素滤波(永久免费版)
  • 利用DeepFlow解决APISIX故障诊断中的方向偏差问题
  • 2024 “源鲁杯“ Round[1] web部分
  • 无线网卡知识的学习-- mac80211主要代码流程
  • Eclipse 软件:配置 JDBC、连接 MySQL 数据库、导入 jar 包
  • PDT 数据集:首个基于无人机的高精密度树木病虫害目标检测数据集
  • 大数据学习---快速了解clickhouse数据库
  • Python 网络爬虫教程
  • VScode远程开发之remote 远程开发(二)
  • 华为云桌面:构建灵活高效的数字化工作环境
  • Java项目实战II基于微信小程序UNIAPP+SSM+MySQL的电子点餐系统(开发文档+数据库+源码)
  • Python Q-learning 算法详解与应用案例
  • CTF(九)
  • 大范围实景三维智能调色 | 模方自动化匀色解决方案
  • 【贪心算法】(第十篇)
  • 转行AI产品经理,第二步怎么走