bean的作用域解析(bean作用域有哪些,说一下各种使用场景-)

  本篇文章为你整理了bean的作用域解析(bean作用域有哪些,说一下各种使用场景?)的详细内容,包含有bean的作用域是什么意思 bean作用域有哪些,说一下各种使用场景? bean的运用域 bean的作用域和生命周期是什么 bean的作用域解析,希望能帮助你了解 bean的作用域解析。

   1.在Spring中,Bean的作用域可以通过scope属性来指定。

   2.指定作用域的目的是 存储在此类单例bean的高速缓存中,并且对该命名bean的所有后续请求和引用都返回该高速缓存的对象。(本身的理念就是以空间换时间的思维,创建步骤繁杂,而且频繁用到,我就存起来,下次用的时候就不用了创建了)

   3.了解了目的之后,自然也就有了多种类型,大多数会使用singleton,当然也会有希望每次用到的就是新产生的故而出现prototype类型,还有就是某些范围经常用到,另一些范围不经常用到的,衍生了request和session的范围性质的单例
 

   类型与范围

   常见的有:

   1)singleton:代表单例的,也是默认值(singleton存储在三级缓存内,本质上是容器applicationcontext里面的三级缓存)

   2)prototype:代表多例的(prototype不会对bean进行存储,而是在每次需要的时候进行创建)

   3)request:代表范围性质的单例(request存储在对应的请求构建的请求对象里面setAttribute)

   4)session:代表范围性质的单例(session存储在对应的请求构建的请求对象里面setAttribute)

   5)application:application则是作用域整个应用里面多个applicationcontext共享

   6)包括自定义作用域

  代码展示

  

// mbd 指的是前面部分的 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

 

  if (mbd.isSingleton()) {

   sharedInstance = getSingleton(beanName, () - {

   try {

   return createBean(beanName, mbd, args);

   catch (BeansException ex) {

   destroySingleton(beanName);

   throw ex;

   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

  else if (mbd.isPrototype()) {

   // Its a prototype - create a new instance.

   Object prototypeInstance = null;

   try {

   beforePrototypeCreation(beanName);

   prototypeInstance = createBean(beanName, mbd, args);

   finally {

   afterPrototypeCreation(beanName);

   bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);

  else {

   String scopeName = mbd.getScope();

   // 这一步获取的就是存储单例的缓存,针对不同类型获取不同的缓存块【如request对应的RequestScope,session对应的SessionScope】

   final Scope scope = this.scopes.get(scopeName);

   if (scope == null) {

   throw new IllegalStateException("No Scope registered for scope name " + scopeName + "");

   try {

   //类似于getSingleton的方式,在缓存中拿不到才会走工厂方法获取

   Object scopedInstance = scope.get(beanName, () - {

   beforePrototypeCreation(beanName);

   try {

   return createBean(beanName, mbd, args);

   finally {

   afterPrototypeCreation(beanName);

   bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);

   catch (IllegalStateException ex) {

   throw new BeanCreationException(beanName,

   "Scope " + scopeName + " 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",

   ex);

  }

 

  

  

  代码分析

   对于Prototype部分的分析

   1.先是涉及到检测循环依赖部分的

   beforePrototypeCreation(beanName); //记录循环依赖,针对还没有创建完成的Bean进行记录

   afterPrototypeCreation(beanName); //销毁记录,已创建完了就必须销毁,不然A依赖于B,B都创建完了,你还觉得别人还没创建

   2.涉及创建Bean部分的
 

   了解过源码的都知道,在创建过程中,如果bean实例化但是未初始化会有一个对外暴露的方式,就是存储于单例池中

   故对于多例情况,bean是不做缓存的

  

   对于Singleton部分的分析

   对于单例的bean有它自己的处理逻辑,getSingleton方法:

  

public Object getSingleton(String beanName, ObjectFactory ? singletonFactory) {

 

   //加锁是保证单例创建的不冲突

   synchronized (this.singletonObjects) {

   //尝试从单例池中获取

   Object singletonObject = this.singletonObjects.get(beanName);

   if (singletonObject == null) {

   //记录循环依赖,针对还没有创建完成的Bean进行记录

   beforeSingletonCreation(beanName);

   boolean newSingleton = false;

   boolean recordSuppressedExceptions = (this.suppressedExceptions == null);

   if (recordSuppressedExceptions) {

   this.suppressedExceptions = new LinkedHashSet ();

   try {

   //从工厂方法中,创建bean对象

   singletonObject = singletonFactory.getObject();

   newSingleton = true;

   catch (IllegalStateException ex) {}

   catch (BeanCreationException ex) {}

   finally {

   //销毁记录,已创建完了就必须销毁

   afterSingletonCreation(beanName);

   if (newSingleton) {

   //创建完了要添加进入单例池

   addSingleton(beanName, singletonObject);

   return singletonObject;

  }

 

  

   对于其余部分的分析(包括request,session等和自定义都是走这部分的逻辑)

   针对request,session等,代码 scope.get 这部分深入进去其实是通用方法(也是模板设计模式),AbstractRequestAttributesScope类#get方法:

  

@Override

 

  public Object get(String name, ObjectFactory ? objectFactory) {

   RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();

   Object scopedObject = attributes.getAttribute(name, getScope());

   if (scopedObject == null) {

   scopedObject = objectFactory.getObject();

   attributes.setAttribute(name, scopedObject, getScope());

   // Retrieve object again, registering it for implicit session attribute updates.

   // As a bonus, we also allow for potential decoration at the getAttribute level.

   Object retrievedObject = attributes.getAttribute(name, getScope());

   if (retrievedObject != null) {

   // Only proceed with retrieved object if still present (the expected case).

   // If it disappeared concurrently, we return our locally created instance.

   scopedObject = retrievedObject;

   return scopedObject;

  }

 

  

   这块便是针对缓存的获取,通用理解为attributes.getAttribute(name, getScope()); 等同于session.getAttribute(beanName)或request.getAttribute(beanName)

   工厂方法(Lambda表达式部分)针对的便是缓存没有时候的创建逻辑

  

  分析汇总

   1.对于作用域,本质上是存储在此类单例bean的高速缓存中,并且对该命名bean的所有后续请求和引用都返回该高速缓存的对象,便是为了达到以空间换时间的优化方式。

   2.对于创建Bean,都要进行循环依赖的预防。

  

  

AbstractRequestAttributesScope

 

  以上就是bean的作用域解析(bean作用域有哪些,说一下各种使用场景?)的详细内容,想要了解更多 bean的作用域解析的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: