Spring framework Day14:配置类的Lite模式和Full模式

news2024/11/23 5:07:00

前言

Lite模式和Full模式是指在软件或系统中的不同配置选项。一般来说,Lite模式是指较为简洁、轻量级的配置,而Full模式则是指更加完整、功能更丰富的配置。

Lite模式通常会去除一些不常用或占用资源较多的功能,以提高系统的运行效率和响应速度。这样可以在资源有限或对系统性能要求较高的情况下使用,比如在低配置的计算设备上或移动设备上。

Full模式则包含了系统或软件的所有功能和特性,同时可能会占用更多的内存和处理器资源。这样可以满足用户对更多功能和高级选项的需求,适合在高配置的计算设备上使用。

选择Lite模式还是Full模式取决于用户的需求和使用场景。如果用户需要更快的响应速度和轻量级的操作体验,或者使用的是资源受限的设备,那么Lite模式可能更适合。而如果用户需要更多功能和高级选项,并且使用的是高配置的设备,那么Full模式可能更适合。

需要注意的是,Lite模式和Full模式的具体配置内容可能因软件或系统而异,用户在选择时应根据具体情况进行判断和比较。

一、开始学习

1、新建项目,结构如下

2、添加 spring 依赖
 
    <!-- spring 的核心依赖 -->
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.23</version>
        </dependency>
 
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.5</version>
        </dependency>
 
    </dependencies>
 3、在 service 包下新建一个 UserService 接口,在 impl 包下新建一个 UserServiceImpl 实现类

UserService 接口

public interface UserService {
 
    void add();
 
}

UserServiceImpl 实现类

@Slf4j
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        log.info("添加用户");
    }
}
4、在 controller 包下新建一个 USerController 类
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    public void addUser() {

        userService.add();
    }

}

这段代码使用了Lombok库中的@RequiredArgsConstructor注解,该注解会生成一个带有final修饰的构造方法,用于对类中的final属性进行初始化。在这段代码中,通过使用@RequiredArgsConstructor注解实现了UserController类的构造方法,在构造方法中初始化了userService属性,避免了手动编写构造方法的繁琐。

需要注意的是,使用@RequiredArgsConstructor注解时,必须保证被注解的属性为非空(final)属性,否则在编译时就会出现错误。因此,在使用该注解时,需要仔细检查每一个被注解的属性是否满足要求。

5、在config 包下新建一个 AppConfig 配置类

@Slf4j
@Configuration
public class AppConfig {

    /**
     * 装配 Usersevice
     *
     * @return
     */
    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }

    /**
     * 装配 UserController 并注入 UserService
     *
     * @return
     */
    @Bean
    public UserController userController() {

        // 得到需要注入的 Bean
        UserService userService = userService();
        log.info("1:" + userService);
        UserService userService1 = userService();
        log.info("2:" + userService1);
        // 将 bean 通过构造方法注入
        return new UserController(userService);
    }

}

这段代码是一个使用Spring框架的Java配置类,其中包含了两个@Bean方法用于将UserService和UserController装配到Spring容器中。

在方法userService()中,使用@Bean注解声明一个UserService的实例,并返回该实例。该方法会在Spring容器启动时被调用,将UserService加入到Spring容器中。

在方法userController()中,同样使用@Bean注解声明一个UserController的实例,并注入一个UserService的实例。在这个方法内部,通过调用userService()方法来获取已经装配到Spring容器中的UserService实例。然后,将得到的UserService实例作为参数传递给UserController的构造方法,创建并返回UserController的实例。

需要注意的是,在这段代码中,还使用了Lombok库中的@Slf4j注解,用于自动生成日志记录器。通过在类上添加该注解,可以在Bean方法中使用log记录日志,避免手动编写日志记录器带来的繁琐。

@Configuration注解是Spring框架中的一个核心注解,用于标识一个类为配置类。配置类主要用于定义和组织Bean的创建和装配过程。

具体来说,@Configuration注解通常与@Bean注解一起使用。在一个带有@Configuration注解的类中,可以使用@Bean注解声明方法,并将该方法返回的对象注册为一个Bean。Spring容器在启动时会扫描这些类,并实例化这些Bean并将其添加到容器中。

 6、测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserController bean = context.getBean(UserController.class);
        bean.addUser();
    }

}

运行结果

 此时,可以看到我们输出的 userservice 和 userservice1 的地址是一样的,因为使用了代理模式,使用了 @Configuration 默认情况下,当proxyBeanMethods设置为true时,Spring容器会将@Bean注解的方法的返回值缓存起来作为单例对象。这样可以确保每次获取该Bean都是同一个实例,提高了性能和一致性。

 

 二、禁用代理模式

1、修改 AppConfig 配置类

