Spring Cloud @Refersh原理

概述

@RefreshScope位于spring-cloud-context,可将@Bean定义放入org.springframework.cloud.context.scope.refresh.RefreshScope中。 RefreshScope(org.springframework.cloud.context.scope.refresh), 即@Scope("refresh")是spring cloud提供的一种特殊的scope实现,用来实现配置、实例热加载。
用这种方式注解的Bean可以在运行时刷新,并且使用它们的任何组件都将在下一个方法调用前获得一个新实例,该实例将完全初始化并注入所有依赖项。

所有@RefreshScope的Bean都是延迟加载的,只有在第一次访问时才会初始化;刷新Bean也是同理,下次访问时会创建一个新的对象。使用它我们可以用动态的更新代码中引用的配置文件的配置或者本地的配置。

实现原理

由上面得知,@RefreshScope是一个复合注解,被标注了@Scope("refresh") ,其将Bean的Scope变为refresh这个类型。

Scope相关代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
@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;
}

在SpringIOC中,我们熟知的BeanScope有单例(singleton)、原型(prototype),Bean的Scope影响了Bean的创建方式,例如创建Scope=singleton的Bean时,IOC会保存实例在一个Map中,保证这个Bean在一个IOC上下文有且仅有一个实例。
SpringCloud新增了一个refresh范围的scope,同样用了一种独特的方式改变了Bean的创建方式,使得其可以通过外部化配置(.properties文件等)的刷新,在应用不需要重启的情况下热加载新的外部化配置的值。
那么这个scope是如何做到热加载的呢?RefreshScope主要做了以下动作:

  • 单独管理Bean生命周期
    创建Bean的时候如果是RefreshScope就缓存在一个专门管理的ScopeMap中,这样就可以管理Scope是Refresh的Bean的生命周期了

  • 重新创建Bean
    外部化配置刷新之后,会触发一个动作,这个动作将上面的ScopeMap中的Bean清空,这样,这些Bean就会重新被IOC容器创建一次,使用最新的外部化配置的值注入类中,达到热加载新值的效果。

下面列举了几种scope:

  • RequestScope:从当前web request中获取实例的实例
  • SessionScope:从Session中获取实例的实例
  • ThreadScope:从ThreadLocal中获取的实例
  • RefreshScope:从内建缓存中获取的实例

另外我们可以看到@RefreshScope的代理模式proxyMode为ScopedProxyMode.TARGET_CLASS。当ScopedProxyModeTARGET_CLASS的时候会给当前创建的bean生成一个代理对象,会通过代理对象来访问,如实例不存在就创建一个新的实例。

RefreshScope对象刷新

我们一般是使用@Value、@ConfigurationProperties去获取配置变量值,其底层在IOC中则是通过上下文的Environment对象去获取property值,然后依赖注入利用反射Set到Bean对象中去的。当我们更新Environment里的Property值,然后重新创建一次RefreshBean,再进行一次上述的依赖注入,@Value的变量值就可以加载为最新的了。

spring-cloud-context-2.1.0.RELEASE-sources/META-INF/spring.factories我们看到RefreshAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Configuration
@ConditionalOnClass({RefreshScope.class})
@ConditionalOnProperty(
name = {"spring.cloud.refresh.enabled"},
matchIfMissing = true
)
@AutoConfigureBefore({HibernateJpaAutoConfiguration.class})
public class RefreshAutoConfiguration {
public static final String REFRESH_SCOPE_NAME = "refresh";
public static final String REFRESH_SCOPE_PREFIX = "spring.cloud.refresh";
public static final String REFRESH_SCOPE_ENABLED = "spring.cloud.refresh.enabled";

public RefreshAutoConfiguration() {
}

@Bean
@ConditionalOnMissingBean({RefreshScope.class})
public static RefreshScope refreshScope() {
return new RefreshScope();
}

@Bean
@ConditionalOnMissingBean
public static LoggingRebinder loggingRebinder() {
return new LoggingRebinder();
}

@Bean
@ConditionalOnMissingBean
public ContextRefresher contextRefresher(ConfigurableApplicationContext context, RefreshScope scope) {
return new ContextRefresher(context, scope);
}

@Bean
public RefreshEventListener refreshEventListener(ContextRefresher contextRefresher) {
return new RefreshEventListener(contextRefresher);
}

...
}

