java spring scope_如何在Spring中自定义scope的方法示例
大家对于 Spring 的 scope 应该都不会默认。所谓 scope,字面理解就是“作用域”、“范围”,如果一个 bean 的 scope 配置为 singleton,则从容器中获取 bean 返回的对象都是相同的;如果 scope 配置为prototype,则每次返回的对象都不同。
一般情况下,Spring 提供的 scope 都能满足日常应用的场景。但如果你的需求极其特殊,则本文所介绍自定义 scope 合适你。
Spring 内置的 scope
默认时,所有 Spring bean 都是的单例的,意思是在整个 Spring 应用中,bean的实例只有一个。可以在 bean 中添加 scope 属性来修改这个默认值。scope 属性可用的值如下:
范围
描述
singleton
每个 Spring 容器一个实例(默认值)
prototype
允许 bean 可以被多次实例化(使用一次就创建一个实例)
request
定义 bean 的 scope 是 HTTP 请求。每个 HTTP 请求都有自己的实例。只有在使用有 Web 能力的 Spring 上下文时才有效
session
定义 bean 的 scope 是 HTTP 会话。只有在使用有 Web 能力的 Spring ApplicationContext 才有效
application
定义了每个 ServletContext 一个实例
websocket
定义了每个 WebSocket 一个实例。只有在使用有 Web 能力的 Spring ApplicationContext 才有效
如果上述 scope 仍然不能满足你的需求,Spring 还预留了接口,允许你自定义 scope。
Scope 接口
org.springframework.beans.factory.config.Scope接口用于定义scope的行为:
package org.springframework.beans.factory.config;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.lang.Nullable;
public interface Scope {
Object get(String name, ObjectFactory> objectFactory);
@Nullable
Object remove(String name);
void registerDestructionCallback(String name, Runnable callback);
@Nullable
Object resolveContextualObject(String key);
@Nullable
String getConversationId();
}
一般来说,只需要重新 get 和 remove 方法即可。
自定义线程范围内的scope
现在进入实战环节。我们要自定义一个Spring没有的scope,该scope将bean的作用范围限制在了线程内。即,相同线程内的bean是同个对象,跨线程则是不同的对象。
1. 定义scope
要自定义一个Spring的scope,只需实现 org.springframework.beans.factory.config.Scope接口。代码如下:
package com.waylau.spring.scope;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
/**
* Thread Scope.
*
* @since 1.0.0 2019年2月13日
* @author Way Lau
*/
public class ThreadScope implements Scope {
private final ThreadLocal> threadLoacal = new ThreadLocal>() {
@Override
protected Map initialValue() {
return new HashMap();
}
};
public Object get(String name, ObjectFactory> objectFactory) {
Map scope = threadLoacal.get();
Object obj = scope.get(name);
// 不存在则放入ThreadLocal
if (obj == null) {
obj = objectFactory.getObject();
scope.put(name, obj);
System.out.println("Not exists " + name + "; hashCode: " + obj.hashCode());
} else {
System.out.println("Exists " + name + "; hashCode: " + obj.hashCode());
}
return obj;
}
public Object remove(String name) {
Map scope = threadLoacal.get();
return scope.remove(name);
}
public String getConversationId() {
return null;
}
public void registerDestructionCallback(String arg0, Runnable arg1) {
}
public Object resolveContextualObject(String arg0) {
return null;
}
}
在上述代码中,threadLoacal用于做线程之间的数据隔离。换言之,threadLoacal实现了相同的线程相同名字的bean是同一个对象;不同的线程的相同名字的bean是不同的对象。
同时,我们将对象的hashCode打印了出来。如果他们是相同的对象,则hashCode是相同的。
2. 注册scope
定义一个AppConfig配置类,将自定义的scope注册到容器中去。代码如下:
package com.waylau.spring.scope;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.config.CustomScopeConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* App Config.
*
* @since 1.0.0 2019年2月13日
* @author Way Lau
*/
@Configuration
@ComponentScan
public class AppConfig {
@Bean
public static CustomScopeConfigurer customScopeConfigurer() {
CustomScopeConfigurer customScopeConfigurer = new CustomScopeConfigurer();
Map map = new HashMap();
map.put("threadScope", new ThreadScope());
// 配置scope
customScopeConfigurer.setScopes(map);
return customScopeConfigurer;
}
}
“threadScope”就是自定义ThreadScope的名称。
3. 使用scope
接下来就根据一般的scope的用法,来使用自定义的scope了。代码如下:
package com.waylau.spring.scope.service;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
/**
* Message Service Impl.
*
* @since 1.0.0 2019年2月13日
* @author Way Lau
*/
@Scope("threadScope")
@Service
public class MessageServiceImpl implements MessageService {
public String getMessage() {
return "Hello World!";
}
}
其中@Scope("threadScope")中的“threadScope”就是自定义ThreadScope的名称。
4. 定义应用入口
定义Spring应用入口:
package com.waylau.spring.scope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.waylau.spring.scope.service.MessageService;
/**
* Application Main.
*
* @since 1.0.0 2019年2月13日
* @author Way Lau
*/
public class Application {
public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
MessageService messageService = context.getBean(MessageService.class);
messageService.getMessage();
MessageService messageService2 = context.getBean(MessageService.class);
messageService2.getMessage();
}
}
运行应用观察控制台输出如下:
Not exists messageServiceImpl; hashCode: 2146338580
Exists messageServiceImpl; hashCode: 2146338580
输出的结果也就验证了ThreadScope“相同的线程相同名字的bean是同一个对象”。
如果想继续验证ThreadScope“不同的线程的相同名字的bean是不同的对象”,则只需要将Application改造为多线程即可。
package com.waylau.spring.scope;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.waylau.spring.scope.service.MessageService;
/**
* Application Main.
*
* @since 1.0.0 2019年2月13日
* @author Way Lau
*/
public class Application {
public static void main(String[] args) throws InterruptedException, ExecutionException {
@SuppressWarnings("resource")
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
CompletableFuture task1 = CompletableFuture.supplyAsync(()->{
//模拟执行耗时任务
MessageService messageService = context.getBean(MessageService.class);
messageService.getMessage();
MessageService messageService2 = context.getBean(MessageService.class);
messageService2.getMessage();
//返回结果
return "result";
});
CompletableFuture task2 = CompletableFuture.supplyAsync(()->{
//模拟执行耗时任务
MessageService messageService = context.getBean(MessageService.class);
messageService.getMessage();
MessageService messageService2 = context.getBean(MessageService.class);
messageService2.getMessage();
//返回结果
return "result";
});
task1.get();
task2.get();
}
}
观察输出结果;
Not exists messageServiceImpl; hashCode: 1057328090
Not exists messageServiceImpl; hashCode: 784932540
Exists messageServiceImpl; hashCode: 1057328090
Exists messageServiceImpl; hashCode: 784932540
上述结果验证ThreadScope“相同的线程相同名字的bean是同一个对象;不同的线程的相同名字的bean是不同的对象”
源码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
相关文章:

