@Configuration源码解析

1. 读前准备

读本篇文章前最好先理解ConfigurationClassPostProcessor
SpringBoot 源码解析5:ConfigurationClassPostProcessor整体流程和@ComponentScan源码分析

2. Demo

@Configuration
public class MyConfiguration {
    
    @Bean
    public MyBean configuration1() {
        return myBean();
    }
    
    @Bean
    public MyBean configuration2() {
        return myBean();
    }

    @Bean
    public MyBean myBean() {
        System.out.println("只会进入一次");
        return new MyBean();
    }

}

public class MyBean {

}

这是一个简单的demo,myBean方法只会被调用一次,源码解读以demo为例。

3. Configuration注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

	/**
	 * Explicitly specify the name of the Spring bean definition associated with the
	 * {@code @Configuration} class. If left unspecified (the common case), a bean
	 * name will be automatically generated.
	 * <p>The custom name applies only if the {@code @Configuration} class is picked
	 * up via component scanning or supplied directly to an
	 * {@link AnnotationConfigApplicationContext}. If the {@code @Configuration} class
	 * is registered as a traditional XML bean definition, the name/id of the bean
	 * element will take precedence.
	 * @return the explicit component name, if any (or empty String otherwise)
	 * @see AnnotationBeanNameGenerator
	 */
	@AliasFor(annotation = Component.class)
	String value() default "";

	/**
	 * Specify whether {@code @Bean} methods should get proxied in order to enforce
	 * bean lifecycle behavior, e.g. to return shared singleton bean instances even
	 * in case of direct {@code @Bean} method calls in user code. This feature
	 * requires method interception, implemented through a runtime-generated CGLIB
	 * subclass which comes with limitations such as the configuration class and
	 * its methods not being allowed to declare {@code final}.
	 * <p>The default is {@code true}, allowing for 'inter-bean references' within
	 * the configuration class as well as for external calls to this configuration's
	 * {@code @Bean} methods, e.g. from another configuration class. If this is not
	 * needed since each of this particular configuration's {@code @Bean} methods
	 * is self-contained and designed as a plain factory method for container use,
	 * switch this flag to {@code false} in order to avoid CGLIB subclass processing.
	 * <p>Turning off bean method interception effectively processes {@code @Bean}
	 * methods individually like when declared on non-{@code @Configuration} classes,
	 * a.k.a. "@Bean Lite Mode" (see {@link Bean @Bean's javadoc}). It is therefore
	 * behaviorally equivalent to removing the {@code @Configuration} stereotype.
	 * @since 5.2
	 */
	boolean proxyBeanMethods() default true;

}
  1. 我们可以看到,@Configuration注解由@Component标注。所以,在ComponentScan扫描器的时候,会扫描到@Configuration标注的类。
  2. value属性:就是Bean的别名。
  3. proxyBeanMethods:是否代理beanMethod。在Spring中,beanMethod指的就是由@Bean标注的方法。
  4. proxyBeanMethods = true属性的理解:为true就说明MyConfiguration 需要被代理,Spring会生成一个代理类,从而生成一个MyConfiguration 代理对象。读过AOP源码的都知道,代理的对象是会回调拦截器的。第一次会直接调用myBean()方法,获取方法的返回值,放入到缓存中;第二次调用myBean()方法的时候,会从缓存中获取,不会再次调用。这也就保证了bean的单例性。

4. ConfigurationClassPostProcessor解析Configuration注解

ConfigurationClassPostProcessor源码整体流程可阅读:SpringBoot 源码解析5:ConfigurationClassPostProcessor整体流程和@ComponentScan源码分析

4.1 设置是否需要代理的标识

Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
	beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
else if (config != null || isConfigurationCandidate(metadata)) {
	beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
	return false;
}
  1. 配置类注解的解析是在ConfigurationClassPostProcessor中完成的,在解析的流程里面调用了ConfigurationClassUtils#checkConfigurationClassCandidate方法。
    调用链:ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry → ConfigurationClassPostProcessor#processConfigBeanDefinitions → ConfigurationClassUtils#checkConfigurationClassCandidate
  2. 我们可以看看到,如果proxyBeanMethods = true,那么就会设置一个CONFIGURATION_CLASS_FULL,便于后续判断该类是否要生成一个代理对象。

