跨境互联网 跨境互联网
首页
  • AI 工具

    • 绘图提示词工具 (opens new window)
    • ChatGPT 指令 (opens new window)
  • ChatGPT

    • ChatGP T介绍
    • ChatGPT API 中文开发手册
    • ChatGPT 中文调教指南
    • ChatGPT 开源项目
  • Midjourney

    • Midjourney 文档
  • Stable Diffusion

    • Stable Diffusion 文档
  • 其他

    • AIGC 热门文章
    • 账号合租 (opens new window)
    • 有趣的网站
  • Vue

    • Vue3前置
  • JAVA基础

    • Stream
    • Git
    • Maven
    • 常用第三方类库
    • 性能调优工具
    • UML系统建模
    • 领域驱动设计
    • 敏捷开发
    • Java 测试
    • 代码规范及工具
    • Groovy 编程
  • 并发编程&多线程

    • 并发编程
    • 高性能队列 Disruptor
    • 多线程并发在电商系统下的应用
  • 其他

    • 面试题
  • 消息中间中间件

    • Kafka
    • RabbitMQ
    • RocketMQ
  • 任务调度

    • Quartz
    • XXL-Job
    • Elastic-Job
  • 源码解析

    • Mybatis 高级使用
    • Mybatis 源码剖析
    • Mybatis-Plus
    • Spring Data JPA
    • Spring 高级使用
    • Spring 源码剖析
    • SpringBoot 高级使用
    • SpringBoot 源码剖析
    • Jdk 解析
    • Tomcat 架构设计&源码剖析
    • Tomcat Web应用服务器
    • Zookeeper 高级
    • Netty
  • 微服务框架

    • 分布式原理
    • 分布式集群架构场景化解决方案
    • Dubbo 高级使用
    • Dubbo 核心源码剖析
    • Spring Cloud Gateway
    • Nacos 实战应用
    • Sentinel 实战应用
    • Seata 分布式事务
  • 数据结构和算法的深入应用
  • 存储

    • 图和Neo4j
    • MongoDB
    • TiDB
    • MySQL 优化
    • MySQL 平滑扩容实战
    • MySQL 海量数据存储与优化
    • Elasticsearch
  • 缓存

    • Redis
    • Aerospike
    • Guava Cache
    • Tair
  • 文件存储

    • 阿里云 OSS 云存储
    • FastDF 文件存储
  • 基础

    • Linux 使用
    • Nginx 使用与配置
    • OpenResty 使用
    • LVS+Keepalived 高可用部署
    • Jekins
  • 容器技术

    • Docker
    • K8S
    • K8S
  • 01.全链路(APM)
  • 02.电商终极搜索解决方案
  • 03.电商亿级数据库设计
  • 04.大屏实时计算
  • 05.分库分表的深入实战
  • 06.多维系统下单点登录
  • 07.多服务之间分布式事务
  • 08.业务幂等性技术架构体系
  • 09.高并发下的12306优化
  • 10.每秒100W请求的秒杀架构体系
  • 11.集中化日志管理平台的应用
  • 12.数据中台配置中心
  • 13.每天千万级订单的生成背后痛点及技术突破
  • 14.红包雨的架构设计及源码实现
  • 人工智能

    • Python 笔记
    • Python 工具库
    • 人工智能(AI) 笔记
    • 人工智能(AI) 项目笔记
  • 大数据

    • Flink流处理框架
  • 加密区

    • 机器学习(ML) (opens new window)
    • 深度学习(DL) (opens new window)
    • 自然语言处理(NLP) (opens new window)
AI 导航 (opens new window)

Revin

