ScopedFactoryBean 入门级解析

今天来解释一下在Bean上面加上@Scope注解会发生的事情

ScopedFactoryBean

根据@scope的注解属性,判断是否需要scoped代理

    static BeanDefinitionHolder applyScopedProxyMode(
            ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

        // 获取@scope的proxyMode属性
        ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
        // 如果此类不需要代理,默认是不需要的代理的
        if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
            return definition;
        }
        // 如果需要cglib代理
        boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
        // 返回被代理后的beanDefinition
        return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
    }

具体实现是
org.springframework.aop.scope.ScopedProxyUtils.createScopedProxy()

    public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
            BeanDefinitionRegistry registry, boolean proxyTargetClass) {

        String originalBeanName = definition.getBeanName();
        BeanDefinition targetDefinition = definition.getBeanDefinition();
        // 生成代理bean的名称,就是在前面加上"scopedTarget"前缀
        String targetBeanName = getTargetBeanName(originalBeanName);

        // Create a scoped proxy definition for the original bean name,
        // "hiding" the target bean in an internal target definition.
        // 创建一个scope级别的BeanDefinition
        RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
        proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
        proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
        proxyDefinition.setSource(definition.getSource());
        proxyDefinition.setRole(targetDefinition.getRole());

        proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
        if (proxyTargetClass) {
            targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
            // ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
            // 不需要在这里明确的设置,因为默认是true
        }
        else {
            proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
        }

        // Copy autowire settings from original bean definition.
        // 从源bean定义中拷贝自动装配的配置
        proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
        // 是否按照默认的策略进行装配
        proxyDefinition.setPrimary(targetDefinition.isPrimary());
        if (targetDefinition instanceof AbstractBeanDefinition) {
            // 拷贝qualifiers的配置
            proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
        }

        // The target bean should be ignored in favor of the scoped proxy.
        // 设置源bean在其它bean依赖于它的时候,不被作为一个候选项,因为需要放进去的是一个scoped的代理bean
        targetDefinition.setAutowireCandidate(false);
        // 当然也不按照默认的策略填充它
        targetDefinition.setPrimary(false);

        // Register the target bean as separate bean in the factory.
        // 注册源beandefine
        registry.registerBeanDefinition(targetBeanName, targetDefinition);

        // Return the scoped proxy definition as primary bean definition
        // (potentially an inner bean).
        // 现在返回替换为代理bean的holder
        return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
    }

这是BeanDefine实现完成了
在真正的实例化的时候,这个bean会返回一个特殊的代理,
为什么特殊呢,别的代理都是代理同一个bean,但是这个代理牛逼,只是存一下代理的类的信息,每一次都去beanfactory去取。
如果bean的scope是prototype,当然每一次beanfactory都会创建新的bean
如果bean是单例的,当然返回容器缓存的bean。
他是怎么是实现的呢?
在getObject()的时候,从beanfactory去取。。详细看下面源码
org.springframework.aop.scope.ScopedProxyFactoryBean

会先设置BeanFactory

    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);
        //这个这个代理Bean设置Bean的来源,很重要。这个方法决定了,
        //每次取target的时候,都会调用beanFactory.getBean,所以scope为prototype的时候,可以正确的每一次都是新的实例
        // 因为是SimpleBeanTargetSource
        pf.setTargetSource(this.scopedTargetSource);

        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.");
        }

        // 如果没有强制代理对应class,那么就是代理接口
        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 scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
        pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));


        // AopInfrastructureBean这个interface意味着这个Bean不受自动代理的影响,即便是切点匹配到了它
        pf.addInterface(AopInfrastructureBean.class);

        this.proxy = pf.getProxy(cbf.getBeanClassLoader());
    }

org.springframework.aop.scope.DefaultScopedObject

        /**
     *  就是这里 ,每一次调用被注入实例的时候都从工厂中获取
     * @return 根据scope的类型由工厂是否返回新的实例
     */
    @Override
    public Object getTargetObject() {
        return this.beanFactory.getBean(this.targetBeanName);
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值