@Configuration 注解的 Full 模式和 Lite 模式!

@Configuration 注解相信各位小伙伴经常会用到,但是大家知道吗,这个注解有两种不同的模式,一种叫做 Full 模式,另外一种则叫做 Lite 模式。

准确来说,Full 模式和 Lite 模式其实

1. 概念梳理

首先我们先来看一下 Spring 官方文档中对 Full 模式和 Lite 模式的一个介绍:

图片

Spring 容器在处理 Bean 时的两种不同行为。

这个文档主要讲了这样几件事情:

  1. 我们可以通过在一个方法上添加 @Bean 注解,进而将该方法的返回值暴露给 Spring 容器,在这种场景下,@Bean 注解实际上就是一种通用的工厂方法机制。

  2. 当一个添加了 @Bean 注解的方法位于一个没有添加 @Configuration 注解的类里边时,那么这个添加了 @Bean 注解的方法在处理时就会按照 Lite 模式来处理。

  3. 当一个 Bean 被声明在添加了 @Component 注解的类中,那么会按照 Lite 模式来处理。

  4. 当一个 Bean 被声明在一个普通的类中时(plain old class),按照 Lite 模式来处理(这一点感觉和第二点差不多)。

  5. 在 Lite 模式下,@Bean 注解标记的方法最终不会被 CGLIB 进行代理,就是一个普通的工厂方法,因此,在 @Bean 标记的方法中,不能调用其他 @Bean 注解标记的方法,如果有需要,可以通过方法参数注入自己所需要的 Bean。

  6. 由于 Lite 模式下并不会使用 CGLIB,因此 @Bean 标记的方法可以是 final 类型的。

  7. 在大多数场景下,我们在一个 @Configuration 注解标记的类中,使用 @Bean 注解向 Spring 容器注册一个 Bean,都是 Full 模式。

官网文档的介绍还是有些抽象,接下来松哥通过具体的案例来和大家演示 Full 模式和 Lite 模式的差别。

2. Full 模式

先看 Full 模式,中文也可以称之为 完整 模式,我们平时使用时,在一个配置类上添加 @Configuration 注解,且不添加任何额外属性,这就是 Full 模式了。

Full 模式最大的特点是会给配置类通过 CGLIB 生成一个代理,所有被 @Bean 注解标记的方法将来都是通过代理方法进行调用。

假设我有如下配置类:

@Configuration
public class JavaConfig {@BeanUser user() {return new User();}
}

现在,我们去 Spring 容器获取这个配置类:

public class JavaDemo {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);JavaConfig config = ctx.getBean(JavaConfig.class);System.out.println("config.getClass() = " + config.getClass());}
}

打印结果如下:

图片

大家看到,最终从 Spring 容器中拿到的 JavaConfig 实例并不是原始的 JavaConfig 对象,而是一个被代理的 JavaConfig 对象。

为什么要代理呢?肯定是为了实现某些功能。

大家看下面这个案例:

@Configuration
public class JavaConfig {@BeanUser user() {User user = new User();user.setDog(dog());return user;}@BeanDog dog() {return new Dog();}
}

在 Full 模式下,在 user() 方法中调用 dog() 方法的时候,调用的是一个代理对象的 dog 方法,在这个代理对象的 dog 方法中,会首先去检查 Spring 容器中是否存在 Dog 对象,如果存在,则直接使用 Spring 容器中的 dog 对象,就不会真正去执行 dog 方法而获取到一个新的 dog 对象了,如果 Spring 容器中不存在 dog 对象,才会创建新的 dog 对象出来。

一言以蔽之,在 Full 模式下,user 中的 dog 对象和 dog 方法注册到 Spring 容器的 dog 对象是同一个。

在 Full 模式下,由于要给当前类生成代理,然后去代理 @Bean 注解标记的方法,因此,这些 @Bean 注解标记的方法不能是 final 或者 private 类型的,因为 final 或者 private 类型的方法无法被重写,也就没法生成代理对象,如果添加了 final 或者 private 修饰符,那么会抛出如下异常:

图片

3. Lite 模式

再来看 Lite 模式,这种模式可以认为是一种精简模式。

怎么开启呢?我们可以去除配置类上的 @Configuration 注解,或者去除之后添加 @Component 注解,又或者使用 @ComponentScan、@ImportResource、@Import 等注解标记类,那么最终都是 Lite 模式:

@Component
public class JavaConfig {@Beanfinal User user() {User user = new User();user.setDog(dog());return user;}@BeanDog dog() {return new Dog();}
}

此时就是 Lite 模式,现在我们去 Spring 容器中获取这个配置类:

public class JavaDemo {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);JavaConfig config = ctx.getBean(JavaConfig.class);System.out.println("config.getClass() = " + config.getClass());}
}

最终打印结果如下:

图片

