Spring之@RefreshScope探祕(一)

Spring BeanFactory對於含有@RefreshScope註解的bean加載

Spring BeanFactory對於Bean的加載是大致分爲三種的,第一種:單例bean,Scope爲Singleton,第二種:多例bean,Scope爲Prototype,然後就是第三種,除上述兩類的都屬於第三種,其中就有Scope爲refresh的bean,即被@RefreshScope註解過的bean,BeanFactory對於Scope爲refresh的bean的加載代碼如下:

	String scopeName = mbd.getScope();
	final Scope scope = this.scopes.get(scopeName);
	if (scope == null) {
		throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
	}
	try {
		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);
	}

分析如下:

  • 1.首先根據BeanDefinition獲取scopeName,然後從Scope實例列表裏面獲取到相應的實例,針對@RefreshScope而言,scopeName爲refresh,Scope實例爲RefreshScope類型的實例
  • 2.接下來通過Scope的get(String name, ObjectFactory<?> objectFactory)方法獲取實例,如果獲取不到將會通過傳遞的ObjectFactory工廠對象創建一個實例(創建的具體過程這裏不贅述)

RefreshScope類詳解

RefreshScope是繼承的GenericScope的get(String name, ObjectFactory<?> objectFactory)方法,GenericScope中會爲bean做一個簡單的緩存,如下:

	@Override
	public Object get(String name, ObjectFactory<?> objectFactory) {
		BeanLifecycleWrapper value = this.cache.put(name,
				new BeanLifecycleWrapper(name, objectFactory));
		this.locks.putIfAbsent(name, new ReentrantReadWriteLock());
		try {
			return value.getBean();
		}
		catch (RuntimeException e) {
			this.errors.put(name, e);
			throw e;
		}
	}

分析如下:

  • 1.初始化一個管理bean生命週期的BeanLifecycleWrapper實例,如果不存在這個beanName的緩存的情況下會將這個BeanLifecycleWrapper實例放入BeanLifecycleWrapperCache緩存(其實這裏有點缺陷,就是並不需要每次去初始化一個BeanLifecycleWrapper實例)
  • 2.如果不存在這個beanName對應的讀寫鎖,將會初始化一個ReentrantReadWriteLock放入locks這個map集合中
  • 3.通過BeanLifecycleWrapper的getBean()方法獲取bean
  • 4.如果有異常,先統計異常然後再重新拋出去
BeanLifecycleWrapper的getBean()
	public Object getBean() {
		if (this.bean == null) {
			synchronized (this.name) {
				if (this.bean == null) {
					this.bean = this.objectFactory.getObject();
				}
			}
		}
		return this.bean;
	}

其實就是通過對象創建工廠ObjectFactory創建一個新的bean(這裏的雙重檢查鎖也有點問題,bean字段並沒有用volatile聲明,多線程創建的話即使有某個線程創建成功了,其他線程也感知不到)

由此可見,如果BeanLifecycleWrapperCache中關於beanName的緩存的BeanLifecycleWrapper實例不變的話,那麼將一直獲取的是上述過程創建的bean(BeanLifecycleWrapper沒有提供公開的setBean方法,因此基本不用擔心BeanLifecycleWrapper緩存的bean實例被重新設置爲null)
RefreshScope的refresh與refreshAll
	@ManagedOperation(description = "Dispose of the current instance of bean name "
			+ "provided and force a refresh on next method execution.")
	public boolean refresh(String name) {
		if (!name.startsWith(SCOPED_TARGET_PREFIX)) {
			// User wants to refresh the bean with this name but that isn't the one in the
			// cache...
			name = SCOPED_TARGET_PREFIX + name;
		}
		// Ensure lifecycle is finished if bean was disposable
		if (super.destroy(name)) {
			this.context.publishEvent(new RefreshScopeRefreshedEvent(name));
			return true;
		}
		return false;
	}

	@ManagedOperation(description = "Dispose of the current instance of all beans "
			+ "in this scope and force a refresh on next method execution.")
	public void refreshAll() {
		super.destroy();
		this.context.publishEvent(new RefreshScopeRefreshedEvent());
	}

分析如下:

  • 1.refresh專門針對某一個bean的,在成功銷燬之後發推送一個針對該bean的RefreshScopeRefreshedEvent事件
  • 2.refreshAll會銷燬所有Scope爲refresh的bean,在銷燬完成之後會推送一個RefreshScopeRefreshedEvent事件
refresh bean的銷燬
單個銷燬
	protected boolean destroy(String name) {
		BeanLifecycleWrapper wrapper = this.cache.remove(name);
		if (wrapper != null) {
			Lock lock = this.locks.get(wrapper.getName()).writeLock();
			lock.lock();
			try {
				wrapper.destroy();
			}
			finally {
				lock.unlock();
			}
			this.errors.remove(name);
			return true;
		}
		return false;
	}

分析如下:

  • 1.從BeanLifecycleWrapperCache中移除針對該bean設置的緩存
  • 2.如果存在該bean的緩存,先獲取到讀寫鎖,然後加鎖並執行BeanLifecycleWrapper的destroy()方法,執行完成之後解鎖,移除錯誤列表errors中該bean對應的錯誤信息
全部銷燬
	@Override
	public void destroy() {
		List<Throwable> errors = new ArrayList<Throwable>();
		Collection<BeanLifecycleWrapper> wrappers = this.cache.clear();
		for (BeanLifecycleWrapper wrapper : wrappers) {
			try {
				Lock lock = this.locks.get(wrapper.getName()).writeLock();
				lock.lock();
				try {
					wrapper.destroy();
				}
				finally {
					lock.unlock();
				}
			}
			catch (RuntimeException e) {
				errors.add(e);
			}
		}
		if (!errors.isEmpty()) {
			throw wrapIfNecessary(errors.get(0));
		}
		this.errors.clear();
	}

跟單個銷燬是差不多的過程,不贅述

BeanLifecycleWrapper之destroy()
	public void destroy() {
		if (this.callback == null) {
			return;
		}
		synchronized (this.name) {
			Runnable callback = this.callback;
			if (callback != null) {
				callback.run();
			}
			this.callback = null;
			this.bean = null;
		}
	}

執行銷燬方法,並將緩存的bean以及callback設置爲null,下一次獲取bean的話將會重新執行ObjectFactory的getObject()方法獲取新的bean

註冊銷燬方法
    // BeanLifecycleWrapper
    public void setDestroyCallback(Runnable callback) {
		this.callback = callback;
	}

     // GenericScope
	@Override
	public void registerDestructionCallback(String name, Runnable callback) {
		BeanLifecycleWrapper value = this.cache.get(name);
		if (value == null) {
			return;
		}
		value.setDestroyCallback(callback);
	}

    // AbstractBeanFactory
	protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
		AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
		if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
			if (mbd.isSingleton()) {
				// Register a DisposableBean implementation that performs all destruction
				// work for the given bean: DestructionAwareBeanPostProcessors,
				// DisposableBean interface, custom destroy method.
				registerDisposableBean(beanName,
						new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
			}
			else {
				// A bean with a custom scope...
				Scope scope = this.scopes.get(mbd.getScope());
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
				}
				scope.registerDestructionCallback(beanName,
						new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
			}
		}
	}

在看到registerDisposableBeanIfNecessary這個方法時,相信看過之前寫的一篇Spring bean銷燬的文章的朋友會比較熟系,文章地址:Spring bean銷燬的過程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章