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销毁的过程

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