4.2 解析BeanMethod

//ConfigurationClassParser#doProcessConfigurationClass方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
	configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
	AnnotationMetadata original = sourceClass.getMetadata();
	// 通过jvm的方式,获取beanMethod
	Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
	if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
		// Try reading the class file via ASM for deterministic declaration order...
		// Unfortunately, the JVM's standard reflection returns methods in arbitrary
		// order, even between different runs of the same application on the same JVM.
		// 如果存在多个BeanMethod,那么通过jvm的方法是不能保证BeanMethod的顺序的,那么就通过ASM方式
		try {
			AnnotationMetadata asm =
					this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
			Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
			if (asmMethods.size() >= beanMethods.size()) {
				Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
				for (MethodMetadata asmMethod : asmMethods) {
					for (MethodMetadata beanMethod : beanMethods) {
						if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
							selectedMethods.add(beanMethod);
							break;
						}
					}
				}
				if (selectedMethods.size() == beanMethods.size()) {
					// All reflection-detected methods found in ASM method set -> proceed
					beanMethods = selectedMethods;
				}
			}
		}
		catch (IOException ex) {
			logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
			// No worries, let's continue with the reflection metadata we started with...
		}
	}
	return beanMethods;
}
  1. ConfigurationClassParser#retrieveBeanMethodMetadata方法完成了对beanMethod的读取。
  2. 首先通过jvm的方式,获取beanMethod。jvm方法获方法是不能保证顺序的,如果有多个beanMethod,那么就通过ASM的方式获取beanMethod。

4.3 注册BeanDefinition

ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
	ConfigurationClass configClass = beanMethod.getConfigurationClass();
	MethodMetadata metadata = beanMethod.getMetadata();
	String methodName = metadata.getMethodName();

	// Do we need to mark the bean as skipped by its condition?
	if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
		configClass.skippedBeanMethods.add(methodName);
		return;
	}
	if (configClass.skippedBeanMethods.contains(methodName)) {
		return;
	}

	AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
	Assert.state(bean != null, "No @Bean annotation attributes");

	// Consider name and any aliases
	List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
	String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

	// Register aliases even when overridden
	for (String alias : names) {
		this.registry.registerAlias(beanName, alias);
	}

	// Has this effectively been overridden before (e.g. via XML)?
	if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
		if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
			throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
					beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
					"' clashes with bean name for containing configuration class; please make those names unique!");
		}
		return;
	}

	ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
	beanDef.setResource(configClass.getResource());
	beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

	if (metadata.isStatic()) {
		// static @Bean method
		if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
			beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
		}
		else {
			beanDef.setBeanClassName(configClass.getMetadata().getClassName());
		}
		beanDef.setUniqueFactoryMethodName(methodName);
	}
	else {
		// instance @Bean method
		beanDef.setFactoryBeanName(configClass.getBeanName());
		beanDef.setUniqueFactoryMethodName(methodName);
	}

	if (metadata instanceof StandardMethodMetadata) {
		beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
	}

	beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
	beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
			SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

	AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

	Autowire autowire = bean.getEnum("autowire");
	if (autowire.isAutowire()) {
		beanDef.setAutowireMode(autowire.value());
	}

	boolean autowireCandidate = bean.getBoolean("autowireCandidate");
	if (!autowireCandidate) {
		beanDef.setAutowireCandidate(false);
	}

	String initMethodName = bean.getString("initMethod");
	if (StringUtils.hasText(initMethodName)) {
		beanDef.setInitMethodName(initMethodName);
	}

	String destroyMethodName = bean.getString("destroyMethod");
	beanDef.setDestroyMethodName(destroyMethodName);

	// Consider scoping
	ScopedProxyMode proxyMode = ScopedProxyMode.NO;
	AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
	if (attributes != null) {
		beanDef.setScope(attributes.getString("value"));
		proxyMode = attributes.getEnum("proxyMode");
		if (proxyMode == ScopedProxyMode.DEFAULT) {
			proxyMode = ScopedProxyMode.NO;
		}
	}

	// Replace the original bean definition with the target one, if necessary
	BeanDefinition beanDefToRegister = beanDef;
	if (proxyMode != ScopedProxyMode.NO) {
		BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
				new BeanDefinitionHolder(beanDef, beanName), this.registry,
				proxyMode == ScopedProxyMode.TARGET_CLASS);
		beanDefToRegister = new ConfigurationClassBeanDefinition(
				(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
	}

	if (logger.isTraceEnabled()) {
		logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
				configClass.getMetadata().getClassName(), beanName));
	}
	this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