首页
  • AI 工具

    • 绘图提示词工具 (opens new window)
    • ChatGPT 指令 (opens new window)
  • ChatGPT

    • ChatGP T介绍
    • ChatGPT API 中文开发手册
    • ChatGPT 中文调教指南
    • ChatGPT 开源项目
  • Midjourney

    • Midjourney 文档
  • Stable Diffusion

    • Stable Diffusion 文档
  • 其他

    • AIGC 热门文章
    • 账号合租 (opens new window)
    • 有趣的网站
  • Vue

    • Vue3前置
  • JAVA基础

    • Stream
    • Git
    • Maven
    • 常用第三方类库
    • 性能调优工具
    • UML系统建模
    • 领域驱动设计
    • 敏捷开发
    • Java 测试
    • 代码规范及工具
    • Groovy 编程
  • 并发编程&多线程

    • 并发编程
    • 高性能队列 Disruptor
    • 多线程并发在电商系统下的应用
  • 其他

    • 面试题
  • 消息中间中间件

    • Kafka
    • RabbitMQ
    • RocketMQ
  • 任务调度

    • Quartz
    • XXL-Job
    • Elastic-Job
  • 源码解析

    • Mybatis 高级使用
    • Mybatis 源码剖析
    • Mybatis-Plus
    • Spring Data JPA
    • Spring 高级使用
    • Spring 源码剖析
    • SpringBoot 高级使用
    • SpringBoot 源码剖析
    • Jdk 解析
    • Tomcat 架构设计&源码剖析
    • Tomcat Web应用服务器
    • Zookeeper 高级
    • Netty
  • 微服务框架

    • 分布式原理
    • 分布式集群架构场景化解决方案
    • Dubbo 高级使用
    • Dubbo 核心源码剖析
    • Spring Cloud Gateway
    • Nacos 实战应用
    • Sentinel 实战应用
    • Seata 分布式事务
  • 数据结构和算法的深入应用
  • 存储

    • 图和Neo4j
    • MongoDB
    • TiDB
    • MySQL 优化
    • MySQL 平滑扩容实战
    • MySQL 海量数据存储与优化
    • Elasticsearch
  • 缓存

    • Redis
    • Aerospike
    • Guava Cache
    • Tair
  • 文件存储

    • 阿里云 OSS 云存储
    • FastDF 文件存储
  • 基础

    • Linux 使用
    • Nginx 使用与配置
    • OpenResty 使用
    • LVS+Keepalived 高可用部署
    • Jekins
  • 容器技术

    • Docker
    • K8S
    • K8S
  • 01.全链路(APM)
  • 02.电商终极搜索解决方案
  • 03.电商亿级数据库设计
  • 04.大屏实时计算
  • 05.分库分表的深入实战
  • 06.多维系统下单点登录
  • 07.多服务之间分布式事务
  • 08.业务幂等性技术架构体系
  • 09.高并发下的12306优化
  • 10.每秒100W请求的秒杀架构体系
  • 11.集中化日志管理平台的应用
  • 12.数据中台配置中心
  • 13.每天千万级订单的生成背后痛点及技术突破
  • 14.红包雨的架构设计及源码实现
  • 人工智能

    • Python 笔记
    • Python 工具库
    • 人工智能(AI) 笔记
    • 人工智能(AI) 项目笔记
  • 大数据

    • Flink流处理框架
  • 加密区

    • 机器学习(ML) (opens new window)
    • 深度学习(DL) (opens new window)
    • 自然语言处理(NLP) (opens new window)
AI 导航 (opens new window)
  • Spring Data JPA
  • MyBatis

  • Spring

    • Spring高级使用

      • Spring概述
      • Spring核心思想
      • 手写实现 IoC 和 AOP
      • Spring IOC 应用
        • 1.1 BeanFactory与ApplicationContext区别
        • 1.2 纯xml模式
          • xml 文件头
          • 实例化Bean的三种方式
          • 方式一:使用无参构造函数
          • 方式二:使用静态方法创建
          • 方式三:使用实例化方法创建
          • Bean的X及生命周期
          • 作用范围的改变
          • 不同作用范围的生命周期
          • Bean标签属性
          • DI 依赖注入的xml配置
          • 依赖注入分类
          • 依赖注入的配置实现之构造函数注入
          • 依赖注入的配置实现之set方法注入
          • 复杂数据类型注入
        • 1.3 xml与注解相结合模式
          • xml中标签与注解的对应(IoC)
          • DI 依赖注入的注解实现方式
          • @Autowired(推荐使用)
          • @Resource
        • 1.4 纯注解模式
        • 2.1 lazy-Init 延迟加载
        • 2.2 FactoryBean 和 BeanFactory
        • 2.3 后置处理器
          • 2.3.1 BeanPostProcessor
          • 2.3.2 BeanFactoryPostProcessor
      • Spring IOC源码深度剖析
      • Spring AOP 应用
      • Spring AOP源码深度剖析
    • Spring源码剖析

    • 资料
  • SpringBoot

  • Jdk

  • Tomcat

  • Netty

  • 若依

  • Traefik

  • Openresty

  • 开源框架
  • Spring
  • Spring高级使用
Revin
2023-07-23
目录

Spring IOC 应用

# 第1节 Spring IoC基础

Spring高级框架课程笔记_Page26_01

# 1.1 BeanFactory与ApplicationContext区别

BeanFactory是Spring框架中IoC容器的顶层接口,它只是用来定义一些基础功能,定义一些基础规范,而ApplicationContext是它的一个子接口,所以ApplicationContext是具备BeanFactory提供的全部功能的。

通常,我们称BeanFactory为SpringIOC的基础容器,ApplicationContext是容器的高级接口,比

BeanFactory要拥有更多的功能,比如说国际化支持和资源访问(xml,java配置类)等等

Spring高级框架课程笔记_Page26_02

启动 IoC 容器的方式

  • Java环境下启动IoC容器

    • ClassPathXmlApplicationContext:从类的根路径下加载配置文件(推荐使用)
    • FileSystemXmlApplicationContext:从磁盘路径上加载配置文件
    • AnnotationConfigApplicationContext:纯注解模式下启动Spring容器
  • Web环境下启动IoC容器

    • 从xml启动容器
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
  <display-name>Archetype Created Web Application</display-name>
  
  <!--配置Spring ioc容器的配置文件-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <!--使用监听器启动Spring的IOC容器-->
  <listener>
    <listener-class>
      org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>
</web-app>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    • 从配置类启动容器
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>


  <display-name>Archetype Created Web Application</display-name>
  
  <!--告诉ContextloaderListener知道我们使用注解的方式启动ioc容器-->
  <context-param>
    <param-name>contextClass</param-name>
    <param-value>
       org.springframework.web.context.support.AnnotationConfigWebApplicationContext
    </param-value>
  </context-param>
  <!--配置启动类的全限定类名-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>com.lagou.edu.SpringConfig</param-value>
  </context-param>
  
  <!--使用监听器启动Spring的IOC容器-->
  <listener>
    <listener-class>
      org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>
</web-app>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 1.2 纯xml模式

本部分内容我们不采用一一讲解知识点的方式,而是采用Spring IoC 纯 xml 模式改造我们前面手写的IoC 和 AOP 实现,在改造的过程中,把各个知识点串起来。

  • # xml 文件头

<?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
    https://www.springframework.org/schema/beans/spring-beans.xsd">
1
2
3
4
5
  • # 实例化Bean的三种方式

    • # 方式一:使用无参构造函数

在默认情况下,它会通过反射调用无参构造函数来创建对象。如果类中没有无参构造函数,将创建

失败。

<!--配置service对象-->
<bean id="userService" class="com.lagou.service.impl.TransferServiceImpl">
</bean>
1
2
3
    • # 方式二:使用静态方法创建

在实际开发中,我们使用的对象有些时候并不是直接通过构造函数就可以创建出来的,它可能在创

建的过程 中会做很多额外的操作。此时会提供一个创建对象的方法,恰好这个方法是static修饰的

方法,即是此种情 况。

例如,我们在做Jdbc操作时,会用到java.sql.Connection接口的实现类,如果是mysql数据库,那

么用的就 是JDBC4Connection,但是我们不会去写 JDBC4Connection connection = new

JDBC4Connection() ,因 为我们要注册驱动,还要提供URL和凭证信息,

用 DriverManager.getConnection 方法来获取连接。

那么在实际开发中,尤其早期的项目没有使用Spring框架来管理对象的创建,但是在设计时使用了

工厂模式 解耦,那么当接入spring之后,工厂类创建对象就具有和上述例子相同特征,即可采用

此种方式配置。

<!--使用静态方法创建对象的配置方式-->
<bean id="userService" class="com.lagou.factory.BeanFactory" factory-method="getTransferService"></bean>
1
2
    • # 方式三:使用实例化方法创建

此种方式和上面静态方法创建其实类似,区别是用于获取对象的方法不再是static修饰的了,而是

类中的一 个普通方法。此种方式比静态方法创建的使用几率要高一些。

在早期开发的项目中,工厂类中的方法有可能是静态的,也有可能是非静态方法,当是非静态方法

