ScopedProxyMode

ScopedProxyMode

首先查看下 @Scope 注解的定义信息,其共有三个方法,分别为 value、scopeName、proxyMode,其中 value 和 scopeName 利用了 Spring 的显性覆盖,这两个方法的作用是一样的,只不过 scopeName 要比 value 更具有语义性。重点是 proxyMode 方法,其默认值为 ScopedProxyMode.DEFAULT。

@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;

}

ScopedProxyMode 是一个枚举类,该类共定义了四个枚举值,分别为 NO、DEFAULT、INTERFACE、TARGET_CLASS,其中 DEFAULT 和 NO 的作用是一样的。INTERFACES 代表要使用 JDK 的动态代理来创建代理对象,TARGET_CLASS 代表要使用 CGLIB 来创建代理对象。

public enum ScopedProxyMode {
	DEFAULT,
	NO,
	INTERFACES,
	TARGET_CLASS
}

首先我们通过代码案例来看来不同取值的差异:

public class MyBean {
    @Autowired
    private ScopeProxyBean proxyBean;

    public void test(){
        proxyBean.code();
    }

}

@Scope(value = DefaultListableBeanFactory.SCOPE_PROTOTYPE/*,proxyMode = ScopedProxyMode.TARGET_CLASS*/)
public class ScopeProxyBean {

    public void code() {
        System.out.println(this.hashCode());

    }
}

// 测试用例
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestSpring.class)
public class TestSpring {
    Logger logger = LoggerFactory.getLogger(getClass());

    @Test
    public void test1() throws UnknownHostException {
       AnnotationConfigApplicationContext applicationContext =
        new AnnotationConfigApplicationContext();
        applicationContext.register(MyBean.class);
        applicationContext.register(ScopeProxyBean.class);
        applicationContext.refresh();
        MyBean bean = applicationContext.getBean(MyBean.class);
        for (int i = 0; i < 10; i++) {
            bean.test(); // 这里生成的所有 Bean 的 hashCode 都是一致的
        }
    }
}

下面调整 @Scope 注解中的 proxyMode 属性为 ScopedProxyMode.TARGET_CLASS,能看到会得到不同的 hashCode 的值。

源码解析

在 ClassPathBeanDefinitionScanner 的 doScan 方法中,对于 findCandidateComponents 方法返回值进行遍历时,会首先调用 ScopeMetadataResolver 的 resolveScopeMetadata 方法,传入 BeanDefinition 对象。该方法会返回一个 ScopeMetadata 对象,然后将该对象设置到 BeanDefinition 中去,通过 BeanDefinition 的 setScope 方法。接下来便是通过 BeanNameGenerator 的 generatedBeanName 方法来生成 BeanName,判断 BeanDefinition 对象(以下简称为 candidate)是否是 AbstractBeanDefinition,如果判断成立,则调用 postProcessBeanDefinition 方法(该方法主要用来设置 BeanDefinition 的一些默认值),判断 candidate 是否是 AnnotatedBeanDefinition,如果判断成立则调用 AnnotationConfigUtils 的 processCommonDefinitionAn-notations 方法(通过方法名也可以看出,该方法主要用来解析一些通用的注解)。

调用 checkCandidate 方法,如果该方法返回值为 true(该方法用来判断当前(注意,不是层级查找)IoC 容器中是否指定 BeanName 的 BeanDefinition 信息,如果包含,则进行兼容性比对)。创建 BeanDefinitionHolder 实例,然后调用 AnnotationConfigUtils 的 applyScopedProxyMode 方法来根据前面解析好的 ScopeMetadata 对象来处理 BeanDefinitionHolder,注意这里传了 BeanDefinitionRegistry 实例,最后调用 registerBeanDefinition 方法将 AnnotationConfigUtils 的 applyScopedProxyMode 方法返回值注册到 BeanDefinition 到 IoC 容器中。