可以看到BeanDefinition中保存了两个最重要的属性factoryBeanName和factoryMethodName。
在这里插入图片描述

5. 配置类增强

Spring是先回调ConfigurationClassPostProcessor#processConfigBeanDefinitions
再回调ConfigurationClassPostProcessor#postProcessBeanFactory。

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	int factoryId = System.identityHashCode(beanFactory);
	if (this.factoriesPostProcessed.contains(factoryId)) {
		throw new IllegalStateException(
				"postProcessBeanFactory already called on this post-processor against " + beanFactory);
	}
	this.factoriesPostProcessed.add(factoryId);
	if (!this.registriesPostProcessed.contains(factoryId)) {
		// BeanDefinitionRegistryPostProcessor hook apparently not supported...
		// Simply call processConfigurationClasses lazily at this point then.
		processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
	}

	enhanceConfigurationClasses(beanFactory);
	beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

而配置类增强,就是在postProcessBeanFactory方法中完成了,调用了ConfigurationClassPostProcessor#enhanceConfigurationClasses。

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
	// 存放的是要被增强的BeanDefinition
	Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
	// 遍历所有已经注册完成的bean的名称
	for (String beanName : beanFactory.getBeanDefinitionNames()) {
		// 获取beanDefinition
		BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
		// 获取是否代理的标识
		Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
		MethodMetadata methodMetadata = null;
		if (beanDef instanceof AnnotatedBeanDefinition) {
			methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
		}
		if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
			// Configuration class (full or lite) or a configuration-derived @Bean method
			// -> resolve bean class at this point...
			// 如果beanClass属性不是class类型,那么就设置classLoader,便于加载类。
			AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
			if (!abd.hasBeanClass()) {
				try {
					abd.resolveBeanClass(this.beanClassLoader);
				}
				catch (Throwable ex) {
					throw new IllegalStateException(
							"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
				}
			}
		}
		if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
			if (!(beanDef instanceof AbstractBeanDefinition)) {
				throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
						beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
			}
			else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
				logger.info("Cannot enhance @Configuration bean definition '" + beanName +
						"' since its singleton instance has been created too early. The typical cause " +
						"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
						"return type: Consider declaring such methods as 'static'.");
			}
			configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
		}
	}
	if (configBeanDefs.isEmpty()) {
		// nothing to enhance -> return immediately
		return;
	}
	// 走到这里,就说明有BeanDefinition需要被代理
	ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
	for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
		AbstractBeanDefinition beanDef = entry.getValue();
		// If a @Configuration class gets proxied, always proxy the target class
		// 设置代理方式
		beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
		// Set enhanced subclass of the user-specified bean class
		Class<?> configClass = beanDef.getBeanClass();
		//生成代理类
		Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
		if (configClass != enhancedClass) {
			if (logger.isTraceEnabled()) {
				logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
						"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
			}
			// 将代理类方法到BeanDefinition中
			beanDef.setBeanClass(enhancedClass);
		}
	}
}
  1. 先找到所有需要被代理的BeanDefinition。
  2. 通过ConfigurationClassEnhancer对代理类进行增强,放入到BeanDefinition中的beanClass是代理类,后期实例化生成的就是代理对象。

5.1 增强拦截器

ConfigurationClassEnhancer#enhance

public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
	if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
		if (logger.isDebugEnabled()) {
			logger.debug(String.format("Ignoring request to enhance %s as it has " +
					"already been enhanced. This usually indicates that more than one " +
					"ConfigurationClassPostProcessor has been registered (e.g. via " +
					"<context:annotation-config>). This is harmless, but you may " +
					"want check your configuration and remove one CCPP if possible",
					configClass.getName()));
		}
		return configClass;
	}
	Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
	if (logger.isTraceEnabled()) {
		logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
				configClass.getName(), enhancedClass.getName()));
	}
	return enhancedClass;
}