时,即可 采用下面的配置方式:

<!--使用实例方法创建对象的配置方式-->
<bean id="beanFactory"
class="com.lagou.factory.instancemethod.BeanFactory"></bean>
<bean id="transferService" factory-bean="beanFactory" factory-method="getTransferService"></bean>
1
2
3
4
  • # Bean的X及生命周期

    • # 作用范围的改变

在spring框架管理Bean对象的创建时,Bean对象默认都是单例的,但是它支持配置的方式改

变作用范围。作用范围官方提供的说明如下图:

Spring高级框架课程笔记_Page29_01

在上图中提供的这些选项中,我们实际开发中用到最多的作用范围就是singleton(单例模式)和

prototype(原型模式,也叫多例模式)。配置方式参考下面的代码:

<!--配置service对象-->
<bean id="transferService" class="com.lagou.service.impl.TransferServiceImpl" scope="singleton">
</bean>
1
2
3
    • # 不同作用范围的生命周期

单例模式:singleton

对象出生:当创建容器时,对象就被创建了。

对象活着:只要容器在,对象一直活着。

对象死亡:当销毁容器时,对象就被销毁了。

一句话总结:单例模式的bean对象生命周期与容器相同。

多例模式:prototype

对象出生:当使用对象时,创建新的对象实例。

对象活着:只要对象在使用中,就一直活着。

对象死亡:当对象⻓时间不用时,被java的垃圾回收器回收了。

一句话总结:多例模式的bean对象,spring框架只负责创建,不负责销毁。

  • # Bean标签属性

在基于xml的IoC配置中,bean标签是最基础的标签。它表示了IoC容器中的一个对象。换句话

说,如果一个对象想让spring管理,在XML的配置中都需要使用此标签配置,Bean标签的属性如

下:

id属性: 用于给bean提供一个唯一标识。在一个标签内部,标识必须唯一。

*class属性:*用于指定创建Bean对象的全限定类名。

**name属性:**用于给bean提供一个或多个名称。多个名称用空格分隔。

**factory-bean属性:**用于指定创建当前bean对象的工厂bean的唯一标识。当指定了此属性之后,

class属性失效。

factory-method属性:用于指定创建当前bean对象的工厂方法,如配合factory-bean属性使用,

则class属性失效。如配合class属性使用,则方法必须是static的。

**scope属性:**用于指定bean对象的作用范围。通常情况下就是singleton。当要用到多例模式时,

可以配置为prototype。

**init-method属性:**用于指定bean对象的初始化方法,此方法会在bean对象装配后调用。必须是

一个无参方法。

destory-method属性:用于指定bean对象的销毁方法,此方法会在bean对象销毁前执行。它只

能为scope是singleton时起作用。

  • # DI 依赖注入的xml配置

    • # 依赖注入分类

      • 按照注入的方式分类

构造函数注入:顾名思义,就是利用带参构造函数实现对类成员的数据赋值。

**set方法注入:**它是通过类成员的set方法实现数据的注入。(使用最多的)

      • 按照注入的数据类型分类

基本类型和String

注入的数据类型是基本类型或者是字符串类型的数据。

其他Bean类型

注入的数据类型是对象类型,称为其他Bean的原因是,这个对象是要求出现在IoC容器

中的。那么针对当前Bean来说,就是其他Bean了。

复杂类型(集合类型)

注入的数据类型是Aarry,List,Set,Map,Properties中的一种类型。

    • # 依赖注入的配置实现之构造函数注入

顾名思义,就是利用构造函数实现对类成员的赋值。它的使用要求是,类中提供的构造函数参数个数必须和配置的参数个数一致,且数据类型匹配。同时需要注意的是,当没有无参构造时,则必须提供构造函数参数的注入,否则Spring框架会报错。

Spring高级框架课程笔记_Page31_01

Spring高级框架课程笔记_Page31_02

在使用构造函数注入时,涉及的标签是 constructor-arg ,该标签有如下属性:

name:用于给构造函数中指定名称的参数赋值。

index:用于给构造函数中指定索引位置的参数赋值。

value:用于指定基本类型或者String类型的数据。

ref:用于指定其他Bean类型的数据。写的是其他bean的唯一标识。

    • # 依赖注入的配置实现之set方法注入