大家看到,我们从 Spring 容器中拿到的就是原始的对象,而不是一个被代理过的对象。因此:

  1. 由于 @Bean 注解标记的方法没有被代理,因此,该方法可以是 final 也可以是 private,运行时都不会报错。

  2. 由于 @Bean 方法没有被代理,因此在 user 方法中调用 dog 方法的时候,就直接调用了,这就导致 user 中的 dog 和最终 dog 方法注册到 Spring 容器中的 dog 不是同一个。

针对第二点,如果想要确保 user 中的 dog 和 Spring 容器中的 dog 是同一个,那么可以通过参数将所需要的对象注入进来,类似下面这样:

@Component
public class JavaConfig {@Beanfinal User user(Dog dog) {User user = new User();user.setDog(dog);return user;}@BeanDog dog() {return new Dog();}
}

当 Spring 容器调用 user 方法初始化 User 对象时,发现该方法还有参数,因此会去容器中查找这个参数,找到了直接使用。

另外,我们也可以在类上添加 @Configuration 注解,但是通过修改属性值来启用 Lite 模式:

@Configuration(proxyBeanMethods = false)
public class JavaConfig {@Beanfinal User user(Dog dog) {User user = new User();user.setDog(dog);return user;}@BeanDog dog() {return new Dog();}
}

如果设置了 proxyBeanMethods 属性为 false,那么也就是 Lite 模式了,其实我们从属性名称上也能看出来端倪:是否代理 @Bean 注解标记的方法。

4. 小结

总结一下:

  1. Lite 模式下,配置类中的方法就是普通方法,可以是 final 类型,也可以是 private。

  2. Lite 模式下,不需要通过 CGLIB 生成动态代理类,所以启动速度会快一些。

  3. Lite 模式下,一个 @Bean 方法调用另外一个 @Bean 方法,会导致同一个 Bean 被初始化两次。

  4. Full 模式下,会给配置类生成一个动态代理类,配置类中的所有方法都将被动态代理,因此配置类中的方法不能是 final 或者 private 的。

  5. Full 模式下,一个 @Bean 方法调用另外一个 @Bean 方法,动态代理方法会先去容器中检查是否存在该 Bean,如果存在,则直接使用容器中的 Bean,否则才会去创建新的对象。

日常开发中,我们使用较多的是 Full 模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/130781.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLO算法改进6【中阶改进篇】:depthwise separable convolution轻量化C3

