5_Spring Bean Scope 失效分析

news/2024/10/4 21:44:08/文章来源:https://www.cnblogs.com/lilyflower/p/18269832

Scope作用域

1. Scope类型有哪些

截至目前为止,Spring 目前有如下几种scope:

  • singleton: 从ioc容器中返回的都是同一个对象
  • prototype: 从ioc容器中可以返回多个对象
  • request: 该类型的bean的生命周期就和request请求一样,每当有request请求发送过来,就会创建一个bean对象放入request域,请求结束之后bean生命周期会结束
  • session: 会话域,会话开始,bean的生命周期开始;会话结束,bean的生命周期结束
  • application: 应用程序域,程序启动,该bena会被创建;程序结束后,该bean会被销毁,在spring boot中,应用程序域指的是web servlet context

分别编写不同作用域的bean

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

编写controller然后使用浏览器进行访问:

@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) throws JsonProcessingException {ServletContext context = request.getServletContext();String sb = "<ul>" +"<li>" + "request scope:"+ beanForRequest +"</li>"+"<li>" + "session scope:"+ beanForSession +"</li>"+"<li>" + "application scope:"+ beanForApplication +"</li>"+"</ul>";return sb;}
}

image-20240626191826404

再次刷新浏览器

image-20240626191848244

换一个浏览器重新访问:

image-20240626191919991

我们发现,不同的request请求,其request scope是不一样的;不同的ssession会话,其session scope是不一样的。

如果把对应的@Lazy注解去掉之后重新启动,我们发现控制台会报错:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myController': Unsatisfied dependency expressed through field 'beanForRequest': Error creating bean with name 'beanForRequest': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton

2. 在singleton中使用其它几种scope的注意事项

为了分析上面由于没有加@Lazy注解导致的报错,这里首先举一个例子

编写一个Bean

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

在主方法中手动从IOC容器中多次获取bean对象

@SpringBootApplication
public class SpringScopeApplication {private static final Logger log = LoggerFactory.getLogger(SpringScopeApplication.class);public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringScopeApplication.class);E e = context.getBean(E.class);log.info("{}",e.getF1());log.info("{}",e.getF1());log.info("{}",e.getF1());context.close();}
}

运行结果如下:

19:32:22.045 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F1@58294867
19:32:22.048 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F1@58294867
19:32:22.048 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F1@58294867Process finished with exit code 0

这就是我们当从单例中获取多例属性对象时失效的问题。

3. scope 失效分析

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

Snipaste_2024-06-26_19-37-33

解决思路

  • 仍然使用@Lazy注解生成代理
  • 代理对象虽然还是同一个,但当每次调用代理对象的任一方法时,由代理对象创建新的F对象

image-20240626193926862

  • 通过对象工厂 ObjectFactory 获取bean对象
  • 通过ApplicationContext获取bean对象

3.1 使用第一种方法(使用代理)

@Component
public class E {@Autowired@Lazyprivate F1 f1;public F1 getF1(){return f1;}
}@Scope("prototype")
@Component
class F1{ }

运行结果如下:

19:40:44.861 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F1@44cb460e
19:40:44.866 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F1@59546cfe
19:40:44.867 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F1@2d2acd89Process finished with exit code 0

3.2 使用第二种方法(使用代理)

可以在@Scope注解中指定proxyMode为ScopedProxyMode.TARGET_CLASS

如:

@Component
public class E {@Autowired@Lazyprivate F1 f1;@Autowiredprivate F2 f2;public F1 getF1(){return f1;}public F2 getF2(){return f2;}
}@Scope("prototype")
@Component
class F1{}@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
class F2{ }
@SpringBootApplication
public class SpringScopeApplication {private static final Logger log = LoggerFactory.getLogger(SpringScopeApplication.class);public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringScopeApplication.class);E e = context.getBean(E.class);log.info("{}",e.getF1());log.info("{}",e.getF1());log.info("{}",e.getF1());log.info("{}",e.getF2());log.info("{}",e.getF2());log.info("{}",e.getF2());context.close();}
}

运行结果如下:

19:48:26.218 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F1@29a69a35
19:48:26.223 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F1@4d48bd85
19:48:26.223 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F1@58a120b0
19:48:26.223 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F2@5c748168
19:48:26.226 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F2@6441c486
19:48:26.226 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F2@834831bProcess finished with exit code 0	

3.3 使用第三种办法(不使用代理)

声明一个对象工厂类型的成员变量,在每次创建该对象时直接从工厂中创建即可:

@Component
public class E {@Autowiredprivate ObjectFactory<F3> f3;public F3 getF3(){return f3.getObject();}
}@Scope(value = "prototype")
@Component
class F3{ }
@SpringBootApplication
public class SpringScopeApplication {private static final Logger log = LoggerFactory.getLogger(SpringScopeApplication.class);public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringScopeApplication.class);E e = context.getBean(E.class);log.info("{}", e.getF3());log.info("{}", e.getF3());log.info("{}", e.getF3());context.close();}
}

测试如下:

19:55:21.144 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F3@2301b75
19:55:21.160 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F3@6e1d4137
19:55:21.160 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F3@29a4f594Process finished with exit code 0

3.4 使用第四种方法(不使用代理)

通过注入ApplicationContext对象获取多例对象

@Component
public class E {@Autowiredprivate ApplicationContext context;public F4 getF4(){return context.getBean(F4.class);}}@Scope(value = "prototype")
@Component
class F4{
}
	@SpringBootApplication