private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
// 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) {
			// 根据指定包路径扫描Bean资源并加载
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				// 使用AnnotationScopeMetadataResolver的resolveScopeMeatdata方法来根据Bean中@Scope(如果有)注解创建ScopeMeatdata对象
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				// 调用AnnotationBeanNameGenerator的generatorBeanName方法生成beanName
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				// 如果BeanDefinition是AbstractBeanDefinition类型的,设置BeanDefinition的默认值
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				// 如果BeanDefinition是AnnotatedBeanDefinition类型,解析通用注解
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				// 如果BeanDefinition可以兼容
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					// 解析Bean中的@Scope注解
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

首先分析下 ScopeMetadataResolver 这个接口。该接口存在两个实现类,分别为 AnnotationScopeM-etadataResolver 和 Jsr330ScopeMetadataResolver。AnnotationScopeMetadataResolver 用来处理 Spring 的@Scope 注解,而 Jsr330ScopeMetadataResolver 则用来处理 Jsr-330 规范中提出的@Scope 注解。ClassPathBeanDefinitionScanner 默认使用的是 AnnotationScopeMetadataResolver。

在 AnnotationScopeMetadataResolver 的 resolveScopeMetadata 方法中,首先创建 ScopeMetadata 实例,然后判断传入的 BeanDefinition 是否是 AnnotatedBeanDefinition 类型的。这里需要说明下通过 Cl-assPathBeanDefinitionScanner 扫描的类信息并创建的 BeanDefinition 都是 ScannedGenericBeanDefin-ition 类型的,该类型实现了 AnnotatedBeanDefinition 接口,因此这里的判断成立。

判断成立后首先将 BeanDefinition 强制转型为 AnnotatedBeanDefinition,调用 AnnotationConfigUtils 的 attributesFor 方法,传入从注解元数据(AnnotationMetadata)以及@Scope 注解的类型,返回 AnnotationAttributes 对象(以下简称 attributes),如果返回的对象不为空,则设置 ScopeMetadata 的 scopeName(通过调用 atributes 的 getString 方法),调用 attributes 的 getEnum 方法来获取@Scope 注解中 proxyMode 方法的返回值,如果返回的 proxyMode 等等于 ScopeProxyMode 的 DEFAULT,则将 proxyMode 重置为 ScopedProxyMode.NO(这也是前面讲到的 DEFAULT 和 NO 的作用是一样的),将 proxyMode 设置到 metadata 中。

最后返回设置好的 metadata。

public AnnotationScopeMetadataResolver() {
		this.defaultProxyMode = ScopedProxyMode.NO;
}
// AnnotationScopeMetadataResolver#resolveScopeMetadata
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) {
         metadata.setScopeName(attributes.getString("value"));
         ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
         if (proxyMode == ScopedProxyMode.DEFAULT) {
            proxyMode = this.defaultProxyMode;
         }
         metadata.setScopedProxyMode(proxyMode);
      }
   }
   return metadata;
}

在 AnnotationConfigUtils 的 applyScopedProxyMode 方法中,通过传入的 ScopeMetadata 实例的 getScopedProxyMode 方法来获取 ScopedProxyMode,如果获取到的 ScopedProxyMode 等于 ScopedProxyMode.NO,则直接原样返回。接下来则是判断获取到的 scopedProxyMode 是否等于 ScopedProxyMode.TARGET_CLASS,并将比较结果赋值给 proxyTargetClass,调用 ScopedProxyCreator 的 createScopeProxy 方法。

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

   ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
   if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
      return definition;
   }
   boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
   return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}

在 ScopedProxyCreator 的 createScopedProxy 方法中直接委派给 ScopedProxyUtils 的 createdScopedProxy 方法实现。

// ScopedProxyCreator#createScopedProxy
public static BeanDefinitionHolder createScopedProxy(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {

   return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
}

在 ScopedProxyUtils 的 createScopedProxy 方法中,调用传入的 BeanDefinitionHolder 的 getBeanName 方法获取 beanName 并赋值给 originalBeanName,调用传入的 BeanDefinitionHolder 的 getBeanDefinition 方法来获取 BeanDefinition 并赋值给 targetBeanDefinition 变量,调用 getTargetBeanName 方法来处理 originalBeanName 并赋值给 targetBeanName 变量(该方法的处理逻辑就是在传入的 beanName 前拼接上“scopedTarget.”)。

重点是接下来创建的 RootBeanDefinition-proxyDefinition,传入的 beanClass 为 ScopedProxyFactoryBean 的 Class,根据 targetBeanDefinition 以及 targetBeanName 来创建 BeanDefinitionHolder 并设置到 proxyDefinition 的 decoratedDefinition 属性中,设置 targetDefinition 到 proxyDefinition 的 originatingBeanDefinition 属性中,获取 proxyDefinition 的属性元数据(getPropertyValues 方法),将其 targetBea-nName 的属性值设置为 targetBeanName。设置将 targetBeanDefinition 的 autowireCandidate 以及 primary 设置为 false(设置这两个属性的意义在后面会分析到)。

通过调用传入的 BeanDefinitionRegistry 的 registerBeanDefinition 方法,来注册 targetDefinition,需重点关注的是,在注册 targetDefinition 时,传递的 beanName 为 targetBeanName(即拼接上“scopedTarget.”前缀的 beanName)。最后创建 BeanDefinitionHolder,指定的 beanName 却为 originalBeanName(即未拼接上“scopedTarget.”前缀的 beanName)。返回该实例。

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

   String originalBeanName = definition.getBeanName();
   BeanDefinition targetDefinition = definition.getBeanDefinition();
   String targetBeanName = getTargetBeanName(originalBeanName);

   // Create a scoped proxy definition for the original bean name,
   // "hiding" the target bean in an internal target definition.
   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.
   } else {
      proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
   }

   // Copy autowire settings from original bean definition.
   proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
   proxyDefinition.setPrimary(targetDefinition.isPrimary());
   if (targetDefinition instanceof AbstractBeanDefinition) {
      proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
   }

   // The target bean should be ignored in favor of the scoped proxy.
   targetDefinition.setAutowireCandidate(false);
   targetDefinition.setPrimary(false);

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

   // Return the scoped proxy definition as primary bean definition
   // (potentially an inner bean).
   return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}

private static final String TARGET_NAME_PREFIX = "scopedTarget.";

public static String getTargetBeanName(String originalBeanName) {
		return TARGET_NAME_PREFIX + originalBeanName;
}

把目光回到调用入口处-ClassPathBeanDefinitionScanner 的 doScan 方法中,在该方法的最后将 Annot-ationConfigUtils 的 applyScopedProxyMode 方法返回的 BeanDefinitionHolder 注册到 BeanDefinitionRegistry 中。这意味着如果某个 Bean 添加了@Scope 注解,并且将 proxyMode 设置为非 DEFAULT、NO 时,IoC 容器中将会存在该 Bean 的两个实例,一个名为“scopedTarget.beanName”其对应的是真正的 Bean 实例,另一个为“beanName”其对应的是 ScopedProxyFactoryBean 创建出来的目标 Bean 的代理对象。

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
		AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);

代码验证

使用启动类来进行 @Scope 的 proxyMode 属性测试。

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ScopedBeanDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(ScopedBeanDemo.class);
        context.refresh();
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        Stream.of(beanDefinitionNames)
                .forEach(
                        beanName -> {
                            Class<?> beanType = context.getType(beanName);
                            System.out.printf("beanName : %s -----> beanType:%s \n",beanName,beanType.getName());
                        });
    }
}

可以发现,IoC 容器中的确存在 ScopedBeanDemo 的两个 BeanDefinition 数据,一个 beanName 为“scopedTarget.scopedBeanName”,另一个为“scopeBeanDemo”。如上面的分析结果,IoC 容器中存在两个相同类型的 Bean,那么当我们通过 BeanFactory 的 getBean(Class)方法来查找时,是会抛出异常呢?还是正常返回呢?如果正常返回,那么该返回那个呢?

import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;