createClass方法通过当前的类和classLoader生成代理类

private Class<?> createClass(Enhancer enhancer) {
	Class<?> subclass = enhancer.createClass();
	// Registering callbacks statically (as opposed to thread-local)
	// is critical for usage in an OSGi environment (SPR-5932)...
	Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
	return subclass;
}

可以看到设置了拦截器BeanMethodInterceptor

private static final Callback[] CALLBACKS = new Callback[] {
		new BeanMethodInterceptor(),
		new BeanFactoryAwareMethodInterceptor(),
		NoOp.INSTANCE
};

接下来,我们就来查看BeanMethodInterceptor,也是保证单例bean的重要实现逻辑。

6. ConfigurationClassEnhancer.BeanMethodInterceptor#intercept

public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
			MethodProxy cglibMethodProxy) throws Throwable {

	// 获取Bean工厂
	ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
	// 获取bean的名称
	String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);

	// Determine whether this bean is a scoped-proxy
	// 是否存在Scoped注解
	if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
		String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
		if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
			beanName = scopedBeanName;
		}
	}

	// To handle the case of an inter-bean method reference, we must explicitly check the
	// container for already cached instances.

	// First, check to see if the requested bean is a FactoryBean. If so, create a subclass
	// proxy that intercepts calls to getObject() and returns any cached bean instance.
	// This ensures that the semantics of calling a FactoryBean from within @Bean methods
	// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
	// 判断是否为FactoryBean
	if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
			factoryContainsBean(beanFactory, beanName)) {
		Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
		if (factoryBean instanceof ScopedProxyFactoryBean) {
			// Scoped proxy factory beans are a special case and should not be further proxied
		}
		else {
			// It is a candidate FactoryBean - go ahead with enhancement
			return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
		}
	}
	
	// 判断beanMethod是否是当前正在创建
	if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
		// The factory is calling the bean method in order to instantiate and register the bean
		// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
		// create the bean instance.
		if (logger.isInfoEnabled() &&
				BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
			logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
							"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
							"result in a failure to process annotations such as @Autowired, " +
							"@Resource and @PostConstruct within the method's declaring " +
							"@Configuration class. Add the 'static' modifier to this method to avoid " +
							"these container lifecycle issues; see @Bean javadoc for complete details.",
					beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
		}
		// 如果当前beanMethod为正在创建的beanMethod,那么就直接通过jvm回调我们自己写的方法
		return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
	}
	//如果beanMethod不为当前正在创建的beanMethod,那么就说明正在嵌套调用,即一个beanMethod调用另外一个BeanMethod
	return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
  1. 在Spring实例化Bean的时候,调用这个拦截器之前,会将当前的方法放入到本地线程SimpleInstantiationStrategy#currentlyInvokedFactoryMethod中。通过isCurrentlyInvokedFactoryMethod方法可以判断当前的方法是否为正在创建的beanMethod。
  2. 如果不是正在创建的BeanMethod,就说明是嵌套调用。
  3. 通过之前的阅读我们可以知道,Spring通过ASM的方式保证了方法的顺序。
    调用链:
    1. 在createBeanInstance方法实例化bean的时候,会将configuration1方法保存到SimpleInstantiationStrategy#currentlyInvokedFactoryMethod中。
    2. 由于是MyConfiguration 是被代理的,方法的回调会进入拦截器。
    3. 第①次进入拦截器的方法为configuration1,会直接通过cglibMethodProxy.invokeSuper回调我们本地的configuration1方法。
    4. configuration1方法里面,调用了myBean方法,第②次进入拦截器的是myBean方法。但是在拦截器里面并没有修改currentlyInvokedFactoryMethod属性,所以currentlyInvokedFactoryMethod中存放的还是configuration1。
    5. 通过isCurrentlyInvokedFactoryMethod方法判断myBean失败,所以会走resolveBeanReference方法。在resolveBeanReference中会通过getBean方法获取到myBean方法对应的bean,此时也会第③次进入拦截器。不同的是,在拦截器外会修改currentlyInvokedFactoryMethod属性,所以isCurrentlyInvokedFactoryMethod判断成功,调用cglibMethodProxy.invokeSuper返回myBean,但是回调完毕之后会将currentlyInvokedFactoryMethod中存放的方法改为configuration1。
    6. 上一步创建完毕之后,返回到configuration1方法也回调完成,最终configuration1的Bean也创建完成。
    7. 当configuration2创建的时候,会第④次进入此拦截器,同样的是在拦截器外部设置了currentlyInvokedFactoryMethod为configuration2。所以会通过cglibMethodProxy.invokeSuper进入到本地写好的方法。
    8. configuration2中又调用了myBean,会第⑤次进入拦截器,currentlyInvokedFactoryMethod中保存的是configuration2,所以会调用resolveBeanReference方法。此时的myBean是从单例池singletonObjects中获取的,不会重复创建。最终,configuration2调用完毕。

