@RefreshScope及@Scope原理分析

基本原理

 

详细流程

(1)@Scope注解的解析

@Scope注解可用于类和方法上

类上的@Scope解析,在ConfigurationClassPostProcessor中,解析componentScan的时候进行解析。

具体位置在:org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan

// 解析scope 
// 在解析的过程中会注册一个bd={scopedTarget.testService={scope="refresh", beanClass="TestService"}} 
// 然后返回一个dbHolder={testService={scope="", beanClass="ScopedProxyFactoryBean"}}
 definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); 
// 然后把{testService={scope="", beanClass="ScopedProxyFactoryBean"}} 返回 
beanDefinitions.add(definitionHolder);

方法上的@Scope解析,在解析完配置类后,注册@Bean和@Import的时候进行解析的。

具体位置是:org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

// 此处才把@Bean的方法和@Import 注册到BeanDefinitionMap中 
// 方法上的@Scope解析 
this.reader.loadBeanDefinitions(configClasses);

解析完成后,会注册两个bd

  • testService={scope="", beanClass="ScopedProxyFactoryBean"}
  • scopedTarget.testService={scope="refresh", beanClass="TestService"}

(2)RefreshAutoConfiguration

在spring-cloud-context项目下,spring.factories中

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\ 
org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration,\
 org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,\ 
org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration,\ 
org.springframework.cloud.autoconfigure.WritableEnvironmentEndpointAutoConfiguration

RefreshAutoConfiguration

  • 定义了@Bean RefreshEventListener 监听ApplicationReadyEvent和RefreshEvent
  • 定义了@Bean RefreshScope

RefreshScope继承GenericScope, 而GenericScope实现了BeanDefinitionRegistryPostProcessor,

GenericScope利用BeanDefinitionRegistryPostProcessor的LockedScopedProxyFactoryBean()方法,将ScopedProxyFactoryBean替换成LockedScopedProxyFactoryBean

利用BeanDefinitionRegistryPostProcessor或者BeanFactoryPostProcessor的postProcessBeanFactory()方法注册了scope的处理器:refresh=new RefreshScope();

beanFactory.registerScope(this.name, this);

(3)获取bean

bean = getBean("testService")

testService对应的bd是{scope="singleton", beanClass=LockedScopedProxyFactoryBean}

getBean("testService")实际上获取的是单实例:LockedScopedProxyFactoryBean实例,实例化时,会初始化属性scopedTargetSouce=new SimpleBeanTargetSource(),这个scopedTargetSource接下来会有很大的用处。

LockedScopedProxyFactoryBean继承ScopedProxyFactoryBean 并且实现了BeanFactoryAware,在实例化后会执行setBeanFactory(),先执行父类ScopedProxyFactoryBean的setBeanFactory(),在这个方法里,会创建一个代理proxyFactory,这个proxyFactory的targetSource就是上面的scopedTargetSource,然后利用proxyFactory创建TestService的代理proxy。

并添加一个advise:DelegatingIntroductionInterceptor。

截止执行LockedScopedProxyFactoryBean的setBeanFactory()里的后续代码,proxy.addAdvice(0, this),即上面添加的DelegatingIntroductionInterceptor被替换了,且将LockedScopedProxyFactoryBean自己作为拦截器。

到这里bean就获取成功了,就是上面创建的proxy。

(4)执行bean.XXmethod()

这里就会走到proxy的invoke()方法来,即LockedScopedProxyFactoryBean的invoke()方法,

方法里先从locks中获取对应的读写锁,然后加读锁。

接着执行:

return ReflectionUtils.invokeMethod(method, advised.getTargetSource().getTarget(), invocation.getArguments());

即利用反射,执行target的method方法,advised.getTargetSource就是上面的SimpleBeanTargetSource,即调用SimpleBeanTargetSource的getTarget()方法

public Object getTarget() throws Exception { 
    return this.getBeanFactory().getBean(this.getTargetBeanName()); 
}

即beanFactory.getBean(“scopedTarget.testService”)

scopedTarget.testService的bd={scope="refresh", beanClass="TestService"}

在beanFactory.getBean()的调用中,会根据bd的scope类型,利用scope的处理器获取相应的bean

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

scope="refresh",就不会走if和else if,走的最后的els

 这里就回到了RefreshScope.get() --> GenericScope.get()

/** 
 * getBean()的时候,会调到这里来, 
 * @param name 
 * @param objectFactory 
 * @return 
 */ 
@Override public Object get(String name, ObjectFactory<?> objectFactory) {
    // 先保存到缓存中,这里的objectFactory就是上图中的createBean() 
    BeanLifecycleWrapper value = this.cache.put(name, new                 BeanLifecycleWrapper(name, objectFactory)); 
    // 放置读写锁 
    this.locks.putIfAbsent(name, new ReentrantReadWriteLock()); 
    try { 
        // 这里getBean(),实际上创建的是TestService 
        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; }

就是调用createBean()的流程了,创建完bean之后,不会往一级缓存中存放,因为scope=refresh不是单例模式。

到这里target即TestService的实例就创建完成了。接着就是反射调用target的xxmethod方法了。

(5)第二次调用bean.xxxMethod()

在未修改配置的情况下,第二次调用时,从cache中获取BeanLifecycleWrapper然后获取bean,就相当于直接从缓存中读取了。

(6)修改配置,产生RefreshEvent事件。

前面说了RefreshAutoConfiguration中定义了RefreshEventListener监听RefreshEvent事件,

在接收到RefreshEvent事件之后,会调用RefreshScope的refreshAll()方法,这个方法又调用了super.destroy()即GenericScope.destroy()

public void destroy() { 
    List<Throwable> errors = new ArrayList<Throwable>(); 
    // 清空cache缓存 
    Collection<BeanLifecycleWrapper> wrappers = this.cache.clear(); 
    // 逐个销毁wrapper 
    for (BeanLifecycleWrapper wrapper : wrappers) { 
        try { 
            // 加写锁 
            Lock lock = this.locks.get(wrapper.getName()).writeLock(); 
            lock.lock(); 
            try { 
                // 销毁wrapper(调用callback, bean=null) 
                wrapper.destroy(); 
            } finally { 
                lock.unlock(); 
            } 
        } catch (RuntimeException e) {
             errors.add(e); 
        } 
    } 
    if (!errors.isEmpty()) { 
        throw wrapIfNecessary(errors.get(0)); 
    } 
    this.errors.clear();
 }

可以看到,情况了cache缓存,下次再有方法调用时,cache为空,就又会新建wrapper,新建bean

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值