1 @Scope

作用域 描述
singleton 每一个Spring IoC容器都拥有唯一的一个实例对象(默认作用域)
prototype 一个BeanDefinition对应多个对象实例,每次取出的都是不同的对象
request 每一个HTTP请求都有自己的Bean实例
session 一个Bean的作用域为HTTPsession的生命周期
global session 一个Bean的作用域为全局HTTPSession的生命周期

除此之外,SpringCloud新增了一个名为“refresh”的作用域,目的在于可以在不重启应用的情况下热加载外部配置(yml或properties)。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {

	/**
	 * 作用跟scopeName一样
	 */
	@AliasFor("scopeName")
	String value() default "";

	/**
	 *  singleton  表示该bean是单例的。(默认)
   *  prototype    表示该bean是多例的,即每次使用该bean时都会新建一个对象。
   *  request        在一次http请求中,一个bean对应一个实例。
   *  session        在一个httpSession中,一个bean对应一个实例
	 */
	@AliasFor("value")
	String scopeName() default "";

	/**
	 *  DEFAULT			  不使用代理。(默认)
	 * 	NO				    不使用代理,等价于DEFAULT。
	 * 	INTERFACES		使用基于接口的代理(jdk dynamic proxy)。
	 * 	TARGET_CLASS	使用基于类的代理(cglib)。
	 */
	ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;

}

2 @RefreshScope注解

它就是 @Scope ,一个scopeName="refresh"的@Scope。

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {

	/**
	 * 当proxyMode属性的值为ScopedProxyMode.TARGET_CLASS时,
	 * 会给当前创建的bean 生成一个代理对象,会通过代理对象来访问,
	 * 每次访问都会从缓存取或者创建一个新的代理对象。
	 */
	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}

3 Scope接口

public interface Scope {

	/**
	 * 创建一个新的bean 
	 * @RefreshScope在调用刷新的时候会使用此方法来给我们创建新的对象,
	 * 这样就可以通过spring 的装配机制将属性重新注入了,也就实现了所谓的动态刷新。
	 */
	Object get(String name, ObjectFactory<?> objectFactory);

	@Nullable
	Object remove(String name);

	void registerDestructionCallback(String name, Runnable callback);

	@Nullable
	Object resolveContextualObject(String key);
	@Nullable
	String getConversationId();
}

4 GenericScope类

// 继承Scope接口实现get方法
public class GenericScope
		implements Scope, BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor, DisposableBean {
	
	private BeanLifecycleWrapperCache cache = new BeanLifecycleWrapperCache(new StandardScopeCache());
	private ConcurrentMap<String, ReadWriteLock> locks = new ConcurrentHashMap<>();
	
	/**
	 * 对get方法的实现,获取一个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;
		}
	}
	
	/**
	 * 清除缓存
	 * 将bean==null 等待垃圾回收器回收
	 */
	@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();
	}
	
	
}

5 RefreshScope类


@ManagedResource
public class RefreshScope extends GenericScope
		implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, Ordered {
		
		
		/**
		 * 清除缓存,清除对象
		 */
		public void refreshAll() {
			super.destroy();
			this.context.publishEvent(new RefreshScopeRefreshedEvent());
		}
		
}		

6 ContextRefresher类

public abstract class ContextRefresher {

	private RefreshScope scope;
	
	/**
	 * 对外暴露的方法调用
	 */
	public synchronized Set<String> refresh() {
		Set<String> keys = refreshEnvironment();
		this.scope.refreshAll();
		return keys;
	}
	
}

7 RefreshEventListener类

public class RefreshEventListener implements SmartApplicationListener {

	private ContextRefresher refresh;
	
	/**
	 * 处理刷新事件
	 */
	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationReadyEvent) {
			handle((ApplicationReadyEvent) event);
		}
		else if (event instanceof RefreshEvent) {
			handle((RefreshEvent) event);
		}
	}
	
	/**
	 * 调用ContextRefresher类的刷新方法
	 */
	public void handle(RefreshEvent event) {
		if (this.ready.get()) { // don't handle events before app is ready
			log.debug("Event received " + event.getEventDesc());
			Set<String> keys = this.refresh.refresh();
			log.info("Refresh keys changed: " + keys);
		}
	}
}