@Slf4j
@Configuration(proxyBeanMethods = false)
public class AppConfig {

    /**
     * 装配 Usersevice
     *
     * @return
     */
    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }

    /**
     * 装配 UserController 并注入 UserService
     *
     * @return
     */
    @Bean
    public UserController userController() {

        // 得到需要注入的 Bean
        UserService userService = userService();
        log.info("1:" + userService);
        UserService userService1 = userService();
        log.info("2:" + userService1);
        // 将 bean 通过构造方法注入
        return new UserController(userService);
    }

}

@Configuration(proxyBeanMethods = false) 禁用了代理模式。在这种情况下,Spring容器将不会使用CGLIB动态代理来创建userService()userController()方法返回的Bean实例。

对于userService()方法,它没有任何依赖关系,每次调用都返回新的UserServiceImpl实例,无需代理。

对于userController()方法,它依赖于userService()方法返回的Bean实例。由于禁用了代理模式,每次调用userService()方法时都会返回一个新的实例,并且这个实例会被注入到UserController的构造方法中。

所以,在日志输出中看到的userServiceuserService1的值是不同的,它们引用的是不同的UserServiceImpl对象。

通过禁用代理模式,您可以确保每个Bean都是原始的实例,并且不存在代理对象的干扰。

2、测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserController bean = context.getBean(UserController.class);
        bean.addUser();
    }

}

 运行结果

 3、编译异常

 这个警告信息的意思是,您在一个@Configuration配置类中使用了@Bean注解的方法,并且将proxyBeanMethods设置为false,这可能会导致一些问题。

proxyBeanMethods@Configuration注解的一个属性,用于指定是否使用代理模式来管理@Bean注解的方法中创建的对象,默认值为true。当设置为true时,Spring容器将使用CGLIB动态代理来管理这些@Bean注解的方法和它们依赖的其他Bean。当设置为false时,Spring容器将直接调用该方法并返回该方法的返回值作为Bean实例。

如果您将proxyBeanMethods设置为false,则表示您不希望使用代理模式来管理Bean,但是同时使用@Bean注解的方法将直接调用,而没有使用Spring容器来管理这些Bean,这可能会导致一些问题。例如,有些Bean之间可能会产生循环依赖问题,导致应用程序无法启动。

为了避免这个问题,建议您将proxyBeanMethods设置为true,或者尽可能使用依赖注入,而不是直接调用@Bean注解的方法。

但是呢,并不会影响程序的正常运行。

 

三、使用代理模式和禁用代理模式的区别 

代理模式和禁用代理模式的主要区别在于Spring容器处理@Bean注解的方法时所采用的方式。

proxyBeanMethods设置为true时,Spring容器会使用CGLIB动态代理来管理@Bean注解的方法和它们之间的依赖关系。

proxyBeanMethods设置为false时,Spring容器不使用代理,直接调用@Bean注解的方法并返回该方法的返回值作为Bean实例。

1、使用代理模式有以下几个优点:
  1. 循环依赖解决:如果存在循环依赖,代理模式可以通过提前暴露代理对象来解决循环依赖问题。代理对象可以在被依赖之前就可以被注入,从而解决了循环依赖的限制。

  2. 单例对象缓存:默认情况下,当proxyBeanMethods设置为true时,Spring容器会将@Bean注解的方法的返回值缓存起来作为单例对象。这样可以确保每次获取该Bean都是同一个实例,提高了性能和一致性。

2、而禁用代理模式则可能会导致以下问题:
  1. 循环依赖无法解决:如果存在循环依赖,则会导致应用程序无法启动。

  2. 缺少单例对象缓存:由于每次调用@Bean注解的方法都会返回一个新的实例,因此可能会导致性能问题或意外的行为。

因此,通常情况下建议使用代理模式,并将proxyBeanMethods设置为true,默认就是 true

四、通过代码了解代理模式

 1、在 proxy 包下新建 A、B、BProxy 类

B类

/**
 * @Date 2023-10-08
 * @Author qiu
 *
 * 目标对象(被代理的对象)
 */
@Slf4j
public class B {

    public void say() {
        log.info("Hello world!");
    }

}

BProxy 类

/**
 * @Date 2023-10-08
 * @Author qiu
 * <p>
 * 代理对象
 */
@Slf4j
public class BProxy {

    /**
     * 声明一个被代理的对象
     */
    private B b;

    public BProxy(B b) {
        this.b = b;
    }

    public void say() {
        // 目标方法前
        before();

        // 调用目标对象的 say 方法
        b.say();

        // 目标方法后
        after();
    }

    /**
     * 调用目标方法前要执行的逻辑
     */
    private void before() {
        log.info("调用目标之前执行的业务逻辑.....");
    }

