1.写在前面
上篇博客主要Spring在创建Bean的时候,第一次调用的Bean的后置处理器的过程,同时笔者也打算将整个Spring创建的Bean的过程,通过这个系列,将Bean的创建过程给讲清楚,废话不多说,我们继续看剩下的代码。这篇博客篇幅过于长,请读者耐心的看完所有的内容。
2.Spring实例化Bean之instanceSupplier创建
我们直接看代码,具体的代码如下:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// 获取这次要创建的Bean的Class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
// 这个只有在方法注入的时候有用,先不讲
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 给BeanPostProcessors一个返回代理而不是目标bean实例的机会。这儿如果定义自定义的TargetSource会在这里处理
// 第一次调用BeanPostProcessor
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
//开始创建Bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
上面的代码前面一部分笔者已经讲了,可以看下笔者前面的一篇博客Spring源码系列(十一)Spring创建Bean的过程(一),今天,笔者继续看后面的代码,下面会调用doCreateBean(beanName, mbdToUse, args);
方法,具体的代码如下:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//先从未完成的FactoryBean的高速缓存中取出这个Bean,一般情况下为空
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//创建Bean的实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
上面的代码的篇幅过于长,所以笔者要分很多次来讲,上面的方法,走来是先从未完成的FactoryBean的高速缓存中取出这个Bean,一般情况下为空,这个时候就会调用createBeanInstance(beanName, mbd, args);
方法,具体的代码如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 获取Bean的Class,这儿获取的A.Class,因为笔者条件断点的是a
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
//获取供给型的接口,直接创建Bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
上面的代码,走来先获取Bean的Class,然后获取这个BeanDefinition
的instanceSupplier
,这是一个供给型接口,Java8才支持的特性,这儿一般的时候都是为空,只有在提供的时候,才不为空,那怎么不为空?具体的代码如下:
package com.ys.constructor;
import com.ys.beanLife.bean.A;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;
@Component
public class ABeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition a = (GenericBeanDefinition) beanFactory.getBeanDefinition("a");
a.setInstanceSupplier(A::new);
}
}
我们通过修改A的BeanDefinition
的instanceSupplier
的属性,给其中提供了创建A的方法,然后这儿上面的代码获取instanceSupplier
的属性就不为空,然后就会通过调用obtainFromSupplier(instanceSupplier, beanName);
来调用你写的lambda的表达式来创建对应的对象。笔者这儿录了GIF,大家可以参考一下,具体的如下:
3.Spring实例化Bean之FactoryMethodName创建
FactoryMethodName正常的情况下都是为空的,只有特殊的情况才不会为空,就是xml的配置的时候不为空,具体可以参考笔者的博客Spring源码系列(二)BeanDefinition(一),为了调试的方便,笔者这儿还是写了如下的代码,也就是设置factoryMethodName
和FactoryBeanName
,具体的代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="serviceLocator" class="com.ys.beanDefinition.factoryBeanOrFactoryMethod.DefaultServiceLocator"/>
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
</beans>
package com.ys.beanDefinition.factoryBeanOrFactoryMethod;
public interface ClientService {
}
package com.ys.beanDefinition.factoryBeanOrFactoryMethod;
public class ClientServiceImpl implements ClientService{
}
package com.ys.beanDefinition.factoryBeanOrFactoryMethod;
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
package com.ys.beanDefinition.factoryBeanOrFactoryMethod;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext xml = new ClassPathXmlApplicationContext("SpringFactoryBean.xml");
System.out.println(xml.getBean(ClientService.class));
}
}
上面的clientService
是通过serviceLocator
这个工厂bean中的工厂方法createClientServiceInstance
创建的,然后直接看调用的过程。具体的代码如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 获取Bean的Class,这儿获取的A.Class,因为笔者条件断点的是a
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
//获取供给型的接口,直接创建BeanWrapper
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//通过FactoryMethodName创建BeanWrapper
//通过条件断点将beanName设置成clientService,这个时候这个判断应该就不会为空,然后会调用instantiateUsingFactoryMethod(beanName, mbd, args);方法
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
上面的代码判断BeanDefinition
的factoryMethodName
的值是不是为空,这儿的判断是不为空,因为我们通过xml的方式,进行了对应设置,所以这儿会调用instantiateUsingFactoryMethod(beanName, mbd, args);
方法,具体的代码如下:
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
上面的代码是通过创建的ConstructorResolver(this)
的对象调用instantiateUsingFactoryMethod(beanName, mbd, explicitArgs)
方法,具体的代码如下:
public BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
//先创建BeanWrapper的实例
BeanWrapperImpl bw = new BeanWrapperImpl();
//初始化BeanWrapper
this.beanFactory.initBeanWrapper(bw);
//用来存FactoryBean
Object factoryBean;
//用来存FactoryBean的class对象
Class<?> factoryClass;
//是否是静态的工厂方法
boolean isStatic;
//这个时候的FactoryBeanName应该是serviceLocator,我们通过xml配置的
String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
//如果工厂beanName等与要创建的BeanName就直接报错
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
//获取对应的FactoryBean,这儿取出来的是DefaultServiceLocator
factoryBean = this.beanFactory.getBean(factoryBeanName);
//如果这个BeanDefinition是单例的同时这儿工厂已经包含了这个Bean,直接报错
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
//获取FactoryBean的class,这儿就是DefaultServiceLocator.class
factoryClass = factoryBean.getClass();
isStatic = false;
}
else {
// It's a static factory method on the bean class.
//通过静态工厂的方法创建Bean
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"bean definition declares neither a bean class nor a factory-bean reference");
}
//所以这儿的FactoryBean值为空
factoryBean = null;
//取出对应的BeanClass的class文件
factoryClass = mbd.getBeanClass();
isStatic = true;
}
//要使用的工厂方法
Method factoryMethodToUse = null;
//参数
ArgumentsHolder argsHolderToUse = null;
//使用的参数
Object[] argsToUse = null;
//一般的情况下为空,只有在调用getBean()方法的时候传入,但是这儿传进来的都是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;
//是不是唯一的工厂方法,默认的值为空,通过RootBeanDefinition中的setUniqueFactoryMethodName设置的,这儿一般都不会设置
//这个只有在加了@Bean的时候会起作用,下面的判断会进,因为spring在解析@Bean的时候,创建的RootBeanDefinition的时候,会设置这两个值。
//其他的时候都是为空的
//下面就是指定了对应的工厂方法,不需要再次从这个工厂类中找对应的方法。
if (mbd.isFactoryMethodUnique) {
if (factoryMethodToUse == null) {
factoryMethodToUse = mbd.getResolvedFactoryMethod();
}
if (factoryMethodToUse != null) {
candidates = Collections.singletonList(factoryMethodToUse);
}
}
//上面没有设置的话,这儿就是null
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);
}
}
}
//找出的工厂的方法只有一个,同时传入进来的参数也是null,然后创建这个不需要构造函数的参数
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;
}
//通过反射的方式,将这个对象创建创建出来,同时封装到BeanWrapperImpl中去。
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
//找出满足条件的方法不止一个
if (candidates.size() > 1) { // explicitly skip immutable singletonList
//进行排序,第一优先级是public,如果都是public比较参数,参数长的在前
candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);
}
//省略一部分代码,下面的代码就是推断工厂方法。
}
}
上面的代码就是进行工厂方法的查找,如果没有设置唯一的构造方法,spring会先判断是否是有FactoryBeanName,如果有就是通过非静态的方法进行创建,就会从工厂类中找出对应的工厂方法,一般只有一个,也有多个,多个的话就要进行工厂方法的推断,就是下面要讲,上面的代码只表示找到一个工厂方法,就会用这个工厂方法进行创建,这个工厂方法有一个前提就是无参的构造方法,不然下面同样要进行构造函数的推断。如果设置了唯一的构造函数,就直接从对应的变量中取出这些构造函数的值,这个设置唯一的构造函数,只有在解析@Bean注解的时候设置了。讲完了,只有一个工厂方法并且这个工厂方法的是无参的,就要继续讲不满足这个条件的其他的情况了。我们继续看剩下的代码。
3.1待创建Bean的构造函数无参
于是我们写出了如下的测试类,就是将我们的工厂类中又添加了一个工厂方法,只不过多了一个参数,并不是无参的,这个时候找出来的就是两个满足条件的工厂方法,就要进行对应的推断了。这种是创建的Bean中只有一个构造函数,同时这个构造函数是无参的。这是第一种的情况。
package com.ys.beanDefinition.factoryBeanOrFactoryMethod;
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
public ClientService createClientServiceInstance(String name) {
return clientService;
}
}
我们继续看原来的代码,我们看下排序的规则,是不是第一优先级的public,然后第二优先级是参数的长度。具体的如下图:
排序之前,就是按照你这个工厂类中定义的工厂方法的顺序。
排序之后,就是第一优先级是public,然后就是第二优先级是参数的长度
public BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
//省略一部分代码
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;
//只有设置按构造器注入这个值才不为false,@Bean注解默认的就是构造器的注入的。
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.
//判读创建这个Bean需不需要构造函数的参数,我们这儿的情况是不需要的
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) {
//获取这个方法的参数名称
//这儿获取的是name
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;
}
}
//计算差异值
//mbd.isLenientConstructorResolution() 判断是不是宽松模式,默认是宽松模式
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).
//要使用的工厂方法不为空,同时这次计算的差异值的权重等于最小的权重值,不是宽松的模式,
//上次找到工厂方法参数长度和这次找的是一样的,类型是不一样
//Spring这个时候就无法确定使用哪个构造函数
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) {
//将传入的参数的类名存进去argTypes
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());
//同时也是遍历这个参数的值,添加到argTypes
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") + ".");
}
//工厂方法的返回值为void,直接抛出异常
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;
}
虽然笔者在上面写了很详细的注释,但是读者看起来还是比较烦,直接上GIF,然后笔者对着执行的流程进行解释。
可以看到在没有提供构造函数的参数的时候,直接进了对应的else,然后最小的参数值就是0,具体的如下的代码:
if (mbd.hasConstructorArgumentValues()) {
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
else {
minNrOfArgs = 0;
}
这个参数的值会影响到下面的解析构造函数的流程,因为要遍历所有的工厂方法,如果它的方法的参数值大于等于最小的参数值,才会进行相应的操作。具体的如下:
if (parameterCount >= minNrOfArgs)
我们先不考虑在调用getBean方法的时候给定了参数,因为正常情况下,我们提供Bean,都是不会给定对应的参数的,所以暂时不考虑,但是如果给了,方法参数的长度和给定的参数的长度要必须一致。那我们直接看没有给定的情况吧。具体的代码如下:
//用来存参数的名称的
String[] paramNames = null;
//用来获取参数名称的工具类
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
//获取方法的参数的名称的数组
paramNames = pnd.getParameterNames(candidate);
}
//调用创建ArgumentsHolder的方法。这个方法比较重要,我们还是看下。
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);
上面的代码会调用到createArgumentArray(beanName, mbd, resolvedValues, bw,paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);
,具体的代码如下:
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
//用户自定义的类型转换器,默认是空的,因为用户没有定义
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
//如果是空的就使用默认的的类型装换器
TypeConverter converter = (customConverter != null ? customConverter : bw);
//创建参数的处理器对象
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
//创建对应集合,其中存的是构造函数的参数的封装
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
//遍历所有的参数类型
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
//取出类型
Class<?> paramType = paramTypes[paramIndex];
//取出参数名
String paramName = (paramNames != null ? paramNames[paramIndex] : "");
// Try to find matching constructor argument value, either indexed or generic.
// 尝试找到匹配的构造函数参数值,无论是索引的还是通用的
ConstructorArgumentValues.ValueHolder valueHolder = null;
//这个值是只有在有构造函数参数的时候才会有值,所以这儿直接跳过
if (resolvedValues != null) {
valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
// If we couldn't find a direct match and are not supposed to autowire,
// let's try the next generic, untyped argument value as fallback:
// it could match after type conversion (for example, String -> int).
if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
}
}
//这个值只有在上面解析过后才有值,这儿也是为空
if (valueHolder != null) {
// We found a potential match - let's give it a try.
// Do not consider the same value definition multiple times!
usedValueHolders.add(valueHolder);
Object originalValue = valueHolder.getValue();
Object convertedValue;
if (valueHolder.isConverted()) {
convertedValue = valueHolder.getConvertedValue();
args.preparedArguments[paramIndex] = convertedValue;
}
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
try {
convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
}
catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Could not convert argument value of type [" +
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
Object sourceHolder = valueHolder.getSource();
if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
args.resolveNecessary = true;
args.preparedArguments[paramIndex] = sourceValue;
}
}
args.arguments[paramIndex] = convertedValue;
args.rawArguments[paramIndex] = originalValue;
}
//进入这个判断,表示找不到明确的匹配项:我们应该自动装配,或者必须为给定结构创建参数数组失败
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
// No explicit match found: we're either supposed to autowire or
// have to fail creating an argument array for the given constructor.
// 不是自动装配直接抛出异常
if (!autowiring) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Ambiguous argument values for parameter of type [" + paramType.getName() +
"] - did you specify the correct bean references as arguments?");
}
try {
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = autowiredArgumentMarker;
args.resolveNecessary = true;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
}
}
}
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName +
"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
" to bean named '" + autowiredBeanName + "'");
}
}
return args;
}
由于我们第一次调用这个方法的时候传入的是有参数的工厂方法,而创建这个Bean中没有提供有参数的构造函数,同时也不是自动装配的,所以这儿直接会报错,直接返回。如果是无参的工厂方法进入了这个方法的时候,两个循环就会直接结束,不会进入这两个循环,直接返回。这个时候只不过args中三个数组的值为空,同时还有一个参数的值默认是false,具体的如下图:
那么这个类有什么用呢?别急,继续往下看,就是用来计算权重的,具体的代码如下:
//默认是宽松模式
//如果是宽松模式获取类型的权重值
//如果不是宽松模式获取分配的权重值
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);
}
我们要搞清楚,上面计算权重的方法,我们先看argsHolder.getTypeDifferenceWeight(paramTypes)
的代码,具体的代码如下:
public int getTypeDifferenceWeight(Class<?>[] paramTypes) {
// If valid arguments found, determine type difference weight.
// Try type difference weight on both the converted arguments and
// the raw arguments. If the raw weight is better, use it.
// Decrease raw weight by 1024 to prefer it over equal converted weight.
//如果找到有效的参数,请确定类型差异权重。
//在转换后的参数和原始参数上尝试使用类型差异权重。如果原始重量更好,请使用它。
//将原始重量减少1024,以使其优于相等的转换重量。
int typeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.arguments);
int rawTypeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024;
return Math.min(rawTypeDiffWeight, typeDiffWeight);
}
可以发现分别通过了两个参数的数组进行了计算,然后取出最小的那个,具体的代码如下:
public static int getTypeDifferenceWeight(Class<?>[] paramTypes, Object[] args) {
int result = 0;
//遍历所有的参数类型
for (int i = 0; i < paramTypes.length; i++) {
//判断是否是可分配的,包装类型和原始类型是可以分配,还有就是相同类型的,利用的是反射的原理
//如果是不可分配的,就直接返回int最大的值,这儿的可分配下面会说清楚
if (!ClassUtils.isAssignableValue(paramTypes[i], args[i])) {
return Integer.MAX_VALUE;
}
//如果是可分配的走下面的逻辑
//如果要填充的参数的值不为空
if (args[i] != null) {
//获取参数的class
Class<?> paramType = paramTypes[i];
//获取参数的父类的class
Class<?> superClass = args[i].getClass().getSuperclass();
//递归所有的父类
while (superClass != null) {
//如果传入进来的参数的类型等于这个父类,就在结果上加2
if (paramType.equals(superClass)) {
result = result + 2;
superClass = null;
}
//如果这个父类是传入进来的参数的子类,再给结果上加2,然后获取父类的父类
else if (ClassUtils.isAssignable(paramType, superClass)) {
result = result + 2;
superClass = superClass.getSuperclass();
}
//如果都不是,直接将父类设置为null,直接结束这个循环
else {
superClass = null;
}
}
//如果传入进来的类型是接口的话,给结果加1
if (paramType.isInterface()) {
result = result + 1;
}
}
}
return result;
}
上面提到了一个可分配的,就是isAssignableValue()
方法,那么什么是可分配的呢?先说最简单的吧,如果isAssignableValue(Integer.class,1)
返回的是true,因为原始类型可以转换成包装类型的。现在假设有一个接口I,然后A实现了I,同时B继承A,这个时候isAssignableValue(I.class,new A())
返回的是true。isAssignableValue(I.class,new B())
也是返回true,然后isAssignableValue(A.class,new B())
也是返回true,在然后如果调用的是isAssignableValue(B.class,new A())
就是返回false。简单的总结一句话,就是如果右边的参数可以转成左边的参数,就表示可分配的。
上面的方法简单的来说最小值是0,也就是如果无参的话直接是0,还有就是如果传入进来的类型和参数的类型是一样的也是0,再然后就是如果是接口加1,然后会递归它所有父类,直到找到对应的父类是等于当前传入进来的类,每次加上2,最后就是如果有一个参数的类型不满足的话,就直接返回int的最大值。所以这儿的类型越匹配,这儿返回的值就越小。这个方法搞清楚了,我们再来看看分宽松模式下调用的方法getAssignabilityWeight(paramTypes)
,具体的代码如下:
public int getAssignabilityWeight(Class<?>[] paramTypes) {
//遍历所有的类型,如果有一个参数是不可分配的话就直接返回int的最大值,这个参数是转换后的参数
for (int i = 0; i < paramTypes.length; i++) {
if (!ClassUtils.isAssignableValue(paramTypes[i], this.arguments[i])) {
return Integer.MAX_VALUE;
}
}
//遍历所有的类型,如果有一个参数是不可分配的话就直接返回int的最大值减去512,这个参数是原始的参数
for (int i = 0; i < paramTypes.length; i++) {
if (!ClassUtils.isAssignableValue(paramTypes[i], this.rawArguments[i])) {
return Integer.MAX_VALUE - 512;
}
}
//如果都满足的话,直接就int的最大值减去1024
return Integer.MAX_VALUE - 1024;
}
上面的方法比较简单,笔者就不做过多的解释,由于这儿用的无参的构造函数,然后又是宽松的模式,所有这儿会调用argsHolder.getTypeDifferenceWeight(paramTypes)
方法,最后返回的值是-1024,这个时候会调用下面的if判断,具体的代码如下:
//如果计算出来的权重值小于最小的权重值,就进行相应的赋值
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的判断只有在非宽松的模式下有用,因为非宽松的模式下,那种粗粒度的计算,很容易计算出来的权重是一样的。
最后我们再来看下剩下的代码,就是对结果进行了判断,主要是三个if,我们先看第一个if的代码,具体的代码如下:
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") + ".");
}
上面的代码看着很多,其实就要搞懂一个,就是这个判断只有在工厂方法没有找到或者要使用参数没有找到的情况,然后取出所有的参数,组装成错误信息,然后抛出去。
再来看第二个if的判断,具体的代码如下:
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!");
}
如果找到的工厂的方法的返回值是void,就直接抛出异常。因为创建对应的对象的工厂方法的返回值不可能为空。
再来看第三个if的判断,具体的代码如下:
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);
}
如果找到的有歧义的工厂不为空话,spring不知道调用哪个工厂方法进行创建对象,所以这儿就直接抛出异常。
最后调用如下的代码将这个工厂方法存起来,同时也调用的对应的方法,将这个对象给创建出来。具体的代码如下:
if (explicitArgs == null && argsHolderToUse != null) {
mbd.factoryMethodToIntrospect = factoryMethodToUse;
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
至此第一种无参的构造函数的工厂方法创建Bean的过程就讲完了。
3.2待创建Bean的构造函数有参
测试代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="factoryBean" class="com.ys.factoryMethod.Factory"/>
<bean id="product"
factory-bean="factoryBean"
factory-method="createProduct">
<constructor-arg name="name" value="苹果12Pro"/>
<constructor-arg name="price" value="9888"/>
</bean>
</beans>
package com.ys.factoryMethod;
public class Factory {
private Product createProduct() {
return new Product();
}
public Product createProduct(String name, Integer price){
return new Product(name,price);
}
public Product createProduct(Integer price){
return new Product(price);
}
public Product createProduct(String name){
return new Product(name);
}
}
package com.ys.factoryMethod;
public class Product {
private String name;
private Integer price;
public Product() {
}
public Product(String name) {
this.name = name;
}
public Product(Integer price) {
this.price = price;
}
public Product(String name, Integer price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
}
package com.ys.factoryMethod;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringFactoryMethod.xml");
System.out.println(applicationContext.getBean(Product.class).getName());
}
}
运行的结果如下:
通过上面的例子发现,我们写的代码时没有问题的,这个时候由于我们指定了对应的构造参数的值,所以这儿走的if的判断的分支就是和上面那种无参的构造函数走的分支就是不一样的了,具体的代码如下:
if (mbd.hasConstructorArgumentValues()) {
//获取构造参数的包装的对象
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
//给解析的构造参数的包装对象进行赋值
resolvedValues = new ConstructorArgumentValues();
//解析对应的构造函数的参数
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
else {
minNrOfArgs = 0;
}
这个时候由于我们待创建的bean中设置了对应的构造函数的参数,所以这个if会进上面的这个判断,上面的代码主要是解析对应的构造函数,就会调用resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
方法,具体的代码如下:
private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {
//获取用户自定义的类型转换器
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
//如果用户自定义的类型转换器为空的话,就使用默认的类型转换器
TypeConverter converter = (customConverter != null ? customConverter : bw);
//创建BeanDefinition的值的解析器
BeanDefinitionValueResolver valueResolver =
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
//这儿获取参数的长度赋值给最小的参数的值
int minNrOfArgs = cargs.getArgumentCount();
//遍历带索引的参数值,这儿这个集合应该为空
for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) {
//获取对应的索引
int index = entry.getKey();
//如果索引小于0直接抛出异常
if (index < 0) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid constructor argument index: " + index);
}
//如果索引+1大于最小的参数的值
if (index + 1 > minNrOfArgs) {
//进行赋值
minNrOfArgs = index + 1;
}
//获取参数的值
ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue();
//如果参数已经解析过了,就直接添加到解析的参数变量中去
if (valueHolder.isConverted()) {
resolvedValues.addIndexedArgumentValue(index, valueHolder);
}
else {
//获取对应的值,如果这儿进入,就会获取到的"苹果12Pro"
Object resolvedValue =
valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
//将这个获取的值包装到ConstructorArgumentValues.ValueHolder中去
ConstructorArgumentValues.ValueHolder resolvedValueHolder =
new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
//将原来的值设置到对象中去
resolvedValueHolder.setSource(valueHolder);
//将转换好的值也设置进去
resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
}
}
//遍历没有设置索引的构造参数的值
for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
//判断是否解析过了
if (valueHolder.isConverted()) {
resolvedValues.addGenericArgumentValue(valueHolder);
}
else {
//这块的逻辑和上面是一样的。
Object resolvedValue =
valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addGenericArgumentValue(resolvedValueHolder);
}
}
//最后返回最小的构造参数个数的值
return minNrOfArgs;
}
上面的方法,就是获取对应构造参数的个数然后返回,同时也会将构造参数转换好,进行对应的封装,封装后的对象如下:
这儿返回的就是2,后面的逻辑差不多,唯一的区别就在createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);
方法中,笔者跳过了一部分,在这要讲清楚。具体的代码如下:
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
//用户自定义的类型转换器,默认是空的,因为用户没有定义
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
//如果是空的就使用默认的的类型装换器
TypeConverter converter = (customConverter != null ? customConverter : bw);
//创建参数的处理器对象
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
//创建对应集合,其中存的是构造函数的参数的封装
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
//遍历所有的参数类型
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
//取出类型
Class<?> paramType = paramTypes[paramIndex];
//取出参数名
String paramName = (paramNames != null ? paramNames[paramIndex] : "");
// Try to find matching constructor argument value, either indexed or generic.
ConstructorArgumentValues.ValueHolder valueHolder = null;
if (resolvedValues != null) {
//尝试找到匹配的构造函数参数值,无论是索引的还是通用的
valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
// If we couldn't find a direct match and are not supposed to autowire,
// let's try the next generic, untyped argument value as fallback:
// it could match after type conversion (for example, String -> int).
// 如果没有找到匹配的,同时这个时候不是自动装配或者这个传进来的参数的长度等于解析的构造参数的个数的时候
//如果我们找不到直接匹配并且不应该自动装配,
//让我们尝试下一个通用的,无类型的参数值作为后备:
//在类型转换后它可以匹配(例如String-> int)。
if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
}
}
//这个值只有在上面解析过后才有值,这儿也是为空
if (valueHolder != null) {
// We found a potential match - let's give it a try.
// Do not consider the same value definition multiple times!
//我们找到了可能的值-让我们尝试一下。
//不要多次考虑相同的值定义!
usedValueHolders.add(valueHolder);
//获取对应值
Object originalValue = valueHolder.getValue();
Object convertedValue;
//下面的方法都是进行一系列的包装
if (valueHolder.isConverted()) {
convertedValue = valueHolder.getConvertedValue();
args.preparedArguments[paramIndex] = convertedValue;
}
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
try {
convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
}
catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Could not convert argument value of type [" +
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
Object sourceHolder = valueHolder.getSource();
if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
args.resolveNecessary = true;
args.preparedArguments[paramIndex] = sourceValue;
}
}
args.arguments[paramIndex] = convertedValue;
args.rawArguments[paramIndex] = originalValue;
}
//进入这个判断,表示找不到明确的匹配项:我们应该自动装配,或者必须为给定结构创建参数数组失败
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
// No explicit match found: we're either supposed to autowire or
// have to fail creating an argument array for the given constructor.
// 不是自动装配直接抛出异常
if (!autowiring) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Ambiguous argument values for parameter of type [" + paramType.getName() +
"] - did you specify the correct bean references as arguments?");
}
//这部分代码是自动装配的时候执行
try {
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = autowiredArgumentMarker;
args.resolveNecessary = true;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
}
}
}
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName +
"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
" to bean named '" + autowiredBeanName + "'");
}
}
return args;
}
上面的方法进行一系列的操作,最后包装的对象如下:
这个时候就会根据这个类和这个时候遍历出来的方法进行对应的方法权重的计算了。然后后面的逻辑就是一样的。这里就不做赘述,上面的包装的对象,也能理解计算权重的时候的两个参数了。具体的方法如下:
public int getTypeDifferenceWeight(Class<?>[] paramTypes) {
// If valid arguments found, determine type difference weight.
// Try type difference weight on both the converted arguments and
// the raw arguments. If the raw weight is better, use it.
// Decrease raw weight by 1024 to prefer it over equal converted weight.
//如果找到有效的参数,请确定类型差异权重。
//在转换后的参数和原始参数上尝试使用类型差异权重。如果原始重量更好,请使用它。
//将原始重量减少1024,以使其优于相等的转换重量。
//这个时候这个计算得到值0,都满足
int typeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.arguments);
//这个时候这个计算得到的值就是Integer.MAX_VALUE - 1024,因为第二个参数"9888"是不可分配的
int rawTypeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024;
return Math.min(rawTypeDiffWeight, typeDiffWeight);
}
可能这个时候有读者会说,你这儿真好在工厂类中提供了一个两个参数的工厂方法,而待创建的Bean真好也是两个参数,在最小参数个数的长度等于2的时候,就直接过滤了后面所有的情况,不具有代表性,于是笔者修改了Factory的代码,具体的代码如下:
package com.ys.factoryMethod;
public class Factory {
private Product createProduct() {
return new Product();
}
public Product createProduct(String name, Integer price){
return new Product(name,price);
}
public Product createProduct(Integer price){
return new Product(price);
}
public Product createProduct(String name){
return new Product(name);
}
public Product createProduct(String name, Integer price, String age) {
return new Product(name, price);
}
}
笔者加了一个三个参数的工厂方法,这个时候前面的操作都是一样,会找出这5个方法,同时参数个数最长的那个在第一位,前面的操作都是一样,唯一不同就是createArgumentArray()
方法,具体的代码如下:
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
//省略一部分代码
//遍历所有的参数类型
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
//取出类型
Class<?> paramType = paramTypes[paramIndex];
//取出参数名
String paramName = (paramNames != null ? paramNames[paramIndex] : "");
// Try to find matching constructor argument value, either indexed or generic.
ConstructorArgumentValues.ValueHolder valueHolder = null;
if (resolvedValues != null) {
//这个时候遍历到第三个参数的时候,这个valueHolder的值是为空
valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
//这个值为空,同时也不是自动装配的,于是进了下面这个判断
if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
}
}
//这个值只有在上面解析过后才有值,这儿也是为空
if (valueHolder != null) {
// We found a potential match - let's give it a try.
// Do not consider the same value definition multiple times!
//我们找到了可能的值-让我们尝试一下。
//不要多次考虑相同的值定义!
usedValueHolders.add(valueHolder);
//获取对应值
Object originalValue = valueHolder.getValue();
Object convertedValue;
//下面的方法都是进行一系列的包装
if (valueHolder.isConverted()) {
convertedValue = valueHolder.getConvertedValue();
args.preparedArguments[paramIndex] = convertedValue;
}
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
try {
convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
}
catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Could not convert argument value of type [" +
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
Object sourceHolder = valueHolder.getSource();
if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
args.resolveNecessary = true;
args.preparedArguments[paramIndex] = sourceValue;
}
}
args.arguments[paramIndex] = convertedValue;
args.rawArguments[paramIndex] = originalValue;
}
//进入这个判断,表示找不到明确的匹配项:我们应该自动装配,或者必须为给定结构创建参数数组失败
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
// No explicit match found: we're either supposed to autowire or
// have to fail creating an argument array for the given constructor.
// 不是自动装配直接抛出异常
if (!autowiring) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Ambiguous argument values for parameter of type [" + paramType.getName() +
"] - did you specify the correct bean references as arguments?");
}
//这部分代码是自动装配的时候执行
try {
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = autowiredArgumentMarker;
args.resolveNecessary = true;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
}
}
}
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName +
"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
" to bean named '" + autowiredBeanName + "'");
}
}
return args;
}
上面的遍历进行到第三个参数的时候,获取的valueHolder
的就是为null
,这个时候会对这个值调用 resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
方法,如果获取的值还是为空,就会调用后面的方法,而这个时候又不是自动装配,所以会直接抛出异常,所以关键就是在于这个方法,具体的代码如下:
// requiredType = null
// requiredName = null
// useValueHolders = 已经使用的参数
public ValueHolder getGenericArgumentValue(@Nullable Class<?> requiredType, @Nullable String requiredName,
@Nullable Set<ValueHolder> usedValueHolders) {
//遍历所有的构造函数的参数
for (ValueHolder valueHolder : this.genericArgumentValues) {
//已经使用值不等于空,同时已经解析的值中如果包含这个构造函数的参数,直接跳过
if (usedValueHolders != null && usedValueHolders.contains(valueHolder)) {
continue;
}
if (valueHolder.getName() != null && (requiredName == null ||
(!requiredName.isEmpty() && !requiredName.equals(valueHolder.getName())))) {
continue;
}
if (valueHolder.getType() != null && (requiredType == null ||
!ClassUtils.matchesTypeName(requiredType, valueHolder.getType()))) {
continue;
}
if (requiredType != null && valueHolder.getType() == null && valueHolder.getName() == null &&
!ClassUtils.isAssignableValue(requiredType, valueHolder.getValue())) {
continue;
}
return valueHolder;
}
return null;
}
从上面的代码可以看出,我们这儿直接返回的是null,因为已经解析过的构造函数的参数包含了所有的构造函数的参数,所以这儿会全部的跳过,就直接返回null,然后判断是不是自动装配,不是自动装配,就直接抛出异常了。所以这种情况也讲清楚了。
3.3@Bean的对象的创建。
至于怎么将@Bean
的注解解析成BeanDefinition
,笔者在讲Spring源码系列(九)MapperScan注解的原理(一)博客中最有有提到,感兴趣的话笔者可以去看看对应的博客,测试代码如下:
package com.ys.annotationBean;
public class A {
}
package com.ys.annotationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public A a() {
return new A();
}
}
package com.ys.annotationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
}
}
这个@Bean
的方式和前面唯一不同的就是,它是自动装配的,并且自动装配的模型是构造器注入,然后就是会设置对应的工厂的方法是唯一的,同时唯一的工厂方法是什么也是会设置的。于是下面的判断和上面就有点不一样,具体的代码如下:
//这个判断是会成立的,因为在解析@Bean的时候,这个值设置了
if (mbd.isFactoryMethodUnique) {
if (factoryMethodToUse == null) {
//获取对应的工厂方法,这儿就是a()方法
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);
}
}
}
这儿如果使用的@Bean
找到的工厂的方法,就只有一个,不会存在多个,所以后面的推断就不会执行。为了方面大家的理解,笔者录了GIF,具体的如下:
4.写在最后
笔者在这篇博客中,大概的介绍了一下工厂方法的推断,这个对后面理解工厂方法的推断有帮助。后面的博客要继续讲对象的其他方式的创建了。