顾名思义,就是利用字段的set方法实现赋值的注入方式。此种方式在实际开发中是使用最多的注

入方式。

Spring高级框架课程笔记_Page32_01

Spring高级框架课程笔记_Page32_02

在使用set方法注入时,需要使用 property 标签,该标签属性如下:

name:指定注入时调用的set方法名称。(注:不包含set这三个字母,druid连接池指定属性名称)

value:指定注入的数据。它支持基本类型和String类型。

ref:指定注入的数据。它支持其他bean类型。写的是其他bean的唯一标识。

    • # 复杂数据类型注入

首先,解释一下复杂类型数据,它指的是集合类型数据。集合分为两类,一类

是List结构(数组结构),一类是Map接口(键值对) 。

接下来就是注入的方式的选择,只能在构造函数和set方法中选择,我们的示例选用set方法注入。

Spring高级框架课程笔记_Page33_01

Spring高级框架课程笔记_Page34_01

在List结构的集合数据注入时, array , list , set 这三个标签通用,另外注值的 value 标签内部

可以直接写值,也可以使用 bean 标签配置一个对象,或者用 ref 标签引用一个已经配合的bean

的唯一标识。

在Map结构的集合数据注入时, map 标签使用 entry 子标签实现数据注入, entry 标签可以使

用key和value属性指定存入map中的数据。使用value-ref属性指定已经配置好的bean的引用。

同时 entry 标签中也可以使用 ref 标签,但是不能使用 bean 标签。而 property 标签中不能使

用 ref 或者 bean 标签引用对象

# 1.3 xml与注解相结合模式

注意:

1)实际企业开发中,纯xml模式使用已经很少了

2)引入注解功能,不需要引入额外的jar

3)xml+注解结合模式,xml文件依然存在,所以,spring IOC容器的启动仍然从加载xml开始

4)哪些bean的定义写在xml中,哪些bean的定义使用注解

第三方jar中的bean定义在xml,比如德鲁伊数据库连接池

自己开发的bean定义使用注解

  • # xml中标签与注解的对应(IoC)

image-20230723121425778

  • # DI 依赖注入的注解实现方式

# @Autowired(推荐使用)

@Autowired为Spring提供的注解,需要导入包

org.springframework.beans.factory.annotation.Autowired。

@Autowired采取的策略为按照类型注入。

public class TransferServiceImpl {
  @Autowired
  private AccountDao accountDao;
}
1
2
3
4

如上代码所示,这样装配回去spring容器中找到类型为AccountDao的类,然后将其注入进来。这

样会产生一个问题,当一个类型有多个bean值的时候,会造成无法选择具体注入哪一个的情况,

这个时候我们需要配合着@Qualifier使用。

@Qualifier告诉Spring具体去装配哪个对象。

public class TransferServiceImpl {
  @Autowired
  @Qualifier(name="jdbcAccountDaoImpl")
  private AccountDao accountDao;
}
1
2
3
4
5

这个时候我们就可以通过类型和名称定位到我们想注入的对象。

# @Resource

@Resource 注解由 J2EE 提供,需要导入包 javax.annotation.Resource。

@Resource 默认按照 ByName 自动注入。

public class TransferService {
  @Resource
  private AccountDao accountDao;
  @Resource(name="studentDao")
  private StudentDao studentDao;
  @Resource(type="TeacherDao")
  private TeacherDao teacherDao;
  @Resource(name="manDao",type="ManDao")
  private ManDao manDao;
}
1
2
3
4
5
6
7
8
9
10

如果同时指定了 name 和 type,则从Spring上下文中找到唯一匹配的bean进行装配,找不

到则抛出异常。

如果指定了 name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异

常。

如果指定了 type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,

都会抛出异常。

如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;

注意:

@Resource 在 Jdk 11中已经移除,如果要使用,需要单独引入jar包

<dependency>
  <groupId>javax.annotation</groupId>
  <artifactId>javax.annotation-api</artifactId>
  <version>1.3.2</version>
</dependency>
1
2
3
4
5

# 1.4 纯注解模式

改造xm+注解模式,将xml中遗留的内容全部以注解的形式迁移出去,最终删除xml,从Java配置类启动

对应注解

@Configuration 注解,表名当前类是一个配置类

