Spring是如何缓存单例bean

来源:互联网 发布:mac 删除智能文件夹 编辑:程序博客网 时间:2024/05/19 13:44

1)//通过调试可以发现,Spring的IOC容器,在装载配置文件的时候,就已经将bean实例化到内存中,要么是以单例,要么是以原型的
   //的方式缓存到内存之中。
   AbstractApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
   applicationContext.getBean("publicBean");
   applicationContext.getBean("publicBean");
   ///AbstractApplicationContext applicationContextCopy=new ClassPathXmlApplicationContext("applicationContext.xml");
   //要获取bean的时候,是直接到内存中去拿bean的。
   //applicationContextCopy.getBean("publicBean");

2)首先Spring在加载完资源文件之后,就已经把bean实例化,并且放在缓存之中。

     在AbstractApplicationContext的refresh()方法中,缓存单例的bean。

// Instantiate all remaining (non-lazy-init) singletons,缓存单例bean
    finishBeanFactoryInitialization(beanFactory);

/**
  * Finish the initialization of this context's bean factory,
  * initializing all remaining singleton beans.
  */
 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
  // Initialize conversion service for this context.
  if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
    beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
   beanFactory.setConversionService(
     beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
  }

  // Stop using the temporary ClassLoader for type matching.
  beanFactory.setTempClassLoader(null);

  // Allow for caching all bean definition metadata, not expecting further changes.
  beanFactory.freezeConfiguration();

  // Instantiate all remaining (non-lazy-init) singletons.//缓存单例bean
  beanFactory.preInstantiateSingletons();
 }

具体的是调用DefaultListableBeanFactory中的preInstantiateSingletons()方法

public void preInstantiateSingletons() throws BeansException {
  if (this.logger.isInfoEnabled()) {
   this.logger.info("Pre-instantiating singletons in " + this);
  }
  synchronized (this.beanDefinitionMap) {
   // Iterate over a copy to allow for init methods which in turn register new bean definitions.
   // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
   List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
   for (String beanName : beanNames) {
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
     if (isFactoryBean(beanName)) {
      final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
      boolean isEagerInit;
      if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
       isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
        public Boolean run() {
         return ((SmartFactoryBean) factory).isEagerInit();
        }
       }, getAccessControlContext());
      }
      else {
       isEagerInit = (factory instanceof SmartFactoryBean &&
         ((SmartFactoryBean) factory).isEagerInit());
      }
      if (isEagerInit) {

       //将bean缓存到具体的缓存中
       getBean(beanName);
      }
     }
     else {

      //将bean缓存到具体的缓存中
      getBean(beanName);
     }
    }
   }
  }
 }

如果是单例bean,一般bean缓存和单例的bean缓存中都存在bean的实例,但是原型的bean只在一般的缓存bean中存在,

获取bean的时候,如果是单例的,就要先查看单例缓存中是否存在,如果存在就直接返回,如果不存在,就去一般的缓存中去找。

如果是原型bean就去一般的缓存中去找。

0 0