深入了解Spring的@Scope注解中作用域代理proxyMode属性的实现

问题引入

代码如下:

@RestController
public class ConfigController {

    @Autowired
    private TestService testService;

    @GetMapping("/testPrototype")
    public String testPrototype() {
        System.out.println(testService);
        return testService.toString();
    }
}
@Scope("prototype")
@Component
public class TestService {
}

当我们访问/testPrototype这个接口的时候,可以发现注入的TestService实例永远都只会有一个,如下图:

也就是说TestService在ConfigController中是以单例存在的,而我们想要的TestService的多例效果则是每次请求/testPrototype这个接口的时候都能够获取到不同的TestService实例,那么怎样才能达到这种效果呢?有两种方式,一种是把TestService的作用域设置为request,另一种就是说每次在调用TestService的方法之前,都需要从spring容器中获取到一个新的TestService实例,然后调用这个新实例的方法,而这种方式就是我们这里所说的作用域代理的方式

什么是bean的作用域代理?

在说作用域代理之前,我们先来讲一下@Scope注解

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {

   @AliasFor("scopeName")
   String value() default "";

   @AliasFor("value")
   String scopeName() default "";

   ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;

}

在@scope注解中有两个属性我们需要关注,一个是value属性,该属性就是我们常说的指定的作用域,比如在spring中默认有singleton,prototype两种,springmvc中默认有request,sessioon等作用域;还有一个属性就是proxyMode属性,该属性就是是否指定作用域代理,它有4个可选的值:

public enum ScopedProxyMode {

   DEFAULT,

   NO,

   INTERFACES,

   TARGET_CLASS

}

其中DEFAULT和NO这两个值表示不使用作用域代理,INTERFACES和TARGET_CLASS都表示使用作用域代理,只不过INTERFACES表示使用JDK动态代理模式,而TARGET_CLASS表示使用cglib代理模式,那么说了这么多这个作用域代理到底有什么用呢?回到上面的问题,在ConfigController中,使用注入的TestService实例并没有办法实现多实例的效果,原因也很简单,就是因为ConfigController是单例的,它在经历spring的bean生命周期属性注入的时候就只注入了一次TestService实例,在这之后ConfigController所拥有的TestService实例就不会变了。如果需要实现多实例TestService得需要是每一次使用TestService的时候都要去spring容器获取,spring容器判断到TestService的scope是prototype的时候就会创建一个新的TestService实例给用户,那么上面的代码我们可以修改成这样:

@RestController
public class ConfigController {
    
    @Autowired
    private ApplicationContext applicationContext;

    @GetMapping("/testPrototype")
    public String testPrototype() {
        TestService testService = applicationContext.getBean(TestService.class);
        System.out.println(testService);
        return testService.toString();
    }
}

每一次都从spring容器中拿TestService实例,而TestService的作用域是多实例的,所以每一次拿到的实例都是不一样的。而使用作用域代理则不需要这么麻烦,还是保持原来的代码结构,只需要在@Scope注解上面声明开启作用域代理就行,代码如下:

@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class TestService {
}

那么作用域代理是如何实现在ConfigController这么一个单例bean中能够使用到多实例的bean呢?我们先来想想这个问题的解决思路,ConfigController这个bean在它的spring生命周期的属性注入的时候注入了TestService实例,也就是说TestService这个属性引用永远都会只指向同一个TestService实例了,这一点是无法更改的,想要更换这个引用指向不同TestService实例基本上是不可能的了,所以这时就可以考虑用代理了,也就是说ConfigController注入的是一个TestService的代理,当调用TestService的方法的时候,TestService代理会去执行目标类的方法,而这个目标类就可以由我们自己来控制了,比如实现多实例,那么就从spring容器中重新拿一遍TestService不就好了,而这也就是spring的作用域代理的实现原理,根据上面的分析总结来说其实作用域代理的出现就是为了解决一个作用域范围大的bean依赖了一个作用域范围小的bean的场景

bean的作用域代理实现原理分析

