SpringBoot之@RefreshScope

注解RefreshScope时一个组合注解。

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {
	// Scope代理模式之ScopedProxyMode,包含TARGET_CLASS、INTERFACES、DEFAULT、NO
	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}

1.ClassPathBeanDefinitionScanner

在这里插入图片描述
在这里插入图片描述

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;
	}
}

后续解析目标bean时其类信息为ScopedProxyFactoryBean。但其实在解析RefreshScope中最终将其设置为LockedScopedProxyFactoryBean,具体参考以下章节。

2.RefreshScope

当前类是通过自动装配候选类RefreshAutoConfiguration触发的。
SpringBoot之@RefreshScope_第1张图片
通过上述UML图得知其几点重要信息:

  1. ApplicationContextAware表明存在应用上下文变量。
  2. 实现了Ordered接口的BeanDefinitionRegistryPostProcessor类型的后置处理器。【实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor后置处理器着重处理所有bean的BeanDefinition】。
  3. 实现了BeanFactoryPostProcessor类型的后置处理器。
  4. 监听ContextRefreshedEvent事件的ApplicationListener类型的监听器。
public class RefreshScope{	
	// BeanDefinitionRegistryPostProcessor类型的后置处理器 核心回调方法
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
			throws BeansException {
		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);
					}
				}
			}
		}
	}
}

通过上述得知,在DefaultListableBeanFactory#beanDefinitionMap中存在两种类型目标类相关的BeanDefinition。那是不是意味着在IOC容器中也存在目标类相关的两种的bean呢?

事实是scopedTarget.xxx类型的BeanDefinition其scope为refresh并非单例所以不会实例化。xxx类型在IOC容器中的单例为LockedScopedProxyFactoryBean。虽然目标类最终存在代理,但是在IOC容器中并非是目标类的代理类。

3.LockedScopedProxyFactoryBean

SpringBoot之@RefreshScope_第2张图片
通过上面章节得知,存在@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中缓存值。

你可能感兴趣的:(spring,boot,后端,java)