RefreshAutoConfiguration中可以看到,注册了刷新事件监听器,我们进去RefreshEventListener看下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class RefreshEventListener implements SmartApplicationListener {
private static Log log = LogFactory.getLog(RefreshEventListener.class);
private ContextRefresher refresh;
private AtomicBoolean ready = new AtomicBoolean(false);

public RefreshEventListener(ContextRefresher refresh) {
this.refresh = refresh;
}

public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationReadyEvent.class.isAssignableFrom(eventType) || RefreshEvent.class.isAssignableFrom(eventType);
}

public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationReadyEvent) {
this.handle((ApplicationReadyEvent)event);
} else if (event instanceof RefreshEvent) {
this.handle((RefreshEvent)event);
}

}

public void handle(ApplicationReadyEvent event) {
this.ready.compareAndSet(false, true);
}

public void handle(RefreshEvent event) {
if (this.ready.get()) {
log.debug("Event received " + event.getEventDesc());
Set<String> keys = this.refresh.refresh();
log.info("Refresh keys changed: " + keys);
}

}
}

onApplicationEvent()方法中实现了对监听RefreshEvent事件的处理方法,在handle(RefreshEvent event) 中可以看到调用了ContextRefresher#refresh()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class ContextRefresher {
private static final String REFRESH_ARGS_PROPERTY_SOURCE = "refreshArgs";
private static final String[] DEFAULT_PROPERTY_SOURCES = new String[]{"commandLineArgs", "defaultProperties"};
private Set<String> standardSources = new HashSet(Arrays.asList("systemProperties", "systemEnvironment", "jndiProperties", "servletConfigInitParams", "servletContextInitParams", "configurationProperties"));
private ConfigurableApplicationContext context;
private RefreshScope scope;

public ContextRefresher(ConfigurableApplicationContext context, RefreshScope scope) {
this.context = context;
this.scope = scope;
}

protected ConfigurableApplicationContext getContext() {
return this.context;
}

protected RefreshScope getScope() {
return this.scope;
}

public synchronized Set<String> refresh() {
Set<String> keys = this.refreshEnvironment();
this.scope.refreshAll();
return keys;
}

public synchronized Set<String> refreshEnvironment() {
// 获取刷新配置前的配置信息,对比用
Map<String, Object> before = this.extract(this.context.getEnvironment().getPropertySources());
// 刷新Environment
this.addConfigFilesToEnvironment();
// 这里上下文的Environment已经是新的值了
// 进行新旧对比,结果返回有变化的值
Set<String> keys = this.changes(before, this.extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
return keys;
}
}
ContextRefresher#refreshEnvironment()-更新Environment里的Property值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
ConfigurableApplicationContext addConfigFilesToEnvironment() {
ConfigurableApplicationContext capture = null;
try {
// 从上下文拿出Environment对象,copy一份
StandardEnvironment environment = copyEnvironment(this.context.getEnvironment());
// SpringBoot启动类builder,准备新做一个Spring上下文启动
SpringApplicationBuilder builder = new SpringApplicationBuilder(Empty.class)
// banner和web都关闭,因为只是想单纯利用新的Spring上下文构造一个新的Environment
.bannerMode(Mode.OFF).web(WebApplicationType.NONE)
// 传入我们刚刚copy的Environment实例
.environment(environment);
// 启动上下文!!!!!!
capture = builder.run();
// 这个时候,通过上下文SpringIOC的启动,刚刚Environment对象就变成带有最新配置值的Environment了
// 获取旧的外部化配置列表
MutablePropertySources target = this.context.getEnvironment()
String targetName = null;
// 遍历这个最新的Environment外部化配置列表
for (PropertySource<?> source : environment.getPropertySources()) {
String name = source.getName();
if (target.contains(name)) {
targetName = name;
}
// 某些配置源不做替换,读者自行查看源码
// 一般的配置源都会进入if语句
if (!this.standardSources.contains(name)) {
if (target.contains(name)) {
// 用新的配置替换旧的配置
target.replace(name, source);
}
else {
//....
}
}
}
}
//....
}