    private void after() {
        log.info("调用目标之后执行的业务逻辑.....");
    }

}
 2、新建 A 类 测试
public class A {

    public static void main(String[] args) {
        // 创建代理对象
        BProxy bProxy = new BProxy(new B());
        bProxy.say();

    }

}

运行结果

 在这个示例中,BProxy类是B类的代理类。代理类持有一个被代理对象 b 的引用,并且在调用 say() 方法时,会在目标方法前后执行额外的逻辑。

BProxy类中的 before() 方法和 after() 方法分别代表了目标方法调用前和调用后需要执行的逻辑。在 say() 方法中,首先会执行 before() 方法,然后调用被代理对象 bsay() 方法,最后再执行 after() 方法。

A 类的 main 方法中,创建了一个 BProxy 对象,并调用其 say() 方法。由于 BProxyB 类的代理类,因此在调用 say() 方法时,额外的逻辑会被执行。

通过静态代理模式,我们可以在不修改原始类 B 的情况下,对其进行功能扩展或增强。这种方式可以在一些场景下提供更灵活的控制和定制逻辑。

3、分析,下图 

 所谓的代理就是可以理解为是一个中间类(中介),当我们需要调用 B 类的方法时,我们通过一个代理类来调用 B 类的方法,为什么需要代理类呢,是因为当我们调用 B 类的方法时需要增加其他的业务逻辑,但是又不能对 B 类去修改,所以使用代理类,在代理类中调用 B 类的方法,并且在代理类中调用 say 方法时,在之前和之后都做了相应业务逻辑处理。而我们用户调用的还是 say 方法,用户不用关心代理类中做了什么事情,它只关注它调用的是它想要的方法即可。

代理类:就是在调用目标对象的方法时,对目标对象的方法进行了增强或者修改。

五、总结

 配置类 Lite 模式(非代理模式)和 Full 模式(代理模式)
 * 当配置类上标注了 @configuration 注解时,并且 proxyBeanMethods
 * 属性设置为 true,此时就是 Full 模式,Full 模式就是 Spring 会为当前
 * 配置类创建一个代理对象,从而创建配置类中所有的 @Bean 注解的方法
 * 这样每当调用配置类只能的 Bean 方法之前,会从容器中进行检查 Bean 实例,
 * 并返回容器中存在的 Bean 对象。
 * 反之就是 Lite 模式,Lite 模式下配置类并不会被代理。每次调用 Bean
 * 方法只是纯粹的调用,并不会经过代理。

Lite 模式(非代理模式)就是:@Configuration(proxyBeanMethods = false)

Full 模式(代理模式)就是:@Configuration

六、gitee 案例

案例完整地址:https://gitee.com/qiu-feng1/spring-framework.git

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

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

相关文章

【C++】 对象模型与内存模型的区别

目录 0 引言1 C 内存模型2 C 对象模型3 二者区别 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;C专栏&#x1f4a5; 标题&#xff1a;【C】 对象模型与内存模型的区别❣️ 寄语&#xff1a;最重要的只有一件事&#xff01;&#x1f388; 最后&am…

Spring(17) AopContext.currentProxy() 类内方法调用切入

目录 一、简介二、代码示例2.1 接口类2.2 接口实现类2.3 AOP切面类2.4 启动类&#xff08;测试&#xff09;2.5 执行结果 一、简介 背景&#xff1a; 在之前 Spring 的 AOP 用法中&#xff0c;只有代理的类才会被切入。例如&#xff1a;我们在 Controller 层调用 Service 的方式…

nginx的优化和防盗链(重点)

一、nginx的优化&#xff08;重点&#xff09; &#xff08;一&#xff09;隐藏版本号 由于nginxbug多&#xff0c;更新版本速度比较快&#xff0c;一旦版本号暴露出去&#xff0c;有可能给对方提供攻击的漏洞 1、在http大模块中修改 2、修改nginx.h源码包 &#xff08;二&a…

竞赛 深度学习LSTM新冠数据预测

文章目录 0 前言1 课题简介2 预测算法2.1 Logistic回归模型2.2 基于动力学SEIR模型改进的SEITR模型2.3 LSTM神经网络模型 3 预测效果3.1 Logistic回归模型3.2 SEITR模型3.3 LSTM神经网络模型 4 结论5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 …

leetcode:1929. 数组串联(python3解法)

难度&#xff1a;简单 给你一个长度为 n 的整数数组 nums 。请你构建一个长度为 2n 的答案数组 ans &#xff0c;数组下标 从 0 开始计数 &#xff0c;对于所有 0 < i < n 的 i &#xff0c;满足下述所有要求&#xff1a; ans[i] nums[i]ans[i n] nums[i] 具体而言&am…