import java.beans.Introspector;
import java.lang.reflect.Field;

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ScopedBeanDemo {

    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(ScopedBeanDemo.class);
        context.refresh();
        // 根据 ScopedBeanDemo 类型来查找
        ScopedBeanDemo byType = context.getBean(ScopedBeanDemo.class);
        // 根据 ScopedBeanDemo 在IoC容器中的BeanName来进行查找 -> 其底层也是通过 Java Beans 中的
        // Introspector#decapitalize方法来生成BeanName
        ScopedBeanDemo byName =
                (ScopedBeanDemo) context.getBean(Introspector.decapitalize("ScopedBeanDemo"));
        // 在 ScopedBeanDemo 在IoC容器中的BeanName 前面拼接上 ScopedProxyUtils#TARGET_NAME_PREFIX 字段的值
        Field field = ScopedProxyUtils.class.getDeclaredField("TARGET_NAME_PREFIX");
        field.setAccessible(true);
        Object value = field.get(null);
        ScopedBeanDemo byScopedName =
                (ScopedBeanDemo)
                        context.getBean(value + Introspector.decapitalize("ScopedBeanDemo"));
        System.out.println("根据ScopedBeanDemo类型查找到的:" + byType.getClass());
        System.out.println("根据ScopedBeanDemo名称查找到的:" + byName.getClass());
        System.out.println("根据scopedTarget.ScopedBeanDemo名称查找到的:" + byScopedName.getClass());
        // 关闭Spring 应用上下文
        context.close();
    }
}

可以发现无论是根据类型还是根据 beanName 来进行 IoC 容器返回的始终是是代理后的对象。只有按其拼接的规则来拼接 beanName 后(在 beanName 前拼接上“scopedTarget.”前缀),再使用 BeanFactory 的 getBean(String)方法来查找才会返回原始对象。按照 beanName 来进行查找,IoC 容器会返回代理对象,这点可以理解,因为在 ScopedProxyUtils 的 createScopedProxy 方法偷梁换柱,将原始的 beanName 对应的 BeanDefinition 替换为代理 BeanDefinition,所以查找根据原始 beanName 查找出来的 bean 为代理 Bean 就不奇怪了,那么为什么根据类型来查找返回的依然是代理 Bean 呢?

这里先说下结论:是因为前面在 ScopedProxyUtils 的 createScopedProxy 方法中将原始的 BeanDefinit-ion(targetDefinition)的 autowireCandidate 设置为 false 导致的。

// The target bean should be ignored in favor of the scoped proxy.
targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);

下面我们来分析下 BeanFactory 的 getBean(Class)方法。AsbtractApplicationContext 实现了该方法,在该方法中首先来对 BeanFactory 实现类实例的存活状态进行校验。之后就是调用 BeanFactory 实现类实例的 getBean 方法,传入要获取的 Class。

// AbstractApplicationContext#getBean(java.lang.Class<T>)
public <T> T getBean(Class<T> requiredType) throws BeansException {
   assertBeanFactoryActive();
   return getBeanFactory().getBean(requiredType);
}

在 DefaultListableBeanFactory 实现的 getBean 方法中,调用 resolveBean 方法来根据类型获取,如果该方法的返回值为 null,抛出 NoSuchBeanDefinitionException 异常。可以看出的是 resolveBean 方法并不会主动抛出异常,而是 getBean 方法抛出的异常,这一点很重要,因为包括 BeanFactory 提供的安全查找 Bean 的 getBeanProvider 方法底层也是基于该方法进行实现,这里就不再展开分析了。

// DefaultListableBeanFactory#getBean(java.lang.Class<T>, java.lang.Object...)
public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
   Assert.notNull(requiredType, "Required type must not be null");
   Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
   if (resolved == null) {
      throw new NoSuchBeanDefinitionException(requiredType);
   }
   return (T) resolved;
}

在 resolveBean 方法中,调用 resolveNamedBean 方法来进行查找,如果该方法返回值不为 null,则直接返回,否则获取当前 IoC 容器的父容器(如果有),层层查找。

// DefaultListableBeanFactory#resolveBean
private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
   NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
   if (namedBean != null) {
      return namedBean.getBeanInstance();
   }
   BeanFactory parent = getParentBeanFactory();
   if (parent instanceof DefaultListableBeanFactory) {
      return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
   }
   else if (parent != null) {
      ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
      if (args != null) {
         return parentProvider.getObject(args);
      }
      else {
         return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
      }
   }
   return null;
}