org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();

   for (String basePackage : basePackages) {
      // 完成了扫描  class文件----有选择性bd
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage);



      for (BeanDefinition candidate : candidates) {
         // 默认解析该类上面的@Scope注解,然后把@Scope注解中的属性封装到ScopeMetadata对象中
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
         candidate.setScope(scopeMetadata.getScopeName());
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         // 如果是AbstractBeanDefinition
         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);
            // 在里面会判断是否需要基于原始的bd去创建一个新的scope代理bd
            // 如果需要,那么这里返回的definitionHolder就是新的scope代理bd,反之就是原始的bd
            definitionHolder =
                  AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder);
            // 注册bd
            // 这里需要注意的是,如果上面返回的definitionHolder是一个新的scope代理bd,那么原始的bd不就没有被注册吗?
            // 答案是如果返回的definitionHolder是一个新的scope代理bd,那么原始的bd就会在applyScopedProxyMode方法中被注册
            registerBeanDefinition(definitionHolder, this.registry);
         }
      }
   }
   return beanDefinitions;
}

当spring容器启动的时候会去扫描所有的bd,然后判断每一个bd中是否有@Scope注解,如果有的话解析@scope注解中的value和proxyMode属性,并把属性值封装到一个ScopeMetadata对象中,代码如下:

public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
   ScopeMetadata metadata = new ScopeMetadata();
   if (definition instanceof AnnotatedBeanDefinition) {
      AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
      // 获取到类上面的注解属性
      AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
            annDef.getMetadata(), this.scopeAnnotationType);
      if (attributes != null) {
         // 获取注解设置的value属性
         metadata.setScopeName(attributes.getString("value"));
         // 获取注解设置的proxyMode属性
         ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
         // 如果proxyMode == DEFAUL,那么proxyMode就等于默认的代理类型
         if (proxyMode == ScopedProxyMode.DEFAULT) {
            proxyMode = this.defaultProxyMode;
         }
         metadata.setScopedProxyMode(proxyMode);
      }
   }
   return metadata;
}

获取到@scope注解的属性值之后,有一行很关键的代码,就是会去判断是否开启了作用域代理

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

   // 获取到scope代理模式
   ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
   // 条件成立:scope代理模式等于NO,直接返回
   // 默认@Scope注解中指定的scope代理模式就是NO
   if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
      return definition;
   }

   // 代码执行到这里说明scope代理模式不是NO
   boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
   // 基于原始的bd创建一个新的scope代理bd
   return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
public static BeanDefinitionHolder createScopedProxy(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {

   return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
}
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
      BeanDefinitionRegistry registry, boolean proxyTargetClass) {

   // 获取原始bd的beanName
   String originalBeanName = definition.getBeanName();
   BeanDefinition targetDefinition = definition.getBeanDefinition();
   // targetBeanName = scopedTarget.beanName
   String targetBeanName = getTargetBeanName(originalBeanName);

   // Create a scoped proxy definition for the original bean name,
   // "hiding" the target bean in an internal target definition.
   // 创建一个新的scope代理的bd对象
   RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
   // 把原始bd放到这个新创建的scope代理bd中
   proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
   proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
   proxyDefinition.setSource(definition.getSource());
   proxyDefinition.setRole(targetDefinition.getRole());

   // 设置属性注入时ScopedProxyFactoryBean类中的targetBeanName属性值为scopedTarget + 原始beanName
   proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
   // 条件成立:使用cglib对原始bd进行代理
   if (proxyTargetClass) {
      // 给原始bd设置一个使用cglib代理的标记位
      targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
   }
   else {
      proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
   }

   // 从原始bd中复制属性注入的配置,比如复制是否需要属性注入,是否是Primary注入
   proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
   proxyDefinition.setPrimary(targetDefinition.isPrimary());
   if (targetDefinition instanceof AbstractBeanDefinition) {
      proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
   }

   // 忽略原始bd,以支持scope代理
   targetDefinition.setAutowireCandidate(false);
   targetDefinition.setPrimary(false);

   // 注册原始bd
   registry.registerBeanDefinition(targetBeanName, targetDefinition);

   // 返回scope代理bd
   return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}

核心就是最后会调用createScopedProxy方法,

1.在这个方法中会去创建一个新的作用域代理bd对象,并且主要的是这个bd中的class类型是ScopedProxyFactoryBean,这个类很明显就是一个FactoryBean,下面我们再详细说这个类,