@ComponentScan 注解,替代 context:component-scan

@PropertySource,引入外部属性配置文件

@Import 引入其他配置类

@Value 对变量赋值,可以直接赋值,也可以使用 ${} 读取资源配置文件中的信息

@Bean 将方法返回对象加入 SpringIOC 容器

# 第2节 Spring IOC高级特性

# 2.1 lazy-Init 延迟加载

Bean的延迟加载(延迟创建)

ApplicationContext 容器的默认行为是在启动服务器时将所有 singleton bean 提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext 实例会创建并配置所有的singleton bean。

比如:

<bean id="testBean" class="cn.lagou.LazyBean" />


该bean默认的设置为:
<bean id="testBean" calss="cn.lagou.LazyBean" lazy-init="false" />
1
2
3
4
5

lazy-init="false",立即加载,表示在spring启动时,立刻进行实例化。

如果不想让一个singleton bean 在 ApplicationContext实现初始化时被提前实例化,那么可以将bean 设置为延迟实例化。

<bean id="testBean" calss="cn.lagou.LazyBean" lazy-init="true" />
1

设置 lazy-init 为 true 的 bean 将不会在 ApplicationContext 启动时提前被实例化,而是第一次向容器通过 getBean 索取 bean 时实例化的。

如果一个设置了立即加载的 bean1,引用了一个延迟加载的 bean2 ,那么 bean1 在容器启动时被实例化,而 bean2 由于被 bean1 引用,所以也被实例化,这种情况也符合延时加载的 bean 在第一次调用时才被实例化的规则。

也可以在容器层次中通过在 元素上使用 "default-lazy-init" 属性来控制延时初始化。如下面配置:

<beans default-lazy-init="true">
<!-- no beans will be eagerly pre-instantiated... -->
</beans>
1
2
3

如果一个 bean 的 scope 属性为 scope="pototype" 时,即使设置了 lazy-init="false",容器启动时也不会实例化bean,而是调用 getBean 方法实例化的。

应用场景

(1)开启延迟加载一定程度提高容器启动和运转性能

(2)对于不常使用的 Bean 设置延迟加载,这样偶尔使用的时候再加载,不必要从一开始该 Bean 就占用资源

# 2.2 FactoryBean 和 BeanFactory

BeanFactory接口是容器的顶级接口,定义了容器的一些基础行为,负责生产和管理Bean的一个工厂,具体使用它下面的子接口类型,比如ApplicationContext;此处我们重点分析FactoryBean

Spring中Bean有两种,一种是普通Bean,一种是工厂Bean(FactoryBean),FactoryBean可以生成

某一个类型的Bean实例(返回给我们),也就是说我们可以借助于它自定义Bean的创建过程。

Bean创建的三种方式中的静态方法和实例化方法和FactoryBean作用类似,FactoryBean使用较多,尤其在Spring框架一些组件中会使用,还有其他框架和Spring框架整合时使用

// 可以让我们自定义Bean的创建过程(完成复杂Bean的定义)
public interface FactoryBean<T> {
  @Nullable
  // 返回FactoryBean创建的Bean实例,如果isSingleton返回true,则该实例会放到Spring容器的单例对象缓存池中Map
  T getObject() throws Exception;
  
  @Nullable
  // 返回FactoryBean创建的Bean类型
  Class<?> getObjectType();
  
