coldsmog开发笔记
JS 事件笔记
Ckeditor 上传WPS图片失败问题
Springboot
SpringBoot 统一异常处理
Springboot 引入外部jar包
Springboot 打成war包
Springboot 多环境配置
SpringBoot @Scope注解学习
Springboot 快速生成项目API文档
SpringCache 缓存
Spring jetcache 二级缓存
Springboot 按条件装配类
FastJson的JsonPath语法
正则表达式语法
Spring 路径匹配
Feign 基础数据操作
监控Feign调用metrics
Springboot feign的性能优化
Jackson 设置序列化属性
SpringBoot 集成 Spring Data Mongodb 操作 MongoDB
MongoDB 的一些注意事项
MongoDB 指令对比
Jackson 解析XML
Springboot Redis注册
SpringBoot RedisTemplate批量插入
Springboot 指标监控Micrometer
springboot validation 注解校验
springboot 引入配置
Springboot 静态文件处理
Springboot 导出csv文件
Springboot 事件驱动(发布/订阅模式)
Springboot 启动过程和扩展点
Springboot 优化停机上下线
Spring自动装配 - 干饭角度学习
Springboot ShardingJDBC
Springboot的重试
springboot 动态修改端口
Oracle
Oracle 中实现自增ID
Oracle 定时任务
Oracle 解锁临时表
Oracle 检查连接数
Oracle 表空间
Oracle 解释执行SQL
markdown作图(适用typora)
服务器压测
业务对象层和数据层
并发限流处理
中间件
Yarn的使用
Dubbo学习笔记-RPC扩展和本地Mock
Dubbo学习笔记-泛化实现进行mock
Redis缓存穿透,缓存击穿,缓存雪崩
Galera 集群说明
Pip 镜像
pip 使用
MySQL命令行
数据库缓存双写方案
Git相关操作
Redis 操作时间复杂度一览
nacos 杂记
mybatis 散记
shardingjdbc
一次线上事故排查发现的Caffeine缓存死锁问题
设计模式
重新讲讲单例模式和几种实现
更优雅地实现策略模式
Http-headers
Prometheus 杂散笔记
JAVA 散记
CompletableFuture
Gson、FastJson、Jackson、json-lib对比总结
jackson 时间的序列化踩坑
JVM
自定义注解
mysql类型和java类型 转换一览表
枚举维护一个Map<value, Enum>的映射
Java中String +、concat、StringBuilder、StringBuffer 性能对比
TraceId 使用
MySQL 多数据源处理
Mybatis-plus 流式查询
JAVA发送win 桌面通知
idea 启动项目失败非代码问题杂记
Lambda 简述
Arthas 使用笔记
一种链式更新数据的数据模式
Skywalking 新增中间件插件
Redission 使用
数据导出为图片
IDEA 的热重启
Netty 工具类
maven 插件
本文档使用 MrDoc 发布
-
+
首页
SpringBoot @Scope注解学习
## 概述 先通过注解的javadoc,可以了解到,@Scope在和@Component注解一起修饰在类上,作为类级别注解时,@Scope表示该类实例的范围,在和@Bean一起修饰在方法上,作为方法级别注解时,@Scope表示该方法返回的实例的范围。 对于@Scope注解,我们常用的属性一般就是:value和proxyMode,value就是指明使用哪种作用域范围,proxyMode指明使用哪种作用域代理。 @Scope定义提供了的作用域范围一般有:singleton单例、prototype原型、requestweb请求、sessionweb会话,同时我们也可以自定义作用域。 ## 作用域范围 - singleton单例范围,这个是比较常见的,Spring中bean的实例默认都是单例的,单例的bean在Spring容器初始化时就被直接创建,不需要通过proxyMode指定作用域代理类型。 - prototype原型范围,这个使用较少,这种作用域的bean,每次注入调用,Spring都会创建返回不同的实例,但是,需要注意的是,如果未指明代理类型,即不使用代理的情况下,将会在容器启动时创建bean,那么每次并不会返回不同的实例,只有在指明作用域代理类型例如TARGET_CLASS后,才会在注入调用每次创建不同的实例。 - requestweb请求范围,(最近遇到的问题就是和request作用域的bean有关,才发现之前的理解有偏差),当使用该作用域范围时(包括下面的session作用域),必须指定proxyMode作用域代理类型,否则将会报错,对于request作用域的bean,(之前一直理解的是每次有http请求时都会创建),但实际上并不是这样,而是Spring容器将会创建一个代理用作依赖注入,只有在请求时并且请求的处理中需要调用到它,才会实例化该目标bean。 - sessionweb会话范围,这个和request类似,同样必须指定proxyMode,而且也是Spring容器创建一个代理用作依赖注入,当有会话创建时,并且在会话中请求的处理中需要调用它,才会实例话该目标bean,由于是会话范围,生命依赖于session。 ## 作用域代理 如果指定为proxyMode = ScopedProxyMode.TARGET_CLASS,那么将使用cglib代理创建代理实例;如果指定为proxyMode = ScopedProxyMode.INTERFACE,那么将使用jdk代理创建代理实例;如果不指定,则直接在Spring容器启动时创建该实例。而且使用代理创建代理实例时,只有在注入调用时,才会真正创建类对象。 ## 除了上述作用域范围,Spring也允许我们自定义范围,主要操作为: 1. 先实现Scope接口创建自定义作用域范围类 2. 使用CustomScopeConfigurer注册自定义的作用域范围 后面写了一个例子实践一下,自定义了一种同一分钟的作用域范围,即同一分钟获取的是相同实例。 首先自定义作用域范围类TimeScope: ``` /** * 首先自定义作用域范围类TimeScope: * Scope接口提供了五个方法,只有get()和remove()是必须实现,get()中写获取逻辑, * 如果已有存储中没有该名称的bean,则通过objectFactory.getObject()创建实例。 */ @Slf4j public class TimeScope implements Scope { private static Map<String, Map<Integer, Object>> scopeBeanMap = new HashMap<>(); @Override public Object get(String name, ObjectFactory<?> objectFactory) { Integer hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); // 当前是一天内的第多少分钟 Integer minute = hour * 60 + Calendar.getInstance().get(Calendar.MINUTE); log.info("当前是第 {} 分钟", minute); Map<Integer, Object> objectMap = scopeBeanMap.get(name); Object object = null; if (Objects.isNull(objectMap)) { objectMap = new HashMap<>(); object = objectFactory.getObject(); objectMap.put(minute, object); scopeBeanMap.put(name, objectMap); } else { object = objectMap.get(minute); if (Objects.isNull(object)) { object = objectFactory.getObject(); objectMap.put(minute, object); scopeBeanMap.put(name, objectMap); } } return object; } @Override public Object remove(String name) { return scopeBeanMap.remove(name); } @Override public void registerDestructionCallback(String name, Runnable callback) { } @Override public Object resolveContextualObject(String key) { return null; } @Override public String getConversationId() { return null; } } ``` ``` /** * 然后注册自定义的作用域范围: */ @Configuration @Slf4j public class BeanScopeConfig { @Bean public CustomScopeConfigurer customScopeConfigurer() { CustomScopeConfigurer customScopeConfigurer = new CustomScopeConfigurer(); Map<String, Object> map = new HashMap<>(); map.put("timeScope", new TimeScope()); customScopeConfigurer.setScopes(map); return customScopeConfigurer; } @Bean @Scope(value = "timeScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public TimeScopeBean timeScopeBean() { TimeScopeBean timeScopeBean = new TimeScopeBean(); timeScopeBean.setCurrentTime(System.currentTimeMillis()); log.info("time scope bean"); return timeScopeBean; } } ``` 然后注入调用timeScopeBean,同一分钟内重复调用,使用相同实例,不同分钟将创建新实例 ## 什么时候使用该注解 我们知道 Spring的IOC默认就是单例模式,但如果该类下有非自动引入的变量成员,就会有线程不安全的问题,比如下面接口,值就在不停地被覆盖 ``` public class UserController { private String token; @PostMapping("login") public void userLogin(@RequestHeader("token") String token) { this.token = token; try { for(int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getId() + "token:" + token); Thread.sleep(2000); } } catch (Exception e) { e.printStackTrace(); } return; } } ``` 添加`@Scope("prototype")`注解后,每次请求返回不停的bean对象。这样就会在我们需要多例的场景中实现需求。 转载自:[秋月https://www.wetsion.site/spring-boot-annotation-scope.html](https://www.wetsion.site/spring-boot-annotation-scope.html)
寒烟濡雨
2022年2月8日 16:40
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
关于 MrDoc
觅思文档MrDoc
是
州的先生
开发并开源的在线文档系统,其适合作为个人和小型团队的云笔记、文档和知识库管理工具。
如果觅思文档给你或你的团队带来了帮助,欢迎对作者进行一些打赏捐助,这将有力支持作者持续投入精力更新和维护觅思文档,感谢你的捐助!
>>>捐助鸣谢列表
微信
支付宝
QQ
PayPal
Markdown文件
分享
链接
类型
密码
更新密码