2.给ScopedProxyFactoryBean的targetBeanName属性设置 一个值,这个targetBeanName等于“scopedTarget.” + 原始bd的beanName,还会根据@scope注解中设置的proxyMode类型去设置proxyTargetClass的值,proxyTargetClass等于true的时候就使用cglib生成代理,否则就使用JDK动态代理;

3.新的作用域代理bd对象复制原始bd对象的一些属性注入的配置属性,并且复制完之后原始bd会把autowireCandidate属性和primary属性都设置为false(表示原始bd不能被其他bd进行属性注入)

4.注册原始bd到容器中

5.返回新的作用域代理bd

外层的方法拿到新的作用域代理bd之后也会把这个bd注册到容器中,也就是说此时容器中会有这个类的原始bd以及由这个类衍生出来的一个作用域代理bd

org.springframework.aop.scope.ScopedProxyFactoryBean

public class ScopedProxyFactoryBean extends ProxyConfig
      implements FactoryBean<Object>, BeanFactoryAware, AopInfrastructureBean {

   /**
    * 目标源对象
    */
   private final SimpleBeanTargetSource scopedTargetSource = new SimpleBeanTargetSource();

   /**
    * 被代理的bean的名称
    */
   @Nullable
   private String targetBeanName;

   /**
    * 当前FactoryBean创建的代理对象
    */
   @Nullable
   private Object proxy;


   /**
    * Create a new ScopedProxyFactoryBean instance.
    */
   public ScopedProxyFactoryBean() {
      setProxyTargetClass(true);
   }


   /**
    * Set the name of the bean that is to be scoped.
    */
   public void setTargetBeanName(String targetBeanName) {
      this.targetBeanName = targetBeanName;
      this.scopedTargetSource.setTargetBeanName(targetBeanName);
   }

   @Override
   public void setBeanFactory(BeanFactory beanFactory) {
      if (!(beanFactory instanceof ConfigurableBeanFactory)) {
         throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
      }
      ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;

      // 给目标源设置一个BeanFactory,因为SimpleBeanTargetSource这个目标源需要从BeanFactory中获取被代理对象
      this.scopedTargetSource.setBeanFactory(beanFactory);

      // 创建一个代理工厂
      ProxyFactory pf = new ProxyFactory();
      // 设置代理配置
      pf.copyFrom(this);
      // 设置目标源
      pf.setTargetSource(this.scopedTargetSource);

      Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");
      // 从BeanFactory中获取到被代理bean的类型
      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.");
      }

      // 使用jdk动态代理
      if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
         pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
      }

      // 创建ScopedObject实例
      ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
      // 给代理对象添加一个introduction类型的拦截器,并且把scopedObject作为introduction实现委托对象
      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);

      // 创建代理对象
      this.proxy = pf.getProxy(cbf.getBeanClassLoader());
   }


   @Override
   public Object getObject() {
      if (this.proxy == null) {
         throw new FactoryBeanNotInitializedException();
      }
      return this.proxy;
   }

   @Override
   public Class<?> getObjectType() {
      if (this.proxy != null) {
         return this.proxy.getClass();
      }
      return this.scopedTargetSource.getTargetClass();
   }

   @Override
   public boolean isSingleton() {
      return true;
   }

}

接下来我们就详细地去看ScopedProxyFactoryBean这个类,这个类继承了FactoryBean接口,所以我们主要关注它的getObject方法,在getObject方法中就直接返回了一个proxy对象,而这个proxy对象是在setBeanFactory方法中初始化的,而setBeanFactoryBean方法的调用时机在bean的生命周期中是在属性注入这个阶段之后执行的

org.springframework.aop.scope.ScopedProxyFactoryBean#setBeanFactory

public void setBeanFactory(BeanFactory beanFactory) {
   if (!(beanFactory instanceof ConfigurableBeanFactory)) {
      throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
   }
   ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;

   // 给目标源设置一个BeanFactory,因为SimpleBeanTargetSource这个目标源需要从BeanFactory中获取被代理对象
   this.scopedTargetSource.setBeanFactory(beanFactory);

   // 创建一个代理工厂
   ProxyFactory pf = new ProxyFactory();
   // 设置代理配置
   pf.copyFrom(this);
   // 设置目标源
   pf.setTargetSource(this.scopedTargetSource);

   Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");
   // 从BeanFactory中获取到被代理bean的类型
   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.");
   }

   // 使用jdk动态代理
   if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
      pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
   }

   // 创建ScopedObject实例
   ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
   // 给代理对象添加一个introduction类型的拦截器,并且把scopedObject作为introduction实现委托对象
   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);

   // 创建代理对象
   this.proxy = pf.getProxy(cbf.getBeanClassLoader());
}

(1)设置目标源

首先会创建一个ProxyFactory对象,我们知道这是一个代理工厂对象,通过这个对象的一些API就可以创建出一个代理对象,而ProxyFactory中比较重要的就是设置一个目标源,我们知道一个代理对象首先它需要有一个目标代理类,也就是它代理的对象是谁,而从目标源中就可以获取到目标代理对象。这里设置的具体目标源是SimpleBeanTargetSource,我们可以看下这个目标源有啥功能

public class SimpleBeanTargetSource extends AbstractBeanFactoryBasedTargetSource {

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

}

很简单,就是从容器中根据beanName去获取到对应的bean作为目标代理对象,也就是说每一次代理对象在调用代理方法的时候,都会从容器中拿到对应的bean作为目标代理对象去执行代理方法。而这个beanName是怎么来的呢?这个就需要回到上面生成ScopedProxyFactoryBean的beanDefinition的时候了,注意这一行代码:

proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);

在创建ScopedProxyFactory的beanDefinition的时候会直接给targetBeanName属性赋值,也就是说这个targetbeanName的值就是target + 上面说的原始beanDefinition的beanBean

public void setTargetBeanName(String targetBeanName) {
   this.targetBeanName = targetBeanName;
   this.scopedTargetSource.setTargetBeanName(targetBeanName);
}

然后在ScopedProxyFactory进行属性注入的时候就会调用到上面的setTargetBeanName方法,此时就会把targetBeanName传给了SimpleTargetSource

(2)给ProxyFactory添加一个advice

在上面设置好了目标源之后,还有一个比较重要的就是添加advice增强器了,因为是代理对象,那么肯定就是对代理目标对象进行了一定的增强,而这里添加的增强器不是普通类型的增强器,而是Introduction类型的advice。那么什么是Introduction类型的代理增强?普通的代理增强是针对方法级别的增强,而Introduction类型的代理则可以针对类的增强,举个例子就是可以指定一个Introduction委托实现类,然后生成的代理对象就会实现这个Introduction委托实现类的所有接口,所以代理对象可以调用这些接口,而接口的实现就是指定的Introduction委托实现类对应实现的接口方法,关于Introduction代理之后会详细讲这一块的实现,这里大概知道它的功能就可以了,我们看下在ScopedProxyFactory中是怎么给ProxyFactory添加Introduction类型的advice:

// 创建ScopedObject实例
ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
// 给代理对象添加一个introduction类型的拦截器,并且把scopedObject作为introduction实现委托对象
pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));

这里创建了一个DefaultScopedObject实例作为DelegatingIntroductionInterceptor的构造函数参数传了进去,先来看下DelegatingIntroductionInterceptor这个类:

public class DelegatingIntroductionInterceptor extends IntroductionInfoSupport
      implements IntroductionInterceptor {

   /**
    * 实现introduction接口的对象
    * 当代理类执行introduction接口的时候,具体调用的是该类上的实现
    */
   @Nullable
   private Object delegate;


   /**
    * 无需子类继承,直接调用该构造方法创建一个实例放到ProxyFactory中,参数代表introduction实现委托类,可以随意指定
    * @param delegate the delegate that implements the introduced interfaces
    */
   public DelegatingIntroductionInterceptor(Object delegate) {
      init(delegate);
   }

   /**
    * 如何会使用到这个构造方法:子类继承于DelegatingIntroductionInterceptor,在创建子类的同时就会调用该构造方法,也就是说子类就会成为introduction实现委托类
    */
   protected DelegatingIntroductionInterceptor() {
      init(this);
   }

   private void init(Object delegate) {
      Assert.notNull(delegate, "Delegate must not be null");
      this.delegate = delegate;
      // 初始化introduction接口
      implementInterfacesOnObject(delegate);

      // We don't want to expose the control interface
      suppressInterface(IntroductionInterceptor.class);
      suppressInterface(DynamicIntroductionAdvice.class);
   }

   @Override
   @Nullable
   public Object invoke(MethodInvocation mi) throws Throwable {
      // 条件成立:要执行的方法属于introduction接口方法
      if (isMethodOnIntroducedInterface(mi)) {
         // 执行introduction实现委托类的方法
         Object retVal = AopUtils.invokeJoinpointUsingReflection(this.delegate, mi.getMethod(), mi.getArguments());

         // Massage return value if possible: if the delegate returned itself,
         // we really want to return the proxy.
         if (retVal == this.delegate && mi instanceof ProxyMethodInvocation) {
            Object proxy = ((ProxyMethodInvocation) mi).getProxy();
            if (mi.getMethod().getReturnType().isInstance(proxy)) {
               retVal = proxy;
            }
         }
         // 直接返回,不进行后续拦截器的链式调用
         return retVal;
      }

      // 不是introduction接口方法继续执行拦截器的链式调用
      return doProceed(mi);
   }
   
   protected Object doProceed(MethodInvocation mi) throws Throwable {
      // If we get here, just pass the invocation on.
      return mi.proceed();
   }

}

