Spring Scope

Spring中五种 Scope域

  • singleton,容器启动时创建(未设置延迟),容器关闭时销毁【单例】
  • prototype,每次使用时创建,不会自动销毁,需要调用 DefaultListableBeanFactory.destroyBean(bean) 销毁【原型】
  • request,每次请求用到此 bean 时创建,请求结束时销毁(每次请求来都会创建一个request域对象放到web request域当中,请求结束会被销毁)
  • session,每个会话用到此 bean 时创建,会话结束时销毁(会话创建时会把session对象创建出来放入web session中,会话结束时销毁,会话有默认销毁时间可以设置,长时间不访问自动销毁)
  • application,web 容器用到此 bean 时创建,容器停止时销毁(ServletContext创建后,首次用bean将其放入ServletContext中,销毁Spring未实现)

单例Bean注入其他Scope Bean不做处理,会出现Scope生效的情况,需要在注入bean对象上添加@Lazy注解

演示:

不同scope域的bean

@Scope("application")
@Component
public class BeanForApplication {private static final Logger log = LoggerFactory.getLogger(BeanForApplication.class);@PreDestroypublic void destroy() {log.debug("destroy");}
}@Scope("session")
@Component
public class BeanForSession {private static final Logger log = LoggerFactory.getLogger(BeanForSession.class);@PreDestroypublic void destroy() {log.debug("destroy");}
}@Scope("request")
@Component
public class BeanForRequest {private static final Logger log = LoggerFactory.getLogger(BeanForRequest.class);@PreDestroypublic void destroy() {log.debug("destroy");}}
@RestController
public class MyController {@Lazy@Autowiredprivate BeanForRequest beanForRequest;@Lazy@Autowiredprivate BeanForSession beanForSession;@Lazy@Autowiredprivate 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;}
}

分析 - singleton 注入其它 scope 失效

以单例注入多例为例

有一个单例对象 E

@Component
public class E {@Autowiredprivate F1 f1;public F1 getF1() {return f1;}
}

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

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

测试:

   E e = context.getBean(E.class);log.debug("{}", e.getF1());log.debug("{}", e.getF1());

输出:

com.lkl.spring.chapter8.sub.F1@72d1ad2e
com.lkl.spring.chapter8.sub.F1@72d1ad2e

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

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

e 创建
e set 注入 f
f 创建

解决

  • 仍然使用 @Lazy 生成代理
  • 代理对象虽然还是同一个,但当每次使用代理对象的任意方法时,由代理创建新的 f 对象
使用f方法
使用f方法
使用f方法
e 创建
e set 注入 f代理
f 创建
f 创建
f 创建
@Component
public class E {@Autowired@Lazypublic void setF(F f) {this.f = f;log.info("setF(F f) {}", f.getClass());}// ...
}

注意

  • @Lazy 也可以加在成员变量上,但加在 set 方法上的目的是可以观察输出,加在成员变量上就不行了
  • @Autowired 加在 set 方法的目的类似
        E e = context.getBean(E.class);log.debug("{}", e.getF1().getClass());log.debug("{}", e.getF1());log.debug("{}", e.getF1());

输出:

class com.lkl.spring.chapter8.sub.F1$$EnhancerBySpringCGLIB$$278636ac
com.lkl.spring.chapter8.sub.F1@9597028
com.lkl.spring.chapter8.sub.F1@4efbca5a

f 对象的类型是代理类型

解决方法

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

    • @Lazy
    • @Scope(value = “prototype”, proxyMode = ScopedProxyMode.TARGET_CLASS)

    image-20230713220952991

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

@Component
public class E {// 方法一@Lazy@Autowiredprivate F1 f1;// 方法二@Autowiredprivate F2 f2;// 方法三@Autowiredprivate ObjectFactory<F3> f3;// 方法四@Autowiredprivate ApplicationContext context;public F1 getF1() {return f1;}public F2 getF2() {return f2;}public F3 getF3() {return f3.getObject();}public F4 getF4() {return context.getBean(F4.class);}
}

前两个使用代理对象解决

第三种通过对象工厂,通过对象工厂获取对象,工厂可以识别对象多例类型

最后一种,直接通过ApplicationContext容器获取多例对象

使用代理对象会有点性能损耗,后面两种方法会好些

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

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

相关文章

sqlserver 存储过程当中如何实现增删改查

--声明存储过程 新增编辑 ALTER procedure [dbo].[Eng_MyAddOrEdtADPro] My_Cocode int, Type int, -- --1 新增 2 编辑 My_KeyId uniqueidentifier, My_PCode int, My_SCode int, My_PName nvarchar(36), My_SName nvarchar(36), My_Orde…