新做了一个Spring上下文,因为Spring启动后会对上下文中的Environment进行初始化,获取最新配置,所以这里利用Spring的启动,达到了获取最新的Environment对象的目的。然后去替换旧的上下文中的Environment对象中的配置值即可。

RefreshScope#refreshAll()-销毁scope缓存

ContextRefresher#refresh()的第二步就是调用RefreshScope#refreshAll()销毁scope缓存。
RefreshScope.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
@ManagedResource
public class RefreshScope extends GenericScope implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, Ordered {
private ApplicationContext context;
private BeanDefinitionRegistry registry;
private boolean eager = true;
private int order = 2147483547;

public RefreshScope() {
super.setName("refresh");
}

public int getOrder() {
return this.order;
}

public void setOrder(int order) {
this.order = order;
}

public void setEager(boolean eager) {
this.eager = eager;
}

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
this.registry = registry;
super.postProcessBeanDefinitionRegistry(registry);
}

public void onApplicationEvent(ContextRefreshedEvent event) {
this.start(event);
}

public void start(ContextRefreshedEvent event) {
if (event.getApplicationContext() == this.context && this.eager && this.registry != null) {
this.eagerlyInitialize();
}

}

private void eagerlyInitialize() {
String[] var1 = this.context.getBeanDefinitionNames();
int var2 = var1.length;

for(int var3 = 0; var3 < var2; ++var3) {
String name = var1[var3];
BeanDefinition definition = this.registry.getBeanDefinition(name);
if (this.getName().equals(definition.getScope()) && !definition.isLazyInit()) {
Object bean = this.context.getBean(name);
if (bean != null) {
bean.getClass();
}
}
}

}

@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("scopedTarget.")) {
name = "scopedTarget." + name;
}

if (super.destroy(name)) {
this.context.publishEvent(new RefreshScopeRefreshedEvent(name));
return true;
} else {
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());
}

public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
}

可以看到这会调用父类GenericScope#destroy()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class GenericScope implements Scope, BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor, DisposableBean {
private static final Log logger = LogFactory.getLog(GenericScope.class);
public static final String SCOPED_TARGET_PREFIX = "scopedTarget.";
private GenericScope.BeanLifecycleWrapperCache cache = new GenericScope.BeanLifecycleWrapperCache(new StandardScopeCache());
private String name = "generic";
private ConfigurableListableBeanFactory beanFactory;
private StandardEvaluationContext evaluationContext;
private String id;
private Map<String, Exception> errors = new ConcurrentHashMap();
private ConcurrentMap<String, ReadWriteLock> locks = new ConcurrentHashMap();

public GenericScope() {
}

public void setId(String id) {
this.id = id;
}

public void setName(String name) {
this.name = name;
}

public void setScopeCache(ScopeCache cache) {
this.cache = new GenericScope.BeanLifecycleWrapperCache(cache);
}

public Map<String, Exception> getErrors() {
return this.errors;
}

public void destroy() {
List<Throwable> errors = new ArrayList();
Collection<GenericScope.BeanLifecycleWrapper> wrappers = this.cache.clear();
Iterator var3 = wrappers.iterator();

while(var3.hasNext()) {
GenericScope.BeanLifecycleWrapper wrapper = (GenericScope.BeanLifecycleWrapper)var3.next();

try {
Lock lock = ((ReadWriteLock)this.locks.get(wrapper.getName())).writeLock();
lock.lock();

try {
wrapper.destroy();
} finally {
lock.unlock();
}
} catch (RuntimeException var10) {
errors.add(var10);
}
}

if (!errors.isEmpty()) {
throw wrapIfNecessary((Throwable)errors.get(0));
} else {
this.errors.clear();
}
}
...
}

这个类中有一个成员变量BeanLifecycleWrapperCache,用于缓存所有已经生成的Bean,在调用get方法时尝试从缓存加载,如果没有的话就生成一个新对象放入缓存,并通过初始化getBean其对应的Bean。清空缓存后,下次访问对象时就会重新创建新的对象并放入缓存了。所以在重新创建新的对象时,也就获取了最新的配置,也就达到了配置刷新的目的。