  // 返回作用域是否单例
  default boolean isSingleton() {
    return true;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Company类

package com.lagou.edu.pojo;
/**
* @author 应癫
*/
public class Company {
    private String name;
    private String address;
    private int scale;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    public String getAddress() {
        return address;
    }
    
    public void setAddress(String address) {
        this.address = address;
    }
    public int getScale() {
        return scale;
    }
    
    public void setScale(int scale) {
        this.scale = scale;
    }
    
    @Override
    public String toString() {
        return "Company{" +
        "name='" + name + '\'' +
        ", address='" + address + '\'' +
        ", scale=" + scale +
        '}';
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

CompanyFactoryBean类

package com.lagou.edu.factory;
import com.lagou.edu.pojo.Company;
import org.springframework.beans.factory.FactoryBean;
/**
* @author 应癫
*/
public class CompanyFactoryBean implements FactoryBean<Company> {
    private String companyInfo; // 公司名称,地址,规模
    public void setCompanyInfo(String companyInfo) {
        this.companyInfo = companyInfo;
    }
    
    @Override
    public Company getObject() throws Exception {
        // 模拟创建复杂对象Company
        Company company = new Company();
        String[] strings = companyInfo.split(",");
        company.setName(strings[0]);
        company.setAddress(strings[1]);
        company.setScale(Integer.parseInt(strings[2]));
        return company;
    }
    
    @Override
    public Class<?> getObjectType() {
        return Company.class;
    }
    
    @Override
    public boolean isSingleton() {
        return true;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

xml配置

<bean id="companyBean" class="com.lagou.edu.factory.CompanyFactoryBean">
<property name="companyInfo" value="拉勾,中关村,500"/>
</bean>
1
2
3

测试,获取FactoryBean产生的对象

Object companyBean = applicationContext.getBean("companyBean");
System.out.println("bean:" + companyBean);


// 结果如下
bean:Company{name='拉勾', address='中关村', scale=500}
1
2
3
4
5
6

测试,获取FactoryBean,需要在id之前添加“&”

Object companyBean = applicationContext.getBean("&companyBean");
System.out.println("bean:" + companyBean);


// 结果如下
bean:com.lagou.edu.factory.CompanyFactoryBean@53f6fd09
1
2
3
4
5
6

# 2.3 后置处理器

Spring提供了两种后处理bean的扩展接口,分别为 BeanPostProcessor 和

BeanFactoryPostProcessor,两者在使用上是有所区别的。

工厂初始化(BeanFactory)—> Bean对象

在BeanFactory初始化之后可以使用BeanFactoryPostProcessor进行后置处理做一些事情

在Bean对象实例化(并不是Bean的整个生命周期完成)之后可以使用BeanPostProcessor进行后置处理做一些事情

注意:对象不一定是springbean,而springbean一定是个对象

SpringBean的生命周期

# 2.3.1 BeanPostProcessor

Spring高级框架课程笔记_Page41_01

该接口提供了两个方法,分别在Bean的初始化方法前和初始化方法后执行,具体这个初始化方法指的是什么方法,类似我们在定义bean时,定义了init-method所指定的方法

定义一个类实现了BeanPostProcessor,默认是会对整个Spring容器中所有的bean进行处理。如果要对具体的某个bean处理,可以通过方法参数判断,两个类型参数分别为Object和String,第一个参数是每个bean的实例,第二个参数是每个bean的name或者id属性的值。所以我们可以通过第二个参数,来判断我们将要处理的具体的bean。

注意:处理是发生在Spring容器的实例化和依赖注入之后。

# 2.3.2 BeanFactoryPostProcessor

BeanFactory级别的处理,是针对整个Bean的工厂进行处理,典型应

用:PropertyPlaceholderConfigurer

Spring高级框架课程笔记_Page41_02

此接口只提供了一个方法,方法参数为ConfigurableListableBeanFactory,该参数类型定义了一些方法

Spring高级框架课程笔记_Page42_01

其中有个方法名为getBeanDefinition的方法,我们可以根据此方法,找到我们定义bean 的

BeanDefinition对象。然后我们可以对定义的属性进行修改,以下是BeanDefinition中的方法

Spring高级框架课程笔记_Page43_01

方法名字类似我们bean标签的属性,setBeanClassName对应bean标签中的class属性,所以当我们拿到BeanDefinition对象时,我们可以手动修改bean标签中所定义的属性值。

BeanDefinition对象:我们在 XML 中定义的 bean标签,Spring 解析 bean 标签成为一个 JavaBean,这个JavaBean 就是 BeanDefinition

注意:调用 BeanFactoryPostProcessor 方法时,这时候bean还没有实例化,此时 bean 刚被解析成

BeanDefinition对象

上次更新: 2025/04/03, 11:07:08
手写实现 IoC 和 AOP
Spring IOC源码深度剖析

← 手写实现 IoC 和 AOP Spring IOC源码深度剖析→

最近更新
01
tailwindcss
03-26
02
PaddleSpeech
02-18
03
whisper
02-18
更多文章>
Theme by Vdoing | Copyright © 2019-2025 跨境互联网 | 豫ICP备14016603号-5 | 豫公网安备41090002410995号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式