7. ConfigurationClassEnhancer.BeanMethodInterceptor#resolveBeanReference

上面我们提到了多次resolveBeanReference方法,它的作用就是解决beanMethod的循环引用。

private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
		ConfigurableBeanFactory beanFactory, String beanName) {

	// The user (i.e. not the factory) is requesting this bean through a call to
	// the bean method, direct or indirect. The bean may have already been marked
	// as 'in creation' in certain autowiring scenarios; if so, temporarily set
	// the in-creation status to false in order to avoid an exception.
	boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
	try {
		if (alreadyInCreation) {
			beanFactory.setCurrentlyInCreation(beanName, false);
		}
		boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
		if (useArgs && beanFactory.isSingleton(beanName)) {
			// Stubbed null arguments just for reference purposes,
			// expecting them to be autowired for regular singleton references?
			// A safe assumption since @Bean singleton arguments cannot be optional...
			for (Object arg : beanMethodArgs) {
				if (arg == null) {
					useArgs = false;
					break;
				}
			}
		}
		Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
				beanFactory.getBean(beanName));
		if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
			// Detect package-protected NullBean instance through equals(null) check
			if (beanInstance.equals(null)) {
				if (logger.isDebugEnabled()) {
					logger.debug(String.format("@Bean method %s.%s called as bean reference " +
							"for type [%s] returned null bean; resolving to null value.",
							beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
							beanMethod.getReturnType().getName()));
				}
				beanInstance = null;
			}
			else {
				String msg = String.format("@Bean method %s.%s called as bean reference " +
						"for type [%s] but overridden by non-compatible bean instance of type [%s].",
						beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
						beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
				try {
					BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
					msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Ignore - simply no detailed message then.
				}
				throw new IllegalStateException(msg);
			}
		}
		Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
		if (currentlyInvoked != null) {
			String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
			beanFactory.registerDependentBean(beanName, outerBeanName);
		}
		return beanInstance;
	}
	finally {
		if (alreadyInCreation) {
			beanFactory.setCurrentlyInCreation(beanName, true);
		}
	}
}

这个方法很简单,通过getBean的方式去获取bean。

8. 实例化BeanMethod

if (mbd.getFactoryMethodName() != null) {
	return instantiateUsingFactoryMethod(beanName, mbd, args);
}

在AbstractAutowireCapableBeanFactory#createBeanInstance中,BeanMethod的实例化是通过instantiateUsingFactoryMethod完成的。

8.1 ConstructorResolver#instantiateUsingFactoryMethod