要缓存Bean对象生成

在调用链中build#run-->refreshContext()-->refresh()-->finishRefresh()中,发布了ContextRefreshedEvent事件。

1
2
3
4
5
6
7
protected void finishRefresh() {
this.clearResourceCaches();
this.initLifecycleProcessor();
this.getLifecycleProcessor().onRefresh();
this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
LiveBeansView.registerApplicationContext(this);
}

RefreshScopeContextRefreshedEvent事件进行了监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class RefreshScope extends GenericScope implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, Ordered {

public void onApplicationEvent(ContextRefreshedEvent event) {
this.start(event);
}

public void start(ContextRefreshedEvent event) {
if (event.getApplicationContext() == this.context && this.eager && this.registry != null) {
this.eagerlyInitialize();
}

}

private void eagerlyInitialize() {
String[] var1 = this.context.getBeanDefinitionNames();
int var2 = var1.length;

for(int var3 = 0; var3 < var2; ++var3) {
String name = var1[var3];
BeanDefinition definition = this.registry.getBeanDefinition(name);
if (this.getName().equals(definition.getScope()) && !definition.isLazyInit()) {
Object bean = this.context.getBean(name);
if (bean != null) {
bean.getClass();
}
}
}

}
}

在eagerlyInitialize方法中,这里会遍历所有的bean名字,找出bean定义的scope=refresh的且非懒加载的,然后进行一次获取,就是提前实例化啦。this.context.getBean(name)底层调用的是RefreshScope对象的get方法去获取,其get方法在父类GenericScope中实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
public static final String SCOPED_TARGET_PREFIX = "scopedTarget.";
private GenericScope.BeanLifecycleWrapperCache cache = new GenericScope.BeanLifecycleWrapperCache(new StandardScopeCache());

public Object get(String name, ObjectFactory<?> objectFactory) {
// 将Bean缓存下来
BeanLifecycleWrapper value = this.cache.put(name,new BeanLifecycleWrapper(name, objectFactory));
this.locks.putIfAbsent(name, new ReentrantReadWriteLock());
try {
// 创建Bean,只会创建一次,后面直接返回创建好的Bean
return value.getBean();
}
catch (RuntimeException e) {
this.errors.put(name, e);
throw e;
}
}

private static class BeanLifecycleWrapper {
private Object bean;
private Runnable callback;
private final String name;
private final ObjectFactory<?> objectFactory;

public BeanLifecycleWrapper(String name, ObjectFactory<?> objectFactory) {
this.name = name;
this.objectFactory = objectFactory;
}

public String getName() {
return this.name;
}

public void setDestroyCallback(Runnable callback) {
this.callback = callback;
}

public Object getBean() {
if (this.bean == null) {
synchronized(this.name) {
if (this.bean == null) {
this.bean = this.objectFactory.getObject();
}
}
}

return this.bean;
}

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

this.callback = null;
this.bean = null;
}
}
}

}

private static class BeanLifecycleWrapperCache {
private final ScopeCache cache;

public BeanLifecycleWrapperCache(ScopeCache cache) {
this.cache = cache;
}

public GenericScope.BeanLifecycleWrapper remove(String name) {
return (GenericScope.BeanLifecycleWrapper)this.cache.remove(name);
}

public Collection<GenericScope.BeanLifecycleWrapper> clear() {
Collection<Object> values = this.cache.clear();
Collection<GenericScope.BeanLifecycleWrapper> wrappers = new LinkedHashSet();
Iterator var3 = values.iterator();

while(var3.hasNext()) {
Object object = var3.next();
wrappers.add((GenericScope.BeanLifecycleWrapper)object);
}

return wrappers;
}

public GenericScope.BeanLifecycleWrapper get(String name) {
return (GenericScope.BeanLifecycleWrapper)this.cache.get(name);
}

public GenericScope.BeanLifecycleWrapper put(String name, GenericScope.BeanLifecycleWrapper value) {
return (GenericScope.BeanLifecycleWrapper)this.cache.put(name, value);
}
}

