【spring源码探索】一分钟搞懂RefreshScope的作用及实现原理

前文

下述文章完全为个人阅读源码的随笔记录,如有错误,欢迎大家指出。

过程

过程很坎坷,而且大家应该都不想看了吧,简而言之就是先写个测试DEMO,然后各种DEBUG。

结论

这次先直接上结论,然后再通过测试DEMO给出验证,最后再去跟代码。
RefreshScope的作用介于Singleton和Prototype之间,你说他是单例啊,他在某些条件下是单例,你说他是多例把,他确实在某些条件下也是多例。
这个条件就在于Refresh。

加了RefreshScope注解的bean,每次容器刷新后,都会重新生成一个对象。

顺便记录一下底层的实现把:

在IOC容器里面,有一个map类型的scopes的缓存,他会根据scope名称不同,分为request、session、refresh、application(至于为啥没有单例和多例,因为单例的缓存已经放在singleObjects里面了,多例就更不用说,压根就不需要缓存)。

咱们这次的关注点是refresh,他map里面取出来的对象就是RefreshScope,RefreshScope的父类GenericScope有一个叫BeanLifecycleWrapperCache,这玩意是缓存的包装对象了,里面的ScopeCache其实也就是一个KEY为beanName,Value是bean的Map缓存,只是这个缓存跟单例池唯一的区别就是他对外提供了一个清空方法(其实单例池咱们也可以给他时改造成这样)

只要调用RefreshScope的refreshAll()方法,就会清空这个缓存,下次再取bean的时候,从缓存里面取不到自然就会重新走getBean()方法重新生成再放进这个缓存里面了。

最后附一个可以直接开DEBUG的DEMO,对源码感兴趣的同学可以兄弟可以直接拿去开搞,请原谅我反射直接做的搬砖工。

	public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext run = SpringApplication.run(Consumer03.class, args);
        Object eurekaClient = run.getBean("scopedTarget.eurekaClient");
        Object eurekaClient1 = run.getBean("scopedTarget.eurekaClient");

        ConfigurableListableBeanFactory beanFactory = run.getBeanFactory();
        Map<String, Scope> scopes = (Map<String, Scope>) getFieldValueByObject(beanFactory, "scopes");
        RefreshScope refreshScope = (RefreshScope) scopes.get("refresh");
        refreshScope.refreshAll();

        Object eurekaClient2 = run.getBean("scopedTarget.eurekaClient");

        System.out.println(eurekaClient1 == eurekaClient);
        System.out.println(eurekaClient1 == eurekaClient2);
    }

    public static Object getFieldValueByObject(Object object, String targetFieldName) throws Exception {

        // 获取该对象的Class
        Class sonClass = object.getClass();
        Class<?> objClass = sonClass.getSuperclass().getSuperclass();

        // 初始化返回值
        Object result = null;

        // 获取所有的属性数组
        Field[] fields = objClass.getDeclaredFields();
        for (Field field : fields) {
            // 属性名称
            String currentFieldName = "";

            try {
                currentFieldName = field.getName();
                System.out.println("currentFieldName:"+currentFieldName);
                if (currentFieldName.equals(targetFieldName)) {
                    field.setAccessible(true);
                    result = field.get(object);

                    return result; // 通过反射拿到该属性在此对象中的值(也可能是个对象)
                }

            } catch (SecurityException e) {
                // 安全性异常
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // 非法参数
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // 无访问权限
                e.printStackTrace();
            }
        }

        return result;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是一个有理想的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值