高级Spring之Scope 详解

news2024/12/22 22:43:04

在当前版本的 Spring 和 Spring Boot 程序中,支持五种 Scope

  • singleton,容器启动时创建(未设置延迟),容器关闭时销毁

  • prototype,每次使用时创建,不会自动销毁,需要调用 DefaultListableBeanFactory.destroyBean(bean) 销毁

  • request,每次请求用到此 bean 时创建,请求结束时销毁

  • session,每个会话用到此 bean 时创建,会话结束时销毁

  • application,web 容器用到此 bean 时创建,容器停止时销毁

有些文章提到有 globalSession 这一 Scope,也是陈旧的说法,目前 Spring 中已废弃

但要注意,如果在 singleton 注入其它 scope 都会有问题,解决方法有

  • @Lazy

  • @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)

  • ObjectFactory

  • ApplicationContext.getBean

案例演示:request, session, application 作用域


/*
    singleton, prototype, request, session, application

    jdk >= 9 如果反射调用 jdk 中方法,会报非法访问异常
    jdk <= 8 不会有问题

    演示 request, session, application 作用域
    打开不同的浏览器, 刷新 http://localhost:8080/test 即可查看效果
    如果 jdk > 8, 运行时请添加 --add-opens java.base/java.lang=ALL-UNNAMED
 */
@SpringBootApplication
public class A08 {
    public static void main(String[] args) {
        SpringApplication.run(A08.class, args);
    }
}

使用不同作用域的Bean如下:

           BeanForApplication

@Scope("application")
@Component
public class BeanForApplication {
    private static final Logger log = LoggerFactory.getLogger(BeanForApplication.class);

    @PreDestroy
    public void destroy() {
        log.debug("destroy");
    }
}

          BeanForRequest

@Scope("request")
@Component
public class BeanForRequest {
    private static final Logger log = LoggerFactory.getLogger(BeanForRequest.class);

    @PreDestroy
    public void destroy() {
        log.debug("destroy");
    }

}

          BeanForSession

@Scope("session")
@Component
public class BeanForSession {
    private static final Logger log = LoggerFactory.getLogger(BeanForSession.class);

    @PreDestroy
    public void destroy() {
        log.debug("destroy");
    }
}

   

使用的Bean使用代码如下:

@RestController
public class MyController {

    @Lazy
    @Autowired
    private BeanForRequest beanForRequest;

    @Lazy
    @Autowired
    private BeanForSession beanForSession;

    @Lazy
    @Autowired
    private BeanForApplication beanForApplication;

    @GetMapping(value = "/test", produces = "text/html")
    public String test(HttpServletRequest request, HttpSession session) {
        ServletContext sc = request.getServletContext();
        String sb = "<ul>" +
                    "<li>" + "request scope:" + beanForRequest + "</li>" +
                    "<li>" + "session scope:" + beanForSession + "</li>" +
                    "<li>" + "application scope:" + beanForApplication + "</li>" +
                    "</ul>";
        return sb;
    }

}

        单例使用其他的例,都得使用@azy注解,否则会失效

   分析 - singleton 注入其它 scope 失效

         以单例注入多例为例

         有一个单例对象 E

@Component
public class E {
    private static final Logger log = LoggerFactory.getLogger(E.class);

    private F f;

    public E() {
        log.info("E()");
    }

    @Autowired
    public void setF(F f) {
        this.f = f;
        log.info("setF(F f) {}", f.getClass());
    }

    public F getF() {
        return f;
    }
}

要注入的对象 F 期望是多例

@Component
@Scope("prototype")
public class F {
    private static final Logger log = LoggerFactory.getLogger(F.class);

    public F() {
        log.info("F()");
    }
}

测试

E e = context.getBean(E.class);
F f1 = e.getF();
F f2 = e.getF();
System.out.println(f1);
System.out.println(f2);

输出

com.tangyuan.demo.cycle.F@6622fc65
com.tangyuan.demo.cycle.F@6622fc65

   发现它们是同一个对象,而不是期望的多例对象

           对于单例对象来讲,依赖注入仅发生了一次,后续再没有用到多例的 F,因此 E 用的始终是第一次依赖注入的 F

解决

  • 仍然使用 @Lazy 生成代理

  • 代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的 f 对象

 

 

@Component
public class E {

    @Autowired
    @Lazy
    public void setF(F f) {
        this.f = f;
        log.info("setF(F f) {}", f.getClass());
    }