public BeanWrapper instantiateUsingFactoryMethod(
		String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

	BeanWrapperImpl bw = new BeanWrapperImpl();
	this.beanFactory.initBeanWrapper(bw);

	Object factoryBean;
	Class<?> factoryClass;
	boolean isStatic;

	String factoryBeanName = mbd.getFactoryBeanName();
	if (factoryBeanName != null) {
		if (factoryBeanName.equals(beanName)) {
			throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
					"factory-bean reference points back to the same bean definition");
		}
		// 先创建工厂bean
		factoryBean = this.beanFactory.getBean(factoryBeanName);
		if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
			throw new ImplicitlyAppearedSingletonException();
		}
		factoryClass = factoryBean.getClass();
		isStatic = false;
	}
	else {
		// It's a static factory method on the bean class.
		if (!mbd.hasBeanClass()) {
			throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
					"bean definition declares neither a bean class nor a factory-bean reference");
		}
		factoryBean = null;
		factoryClass = mbd.getBeanClass();
		isStatic = true;
	}

	Method factoryMethodToUse = null;
	ArgumentsHolder argsHolderToUse = null;
	Object[] argsToUse = null;

	if (explicitArgs != null) {
		argsToUse = explicitArgs;
	}
	else {
		Object[] argsToResolve = null;
		synchronized (mbd.constructorArgumentLock) {
			factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
			if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
				// Found a cached factory method...
				argsToUse = mbd.resolvedConstructorArguments;
				if (argsToUse == null) {
					argsToResolve = mbd.preparedConstructorArguments;
				}
			}
		}
		if (argsToResolve != null) {
			argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
		}
	}

	if (factoryMethodToUse == null || argsToUse == null) {
		// Need to determine the factory method...
		// Try all methods with this name to see if they match the given arguments.
		// 得到代理工厂类对应的实际的工厂类
		factoryClass = ClassUtils.getUserClass(factoryClass);

		List<Method> candidates = null;
		if (mbd.isFactoryMethodUnique) {
			//获取要实例化的方法
			if (factoryMethodToUse == null) {
				factoryMethodToUse = mbd.getResolvedFactoryMethod();
			}
			if (factoryMethodToUse != null) {
				candidates = Collections.singletonList(factoryMethodToUse);
			}
		}
		if (candidates == null) {
			candidates = new ArrayList<>();
			Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
			for (Method candidate : rawCandidates) {
				if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
					candidates.add(candidate);
				}
			}
		}

		if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
			Method uniqueCandidate = candidates.get(0);
			if (uniqueCandidate.getParameterCount() == 0) {
				mbd.factoryMethodToIntrospect = uniqueCandidate;
				synchronized (mbd.constructorArgumentLock) {
					mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
					mbd.constructorArgumentsResolved = true;
					mbd.resolvedConstructorArguments = EMPTY_ARGS;
				}
				//实例化
				bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
				return bw;
			}
		}

		if (candidates.size() > 1) {  // explicitly skip immutable singletonList
			candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);
		}

		ConstructorArgumentValues resolvedValues = null;
		boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
		int minTypeDiffWeight = Integer.MAX_VALUE;
		Set<Method> ambiguousFactoryMethods = null;

		int minNrOfArgs;
		if (explicitArgs != null) {
			minNrOfArgs = explicitArgs.length;
		}
		else {
			// We don't have arguments passed in programmatically, so we need to resolve the
			// arguments specified in the constructor arguments held in the bean definition.
			if (mbd.hasConstructorArgumentValues()) {
				ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
				resolvedValues = new ConstructorArgumentValues();
				minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
			}
			else {
				minNrOfArgs = 0;
			}
		}

		LinkedList<UnsatisfiedDependencyException> causes = null;

		for (Method candidate : candidates) {

			int parameterCount = candidate.getParameterCount();
			if (parameterCount >= minNrOfArgs) {
				ArgumentsHolder argsHolder;

				Class<?>[] paramTypes = candidate.getParameterTypes();
				if (explicitArgs != null) {
					// Explicit arguments given -> arguments length must match exactly.
					if (paramTypes.length != explicitArgs.length) {
						continue;
					}
					argsHolder = new ArgumentsHolder(explicitArgs);
				}
				else {
					// Resolved constructor arguments: type conversion and/or autowiring necessary.
					try {
						String[] paramNames = null;
						ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
						if (pnd != null) {
							paramNames = pnd.getParameterNames(candidate);
						}
						argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
								paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);
					}
					catch (UnsatisfiedDependencyException ex) {
						if (logger.isTraceEnabled()) {
							logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
						}
						// Swallow and try next overloaded factory method.
						if (causes == null) {
							causes = new LinkedList<>();
						}
						causes.add(ex);
						continue;
					}
				}

				int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
						argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
				// Choose this factory method if it represents the closest match.
				if (typeDiffWeight < minTypeDiffWeight) {
					factoryMethodToUse = candidate;
					argsHolderToUse = argsHolder;
					argsToUse = argsHolder.arguments;
					minTypeDiffWeight = typeDiffWeight;
					ambiguousFactoryMethods = null;
				}
				// Find out about ambiguity: In case of the same type difference weight
				// for methods with the same number of parameters, collect such candidates
				// and eventually raise an ambiguity exception.
				// However, only perform that check in non-lenient constructor resolution mode,
				// and explicitly ignore overridden methods (with the same parameter signature).
				else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
						!mbd.isLenientConstructorResolution() &&
						paramTypes.length == factoryMethodToUse.getParameterCount() &&
						!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
					if (ambiguousFactoryMethods == null) {
						ambiguousFactoryMethods = new LinkedHashSet<>();
						ambiguousFactoryMethods.add(factoryMethodToUse);
					}
					ambiguousFactoryMethods.add(candidate);
				}
			}
		}

		if (factoryMethodToUse == null || argsToUse == null) {
			if (causes != null) {
				UnsatisfiedDependencyException ex = causes.removeLast();
				for (Exception cause : causes) {
					this.beanFactory.onSuppressedException(cause);
				}
				throw ex;
			}
			List<String> argTypes = new ArrayList<>(minNrOfArgs);
			if (explicitArgs != null) {
				for (Object arg : explicitArgs) {
					argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
				}
			}
			else if (resolvedValues != null) {
				Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
				valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
				valueHolders.addAll(resolvedValues.getGenericArgumentValues());
				for (ValueHolder value : valueHolders) {
					String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
							(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
					argTypes.add(argType);
				}
			}
			String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"No matching factory method found: " +
					(mbd.getFactoryBeanName() != null ?
						"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
					"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
					"Check that a method with the specified name " +
					(minNrOfArgs > 0 ? "and arguments " : "") +
					"exists and that it is " +
					(isStatic ? "static" : "non-static") + ".");
		}
		else if (void.class == factoryMethodToUse.getReturnType()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Invalid factory method '" + mbd.getFactoryMethodName() +
					"': needs to have a non-void return type!");
		}
		else if (ambiguousFactoryMethods != null) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Ambiguous factory method matches found in bean '" + beanName + "' " +
					"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
					ambiguousFactoryMethods);
		}

		if (explicitArgs == null && argsHolderToUse != null) {
			mbd.factoryMethodToIntrospect = factoryMethodToUse;
			argsHolderToUse.storeCache(mbd, factoryMethodToUse);
		}
	}

	bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
	return bw;
}
  1. 先实例化工厂MyConfiguration。
  2. 再调用instantiate方法调用对应的方法实例化bean。

