Spring scope解惑
在2.0之前只有两种singleton和prototype(网上说的,没去验证),后面增加了session、request、global session三种专门用于web应用程序上下文的Bean
Singleton
这是spring的bean的默认的作用域-单例。但是此单例又与设计模式中的单例模式不一样,设计模式的单例在设计模式的文章中再介绍。
singleton不要简单的理解为全局只有一个,真正的意义是在一个上下文(ApplicationContext)中只有一个。如果在一个项目中有多个ApplicationContext,那么获取的Bean对象就不只一个了
在同一个容器或上下文中,所有对单例bean的请求,只要id与该bean定义相匹配,都会返回同一个实例。简单说就是bean定义为singleton时,ioc容器只会创建该bean的唯一实例,然后存储在单例缓存(singleton cache)中。
singleton的bean是无状态的,只有一份,所以无论哪个线程获取的都是同一个同样的实例,具有线程无关性。Spring使用ThreadLocal解决线程安全问题,这就要求在使用singleton的bean时不能存在属性的改变,如果存在属性改变,就需要慎重使用,采用同步来处理多线程问题,或者考虑使用prototype作用域。
基于上面,我们常用的Controller、Service、Repository、Configuration这些bean基本上都是项目启动就已经初始化完毕,每个bean的属性都已经确定,在运行过程中也不会更改,这样就很适合单例模式。这里再说一下实体类(用@Entity注解修饰的)这个可不是一个bean,试想一下,每次使用实体的时候是不是都是DomainA a = new DomainA();,应该没有人这么用@Autowired private DomainA domianA;
使用scope的方法如下:
@Scope(singleton)
@Component
public class MainService {...}
Prototype
相对应singleton,prototype就属于多例模式,每次请求都会创建一个新的实例,相当于new操作。
对于prototype类型的bean,spring只负责创建初始化,不会对整个生命周期负责,随后的所有操作都交给客户端来处理
现在问一个问题,如何声明一个prototype的bean并使用呢?(先不要急着往下看,想一下,就以在ScopeTestController里面注入prototype的PrototypeService来说明)
~
~
~
~
思考中...
~
~
~
~
可能很多人(包括我)开始会以为像以下这种写法就可以
public interface PrototypeService {
}
@Service
@Scope(prototype)
public class PrototypeServiceImpl implements PrototypeService {
}
@RestController
public class ScopeTestController {
@Autowired
PrototypeService prototypeService;
@GetMapping(/)
public void testPrototype() {
System.out.println(prototypeService);
}
}
启动项目,两次次请求,查看控制台输出
com.ukirin.idle.web.service.impl.PrototypeServiceImpl@74738f89
com.ukirin.idle.web.service.impl.PrototypeServiceImpl@74738f89
?一样?什么情况?
其实仔细想一下也就明白了错在哪,Controller是一个单例,在启动时就已经把Service注入了,所以不可能改变,当然现在你可以这么改,将Controller同样改为prototype的。那么恭喜你回答正确,但是,这不是我们的目的,我们的目的是要看在单例中如何使用。
方法1:从ApplicationContext里面获取
将Controller里面的代码做以下改动
@RestController
public class ScopeTestController {
// @Autowired
// PrototypeService prototypeService;
@Autowired
WebApplicationContext applicationContext;
@GetMapping(/)
public void testPrototype() {
// System.out.println(prototypeService);
System.out.println(applicationContext.getBean(PrototypeService.class));
}
}
这样每次都从上下文中请求一个实例,容器对每个请求都实例化一个新的Service,没有问题
方法2:方法1的变种,采用工厂模式来生成Service
代码就不写了...
方法3:使用代理
很简单,在@Scope里面加上代理模式即可
@Service
@Scope(value = prototype, proxyMode = ScopedProxyMode.INTERFACES)
public class PrototypeServiceImpl implements PrototypeService {
}
@RestController
public class ScopeTestController {
@Autowired
PrototypeService prototypeService;
// @Autowired
// WebApplicationContext applicationContext;
@GetMapping(/)
public void testPrototype() {
System.out.println(prototypeService);
// System.out.println(applicationContext.getBean(PrototypeService.class));
}
}
这样,就可以每次获取不同的Service了,这个的原理就是,在初始化Controller的时候并不是讲一个Service的实体注入,而是注入一个代理,当真正调用Service的时候,代理会对其进行依赖解析,并调用真正的实体bean
额外需要注意的一点是,如果注入的不是接口的实现,而是一个类,那么需要将proxyMode = ScopedProxyMode.INTERFACES改为proxyMode = ScopedProxyMode.TARGET_CLASS
request
该作用域将 bean 的定义限制为 HTTP 请求。只在 web-aware Spring ApplicationContext 的上下文中有效
上述的实验结果是每次请求都会输出不一样的结果,在这里可能会与prototype产生困惑,做以下的实验可以解决你的困惑
public interface PrototypeService {
}
@Service
@Scope(value = request, proxyMode = ScopedProxyMode.INTERFACES)
public class PrototypeServiceImpl implements PrototypeService {
}
public interface MiddleService {
void test();
}
@Service
public class MiddleServiceImpl implements MiddleService {
@Autowired
PrototypeService prototypeService;
@Override
public void test() {
System.out.println(middle : + prototypeService);
}
}
@RestController
public class ScopeTestController {
@Autowired
MiddleService middleService;
@Autowired
PrototypeService prototypeService;
// @Autowired
// WebApplicationContext applicationContext;
@GetMapping(/)
public void testPrototype() {
System.out.println(controller : + prototypeService);
// System.out.println(applicationContext.getBean(PrototypeService.class));
middleService.test();
}
}
输出结果为:
controller : com.ukirin.idle.web.service.impl.PrototypeServiceImpl@6b90371c
middle : com.ukirin.idle.web.service.impl.PrototypeServiceImpl@6b90371c
然后将作用域改为prototype再测试一下
输出结果为:
controller : com.ukirin.idle.web.service.impl.PrototypeServiceImpl@49b2c498
middle : com.ukirin.idle.web.service.impl.PrototypeServiceImpl@ccb8c47
结果显而易见
session
该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。
上述的实验结果是一个会话内输出结果是一样的
global-session
该作用域将 bean 的定义限制为全局 HTTP 会话。只在 web-aware Spring ApplicationContext 的上下文中有效。
Spring scope解惑的更多相关文章
- Spring Scope:Web项目中如何安全使用有状态的Bean对象?
Web系统是最常见的Java应用系统之一,现在流行的Web项目多使用ssm或ssh框架,使用spring进行bean的管理,这为我们编写web项目带来了很多方便,通常,我们的controler层使用注 ...
- Spring scope
scope用来声明IOC容器中的对象应该处的限定场景或者说该对象的存活空间,即在IOC容器在 对象进入相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁 ...
- spring scope="prototype", scope="session"
转自: http://www.cnblogs.com/JemBai/archive/2010/11/10/1873954.html struts+spring action应配置为scope=&quo ...
- Spring——scope详解(转载)
摘自<spring 解密> scope用来声明IOC容器中的对象应该处的限定场景或者说该对象的存活空间,即在IOC容器在 对象进入相应的scope之前,生成并装配这些对象,在该对象不再处于 ...
- spring scope 作用域
转自:http://www.cnblogs.com/qq78292959/p/3716827.html 今天研究了一下scope的作用域.默认是单例模式,即scope="singleton& ...
- Spring scope注解
Spring注解中@scope默认为单例模式(singleton) 设置写法@scope("") 1.singleton单例模式 全局有且仅有一个实例 2.prototype原型模 ...
- Spring scope 配置
Scope 描述的是 Spring 容器如何新建Bean的实例,Spring的Scope有以下几种,通过@Scope来注解实现: 1. Singleton: 一个Spring容器中只有一个Bean的实 ...
- spring scope 属性的取值
Spring 容器是通过单例模式创建 Bean 对象的,也就是说,默认情况下,通过调用 ac.getBean("mybean")方法获得的对象都是同一个 mybean 对象 使用单 ...
- spring scope prototype与singleton区别
1.singleton作用域 当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配 ...
随机推荐
- Thrift初试
Restful 基于 Http 进行通讯. 开放.标准.简单.兼容性升级容易: 性能略低.在 QPS 高或者对响应时间要求苛刻的服务上,可以用 RPC,RPC采用二进制传输.TCP 通讯,所以通常性能 ...
- c# + Sql server 事务处理
事务(Transaction)是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位. 通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便 ...
- Create a Group Policy Central Store
一.How to create a Group Policy Central Store You have downloaded or created your own Group Policy Ad ...
- 把配置和环境解耦 eliminate “works on my machine” problems when collaborating on code with co-workers docker架构与解决的问题
Docker实践 - 懒人的技术笔记 - 博客频道 - CSDN.NET http://blog.csdn.net/lincyang/article/details/43055061 Docker直 ...
- Java 集合框架查阅技巧
如何记录每一个容器的结构和所属体系呢? List ArrayList LinkedList Set HashSet TreeSet 其中,后缀名就是该集合所属的体系,前缀名就是该集合的数据结构. 看到 ...
- django--博客系统--后台管理
1.后台管理功能主要实现了,文章的添加与修改,以及富文本的使用 前端页面 母版 <!DOCTYPE html> <html lang="en"> <h ...
- springcloud Hystrix fallback无效
在使用feign调用服务的时候防止雪崩效应,因此需要添加熔断器.(基于springboot2.0) 一.在控制器的方法上添加 fallbackMethod ,写一个方法返回,无须在配置文件中配置,因 ...
- WebService SOAP WSDL UDDI 使用php的curl、PHP5的SoapClient实现同步
一.基本名词 WebService: WebService是一种跨编程语言和跨操作系统平台的远程调用技术.不同系统,不同语言的数据交换方法都是不同的,这就导致在不同系统,不同语言之间传递数据很麻烦,基 ...
- jmeter+ant+jenkins接口自动环境搭建
ant 下载地址:http://archive.apache.org/dist/ant/binaries/ 下载:apache-ant-1.9.7-bin.zip 解压到系统盘下:D:\apache- ...
- js基本
BOM 浏览器对象模型 DOM 文档对象模型 js主要是来操作DOM和BOM,用的事件驱动方式,通过事件去执行相应函数 如何加载:在html当中有写链接,然后加载的时候会把js函数,数据全取出来,然后 ...