    // ...
}

注意

  • @Lazy 加在也可以加在成员变量上,但加在 set 方法上的目的是可以观察输出,加在成员变量上就不行了

  • @Autowired 加在 set 方法的目的类似

输出

E: setF(F f) class com.itheima.demo.cycle.F$$EnhancerBySpringCGLIB$$8b54f2bc
F: F()
com.tangyuan.demo.cycle.F@3a6f2de3
F: F()
com.tangyuan.demo.cycle.F@56303b57

从输出日志可以看到调用 setF 方法时,f 对象的类型是代理类型

4种解决方法

@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class F2 {
}
  @Autowired
    private ObjectFactory<F3> f3;

 public F3 getF3() {
        return f3.getObject();
    }
     @Autowired
    private ApplicationContext context;

 public F4 getF4() {
        return context.getBean(F4.class);
    }

收获💡

  1. 单例注入其它 scope 的四种解决方法

    • @Lazy

    • @Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)

    • ObjectFactory

    • ApplicationContext

  2. 解决方法虽然不同,但理念上殊途同归: 都是推迟其它 scope bean 的获取

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

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

相关文章

使用Plotly和Python进行交互式数据可视化

使用Plotly和Python进行交互式数据可视化 Python是数据探索和数据分析的好帮手&#xff0c;这都要归功于numpy、pandas、matplotlib等神奇库的支持。在我们的数据探索和数据分析阶段&#xff0c;理解我们正在处理的数据是非常重要的&#xff0c;为此&#xff0c;数据的可视化表…

Swin-Transformer算法解析

本文参考&#xff1a; SwinTransformer&#xff1a;使用shifted window的层级Transformer(ICCV2021)_tzc_fly的博客-CSDN博客 https://zhuanlan.zhihu.com/p/430047908 目录 1 为什么在视觉中使用Transformer 2 Swin-Transformer算法总体架构 3 Swin-Transformer Block详述…

C# 源码 等值线(等高线)云图绘制 ,图上含等高线数值

C# 源码 数据格式为XYZ数据&#xff0c;XY为坐标&#xff0c;Z为对应的值 X Y Z -0.671053 -0.850000 83.330742 -0.671053 -0.850000 85.469604 -0.671053 -0.760526 89.225899 -0.671053 -0.760526 86.994576 -0.671053 -0.760526 86.994576 -0.671053 -0.760526 89.225899 -…

【解读】《云事件响应框架》:云服务用户响应和管理事件首选指南

微信搜索”国际云安全联盟“&#xff0c;回复关键词“云事件”下载本报告 当今互联时代&#xff0c;全面的事件响应策略对于需要管理与降低风险的组织必不可少。然而&#xff0c;在基于云的基础设施和系统的事件响应策略方面&#xff0c;部分由于云的责任共担特性&#xff0c;…

sql的四种连接——左外连接、右外连接、内连接、全连接

一、内连接 满足条件的记录才会出现在结果集中。 二、 左外连接&#xff08;left outer join&#xff0c;outer可省略&#xff09; 左表全部出现在结果集中&#xff0c;若右表无对应记录&#xff0c;则相应字段为NULL 举例说明&#xff1a; 客户表&#xff1a; 订单表&#x…

2023年2月系统集成项目管理工程师认证【报名入口】

系统集成项目管理工程师是全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;简称软考&#xff09;项目之一&#xff0c;是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试&#xff0c;既属于国家职业资格考试&#xff0c;又是职…

Qt 根据参数 自动生成vs 工程

一&#xff0c;需求 给算法部门提供一套代码框架&#xff0c;让其写算法dll。为了使dll能融入主工程&#xff0c;其框架对格式有一定要求&#xff0c;为了增加算法部门的快发效率&#xff0c;因此开发一个小工具&#xff0c;用于自动生成这套框架。 运行后&#xff0c;只需要…

cdh+dolphinscheduler开启kerberos

搭建环境多台linux主机搭建集群CDH 6.3.2 (Parcel)版本dolphinscheduler 1.3.2版本本流程在CDH已搭建完成并可正常使用后&#xff0c;开启kerberos功能dolphinscheduler用于大数据任务管理与执行&#xff0c;是很不错的任务调度平台&#xff0c;是否提前部署均可开启kerberos目…

数据结构与算法:二叉树的学习

1.了解树形结构 1.概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。它具有以下的特点&#xff1a; …