在 resolveNamedBean 方法中,首先根据 getNamesForType 方法来获取指定类型的所有 beanName,该方法的返回值是一个数组。结合前面的代码可以得出这里获取到的 candidateNames 有两个,分别为:scopedTarget.scopedBeanDemo 和 scopedBeanDemo。

因此会进入第一个判断即 candidateNames 的长度大于 1,遍历 candidateNames 集合,对于遍历到的每一个 beanName,通过 containsBeanDefinition 方法来判断当前 IoC 容器中是否包含指定 beanName 的 BeanDefinition 数据(注意这里是对结果进行取反,因此判断失败),第二个判断是根据 beanName 获取到对应的 BeanDefinition 实例后,然后调用其 isAutowireCandidate 方法,注意前面我们已经分析过在 ScopedProxyUtils 的 createScopedProxy 方法将 targetDefinition 的 autowireCandidate 属性设置为 false,因此真正的 BeanDefinition 是不会被作为候选的 BeanDefinition,反而是代理 BeanDefinition 会作为候选的 BeanDefinition。

next,判断 candidateNames 数组的长度是否等等于 1,如果判断成立,则调用 getBean 方法来根据 beanName 获取,并将方法返回结果构建为 NamedBeanHolder 返回。

// DefaultListableBeanFactory#resolveNamedBean
private <T> NamedBeanHolder<T> resolveNamedBean(
      ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {

   Assert.notNull(requiredType, "Required type must not be null");
	// getBean(ScopedBeanDemo.class) -> candidateNames 中存在两个beanName,分别为
	// “scopedTarget.scopedBeanDemo”以及“scopedBeanDemo”。
   String[] candidateNames = getBeanNamesForType(requiredType);

   if (candidateNames.length > 1) {
      List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
      for (String beanName : candidateNames) {
				// 由于真正的ScopedBeanDemo的BeanDefinition的autowireCandidate属性被设置为false,
				// 因此这里被保存到autowireCandidates集合中的是代理Bean的BeanDefinition
         if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
            autowireCandidates.add(beanName);
         }
      }
      if (!autowireCandidates.isEmpty()) {
         candidateNames = StringUtils.toStringArray(autowireCandidates);
      }
   }
		// 如果candidateNames的长度为1,通过getBean方法来触发初始化或者从缓存中获取并构建为
		// NamedBeanHolder 对象返回。
   if (candidateNames.length == 1) {
      String beanName = candidateNames[0];
      return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
   } else if (candidateNames.length > 1) {
      Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
      for (String beanName : candidateNames) {
         if (containsSingleton(beanName) && args == null) {
            Object beanInstance = getBean(beanName);
            candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
         } else {
            candidates.put(beanName, getType(beanName));
         }
      }
      String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
      if (candidateName == null) {
         candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
      }
      if (candidateName != null) {
         Object beanInstance = candidates.get(candidateName);
         if (beanInstance == null || beanInstance instanceof Class) {
            beanInstance = getBean(candidateName, requiredType.toClass(), args);
         }
         return new NamedBeanHolder<>(candidateName, (T) beanInstance);
      }
      if (!nonUniqueAsNull) {
         throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
      }
   }

   return null;
}

总结

@Scope 注解中的 proxyMode 方法值指示了 IoC 容器要不要为 Bean 创建代理,如何创建代理,是使用 JDK 的动态代理还是使用 CGLIB?我们通过源码也了解到 ScopedProxyMode 的 DEFAULT 和 NO 作用是一样的,如果配置为 INTERFACES 或 TARGET_CLASS,在 ScopedProxyUtils 的 createScopedProxy 方法中将会为目标 Bean 创建一个 ScopedProxyFactoryBean 的 BeanDefinition,并使用目标 Bean 的 beanName 来注册这个 BeanDefinition,将目标 Bean 的 beanName 拼接上“ScopedTarget.”前缀来注册目标 Bean 的 BeanDefinition。

同时将目标 BeanDefinition 的 autowireCandidate 属性设置为 false,以此来确保 IoC 容器在查找该类型的单个 Bean 时(getBean 方法)不会返回原始 Bean 实例,而是返回经过代理后的 Bean 实例。

上一页
下一页