文章24 | 阅读 12801 | 点赞0
前文分析了@RefreshScope注解和RefreshScope类相关内容,我们了解到此时被@RefreshScope注解的类所对应的代理类类型已经换成了LockedScopedProxyFactoryBean,本篇主要分析这个类的作用。
首先看一下这个类的类图:
从这个图上可以看到
下面我们具体分析。
@Override
public Object getObject() {
if (this.proxy == null) {
throw new FactoryBeanNotInitializedException();
}
return this.proxy;
}
这个没啥,获取proxy对象。这是一个cglib生成的动态代理对象。 下面看一下这个对象怎么来的
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
Object proxy = getObject();
if (proxy instanceof Advised) {
Advised advised = (Advised) proxy;
advised.addAdvice(0, this);
}
}
先调用父类方法,里面会生成proxy对象,然后取出来添加了一个增强器是自身。也就是MethodInterceptor。
@Override
public void setBeanFactory(BeanFactory beanFactory) {
if (!(beanFactory instanceof ConfigurableBeanFactory)) {
throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
}
ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;
//设置工厂,以便于后面获取代理对象
this.scopedTargetSource.setBeanFactory(beanFactory);
ProxyFactory pf = new ProxyFactory();
pf.copyFrom(this);
pf.setTargetSource(this.scopedTargetSource);
Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");
Class<?> beanType = beanFactory.getType(this.targetBeanName);
if (beanType == null) {
throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +
"': Target type could not be determined at the time of proxy creation.");
}
if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
}
// Add an introduction that implements only the methods on ScopedObject.
ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
// 添加一个DelegatingIntroductionInterceptor拦截器
pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));
// Add the AopInfrastructureBean marker to indicate that the scoped proxy
// itself is not subject to auto-proxying! Only its target bean is.
//标记接口
pf.addInterface(AopInfrastructureBean.class);
//创建cglib动态代理
this.proxy = pf.getProxy(cbf.getBeanClassLoader());
}
可以看到有两个增强器DelegatingIntroductionInterceptor和LockedScopedProxyFactoryBean自身,LockedScopedProxyFactoryBean在前面,实际上当增强器经过LockedScopedProxyFactoryBean的时候就已经返回了。也就是说在refresh作用域场景下用不到DelegatingIntroductionInterceptor这个增强器。
@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();
}
// 拿出proxy
Object proxy = getObject();
ReadWriteLock readWriteLock = this.scope.getLock(this.targetBeanName);
if (readWriteLock == null) {
if (logger.isDebugEnabled()) {
logger.debug("For bean with name [" + this.targetBeanName
+ "] there is no read write lock. Will create a new one to avoid NPE");
}
readWriteLock = new ReentrantReadWriteLock();
}
Lock lock = readWriteLock.readLock();
lock.lock();
try {
if (proxy instanceof Advised) {
// 直接通过proxy拿到被代理的对象执行反射方法就返回了
Advised advised = (Advised) proxy;
ReflectionUtils.makeAccessible(method);
return ReflectionUtils.invokeMethod(method,
advised.getTargetSource().getTarget(),
invocation.getArguments());
}
return invocation.proceed();
}
// see gh-349. Throw the original exception rather than the
// UndeclaredThrowableException
catch (UndeclaredThrowableException e) {
throw e.getUndeclaredThrowable();
}
finally {
lock.unlock();
}
}
可以看到这里直接就返回了
最后把之前RefreshScope的一个内容加进来
RefreshScope类还实现了ApplicationListener接口,也就是说监听上下文刷新完成事件:
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
start(event);
}
public void start(ContextRefreshedEvent event) {
if (event.getApplicationContext() == this.context && this.eager
&& this.registry != null) {
eagerlyInitialize();
}
}
private void eagerlyInitialize() {
for (String name : this.context.getBeanDefinitionNames()) {
BeanDefinition definition = this.registry.getBeanDefinition(name);
// 作用域是refresh的bean定义
if (this.getName().equals(definition.getScope())
&& !definition.isLazyInit()) {
// 先实例化了
Object bean = this.context.getBean(name);
if (bean != null) {
bean.getClass();
}
}
}
}
可以看到,refresh作用域的bean定义也会在启动阶段就实例化了(非懒加载的)。
这里要注意一下这个getBean的过程:
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
回调RefreshScope的get方法:
@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;
}
}
BeanLifecycleWrapper的getBean:
public Object getBean() {
if (this.bean == null) {
synchronized (this.name) {
if (this.bean == null) {
this.bean = this.objectFactory.getObject();
}
}
}
return this.bean;
}
objectFactory.getObject();这段就回去了:
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
这里的createBean就是spring自己的了。
也就是说其实内部维护了一个bean
实例的缓存,就是被代理对象,不存在的话就调用ObjectFactory
的getObject
获取,如果调用过销毁方法,这个bean
就不存在,就会重新创建实例。重新创建实例则重新注入,更新的数据就被注入进去了。
LockedScopedProxyFactoryBean做了什么呢?
至此我们基本明白了spring-cloud中如何通过refreshScope来进行bean刷新的了。那么nacos要做的就是在收到变更配置的消息时,通知到spring-cloud清理掉对应的缓存bean,重新绑定属性源,然后再次使用时就会重新创建一个新的,就会把新的配置注入进来。
下篇我们分析通知销毁缓存的过程。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/qq_19414183/article/details/112286978
内容来源于网络,如有侵权,请联系作者删除!