《Unity Shader 入门精要》 第7章 基础纹理

第7章 基础纹理 纹理最初的目的就是使用一张图片来控制模型的外观。使用纹理映射技术&#xff08;texture mapping&#xff09;&#xff0c;我们可以把一张图黏在模型表面&#xff0c;逐纹素(texel)&#xff08;纹素的名字是为了和像素进行区分&#xff09;地控制模型的颜色。…

爱了爱了,这是什么神仙级Apache Dubbo实战资料,清晰!齐全!已跪!

都2026年了 还没有用过Dubbo&#xff1f; Dubbo是国内最出名的分布式服务框架&#xff0c;也是 Java 程序员必备的必会的框架之一。Dubbo 更是中高级面试过程中经常会问的技术&#xff0c;面试的时候是不是经常不能让面试官满意&#xff1f;无论你是否用过&#xff0c;你都必须…

Postman(2): postman发送带参数的GET请求

发送带参数的GET请求示例&#xff1a;微信公众号获取access_token接口&#xff0c;业务操作步骤1、打开微信公众平台&#xff0c;微信扫码登录&#xff1a;https://mp.weixin.qq.com/debug/cgi-bin/sandbox?tsandbox/login2、打开微信开放文档&#xff0c;找到获取access_toek…

运放电路中各种电阻的计算-运算放大器

运放电路中各种电阻的计算 在学习运算放大器电路的时候&#xff0c;经常需要计算电路的: 输入阻抗Ri&#xff0c; 输出阻抗Ro&#xff0c; 同相端对地等效电阻RP, 反相端对地等效电阻RN&#xff0c; 这些参数很重要&#xff0c;在学习运放相关电路的时候经常要用到&#…

mysql8+mybatis-plus 查询json格式数据

sql 测试json表CREATE TABLE testjson (id int NOT NULL AUTO_INCREMENT,json_obj json DEFAULT NULL,json_arr json DEFAULT NULL,json_str varchar(100) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT2 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;IN…

API 网关策略二三事

作者暴渊&#xff0c;API7.ai 技术工程师&#xff0c;Apache APISIX Committer。 近些年随着云原生和微服务架构的日趋发展&#xff0c;API 网关以流量入口的角色在技术架构中扮演着越来越重要的作用。API 网关主要负责接收所有请求的流量并进行处理转发至上游服务&#xff0c;…

【数据结构和算法】认识队列,并实现循环队列

上接前文&#xff0c;我们学习了栈的相关知识内容&#xff0c;接下来&#xff0c;来认识一个与栈类似的&#xff0c;另一种特殊的线性表&#xff0c;队列&#xff0c;本文目的是了解并认识队列这一概念&#xff0c;并实现循环队列 目录 一、认识队列 1.队列的概念 2.队列的实…

入门力扣自学笔记232 C++ (题目编号:1669)

1669. 合并两个链表 题目&#xff1a; 给你两个链表 list1 和 list2 &#xff0c;它们包含的元素分别为 n 个和 m 个。 请你将 list1 中下标从 a 到 b 的全部节点都删除&#xff0c;并将list2 接在被删除节点的位置。 下图中蓝色边和节点展示了操作后的结果&#xff1a; 请…

Docker-harbor私有仓库部署与管理

目录 前言 一、Harbor概述 二、Harbor的特性 三、Harbor的构成 四、Harbor构建Docker私有仓库 环境配置 部署Harbor服务 物理机访问server IP 添加项目并填写项目名称 通过127.0.0.1来登陆和推送镜像 其他客户端上传镜像到Harbor 维护管理Harbor 创建Harbor用户 …

JavaWeb_JavaScript

一、简介 JavaScript 是一门跨平台、面向对象的脚本语言&#xff0c;而Java语言也是跨平台的、面向对象的语言&#xff0c;只不过Java是编译语言&#xff0c;是需要编译成字节码文件才能运行的&#xff1b;JavaScript是脚本语言&#xff0c;不需要编译&#xff0c;由浏览器直接…

GPT-3是精神病患者吗?从心理学角度评估大型语言模型

原文链接&#xff1a;https://www.techbeat.net/article-info?id4494 作者&#xff1a;seven_ 20世纪60年代&#xff0c;麻省理工学院人工智能实验室的Joseph Weizenbaum编写了第一个自然语言处理&#xff08;NLP&#xff09;聊天机器人ELIZA[1]&#xff0c;ELIZA通过使用模式…