概述
@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 "" ; @AliasFor("value") String scopeName () default "" ; 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主要做了以下动作:
下面列举了几种scope:
RequestScope:从当前web request中获取实例的实例
SessionScope:从Session中获取实例的实例
ThreadScope:从ThreadLocal中获取的实例
RefreshScope:从内建缓存中获取的实例
另外我们可以看到@RefreshScope
的代理模式proxyMode为ScopedProxyMode.TARGET_CLASS
。当ScopedProxyMode
为TARGET_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()); this .addConfigFilesToEnvironment(); 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 { StandardEnvironment environment = copyEnvironment(this .context.getEnvironment()); SpringApplicationBuilder builder = new SpringApplicationBuilder(Empty.class) .bannerMode(Mode.OFF).web(WebApplicationType.NONE) .environment(environment); capture = builder.run(); MutablePropertySources target = this .context.getEnvironment() String targetName = null ; for (PropertySource<?> source : environment.getPropertySources()) { String name = source.getName(); if (target.contains(name)) { targetName = name; } 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 ); }
而RefreshScope
对ContextRefreshedEvent
事件进行了监听
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) { 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; } } 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; 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(); 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); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this .registry); beanDefinitions.add(definitionHolder); this .registerBeanDefinition(definitionHolder, this .registry); } } } return beanDefinitions; }
被打上@RefreshScope
的Bean类会进入接下来ScopedProxyCreator#createScopedProxy
。ScopedProxyUtils
的createScopedProxy
创建一个代理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); RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class); 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 public void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry registry) throws BeansException { for (String name : registry.getBeanDefinitionNames()) { BeanDefinition definition = registry.getBeanDefinition(name); if (definition instanceof RootBeanDefinition) { RootBeanDefinition root = (RootBeanDefinition) definition; if (root.getDecoratedDefinition() != null && root.hasBeanClass() && root.getBeanClass() == ScopedProxyFactoryBean.class) { if (getName().equals(root.getDecoratedDefinition().getBeanDefinition() .getScope())) { root.setBeanClass(LockedScopedProxyFactoryBean.class); root.getConstructorArgumentValues().addGenericArgumentValue(this ); 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) { this .scopedTargetSource.setBeanFactory(beanFactory); ProxyFactory pf = new ProxyFactory(); pf.copyFrom(this ); 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 = this .advised.getTargetSource(); try { target = targetSource.getTarget(); if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { retVal = methodProxy.invoke(target, argsToUse); } else { retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } 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 { 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 的装配机制就是新的属性了
参考资料