学习ExtJS4 常用控件
ExtJS组件配置方式介绍 1.使用逗号分隔参数列表配置组件 首先来看一个简单的逗号分隔参数列表的例子。这个例子非常简单,它用来显示信息提示框。 2.使用Json对象配置组件 接下来看一个使用Json对象配置组件的例子,很多地方习惯性称之为配…

青少年编程竞赛交流群周报(第036周)
2021年10月31日(周日)晚20:00我们在青少年编程竞赛交流群开展了第三十六期直播活动。 一、直播内容 我们直播活动的主要内容如下: 讲解了上次测试中小朋友们做错的题目 Scratch青少年编程能力等级测试模拟题(四级)。…

中国电信打造“三朵云”战略 助力互联网+医疗发展
随着云计算、大数据的快速发展,全行业上云成为一个趋势,在健康医疗这个领域,应大势之趋,纷纷构建医疗云。近日,中国电信医疗云专区北京节点发布会在京顺利召开,会后北京电信副总经理项煌妹接受了中国IDC圈记…

python 数据类笔试题_一道 Python 类的笔试题详解
r {}class C(object):def __init__(self, a, b):self.a aself.b bif b a:orig super(C, cls)r[cls.instance] 1a C(1, a)b C(1, a)c C(1, b)l [a, b, c]for i in l:if i not in r:r[i] 1else:r[i] 1assert r[a] 2assert r[b] 2assert r[c] 1原题目要求如下&…

