| 作用域 | 描述 |
|---|---|
| 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;
}
它就是 @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;
}
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();
}
// 继承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();
}
}
@ManagedResource
public class RefreshScope extends GenericScope
implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, Ordered {
/**
* 清除缓存,清除对象
*/
public void refreshAll() {
super.destroy();
this.context.publishEvent(new RefreshScopeRefreshedEvent());
}
}
public abstract class ContextRefresher {
private RefreshScope scope;
/**
* 对外暴露的方法调用
*/
public synchronized Set<String> refresh() {
Set<String> keys = refreshEnvironment();
this.scope.refreshAll();
return keys;
}
}
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);
}
}
}