8.2 SimpleInstantiationStrategy#instantiate

@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
		@Nullable Object factoryBean, final Method factoryMethod, Object... args) {

	try {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				ReflectionUtils.makeAccessible(factoryMethod);
				return null;
			});
		}
		else {
			ReflectionUtils.makeAccessible(factoryMethod);
		}

		Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
		try {
			currentlyInvokedFactoryMethod.set(factoryMethod);
			Object result = factoryMethod.invoke(factoryBean, args);
			if (result == null) {
				result = new NullBean();
			}
			return result;
		}
		finally {
			if (priorInvokedFactoryMethod != null) {
				currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
			}
			else {
				currentlyInvokedFactoryMethod.remove();
			}
		}
	}
	catch (IllegalArgumentException ex) {
		throw new BeanInstantiationException(factoryMethod,
				"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
				"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
	}
	catch (IllegalAccessException ex) {
		throw new BeanInstantiationException(factoryMethod,
				"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
	}
	catch (InvocationTargetException ex) {
		String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
		if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
				((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
			msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
					"declaring the factory method as static for independence from its containing instance. " + msg;
		}
		throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
	}
}
  1. 这里我们也能看到上面常常提到的currentlyInvokedFactoryMethod属性,用来保存正在调用的method。如果有嵌套的实例化method,会先试用嵌套内部的,嵌套内部使用完毕,再重新设置外部的。
  2. factoryMethod.invoke(factoryBean, args)这个方法中的factoryBean为MyConfiguration的代理对象,所以方法的回调会进入拦截器方法BeanMethodInterceptor#intercept。

读完这篇文章,我们要知道Configuration实现的真正原理。

  • 16
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值