StandardScopeCache实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class StandardScopeCache implements ScopeCache {
private final ConcurrentMap<String, Object> cache = new ConcurrentHashMap();

public StandardScopeCache() {
}

public Object remove(String name) {
return this.cache.remove(name);
}

public Collection<Object> clear() {
Collection<Object> values = new ArrayList(this.cache.values());
this.cache.clear();
return values;
}

public Object get(String name) {
return this.cache.get(name);
}

public Object put(String name, Object value) {
Object result = this.cache.putIfAbsent(name, value);
return result != null ? result : value;
}
}

会封装成一个BeanLifecycleWrapper包装对象,内部也有个bean实例缓存,还能控制销毁的逻辑,其实这个才是关键,只要销毁了就把bean对象释放了,然后再获得的时候又是去创建一个新的,可以获取新的属性,因此可以做动态更新,把包装对象也会放入BeanLifecycleWrapperCache缓存中,底层就是StandardScopeCache的ConcurrentMap,缓存的操作都用StandardScopeCache。还要维护一个读写锁映射,在操作写BeanLifecycleWrapper的时候可以用写锁,读的时候可以用读锁,提高效率。然后还是调用BeanLifecycleWrapper的getBean()获取。

@Refresh注解动态代理对象生成

ClassPathBeanDefinitionScanner的doScan扫描的时候会进行scope的解析和设置,然后进行代理的设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet();
String[] var3 = basePackages;
int var4 = basePackages.length;
// 扫描basePackages所在的包下的所有的类,带@Componet的类都会被注册为BeanDefinition
for(int var5 = 0; var5 < var4; ++var5) {
String basePackage = var3[var5];
Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage);
Iterator var8 = candidates.iterator();

while(var8.hasNext()) {
BeanDefinition candidate = (BeanDefinition)var8.next();
//解析scope注解对象
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName);
}

if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);
}

if (this.checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
//根据Scope代理模式进行设置
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
this.registerBeanDefinition(definitionHolder, this.registry);
}
}
}

return beanDefinitions;
}

被打上@RefreshScope的Bean类会进入接下来ScopedProxyCreator#createScopedProxyScopedProxyUtilscreateScopedProxy创建一个代理bean定义来包装,并且设置好属性,然后注册到容器里,这里注意被代理对象的beanName被改成scopedTarget.xxx了,而代理对象的名字才是被代理对象原来的名字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition, BeanDefinitionRegistry registry, boolean proxyTargetClass) {
String originalBeanName = definition.getBeanName();
BeanDefinition targetDefinition = definition.getBeanDefinition();
String targetBeanName = getTargetBeanName(originalBeanName);
// 重点,这里构造函数中将beanClass设置为了ScopedProxyFactoryBean.class
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
// targetDefinition是被代理的原生Bean
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(targetDefinition.getRole());
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
} else {
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
}

proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition)targetDefinition);
}

targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);
registry.registerBeanDefinition(targetBeanName, targetDefinition);
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}

这里将BeanDefinition的beanClass设置为了ScopedProxyFactoryBean.class,而Scope的通用处理类GenericScope类是一个BeanDefinitionRegistryPostProcessor,其在postProcessBeanDefinitionRegistry回调方法中会针对刚刚那个beanClass为ScopedProxyFactoryBean.class的BeanDefinition做一个特殊的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// GenericScope.class
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
throws BeansException {
// 获取所有BeanDefinition的名称
for (String name : registry.getBeanDefinitionNames()) {
BeanDefinition definition = registry.getBeanDefinition(name);
// 针对RootBeanDefinition这个BeanDefinition来做,这和上面的逻辑吻合
if (definition instanceof RootBeanDefinition) {
RootBeanDefinition root = (RootBeanDefinition) definition;
// 判断BeanClass == ScopedProxyFactoryBean.class
if (root.getDecoratedDefinition() != null && root.hasBeanClass()
&& root.getBeanClass() == ScopedProxyFactoryBean.class) {
if (getName().equals(root.getDecoratedDefinition().getBeanDefinition()
.getScope())) {
// 将BeanClass换为LockedScopedProxyFactoryBean
root.setBeanClass(LockedScopedProxyFactoryBean.class);
root.getConstructorArgumentValues().addGenericArgumentValue(this);
// surprising that a scoped proxy bean definition is not already
// marked as synthetic?
root.setSynthetic(true);
}
}
}
}
}