【优秀作业】粒子群算法(Python)
粒子群优化算法 一、概述 粒子群优化算法(Particle Swarm Optimization,PSO)的思想来源于对鸟捕食行为的模仿,最初,Reynolds.Heppner 等科学家研究的是鸟类飞行的美学和那些能使鸟群同时突然改变方向,分散…

警惕企业中的五种虚假执行力
第一种虚假执行力:无条件服从——只强调员工“服从”,不强调员工的智慧 很多人讲执行力,很喜欢强调员工的无条件服从。这种观念是OEM(代工生产)制造业时代的产物。实际上这是一种基于“规模制造”的虚假执行力,其本质是把人当成了…

真实记录疑似Linux病毒导致服务器 带宽跑满的解决过程
案例描述 由于最近我在重构之前的APP,需要和server端进行数据交互,发现有一个现象,那么就是隔1~2天总会发生获取数据超时的问题,而且必须要重启服务器才能解决。早在之前,我有留意到这个问题,但是由于这个服…

java集合总结_Java中集合总结
Java数组的长度是固定的,为了使程序能够方便地存储和操作数目不固定的一组数据,JDK类库提供了Java集合,这些集合类都位于java.util包中,但是与数组不同的是,集合中不能存放基本类型数据,而只能存放对象的引…

区块链基本解读
最近看着这个区块链,稍有新得,写下菜鸟自己的理解,希望大牛多多指点。 总体心得,如果互联网技术解决的是通讯问题的话,区块链技术解决的是信任问题。 下面举个日常例子:打赌 比如A和B赌石头是否为天然玉石&…

PDO防注入原理分析以及使用PDO的注意事项 (转)
我们都知道,只要合理正确使用PDO,可以基本上防止SQL注入的产生,本文主要回答以下两个问题: 为什么要使用PDO而不是mysql_connect? 为何PDO能防注入? 使用PDO防注入的时候应该特别注意什么? 一、为何要优先使用PDO? P…

LSGO软件技术团队招新 线下组队学习
团队招新 LSGO软件技术团队(Dreamtech算法组)成立于2010年09月,团队主要从事地理信息系统、管理信息系统、计算机视觉等领域的应用开发,团队同时具有培养学生的重要职能,毕业学生分布在IBM、百度、阿里、腾讯、京东、…

java spring 配置文件_[Java教程]Spring配置文件
[Java教程]Spring配置文件02016-03-19 00:00:08Spring配置文件是集成了Spring框架的项目的核心,引擎从哪里开始,中间都执行了哪些操作,小谈一下它的执行流程。容器先是加载web.接着是applicationContext.一种方法是加入ContextLoaderServlet这…
王子朝:一种高效且容错的方法用于协作车辆定位
王子朝是华北电力大学计算机系大四的学生,Dreamtech成员,参加了多期Dreamtech与Datawhale联合组织的组队学习活动,现保送西安电子科技大学深造。 这篇图文是他在线下组队学习时,为大家分享自己所看论文的总结。 希望参与我们组队…

python文件句柄_Python文件操作
classfile(object):def close(self): #real signature unknown; restored from __doc__关闭文件"""close() -> None or (perhaps) an integer. Close the file.Sets data attribute .closed to True. A closed file cannot be used forfurther I/O operation…

XML简单的增改删操作
XML文件的简单增改删,每一个都可以单独拿出来使用。 新创建XML文件,<?xmlversion"1.0"encoding"utf-8"?> <bookstore> <bookgenre"fantasy"ISBN"2-3631-4"> <title>Oberons Legacy&l…

javascript推荐书籍
WEB前端研发工程师,在国内算是一个朝阳职业,这个领域没有学校的正规教育,大多数人都是靠自己自学成才。本文主要介绍自己从事web开发以来(从大二至今)看过的书籍和自己的成长过程,目的是给想了解 JavaScript或者是刚接触JavaScrip…