基于Java的二手车交易管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

基于深度学习网络的疲劳驾驶检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1疲劳检测理论概述 4.2 本课题说明 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 In_layer_Size [227 227 3]; img_size [224,…

BSPHP 未授权访问 信息泄露

漏洞描述 BSPHP 存在未授权访问 泄露用户 IP 和 账户名信息 漏洞复现 访问url&#xff1a; 构造payload访问&#xff1a; /admin/index.php?madmin&clog&atable_json&jsonget&soso_ok1&tuser_login_log&page1&limit10&bsphptime16004073…

【牛客网刷题(数据结构)】:环形链表的约瑟夫问题

描述 编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数&#xff0c;报到 m 的人离开。 下一个人继续从 1 开始报数。 n-1 轮结束以后&#xff0c;只剩下一个人&#xff0c;问最后留下的这个人编号是多少&#xff1f; O(n) 示例1 好环形链表的约瑟夫问题是一个经典的问…

cmd/bat 批处理文件的参数/接收命令行参数

前言 略 接收命令行参数 变量 %1~%9 对应命令行参数 1-9变量%0表示自身如果参数超过9个&#xff0c;则需要shift命令 示例 将下面的内容保存为bat文件&#xff08;比如1.bat&#xff09;&#xff1a; echo off echo.%%0为自身 echo.第0个参数是:%0 echo.第1个参数是:%1 e…

ROS 学习 Gazebo仿真

机器人模型添加Gazebo属性 使用xacro设计的机器人URDF模型已经描述了机器人的外观特征和物理特性&#xff0c;虽然已经具备在Gazebo中仿真的基本条件&#xff0c;但是&#xff0c;由于没有在模型中加入Gazebo的相关属性&#xff0c;还是无法让模型在Gazebo仿真环境中动起来。那…

基于Java的大学生兼职论坛管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

基于STM32_DHT11单总线温湿度传感器驱动

基于STM32_DHT11单总线温湿度传感器驱动 文章目录 基于STM32_DHT11单总线温湿度传感器驱动前言一、DHT11&#xff1f;二、原理1.时序1.主机复位信号和 DHT11 响应信号2.信号‘0’的表示3.信号‘1’的表示4.整个数据信号收发流程 2.数据结构 三、驱动1 .h文件&#xff1a;2 .c文…

力扣-434.字符串中的单词数

Idea 利用C中的 stringstream 指定字符分割字符串 class Solution { public:int countSegments(string s) {int cnt 0;stringstream ss(s);string word;while(ss >> word){cnt;}return cnt;} };

大模型分布式训练并行技术(一)-概述

近年来&#xff0c;随着Transformer、MOE架构的提出&#xff0c;使得深度学习模型轻松突破上万亿规模参数&#xff0c;传统的单机单卡模式已经无法满足超大模型进行训练的要求。因此&#xff0c;我们需要基于单机多卡、甚至是多机多卡进行分布式大模型的训练。 而利用AI集群&am…

【Java 进阶篇】JavaScript流程控制语句详解

JavaScript是一门高级编程语言&#xff0c;具备丰富的流程控制语句&#xff0c;用于控制程序的执行流程。在本篇博客中&#xff0c;我们将深入探讨JavaScript的流程控制语句&#xff0c;包括条件语句、循环语句、以及其他一些控制语句。这篇博客将逐步介绍这些概念&#xff0c;…

智慧公厕:打破传统,解决城市痛点@中期科技

近年来&#xff0c;随着城市化进程的加速推进&#xff0c;智慧公厕成为人民生活质量提升的重要组成部分。作为一个富有创新和科技感的解决方案&#xff0c;智慧公厕不仅满足了人们对公共环境的要求&#xff0c;还提供了一系列便利的服务&#xff0c;让人们的生活更加舒适、便捷…

LabVIEW在安装了其它的NI软件之后崩溃了

LabVIEW在安装了其它的NI软件之后崩溃了 在安装了其它的NI软件之后&#xff0c;一些原本安装好的或者新安装的软件由于缺少必要的DLL而崩溃掉了。例如&#xff0c;在这种情况下&#xff0c;Teststand可能会报下面的错误&#xff1a; RetrievingCOM class factory for compone…

基于Springboot的闲置图书共享系统设计与实现(源码+论文+开题报告+PPT+部署)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

PixMIM论文笔记

论文名称&#xff1a;PixMIM: Rethinking Pixel Reconstruction in Masked Image Modeling 发表时间&#xff1a;2023 年 3 月 4 日 作者及组织&#xff1a;上海人工智能实验室、西蒙菲莎大学、香港中文大学 GitHub&#xff1a;https://github.com/open-mmlab/mmselfsup/tree/d…