SpringBoot之@RefreshScope

注解RefreshScope是对注解@Scope的增强,并且是被spring-cloud-context依赖引进的,但是注解@Scope是Spring自身携带的增强点。

@Scope提供的Mode类型存在default、no、interface、target_class 4种类型,@RefreshScope是在Scope基础上增加了refresh类型。

1.Scope

public class ClassPathBeanDefinitionScanner{
	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {//应用启动类所在的包路径
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);// 获取到全部的候选类
			for (BeanDefinition candidate : candidates) {
				// 解析当前类存在Scope注解
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				//设置Scope的范围:单例singleton、原型prototype、refresh。对于@RefreshScope分析其Scope 为 refresh
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
			//此处针对RefreshScope注解的bean,生成两个BeanDefinition注册在DefaultListableBeanFactory#beanDefinitionMap属性中。
			//其中之一:bean为 scopedTarget.xxx,BeanDefinition中beanClass属性为目标类信息。
			//其中之一:bean位xxx ,其中BeanDefinition中beanClass属性为通过ScopedProxyMode设置为ScopedProxyFactoryBean。
			// ScopedProxyFactoryBean 为FactoryBean
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}
}

以上即为SpringBoot启动流程中遍历启动类所在包下全部的候选类,针对@Scope注解判断这些潜在候选类是否需要ScopedProxyFactoryBean代理处理。

2.RefreshAutoConfiguration

核心类RefreshAutoConfiguration是为了注解RefreshScope引入的,同时引入两个BeanDefinitionRegistryPostProcessor类型的后置处理器之RefreshScopeBeanDefinitionEnhancer & RefreshScope,即只要存在包spring-cloud-context,该后置处理器就会发挥作用。

public class RefreshAutoConfiguration {

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

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

	@Bean
	public RefreshEventListener refreshEventListener(ContextRefresher contextRefresher) {
		return new RefreshEventListener(contextRefresher);
	}
	
	@Component
	protected static class RefreshScopeBeanDefinitionEnhancer implements BeanDefinitionRegistryPostProcessor{

		private Set<String> refreshables = new HashSet<>(Arrays.asList("com.zaxxer.hikari.HikariDataSource"));

		public static final String REFRESH_SCOPE_NAME = "refresh";


		@Override
		public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry){
			bindEnvironmentIfNeeded(registry);
			//从IOC注册表中遍历所有候选bean
			for (String name : registry.getBeanDefinitionNames()) {
				BeanDefinition definition = registry.getBeanDefinition(name);
				if (isApplicable(registry, name, definition)) {
					BeanDefinitionHolder holder = new BeanDefinitionHolder(definition,name);
					// 将当前bean BeanDefinition中class属性重置为 ScopedProxyFactoryBean
					BeanDefinitionHolder proxy = ScopedProxyUtils.createScopedProxy(holder, registry, true);
					definition.setScope("refresh");
					if (registry.containsBeanDefinition(proxy.getBeanName())) {
						registry.removeBeanDefinition(proxy.getBeanName());
					}
					registry.registerBeanDefinition(proxy.getBeanName(),proxy.getBeanDefinition());
				}
			}
		}

		private boolean isApplicable(BeanDefinitionRegistry registry, String name,BeanDefinition definition) {
			String scope = definition.getScope();
			if (REFRESH_SCOPE_NAME.equals(scope)) {// 如果当前bean之scope属性即为refresh则无需代理
				return false;
			}
			String type = definition.getBeanClassName();
			if (!StringUtils.hasText(type) && registry instanceof BeanFactory) {
				Class<?> cls = ((BeanFactory) registry).getType(name);
				if (cls != null) {
					type = cls.getName();
				}
			}
			// 如果当前类的类型为com.zaxxer.hikari.HikariDataSource,则对其进行代理
			if (type != null) {
				return this.refreshables.contains(type);
			}
			return false;
		}
	}
}

但是需要注意的是:RefreshScopeBeanDefinitionEnhancer是专门针对dataSource为com.zaxxer.hikari.HikariDataSource类型的bean。

2.1.RefreshScope

public class RefreshScope{	
	// BeanDefinitionRegistryPostProcessor类型的后置处理器 核心回调方法
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry){
			this.registry = registry;
			super.postProcessBeanDefinitionRegistry(registry);//GenericScope#postProcessBeanDefinitionRegistry
	}
}
public class GenericScope{
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry){
		// 遍历全部的BeanDefinition,BeanDefinition是后续实例化bean需要的类信息
		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) {// 处理ScopedProxyFactoryBean类型的bean
					if (getName().equals(root.getDecoratedDefinition().getBeanDefinition().getScope())) {
						// 将 ScopedProxyFactoryBean类型的bean 再次设置为 LockedScopedProxyFactoryBean类型的bean
						root.setBeanClass(LockedScopedProxyFactoryBean.class);
						root.getConstructorArgumentValues().addGenericArgumentValue(this);
						root.setSynthetic(true);
					}
				}
			}
		}
	}
}

相较于Scope,RefreshScope引入LockedScopedProxyFactoryBean类型。

3.LockedScopedProxyFactoryBean

在这里插入图片描述
通过上面章节得知,存在@RefreshScope的bean其BeanDefinition中Class属性为FactoryBean类型的class,即LockedScopedProxyFactoryBean。

  1. LockedScopedProxyFactoryBean实现了BeanFactoryAware接口。
  2. 实现MethodInterceptor接口实现对目标bean做Cglib代理处理。