常规卷积操作 对于一张55像素、三通道(shape为553),经过33卷积核的卷积层(假设输出通道数为4,则卷积核shape为3334,最终输出4个Feature Map,如果有same padding则尺寸与输入层相同(…

网易按照作者批量采集新闻资讯软件说明文档

大家好,我是淘小白~ 今天给大家介绍的爬虫软件是网易按照作者采集的软件 1、软件语言: Python 2、使用到的工具 Python selenium库、谷歌浏览器、谷歌浏览器驱动 3、文件说明: 4、配置文件说明: 5、环境配置 安装Python&am…

Docker compose容器编排

Docker compose容器编排 1、Docker compose简介 docker-compose是docker的编排工具,用于定义和运行一个项目,该项目包含多个docker容器,在如今的微服务时代,一个项目会存在多个服务,使用docker一个个部署操作的话就会…

[动态规划] (五) 路径问题: LeetCode 62.不同路径

[动态规划] (五) 路径问题: LeetCode 62.不同路径 文章目录 [动态规划] (五) 路径问题: LeetCode 62.不同路径题目解析解题思路状态表示状态转移方程初始化和填表返回值 代码实现总结 62. 不同路径 题目解析 (1) 机器人从左上角到右下角有多少方法 (2) 机器人只能向左或者向右…

Screens for Mac 中文版 远程桌面连接控制工具

Screens Mac 版是Mac os平台上的一款Mac VNC 客户终端,能够自由访问远程计算机设备, Screens Mac 版支持各种强大的远程控制辅助工具,例如剪切板共享、快捷方式自定义、安全连接、多屏幕支持、快速扫描连接等。 Screens 4 for mac支持多种远程桌面协议&…

2023年上半年网络工程师试题

2023年上半年网络工程师试题 【试题一】 阅读以下说明,回答问题1至问题4将解答填入答题纸对应的解答栏内。 【说明】 某企业办公楼网络拓扑如图1-1所示。该网络中交换机Switch1-Switch4均是二层设备,分布在办公楼的各层,上联采用千兆光纤…

Jupyter Notebook交互式开源笔记本工具

1、官网 http://jupyter.org/ 2、什么是Jupyter Notebook Jupyter Notebook一个交互式的开源笔记本工具,可以用于编写、运行、和共享代码、文本、图形等内容。 如下文本、代码、图形 支持多种编程语言,包括python、R和Julia等,可以走一个…

C语言编译过程总结

开发C程序有四个步骤:预处理、编译、汇编和链接。任何一个体系结构处理器上都可以使用C语言程序,只要该体系结构处理器有相应的C语言编译器和库,那么C源代码就可以编译并连接到目标二进制文件上运行。 我们创建一个test.c为例来讲解程序编译的…

CSS解决div行变块 ➕ CSS解决“table中的td文字溢出控制显示字数,显示省略号”的问题

CSS解决div行变块 ➕ CSS解决“table中的td文字溢出控制显示字数,显示省略号”的问题 1. div变块级设置1.1 先看不设置的效果1.2 再看设置之后的效果 2. 解决 table 中 td 内容过长问题2.1 CSS实现(文字溢出控制td显示字数,显示省略号&#x…

手机转接器实现原理,低成本方案讲解

USB-C PD协议里,SRC和SNK双方之间通过CC通信来协商请求确定充电功率及数据传输速率。当个设备需要充电时,它会发送消息去给适配器请求充电,此时充电器会回应设备的请求,并告知其可提供的档位功率,设备端会根据适配器端…

英伟达发布 Windows 版 TensorRT-LLM 库

导读英伟达发布了 Windows 版本的 TensorRT-LLM 库,称其将大模型在 RTX 上的运行速度提升 4 倍。 GeForce RTX 和 NVIDIA RTX GPU 配备了名为 Tensor Core 的专用 AI 处理器,正在为超过 1 亿台 Windows PC 和工作站带来原生生成式 AI 的强大功能。 Tens…

大模型在代码缺陷检测领域的实践

静态代码扫描(SA)能快速识别代码缺陷,如空指针访问、数组越界等,以较高ROI保障质量及提升交付效率。当前扫描能力主要依赖人工经验生成规则,泛化能力弱且迭代滞后,导致漏出。本文提出基于代码知识图谱解决给机器学什么的问题&…

大数据Doris(十六):Doris表的数据划分

文章目录 Doris表的数据划分 一、Partition 二、 Bucket 三、PROPERTIES 四、 ENGINE Doris表的数据划分 Doris支持单分区和复合分

【深度学习】快速制作图像标签数据集以及训练

快速制作图像标签数据集以及训练 制作DataSet 先从网络收集十张图片 每种十张 定义dataSet和dataloader import glob import torch from torch.utils import data from PIL import Image import numpy as np from torchvision import transforms import matplotlib.pyplot…

CAD操作技巧学习总结

1&#xff0c;已知一个圆&#xff0c;画该圆切线。 L命令画直线&#xff0c;再tan指令确定第一个点为切点&#xff0c;依次输入&#xff08;长度&#xff09;<&#xff08;角度&#xff09;&#xff0c;如55<-45,负号为顺时针。 2&#xff0c;中心点偏移。 O命令偏移&am…

go语言 | grpc原理介绍(三)

了解 gRPC 通信模式中的消息流 gRPC 支持四种通信模式&#xff0c;分别是简单 RPC、服务端流式 RPC、客户端流式 RPC 和双向流式 RPC。 简单 RPC 在gRPC中&#xff0c;一个简单的RPC调用遵循请求-响应模型&#xff0c;通常涉及以下几个关键步骤和组件&#xff1a; 请求头&a…

鸿蒙LiteOs读源码教程+向LiteOS中添加一个简单的基于线程运行时的短作业优先调度策略

一、鸿蒙Liteos读源码教程 鸿蒙的源码是放在openharmony文件夹下&#xff0c;openharmony下的kernel文件夹存放操作系统内核的相关代码和实现。 内核是操作系统的核心部分&#xff0c;所以像负责&#xff1a;资源管理、任务调度、内存管理、设备驱动、进程通信的源码都可以在…

升级 MacOS 系统后,playCover 内游戏打不开了如何解决

我们有些小伙伴在升级了 macOS 系统后大概率会遇到之前能够正常使用的 playCover 突然游戏打不开了&#xff0c;最近 mac 刚刚正式推出了 MacOS 14.1 ,导致很多用户打开游戏会闪退&#xff0c;我们其实只需要更新一下 playCover 就可以解决 playCover 正式版更新会比较慢所以我…

基于生成对抗网络的照片上色动态算法设计与实现 - 深度学习 opencv python 计算机竞赛

文章目录 1 前言1 课题背景2 GAN(生成对抗网络)2.1 简介2.2 基本原理 3 DeOldify 框架4 First Order Motion Model5 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于生成对抗网络的照片上色动态算法设计与实现 该项目较为新颖&am…

【rust/esp32】初识slint ui框架并在st7789 lcd上显示

文章目录 说在前面关于slint关于no-std关于dma准备工作相关依赖代码结果参考 说在前面 esp32版本&#xff1a;s3运行环境&#xff1a;no-std开发环境&#xff1a;wsl2LCD模块&#xff1a;ST7789V2 240*280 LCDSlint版本&#xff1a;master分支github地址&#xff1a;这里 关于s…