【青少年编程竞赛交流】10月份微信图文索引
10月份微信图文索引 由于“组队学习”这个公众号的功能主要是组织Datawhale社群中的学习者们每个月的组队学习,所以,我另外新建了这个微信公众号“青少年编程竞赛交流”,在这个公众号上分享有关青少年编程方面的知识。如果大家需要就关注这个…

java 简单万年历_JAVA实现的简单万年历代码
本文实例讲述了JAVA实现的简单万年历。分享给大家供大家参考,具体如下:import java.util.Scanner;public class PrintCalendar {public static void main(String[] args) {int years 0;int month 0;int days 0;boolean isRun false;//從控制台輸入年…

mongoDB 入门指南、示例
http://www.cnblogs.com/hoojo/archive/2011/06/01/2066426.html mongoDB 入门指南、示例 上一篇:简单介绍mongoDB 一、准备工作 1、 下载mongoDB 下载地址:http://www.mongodb.org/downloads 选择合适你的版本 相关文档:http://www.mongodb.…

中国电子学会图形化四级编程题:成语接龙
「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】或【Python】,即可进入。如果加入了之前的社群不需要重复加入。 我们将有关编程题目的教学视频已经发布到抖音号21252972100,小马老…

sidecar学习
1、SideCar的出现 微服务的结构是细粒度的,由多个服务构成,支持不同的服务用不同的语言来编写,比如a服务用python,b服务用java,C服务用php等,我们称为异构语言,那么在利用zuul来代理访问服务的时…

java整数常量区_在Java中,我可以用二进制格式定义一个整数常量吗?
所以,随着Java SE 7的发布,二进制表示法是标准的。 如果你对二进制有一个很好的理解,语法是非常简单明了的。byte fourTimesThree 0b1100; byte data 0b0000110011; short number 0b111111111111111; int overflow 0b1010101010101010101…

[LeetCode 120] - 三角形(Triangle)
问题 给出一个三角形,找出从顶部至底部的最小路径和。每一步你只能移动到下一行的邻接数字。 例如,给出如下三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] 从顶部至底部的最小路径和为11(即235111)。 注意: …

中国电子学会scratch等级考试四级编程题:找出出现次数最多的数字
「青少年编程竞赛交流群」已成立(适合6至18周岁的青少年),公众号后台回复【Scratch】或【Python】,即可进入。如果加入了之前的社群不需要重复加入。 我们将有关编程题目的教学视频已经发布到抖音号21252972100,小马老…

人工智能 有信息搜索 (启发式)
一、最佳优先搜索 根据评价函数选择表现的最佳的节点进行扩展 最佳优先搜索 best-first-search 算法 不同的方法有不同的评价函数 启发函数,标记h(x) h(n)从节点n到目标的最低耗散估计值 启发函数是额外信息的一种最普通的形式 二、贪婪最佳优先搜索 最先扩展离目标…

java 排序算法 讲解_java实现排序算法之冒泡排序法详细讲解
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序。这…

24、线程控制
线程有一套完整的与其有关的函数库可供调用,它们中的绝大多数函数名都以pthread_开头。为了调用这些函数库,必须在程序中包含头文件pthread.h,并且在比那一程序时使用选项-lpthread来链接线程库。 1、线程标识 就像每个进程有一个进程ID一样,…

Datawhale组队学习周报(第038周)
本周报总结了从 11月01日至11月07日,Datawhale组队学习的运行情况,我们一直秉承“与学习者一起成长的理念”,希望这个活动能够让更多的学习者受益。 第 30 期组队学习一共 8 门开源课程,共组建了 8 个学习群,参与的学…

OpenGL概念辨析: 窗口,视口,裁剪区域
1.窗口:这就不用解释了吧 2.视口:就是窗口中用来显示图形的一块矩形区域,它可以和窗口等大,也可以比窗口大或者小。只有绘制在视口区域中的图形才能被显示,如果图形有一部分超出了视口区域,那么那一部分是看…