OpenCV for Python 学习第三天 :图片处理之NumPy库与OpenCV相结合

上一篇博客我们了解了图像在OpenCV中的保存方式。并且我们自己上手创建了一张灰度图像和一张彩色图像。除此之外&#xff0c;我们还了解到了彩色图像通道在OpenCV中和我们日常所了解的不一样&#xff0c;是通过BGR的顺序进行编码的。咱们一定要记清楚哦~ 那么今天&#xff0c;我…

基于单片机心率脉搏心率血压体温血氧检测系统的设计与实现

功能介绍 本次设计通过32系列单片机STM32进行数据处理&#xff0c;配置引脚和JFC103传感器以及温度传感器进行数据通信。采用防水DS18B20进行腋下温度采集&#xff0c;通过单总线方式进行数据传输。心率血氧血压模块通过串口通信方式把采集到的数据发送给单片机&#xff0c;所有…

【前端知识】JavaScript——var 与 let 的区别

【前端知识】JavaScript——var 与 let 的区别 var声明的变量会自动提升到函数作用域顶部&#xff0c;而let不会。 在解析代码时&#xff0c;JavaScript 引擎会注意出现在块后面的 let 声明&#xff0c;只不过在此之前不能以任何方式来引用未声明的变量。在 let 声明之前的执行…

MySQL-DQL-案例

案例 案例1 根据需求完成员工管理的条件分页查询 具体代码 -- 案例1&#xff1a;按需求完成员工管理的条件分页查询 - 根据输入条件&#xff0c;查询第一页数据&#xff0c;每页展示10条记录 -- 输入条件&#xff1a; -- 姓名&#xff1a;张 -- 性别&#xff1a;男 -- 入职时间…

NAT 地址转换路由器配置命令(华为路由器)

#AR1路由器配置 # acl 2000 rule permit source any # interface GigabitEthernet0/0/1 nat outbound 2000 ip address 1.1.1.1 24 # interface GigabitEthernet0/0/0 ip address 172.16.1.1 255.255.255.0 # ip route-static 0.0.0.0 0.0.0.0 1.1.1.2 ip route-static …

怎么进行流程图制作?分享几种绘制方法

怎么进行流程图制作&#xff1f;流程图是一种图形化表示流程的图表&#xff0c;通常用于描述业务、计划或工作流程。它可以帮助人们更好地理解复杂的流程&#xff0c;并且提供了一种清晰的方法来记录和共享流程信息。下面介绍一些绘制流程图的方法&#xff0c;可以帮助我们快速…

Authing 入选长城战略咨询《2023 中国潜在独角兽企业》报告

2023 年 6 月 20 日&#xff0c;长城战略咨询&#xff08;GEI&#xff09;发布《2023 中国潜在独角兽企业研究》报告。Authing 作为国内首家身份云&#xff08;IDaaS&#xff09;厂商入选中国潜在独角兽企业榜单。独角兽企业指具有发展速度快、数量稀少、备受投资者青睐等属性的…

react 初学(1)

1.安装环境 需要Node.js 自行下载安装 然后全局安装create-react-app npm install -g create-react-app 如果出现报错请参考 create-react-app -V 报错无法将“create-react-app”项识别为 cmdlet、函数、脚本文件或可运行程序的名称_Java-请多指教的博客-CSDN博客 2.创建…

HTTP1.1、HTTPS、HTTP2.0 、HTTP3.0

HTTP1.1 优点&#xff1a; 整体方面&#xff1a;简单、灵活和易于扩展、应用广泛和跨平台 性能方面&#xff1a;长连接、管道网络传输解决请求队头阻塞&#xff08;没有使用&#xff09; 缺点&#xff1a; 安全方面&#xff1a;无状态、明文窃听、伪装、篡改 性能方面&am…

【NLP】多头注意力概念(02)

接上文: 【NLP】多头注意力概念(01) 五、计算注意力 将 Q、K 和 V 拆分为它们的头部后,现在可以计算 Q 和 K 的缩放点积。上面的等式表明,第一步是执行张量乘法。但是,必须先转置 K。 展望未来,每个张量的seq_length形状将通过其各自的张量来识别,以确保清晰…

抽象工厂模式

在开发一款游戏时&#xff0c;我们需要开发按钮Button及展板Board等组件&#xff0c;我们有多种风格Ligth或Dark&#xff0c;不同风格下组件的颜色、形状也不相同。如果按照工厂方法模式&#xff0c;则设计如下&#xff1a; 图 工厂方法模式实现上述需求 以上方法存在两个问题…