public class SpringScopeApplication {private static final Logger log = LoggerFactory.getLogger(SpringScopeApplication.class);public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringScopeApplication.class);E e = context.getBean(E.class);log.info("{}", e.getF4());log.info("{}", e.getF4());log.info("{}", e.getF4());context.close();}
}
20:02:07.541 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F4@5327a06e
20:02:07.548 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F4@57d0fc89
20:02:07.548 [main] INFO com.cherry.springscope.SpringScopeApplication -- com.cherry.springscope.bean.F4@58294867Process finished with exit code 0

上述的四种解决方案同样适用于单例对象使用request scope, session scope 等失效的问题。

不管什么方法,都是在运行时推迟其它scope bean的获取!

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

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

相关文章

Profibus DP主站转Modbus模块连接马达保护器案例

在工业自动化控制系统中,Profibus DP和Modbus是常见的通信协议,在同一现场还有可能遇到Modbus协议,ModbusTCP协议,Profinet协议,Profibus协议,Profibus DP协议,EtherCAT协议,EtherNET协议等。本案例介绍了如何使用Profibus DP主站转Modbus模块(XD-MDPBM20)来实现与马…

platform 设备驱动实验

platform 设备驱动实验 Linux 驱动的分离与分层 代码的重用性非常重要,否则的话就会在 Linux 内核中存在大量无意义的重复代码。尤其是驱动程序,因为驱动程序占用了 Linux内核代码量的大头,如果不对驱动程序加以管理,任由重复的代码肆意增加,那么用不了多久Linux 内核的文…

ENVI深度学习V1.0操作教程

软件试用:https://www.cnblogs.com/enviidl/p/16275745.html计算机环境要求:https://www.cnblogs.com/enviidl/p/16309506.html教程下载链接:https://pan.baidu.com/s/15D3c6MXTAnN3STfKuzUg1g 提取码:hek6目录 ENVI Deep Learning V1.0操作教程 1 ENVI Deep Learnin…

ENVIDeepLearning1.1新功能预览

ENVI Deep Learning 1.1 Tech Preveiw目前已经发布,仅在内部测试。迫不及待的要跟大家分享一下新的功能,应该跟1.1正式版没有太大区别。 此版本包含了几个关键改进和新功能:多要素/多类别支持。 新增项目管理功能,用于管理训练图像和ROIs。 训练过程中的状态信息显示改进。…

利用ENV/深度学习工具提取防尘网覆盖信息

为扬尘治理和保护环境,城市的裸露地表、易扬尘物料等要求覆盖防尘网。防尘网一般由聚乙烯材料制作的网状物,颜色主要为黑色和绿色。 本文介绍利用遥感影像和ENVI深度学习工具快速提取防尘网覆盖信息,数据和处理环境如下: 数据源:标准景高分二号3.8米4波段多光谱数据,16bi…

数理方法考前必背

特殊函数 勒让德多项式 前几个勒让德多项式 \[\begin{aligned} P_{0}(x) & = 1 \\ P_{1}(x) & = x=\cos \theta \\ P_{2}(x) & = \dfrac{1}{2}\left(3 x^{2}-1\right)=\dfrac{1}{4}(3 \cos 2 \theta+1) \\ P_{3}(x) & = \dfrac{1}{2}\left(5 x^{3}-3 x\right)=…

机器人建模与控制复习总结

数学补充 符号约定 (1) 一般大写字母的变量表示矢量或矩阵,小写字母的变量表示标量 (2) 左上标和左下标表示变量所在的坐标系 如:\(^AP\)表示坐标系\(\{A\}\)中的位置矢量;\(_B^AR\) 是确定坐标系\(\{A\}\)和坐标系\(\{B\}\)相对关系的矩阵;无左上、下标的位置矢量一般是世…

润生商团出行打车模块(环境安装)2

微服务认证最佳方案 BFF(Backends For Frontends)是“服务于前端的后端”的简称。它的核心思想是在设计后端微服务API接口时,考虑到不同设备的需求,为不同的设备提供不同的API接口。 在没有BFF层的情况下,客户端需要直接访问服务器的公共接口。而在引入BFF层后,客户端不再…

工程热力学复习总结

热力学系统 热力学状态:某一瞬间系统所呈现的宏观物理状况 状态参数:描述物系所处平衡状态的宏观物理量 状态参数是宏观量,是大量粒子的统计平均效应,只有平衡态才有状态参数。状态参数是热力系统状态的单值函数,物理上与过程无关,数学上其微量是全微分。状态参数分类有:…

ENVIDeepLearning1.1正式版发布

ENVI DL 1.1 包含许多重大改进,以提高可用性和训练性能。多类别架构(Multiclass Architecture)深度学习标记工具(Deep Learning Labeling Tool)集成TensorBoard(可查看训练状态)测试系统支持状态其他更新编程申请试用1 多类别架构(…

塑性力学复习总结

基本概念 弹性和塑性 弹性:若外力不大,则外力除去后变形可以全部恢复。这种性质称为材料的弹性,这种可以全部恢复的变形是弹性变形。这时称物体处于弹性状态。 塑性:当外力超过一定限度,则物体将产生不可恢复的变形。这种变形不可恢复的性质称为塑性,不随应力消失而恢复的…

嵌入式计算技术复习总结

嵌入式系统基本概述 定义 从应用角度来看,嵌入式系统是为了特定任务而设计的专用计算机系统,这些任务可以包括控制、监视或者辅助操作机器和设备。从系统构成角度来说,嵌入式系统通常是包含微处理器、存储器、输入/输出(I/O)设备、以及可能还有一个或多个专用设备的计算机系…