GenericScope将ScopeBean,变为LockedScopedProxyFactoryBean这个类。

然而这个类又是一个FactoryBean,由其父类ScopedProxyFactoryBean的getObject方法实现FactoryBean接口,我们知道,创建一个FactoryBean,其实最终会调用其getObject方法,这个方法的返回值才是最终被创建出来的Bean实例,所以我们的重点就在getObject方法中。
可以发现,ScopedProxyFactoryBean还是一个BeanFactoryAware,其setBeanFactory会在比较早的时机被回调:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void setBeanFactory(BeanFactory beanFactory) {

// ...

// 这里是一个比较关键的点,scopedTargetSource变量是一个SimpleBeanTargetSource
// scopedTargetSource中保存了IOC容器
this.scopedTargetSource.setBeanFactory(beanFactory);

// 创建动态代理前,将动态代理的信息都保存到ProxyFactory中
ProxyFactory pf = new ProxyFactory();
pf.copyFrom(this);
// 注意,这里的TargetSource就是刚刚说的scopedTargetSource
pf.setTargetSource(this.scopedTargetSource);

// ...

this.proxy = pf.getProxy(cbf.getBeanClassLoader());
}

接着调用pf的getProxy方法开始进行动态代理。
CGLib动态代理都会实现一个MethodInterceptor,被代理的类的每一个方法调用实质上都是在调用MethodInterceptor的intercept方法,那么我们看看DynamicAdvisedInterceptor这个类的intercept方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 记得吗,刚刚我们反复强调的TargetSource
TargetSource targetSource = this.advised.getTargetSource();
try {
// ...
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
// 重点,这里调用了targetSource的getTarget
// target变量就是被代理的类,调用实际方法的时候反射调用其对应方法
target = targetSource.getTarget();
// ...
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// ...
// target变量就是被代理的类,调用实际方法的时候反射调用其对应方法
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
// target变量就是被代理的类,调用实际方法的时候反射调用其对应方法
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
// target变量就是被代理的类,调用实际方法的时候反射调用其对应方法
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
// ...
}

targetSource的getTarget()方法的返回值是被代理的类,那么这个getTarget做了什么逻辑呢?回顾上面来看我们知道这里TargetSource的实现类是SimpleBeanTargetSource:

1
2
3
4
5
6
7
8
public class SimpleBeanTargetSource extends AbstractBeanFactoryBasedTargetSource {

@Override
public Object getTarget() throws Exception {
// 从IOC中getBean
return getBeanFactory().getBean(getTargetBeanName());
}
}

被打上@RefreshScope的Bean都会被Spring做AOP动态代理,每次调用方法之前,都会去IOC中调用getBean方法获取真正的原始Bean,而原始Bean又被存放在GenericScope对象中的Map里,在refresh刷新配置的时候会清空缓存Map,在刷新配置的时候,调用类方法前去IOC获取Bean,然后到GenericScope查看缓存,发现没有这个Bean缓存就会重新从IOC容器创建一份Bean,依赖注入配置属性值的时候注入的就是最新的值了,这样就能达到动态刷新的作用。

何时触发ContextRefresher#refresh,重新加载配置文件内容

在Nacos修改配置文件内容后,会向上下文发布一个RefreshEvent事件,这时RefreshEventListener监听到对应事件,开始调用handle()处理。

总结


@RefreshScope实现流程:

  • 需要动态刷新的类标注@RefreshScope注解
  • @RefreshScope 注解组合了@Scope注解,并默认了ScopedProxyMode.TARGET_CLASS属性,此属性的功能就是在创建一个代理,在每次调用的时候都用它来调用GenericScope# get方法来获取对象
  • 如属性发生变更会调用ContextRefresher#refresh() --> RefreshScope#refreshAll()进行缓存清理方法调用,并发送刷新事件通知 –> GenericScope真正的清理方法destroy()实现清理缓存
  • 在下一次使用对象的时候,会调用GenericScope get(String name, ObjectFactory<?> objectFactory)方法创建一个新的对象,并存入缓存中,此时新对象因为Spring 的装配机制就是新的属性了

参考资料