public static class LockedScopedProxyFactoryBean<S extends GenericScope>
		extends ScopedProxyFactoryBean implements MethodInterceptor {

	private final S scope;

	private String targetBeanName;//scopedTarget.xxx

	public LockedScopedProxyFactoryBean(S scope) {
		this.scope = scope;
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		// ScopedProxyFactoryBean#setBeanFactory 对目标bean做Cglib代理
		super.setBeanFactory(beanFactory);
		Object proxy = getObject();
		if (proxy instanceof Advised) {
			Advised advised = (Advised) proxy;
			advised.addAdvice(0, this);
		}
	}

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Method method = invocation.getMethod();
		if (AopUtils.isEqualsMethod(method) || AopUtils.isToStringMethod(method)
				|| AopUtils.isHashCodeMethod(method)
				|| isScopedObjectGetTargetObject(method)) {
			return invocation.proceed();
		}
		Object proxy = getObject();
		ReadWriteLock readWriteLock = this.scope.getLock(this.targetBeanName);
		if (readWriteLock == null) {
			readWriteLock = new ReentrantReadWriteLock();
		}
		Lock lock = readWriteLock.readLock();
		lock.lock();
		if (proxy instanceof Advised) {
			Advised advised = (Advised) proxy;
			ReflectionUtils.makeAccessible(method);
			return ReflectionUtils.invokeMethod(method,
					advised.getTargetSource().getTarget(),
					invocation.getArguments());
		}
		return invocation.proceed();
	}

}

3.1.ScopedProxyFactoryBean

public class ScopedProxyFactoryBean extends ProxyConfig
		implements FactoryBean<Object>, BeanFactoryAware, AopInfrastructureBean {
	private final SimpleBeanTargetSource scopedTargetSource = new SimpleBeanTargetSource();
	@Nullable
	private String targetBeanName;
	@Nullable
	private Object proxy;
	public ScopedProxyFactoryBean() {
		setProxyTargetClass(true);
	}
	public void setTargetBeanName(String targetBeanName) {
		this.targetBeanName = targetBeanName;
		this.scopedTargetSource.setTargetBeanName(targetBeanName);
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;
		this.scopedTargetSource.setBeanFactory(beanFactory);
		ProxyFactory pf = new ProxyFactory();
		pf.copyFrom(this);
		// 目标类创建代理,注意是对scopedTargetSource对应的class
		pf.setTargetSource(this.scopedTargetSource);
		// 获取目标类的Class对象
		Class<?> beanType = beanFactory.getType(this.targetBeanName);
		if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
			pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
		}
		ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
		pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));
		pf.addInterface(AopInfrastructureBean.class);
		this.proxy = pf.getProxy(cbf.getBeanClassLoader());
	}


	@Override
	public Object getObject() {
		if (this.proxy == null) {
			throw new FactoryBeanNotInitializedException();
		}
		return this.proxy;
	}
}

如上所示,对目标类实例化过程中由于其BeanDefinition的class为FactoryBean类型的属性值,即存在代理过程。但是代理对象并非存在于IOC容器中,而是通过FactoryBean#getObject实时获取。

4.真正的代理过程

解析HTTP请求过程中,存在通过beanName获取handler过程,如下:

public abstract class AbstractBeanFactory{
	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		final String beanName = transformedBeanName(name);
		Object bean;
		//此时根据beanName从IOC容器中获取的是LockedScopedProxyFactoryBean
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}else {// 如果获取scopedTarget.xxx对应的bean实例信息
			BeanFactory parentBeanFactory = getParentBeanFactory();
			...
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
			...
			if (mbd.isSingleton()) {//scope表示为单例
				...
			}else if (mbd.isPrototype()) {//scope表示为Prototype
				...
			}else {//scope表示为refresh
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);//获取到RefreshScope
				final Scope scope = this.scopes.get(scopeName);
				// 从RefreshScope中获取scopedTarget.xxx对应的bean实例信息,存在则返回,否则通过Lambda表达式新建实例信息
				// scope#get涉及目标类的缓存信息,如果存在缓存表明目标类对应的配置信息没有发生变化。
				// 没有缓存则新建目标类的实例信息,实例化过程也就是对其属性重新赋值的过程,即最新的value值,实现了配置信息动态刷新的功能
				Object scopedInstance = scope.get(beanName, () -> {
					beforePrototypeCreation(beanName);
					try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}
				});
				//scopedInstance 即目标类的实例信息,此时scopedTarget.xxx获取到的就是普通的bean
				bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
			}
		}
		...
		return (T) bean;
	}
	
	protected Object getObjectForBeanInstance(Object beanInstance,String name,String beanName,RootBeanDefinition mbd) {
		//如果beanInstance 不是 FactoryBean 则直接返回
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}
		// 此处就是通过 FactoryBean#getObject获取到目标类的代理对象
		Object object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		...
		return object;
	}
}

通过上述得知目标类最终得到其Cglib代理的对象,执行目标方法时被如下方法拦截:

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

	private final AdvisedSupport advised;

	public DynamicAdvisedInterceptor(AdvisedSupport advised) {
		this.advised = advised;
	}

	@Override
	@Nullable
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;
		Object target = null;
		//advised.getTargetSource:从ProxyFactory中获取targetSource,即scopedTarget.xxx对应的类信息
		TargetSource targetSource = this.advised.getTargetSource();
		...
		// 获取TargetSource实例中目标source即scopedTarget.xxx对应的bean实例信息。继续调用上述AbstractBeanFactory#doGetBean方法
		// 涉及本文中核心逻辑之配置信息动态刷新
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
		Object retVal;
		retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, 
																	methodProxy).proceed();// 最终执行目标类的目标方法
		retVal = processReturnType(proxy, target, method, retVal);
		return retVal;
	}
}

综上所述得知配置信息动态刷新的过程。还缺少一环即配置更新同时删除目标类实例在GenericScope中缓存值。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值