这个类实现了IntroductionInterceptor接口,所以它是一个Introduction类型的增强器。在它的带参构造方法中,参数就表示Introduction委托实现,并且在调用构造方法的时候会调用init方法,在init方法中主要做的就是获取到Introduction委托实现的所有接口,目的就是当代理对象调用代理方法的时候能够去判断该方法是否是一个introduction接口方法,如果是的话就会去调用Introduction委托实现对应的接口方法,如果不是就继续拦截器的链式调用。所以可以知道通过@Scope注解作用域生成的代理对象,可以强转成ScopedObject,然后就可以调用ScopedObject接口下的方法了,对应的实现就是调用DefaultScopedObject,比如我们可以这样使用:

// testService是通过作用域代理产生的代理对象
ScopedObject scopedObject = (ScopedObject) testService;
System.out.println(scopedObject.getTargetObject());

当执行scopedObject.getTargetObject()这行代码的时候会发生什么呢?根据上面说的就会调用到对应的Introduction委托实现的getTargetObject方法,这个Introduction委托实现就是DefaultScopedObject,所以来看下DefaultScopedObject中的实现做了什么:

public class DefaultScopedObject implements ScopedObject, Serializable {

   private final ConfigurableBeanFactory beanFactory;

   private final String targetBeanName;

   public DefaultScopedObject(ConfigurableBeanFactory beanFactory, String targetBeanName) {
      Assert.notNull(beanFactory, "BeanFactory must not be null");
      Assert.hasText(targetBeanName, "'targetBeanName' must not be empty");
      this.beanFactory = beanFactory;
      this.targetBeanName = targetBeanName;
   }


   @Override
   public Object getTargetObject() {
      return this.beanFactory.getBean(this.targetBeanName);
   }

   @Override
   public void removeFromScope() {
      this.beanFactory.destroyScopedBean(this.targetBeanName);
   }

}

可以看到如果我们把代理对象强转成ScopedObject类型,那么当调用getTargetObject方法的时候就能够调用到DefaultScopedObject的getTargetObject方法,通过这个方法就能够获取到原始bean,也就是目标代理对象

总结

当存在一个bean依赖另一个bean,并且被依赖的那个bean的作用域范围是小于依赖它的那个bean的作用域范围的时候,如果被依赖的bean不使用作用域代理的方式,那么被依赖的这个bean的生命周期就会变成与依赖它的那个bean的生命周期一致(具体参考上面单例bean依赖多实例bean的例子),而要想被依赖的这个bean继续拥有自己声明的生命周期,那么spring就提供了作用域代理这一种方式去解决这种问题。作用域代理的实现方式就是对标注了@Scope注解并且开启了proxyMode属性的bean在生成它的BeanDefinition的时候进行拦截,拦截的时候会生成一个新的BeanDefinition,但是这个新的BeanDefinition里面的class是ScopedProxyFactory,这个ScopedProxyFactory就会生成一个代理对象,当这个代理对象去调用代理方法的时候,就会从容器中拿到原始bean作为目标代理对象,也就是说每一次调用被依赖的bean的方法的时候就会从容器中获取一次对应最新的原始bean,这样就可以保证了被依赖的bean自己的生命周期不会受到依赖它的bean所影响了

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值