原创

Spring的Bean能不能被回收?是如何被回收的?

问题背景:

Spring中bean默认是单例模式创建,根据gc roots和单例模式不能被gc,那么spring的bean是怎么被回收的?如果不能被回收,不是内存越来越大!

单例模式介绍

既然要了解Spring中单例类的管理, 那我们先了解下什么是单例模式?

单例模式也属于创建型模式,所谓单例,顾名思义,所指的就是单个实例,也就是说要保证一个类仅有一个实例。

  • 单例模式有以下的特点:
    • ①单例类只能有一个实例
    • ②单例类必须自己创建自己的唯一实例
    • ③单例类必须给所有其他对象提供他自己的这一实例

单例模式实现有三种:饿汉式单例、懒汉式单例、单例注册表。

Spring单例创建对象源代码

我们再看下Spring中单例类的创建过程。
在Spring中,对单例模式的底层实现,是采用单例注册表的方式进行实现的。
源码如下:

类 DefaultSingletonBeanRegistry


public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    /** 
    Cache of singleton objects: bean name --> bean instance 
    充当了Bean实例的缓存,实现方式和单例注册表相同 
    */ 
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

    @Override
    public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
       Assert.notNull(beanName, "'beanName' must not be null");
       synchronized (this.singletonObjects) {
          Object oldObject = this.singletonObjects.get(beanName);
          if (oldObject != null) {
             throw new IllegalStateException("Could not register object [" + singletonObject +
                   "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
          }
          addSingleton(beanName, singletonObject);
       }
    }

    protected void addSingleton(String beanName, Object singletonObject) {
       synchronized (this.singletonObjects) {
          this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
          this.singletonFactories.remove(beanName);
          this.earlySingletonObjects.remove(beanName);
          this.registeredSingletons.add(beanName);
       }
    }

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
       Assert.notNull(singletonFactory, "Singleton factory must not be null");
       synchronized (this.singletonObjects) {
          if (!this.singletonObjects.containsKey(beanName)) {
             this.singletonFactories.put(beanName, singletonFactory);
             this.earlySingletonObjects.remove(beanName);
             this.registeredSingletons.add(beanName);
          }
       }
    }
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        //使用了代码锁定同步块,原理和同步方法相似,但是这种写法效率更高
       synchronized (this.singletonObjects) {
           Object singletonObject = this.singletonObjects.get(beanName);
           if (singletonObject == null) {
              ...
              boolean newSingleton = false;
              ...
              //真正创建Bean实例
              try {
                 singletonObject = singletonFactory.getObject();
                 newSingleton = true;
              }catch (IllegalStateException ex) {
                 ...
              }catch (BeanCreationException ex) {
                 ...
              }
              finally {
                 if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                 }
                 afterSingletonCreation(beanName);
              }
              //向单例注册表注册Bean实例
              if (newSingleton) {
                 addSingleton(beanName, singletonObject);
              }
           }
           return (singletonObject != NULL_OBJECT ? singletonObject : null);
        }
    }

}

类 AbstractBeanFactory


public abstract class AbstractBeanFactory implements ConfigurableBeanFactory{  
       public Object getBean(String name)throws BeansException{  
           return getBean(name,null,null);  
       }

       public Object doGetBean(String name,Class requiredType,Object[] args, boolean typeCheckOnly)throws BeansException{  
          //对传入的Bean name稍做处理,防止传入的Bean name名有非法字符(或则做转码)  
          String beanName=transformedBeanName(name);  
          Object bean=null;  
          //手工检测单例注册表  
          Object sharedInstance = getSingleton(beanName);

          if(sharedInstance!=null){  
             ...  
             //返回合适的缓存Bean实例  
             bean=getObjectForBeanInstance(sharedInstance, name, beanName, null);
          }else{ 
            ...  
            //取得Bean的定义  
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);  
             ...  
            //根据Bean定义判断,此判断依据通常来自于组件配置文件的单例属性开关  
            //<bean id="date" class="java.util.Date" scope="singleton"/>  
            //如果是单例,做如下处理   Create bean instance.
            if (mbd.isSingleton()) { 
                //再次检测单例注册表
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    //真正创建Bean实例
                   @Override
                   public Object getObject() throws BeansException {
                      try {
                         return createBean(beanName, mbd, args);
                      } catch (BeansException ex) {
                         ...
                      }
                   }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }  
           //如果是非单例,即prototpye,每次都要新创建一个Bean实例  
           //<bean id="date" class="java.util.Date" scope="prototype"/>  
           else if (mbd.isPrototype()) {
               // It's 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 { 
                // Scope
            }
        }
        return bean;  
    }  
}

从上面的源代码可以看出,对象存放在一个 Map 中,其中map singletonObjects 是用来存放单例对象的, 这个引用是用final修饰的, 所以在singletonObjects引用会被保存到方法区的常量池中,常量池用的引用,可以作为GC ROOT,所以new HashMap()对象不会被回收。

正文到此结束
广告是为了更好的提供数据服务
本文目录