概述

先通过注解的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,同一分钟内重复调用,使用相同实例,不同分钟将创建新实例

转载自:秋月:https://www.wetsion.site/spring-boot-annotation-scope.html

SpringBoot:@Scope注解学习的更多相关文章

  1. Spring学习(15)--- 基于Java类的配置Bean 之 @Bean & @Scope 注解

    默认@Bean是单例的,但可以使用@Scope注解来覆盖此如下: @Configuration public class MyConfiguration { @Bean @Scope("pr ...

  2. Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariable (转)

    最近需要做些接口服务,服务协议定为JSON,为了整合在Spring中,一开始确实费了很大的劲,经朋友提醒才发现,SpringMVC已经强悍到如此地步,佩服! 相关参考: Spring 注解学习手札(一 ...

  3. SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的

    系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...

  4. 转-Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariable

    转-http://snowolf.iteye.com/blog/1628861/ Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariab ...

  5. SpringBoot + Spring Security 学习笔记(五)实现短信验证码+登录功能

    在 Spring Security 中基于表单的认证模式,默认就是密码帐号登录认证,那么对于短信验证码+登录的方式,Spring Security 没有现成的接口可以使用,所以需要自己的封装一个类似的 ...

  6. SpringBoot常用注解使用

    1.RequestBody和ResponseBody注解 @RequestMapping(“url”),这里的 url写的是请求路径的一部分,一般作用在 Controller的方法上,作为请求的映射地 ...

  7. springboot系列五、springboot常用注解使用说明

    一.controller相关注解 1.@Controller 控制器,处理http请求. 2.@RespController Spring4之后新加的注解,原来返回json需要@ResponseBod ...

  8. Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariable(转)

    最近需要做些接口服务,服务协议定为JSON,为了整合在Spring中,一开始确实费了很大的劲,经朋友提醒才发现,SpringMVC已经强悍到如此地步,佩服! 相关参考: Spring 注解学习手札(一 ...

  9. SpringBoot的注解注入功能移植到.Net平台(开源)

    *:first-child { margin-top: 0 !important; } .markdown-body>*:last-child { margin-bottom: 0 !impor ...

随机推荐

  1. 函数计算: 让小程序开发进入 Serverless 时代

    点击下载<不一样的 双11 技术:阿里巴巴经济体云原生实践> 本文节选自<不一样的 双11 技术:阿里巴巴经济体云原生实践>一书,点击上方图片即可下载! 作者 | 吴天龙(木吴 ...

  2. python学习-class对象

    # 面向对象 python,java,c## 面向过程 C # 类和对象# 类 类型类别.类别 物以类聚 一类事物# 班级.人类.动物类.车.学生类.老师类.手机.电脑# 统称 == 共同特性# 不具 ...

  3. 真伪随机数 ——Random和SecureRandom

    Random Random用来创建伪随机数.所谓伪随机数,是指只要给定一个初始的种子,产生的随机数序列是完全一样的. 要生成一个随机数,可以使用nextInt().nextLong().nextFlo ...

  4. 【程序人生】一个IT人的立功,立言,立德三不朽

    最近几个月很忙,忙着当奶爸,忙着做加班狗,忙着补裤裆学技术……以至于快忘了要思考人生了! 古人立志穷极一生追求“立德”,“立功”,“立言”,以求不朽,为万世所景仰,为后人所传颂,实现人生的意义.立德者 ...

  5. 《Java基础知识》Java接口和抽象类的区别

    抽象类 抽象类必须用 abstract 修饰,子类必须实现抽象类中的抽象方法,如果有未实现的,那么子类也必须用 abstract 修饰.抽象类默认的权限修饰符为 public,可以定义为 public ...

  6. 自定义滚动条(Custom ScrollBar)

    时间如流水,只能流去不流回! 点赞再看,养成习惯,这是您给我创作的动力! 本文 Dotnet9 https://dotnet9.com 已收录,站长乐于分享dotnet相关技术,比如Winform.W ...

  7. javascript树形汇总金额

    在开发企业应用的时候总会遇到树形汇总金额的场景,即将树形的列表中的叶子节点(没有子节点)的金额汇总到父节点上. 这种需求一般是在前端进行处理,即使用JavaScript处理,因为叶子节点的金额可能是不 ...

  8. SpringCloud-创建服务消费者-Ribbon方式(附代码下载)

    场景 SpringCloud-服务注册与实现-Eureka创建服务注册中心(附源码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...

  9. 无法Google的解决方案

    献给新入开发行业的小伙伴. 本文不会事无巨细的讲解每一个细节,只是为读者提供一个路线图,并提供相应的参考资料. 为了更高效的解决各种技术问题,有时不得不到墙外去寻找解决方案.每个开发者效率高了,宏观来 ...

  10. 1001 害死人不偿命的(3n+1)猜想 (15 分)

    卡拉兹(Callatz)猜想: 对任何一个正整数 n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把 (3n+1) 砍掉一半.这样一直反复砍下去,最后一定在某一步得到 n=1.卡拉兹在 1950 ...