Spring啟動過程中實例化部分代碼的分析之Bean的推斷構造方法
針對實例化過程中會做什么的分析,其中主要的是怎么推斷出構造方法,怎么進行匹配
【1】前言
實例化這一步便是在doCreateBean方法的 instanceWrapper = createBeanInstance(beanName, mbd, args);這段代碼中。
【2】對于實例化的疑問
對于Spring中的beanBeanDefinition,需要通過實例化得到一個bean對象才會被放入容器中,而實例化就需要用到構造方法。
分析:一個類存在多個構造方法,那么Spring進行實例化時,該如何去確定到底用哪個構造方法呢?
1. 如果開發(fā)者指定了想要使用的構造方法,那么就用這個構造方法。
2. 如果開發(fā)者沒有指定想要使用的構造方法,則看開發(fā)者有沒有讓Spring自動去選擇構造方法。
3. 如果開發(fā)者也沒有讓Spring自動去選擇構造方法,則Spring利用無參構造方法,如果沒有無參構造方法,則報錯。
開發(fā)者可以通過什么方式來指定使用哪個構造方法呢?
1.通過xml中的<constructor-arg>標簽,這個標簽表示構造方法參數(shù),所以可以根據(jù)這個確定想要使用的構造方法的參數(shù)個數(shù),從而確定想要使用的構造方法
2.通過@Autowired注解,@Autowired注解可以寫在構造方法上,所以哪個構造方法上寫了@Autowired注解,表示開發(fā)者想使用哪個構造方法,當然,它和第一個方式的不同點是,通過xml的方式,我們直接指定了構造方法的參數(shù)值,而通過@Autowired注解的方式,需要Spring通過byType+byName的方式去找到符合條件的bean作為構造方法的參數(shù)值。
3.如果Bean為注解@Lazy修飾的或者非單例的,可以通過getBean方法設置構造方法的入?yún)ⅲ_到指定構造方法的效果。如,applicationContext.getBean("BeanDemo", new CircularRefA());【同理,獲取beanDefinition,使用beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new CircularRefA());指定構造方法參數(shù)】
【3】推斷構造方法源碼分析
1.主體代碼邏輯
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
/**
* ----------0,校驗部分------------
*/
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());
}
/**
* ----------1,通過Supplier實例化部分------------
*/
// BeanDefinition中添加了Supplier,則調用Supplier來得到對象
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
/**
* ----------2,通過工廠方法實例化部分------------
*/
// @Bean對應的BeanDefinition
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
/**
* ----------3,用合適的構造函數(shù)實例化部分------------
*
* 一個類可能有多個構造器,所以Spring得根據(jù)參數(shù)個數(shù)、類型確定需要調用的構造器。
* 原型的BeanDefinition,會多次來創(chuàng)建Bean。故在使用構造器創(chuàng)建實例后,Spring會將解析過后確定下來的構造器或工廠方法保存在緩存中,避免再次創(chuàng)建相同bean時再次解析(節(jié)約時間)
*/
boolean resolved = false; //對構造器是否緩存了
boolean autowireNecessary = false; //緩存的構造器是否有參數(shù)
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
// autowireNecessary表示有沒有必要要進行注入,比如當前BeanDefinition用的是無參構造方法,那么autowireNecessary為false,否則為true,表示需要給構造方法參數(shù)注入值
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
// 如果確定了當前BeanDefinition的構造方法,那么看是否需要進行對構造方法進行參數(shù)的依賴注入(構造方法注入)
if (autowireNecessary) {
// 方法內會拿到緩存好的構造方法的入?yún)?
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 構造方法已經(jīng)找到了,但是沒有參數(shù),那就表示是無參,直接進行實例化
return instantiateBean(beanName, mbd);
}
}
//沒有緩存,從bean后置處理器中為自動裝配尋找構造方法
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 找出最合適的默認構造方法
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 構造函數(shù)自動注入
return autowireConstructor(beanName, mbd, ctors, null);
}
/**
* ----------4,使用默認構造函數(shù)構造部分------------
*/
// 不匹配以上情況,則直接使用無參構造方法
return instantiateBean(beanName, mbd);
}代碼說明
createBeanInstance() 方法是 spring 實例化 bean 的核心代碼,它根據(jù)不同的情況會調用四種實例化方法:
1)obtainFromSupplier() :通過 Supplier 實例化
2)instantiateUsingFactoryMethod():通過工廠方法實例化
3)autowireConstructor():用合適的構造函數(shù)實例化
4)instantiateBean():用無參構造函數(shù)實例化
2.局部分析代碼
1)通過Supplier實例化部分解析
代碼
// BeanDefinition中添加了Supplier,則調用Supplier來得到對象
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}說明
Spring提供的一種機制,雖然不常用,通過設置實現(xiàn)Supplier接口的類,返回一個另一種的對象,類似于FactoryBean的感覺。示例:
//在beanDefinition階段設置好
beanDefinition.setBeanClass(Student.class);
beanDefinition.setInstanceSupplier(new Supplier<Object>() {
@Override
public Object get() {
return new UserServiceImpl1();
}
});
//容器啟動后嘗試獲取驗證
applicationContext.getBean("student"); //返回new UserServiceImpl1()對象2)通過工廠方法實例化部分針(同時也是@Bean注解的處理)解析【如果存疑可以查看注解@Bean解析】
代碼塊
// @Bean對應的BeanDefinition
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}代碼深入部分:instantiateUsingFactoryMethod方法解析
protected BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
// 使用factoryBean來實例化對象
return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}
//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;
//通過beanDefinition獲取到factoryBeanName ,實際就是@Bean注解的方法所在的configuration類
String factoryBeanName = mbd.getFactoryBeanName();
//表示非靜態(tài)方法
if (factoryBeanName != null) {
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(...);
}
factoryBean = this.beanFactory.getBean(factoryBeanName);
// 該mbd已經(jīng)創(chuàng)建過了【代表這個邏輯已經(jīng)走過了】
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
factoryClass = factoryBean.getClass();
isStatic = false;
}
else {//表示靜態(tài)方法
// It's a static factory method on the bean class.
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(...);
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}
Method factoryMethodToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
//如果在調用getBean方法時有傳參,那就用傳的參作為@Bean注解的方法(工廠方法)的參數(shù), 一般懶加載的bean才會傳參,啟動過程就實例化的實際上都沒有傳參
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
//不為空表示已經(jīng)使用過工廠方法,現(xiàn)在是再次使用工廠方法, 一般原型模式和Scope模式采用的上,直接使用該工廠方法和緩存的參數(shù)
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);
}
}
// 調用getBean方法沒有傳參,同時也是第一次使用工廠方法
if (factoryMethodToUse == null || argsToUse == null) {
factoryClass = ClassUtils.getUserClass(factoryClass);
// 獲取configuration類的所有候選方法
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
List<Method> candidateList = new ArrayList<>();
for (Method candidate : rawCandidates) {
// 查找到與工廠方法同名的候選方法,即有@Bean的同名方法
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
candidateList.add(candidate);
}
}
//當與工廠方法同名的候選方法只有一個,且調用getBean方法時沒有傳參,且沒有緩存過參數(shù),直接通過調用實例化方法執(zhí)行該候選方法
if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Method uniqueCandidate = candidateList.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;
}
}
Method[] candidates = candidateList.toArray(new Method[0]);
// 有多個與工廠方法同名的候選方法時,進行排序。public的方法會往前排,然后參數(shù)個數(shù)多的方法往前排
AutowireUtils.sortFactoryMethods(candidates);
ConstructorArgumentValues resolvedValues = null;
boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Method> ambiguousFactoryMethods = null;
int minNrOfArgs;
// 如果調用getBean方法時有傳參,那么工廠方法最少參數(shù)個數(shù)要等于傳參個數(shù)
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
//如果getBean的時候沒有傳參,如果BeanDefinition中有設置,則從BeanDefinition中獲取
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) {
Class<?>[] paramTypes = candidate.getParameterTypes();
if (paramTypes.length >= minNrOfArgs) {
ArgumentsHolder argsHolder;
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);
}
//當傳入的參數(shù)為空,需要根據(jù)工廠方法的參數(shù)類型注入相應的bean
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
paramTypes, paramNames, candidate, autowiring, candidates.length == 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 和argsHolderToUse ,argsToUse ,
* 并把當前權重值設置為最小權重值,等待遍歷的下一個候選工廠方法比對,
* 并且將ambiguousFactoryMethods (表示有含糊同樣權重的候選方法)設置為空
* */
factoryMethodToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
}
/*
* 當遍歷到下一個候選方法的時候,已經(jīng)設置了factoryMethodToUse 且權重值與上一次的最小權重值相等時,
* ambiguousFactoryMethods填值,這個ambiguousFactoryMethods不為空表示有兩個候選方法的最小權重相等,
* spring無法匹配出最適合的工廠方法,如果再繼續(xù)往下遍歷候選器,有更小的權重值,
* 那ambiguousFactoryMethods會再次被設置為空
* */
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) {
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(...);
}
//返回類型不能為void
else if (void.class == factoryMethodToUse.getReturnType()) {
throw new BeanCreationException(...);
}
//存在含糊的兩個工廠方法,不知選哪個
else if (ambiguousFactoryMethods != null) {
throw new BeanCreationException(...);
}
if (explicitArgs == null && argsHolderToUse != null) {
mbd.factoryMethodToIntrospect = factoryMethodToUse;
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
}
//去實例化
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
return bw;
}
3)用合適的構造函數(shù)實例化部分解析
boolean resolved = false; //對構造器是否緩存了
boolean autowireNecessary = false; //緩存的構造器是否有參數(shù)
//判斷是否有傳參,因為getBean方法可以通過傳參指定構造方法參數(shù)類型來進行匹配(故這種對于參數(shù)的不確定是不能緩存的)
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
// autowireNecessary表示有沒有必要要進行注入,比如當前BeanDefinition用的是無參構造方法,那么autowireNecessary為false,否則為true,表示需要給構造方法參數(shù)注入值
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
// 如果確定了當前BeanDefinition的構造方法,那么看是否需要進行對構造方法進行參數(shù)的依賴注入(構造方法注入)
if (autowireNecessary) {
// 方法內會拿到緩存好的構造方法的入?yún)?
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 構造方法已經(jīng)找到了,但是沒有參數(shù),那就表示是無參,直接進行實例化
return instantiateBean(beanName, mbd);
}
}
//沒有緩存,從bean后置處理器中為自動裝配尋找構造方法
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
//存在推斷出來的構造方法集合
//BeanDefinition被設置為AUTOWIRE_CONSTRUCTOR
//BeanDefinition指定了構造方法參數(shù)值
//getBean的時候傳入了構造方法參數(shù)值
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 找出最合適的默認構造方法
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 構造函數(shù)自動注入
return autowireConstructor(beanName, mbd, ctors, null);
}代碼說明
【1】針對determineConstructorsFromBeanPostProcessors方法分析
代碼展示
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName) throws BeansException {
//如果類不為null,且存在InstantiationAwareBeanPostProcessor接口的處理器【其實用的不是它,而是他的子接口SmartInstantiationAwareBeanPostProcessor】
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
//真正存在實現(xiàn)的類是AutowiredAnnotationBeanPostProcessor類
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
}
return null;
}
//AutowiredAnnotationBeanPostProcessor類#determineCandidateConstructors方法
//日志和異常的輸出會被省略
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeanCreationException {
// 判斷是否檢測過
if (!this.lookupMethodsChecked.contains(beanName)) {
try {
// 遍歷目標類中的method,查看是否寫了@Lookup方法
ReflectionUtils.doWithMethods(beanClass, method -> {
Lookup lookup = method.getAnnotation(Lookup.class);
if (lookup != null) {
Assert.state(this.beanFactory != null, "No BeanFactory available");
// 將當前method封裝成LookupOverride并設置到BeanDefinition的methodOverrides中
LookupOverride override = new LookupOverride(method, lookup.value());
try {
RootBeanDefinition mbd = (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition(beanName);
mbd.getMethodOverrides().addOverride(override);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(beanName,"...");
}
}
});
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName, "...", ex);
}
this.lookupMethodsChecked.add(beanName);
}
//先從緩存中獲取,看之前有沒有找過
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
//緩存中沒有
if (candidateConstructors == null) {
// 加鎖,開始尋找
synchronized (this.candidateConstructorsCache) {
//再次從緩存中獲取,看被阻塞的時候沒有有線程已經(jīng)找好了存在緩存中(加鎖并雙重判斷的常規(guī)做法)
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
Constructor<?>[] rawCandidates;
try {
// 拿到所有的構造方法
rawCandidates = beanClass.getDeclaredConstructors();
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "...", ex);
}
List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
// 用來記錄required為true的構造方法,一個類中只能有一個required為true的構造方法
Constructor<?> requiredConstructor = null;
// 用來記錄默認無參的構造方法
Constructor<?> defaultConstructor = null;
// kotlin相關,不用管
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
int nonSyntheticConstructors = 0;
// 遍歷每個構造方法
for (Constructor<?> candidate : rawCandidates) {
if (!candidate.isSynthetic()) {
// 記錄一下普通的構造方法
nonSyntheticConstructors++;
}
else if (primaryConstructor != null) {
continue;
}
// 當前遍歷的構造方法是否寫了@Autowired
AnnotationAttributes ann = findAutowiredAnnotation(candidate);
//沒有@Autowired注解的情況
if (ann == null) {
// 如果beanClass是代理類,則得到被代理的類的類型
Class<?> userClass = ClassUtils.getUserClass(beanClass);
if (userClass != beanClass) {
try {
//尋找被代理的類上的構造方法有沒有@Autowired注解
Constructor<?> superCtor = userClass.getDeclaredConstructor(candidate.getParameterTypes());
ann = findAutowiredAnnotation(superCtor);
}
catch (NoSuchMethodException ex) {}
}
}
/**
* 構造方法如果有@Autowired注解,最后的操作是candidates.add(candidate),但如果出現(xiàn)兩種情況會拋出異常
* a、如果之前有遍歷過@Autowired的構造器,即requiredConstructor不為空
* b、如果當前的@Autowired的required屬性為true,不管之前遍歷過的@Autowired屬性是true還是false
*/
if (ann != null) {
// 整個類中如果有一個required為true的構造方法,那就不能有其他的加了@Autowired的構造方法
if (requiredConstructor != null) {
throw new BeanCreationException(...);
}
//獲取該方法上的@Autowired注解的required屬性
boolean required = determineRequiredStatus(ann);
if (required) {
if (!candidates.isEmpty()) {
throw new BeanCreationException(...);
}
requiredConstructor = candidate;
}
// 記錄所有加了@Autowired的構造方法,不管required是true還是false,如果默認無參的構造方法上也加了@Autowired,那么也會加到candidates中
candidates.add(candidate);
}
else if (candidate.getParameterCount() == 0) { //沒有注解且參數(shù)個數(shù)為0【即無參】
// 記錄唯一一個無參的構造方法
defaultConstructor = candidate;
}
//但是這里沒有處理:有可能存在有參、并且沒有添加@Autowired的構造方法。
}
//存儲有@Autowired注解的構造方法的集合不為空
if (!candidates.isEmpty()) {
// 如果不存在一個required為true的構造方法,則所有required為false的構造方法和無參構造方法都是合格的
if (requiredConstructor == null) {
if (defaultConstructor != null) {
//無參構造方法也添加到集合中
candidates.add(defaultConstructor);
}
else if (candidates.size() == 1 && logger.isInfoEnabled()) {
logger.info(...);
}
}
// 轉為數(shù)組
candidateConstructors = candidates.toArray(new Constructor<?>[0]);
}
// 沒有添加了@Autowired注解的構造方法,并且類中只有一個構造方法,并且是有參的
else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
}
// primaryConstructor不用管
else if (nonSyntheticConstructors == 2 && primaryConstructor != null && defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
}
// primaryConstructor不用管
else if (nonSyntheticConstructors == 1 && primaryConstructor != null) { candidateConstructors = new Constructor<?>[] {primaryConstructor};
}
else {
// 如果有多個有參、并且沒有添加@Autowired的構造方法,是會返回空的
candidateConstructors = new Constructor<?>[0];
}
//將結果存入緩存
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
}
}
}
//有候選構造器則返回,沒有返回null
return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
返回結果預測:
沒有加了@Autowired注解的構造方法
有多個構造方法 --》 返回null
只有一個有參的構造方法 --》 返回此構造方法
只有一個無參的構造方法 --》 返回null
存在加了@Autowired注解的構造方法
只有一個required為true的構造方法 --》 返回此構造方法
有多個required為true的構造方法 --》 拋異常
有一個required為true和其他的required為false的構造方法 --》 視情況而定,可能會拋異常,可能會返回帶注解的構造方法
沒有required為true的構造方法 --》 返回所有required為false的構造方法以及無參構造方法發(fā)現(xiàn)說明
1.在多個構造方法上添加@Autowired注解會發(fā)生什么?
(1)因為@Autowired注解的required屬性默認為true,而根據(jù)源碼展示,如果有一個構造方法上的@Autowired注解的required為true,那么后面的其他的構造方法不管@Autowired注解的required屬性是什么都會報錯。
(2)故如果要在多個構造方法上添加@Autowired注解,那么必須將他們的required屬性設置為false。(這種更安全)
(3)要么就是將@Autowired注解的required屬性設置為true的構造方法放到最后【僅限一個】
4)autowireConstructor方法分析
代碼展示
protected BeanWrapper autowireConstructor( String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
public ConstructorResolver(AbstractAutowireCapableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.logger = beanFactory.getLogger();
}
//ConstructorResolver類#autowireConstructor方法
//省略一些異常和日志
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
// 實例化BeanWrapper,是包裝bean的容器
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
// 如果getBean()傳入了args,那構造方法要用的入?yún)⒕椭苯哟_定好了
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
// 如果getBean()沒有傳入了參數(shù)
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
// 嘗試從緩存中獲取構造方法
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// 從緩存中找到了構造器,那么繼續(xù)從緩存中尋找緩存的構造器參數(shù)
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 緩存沒有的話,那就獲取BeanDefinition指定的那些參數(shù)【可以沒有指定】
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
//argsToResolve不為空,即之前獲取到了參數(shù)【是從BeanDefinition指定的】要解析配置的參數(shù)
if (argsToResolve != null) {
// 解析參數(shù)類型,比如將配置的String類型轉換為list、boolean等類型
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
// 如果沒有確定要使用的構造方法,或者確定了構造方法但是所要傳入的參數(shù)值沒有確定
if (constructorToUse == null || argsToUse == null) {
// 拿到傳入的構造器數(shù)組
Constructor<?>[] candidates = chosenCtors;
//數(shù)組為空
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
//使用public的構造器(默認)或者所有構造器
candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) { throw new BeanCreationException(...); }
}
// 如果只有一個候選構造方法,并且沒有指定所要使用的構造方法參數(shù)值,并且該構造方法是無參的,那就直接用這個無參構造方法進行實例化了
if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Constructor<?> uniqueCandidate = candidates[0];
if (uniqueCandidate.getParameterCount() == 0) {
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
mbd.constructorArgumentsResolved = true;
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
//需要解析構造函數(shù)標志(當構造方法數(shù)組不為空,或是自動裝配構造函數(shù)時)
boolean autowiring = (chosenCtors != null || mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
// 確定要選擇的構造方法的參數(shù)個數(shù)的最小值,后續(xù)判斷候選構造方法的參數(shù)個數(shù)如果小于minNrOfArgs,則直接pass掉
int minNrOfArgs;
if (explicitArgs != null) {
//如果直接傳了構造方法參數(shù)值,那么所用的構造方法的參數(shù)個數(shù)肯定不能少于
minNrOfArgs = explicitArgs.length;
}
else {
// 提取BeanDefinition中的配置的構造函數(shù)參數(shù)
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
// 用于承載解析后的構造函數(shù)參數(shù)的值
resolvedValues = new ConstructorArgumentValues();
// 能解析到的參數(shù)個數(shù)
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// 排序給定的構造函數(shù),public的構造函數(shù)優(yōu)先,參數(shù)數(shù)量降序
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
for (Constructor<?> candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
// 如果已經(jīng)找到選用的構造函數(shù)或者需要的參數(shù)個數(shù)小于當前的構造函數(shù)參數(shù)個數(shù)則終止,前面已經(jīng)經(jīng)過了排序操作
if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
break;
}
if (paramTypes.length < minNrOfArgs) {
// 參數(shù)個數(shù)不相等
continue;
}
ArgumentsHolder argsHolder;
// 沒有通過getBean()指定構造方法參數(shù)值
if (resolvedValues != null) {
try {
// 有參數(shù)則根據(jù)值構造對應參數(shù)類型的參數(shù)
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
// 獲取參數(shù)名稱探索器
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
// 獲取指定構造函數(shù)的參數(shù)名稱
paramNames = pnd.getParameterNames(candidate);
}
}
// 根據(jù)名稱和數(shù)據(jù)類型創(chuàng)建參數(shù)持有者
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
// 當前正在遍歷的構造方法找不到可用的入?yún)ο?,記錄一?
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
else {
// 在調getBean方法是傳入了參數(shù)值,那就表示只能用對應參數(shù)個數(shù)的構造方法
if (paramTypes.length != explicitArgs.length) {
continue;
}
// 構造函數(shù)沒有參數(shù)的情況
argsHolder = new ArgumentsHolder(explicitArgs);
}
// 當前遍歷的構造方法所需要的入?yún)ο蠖颊业搅?,根?jù)參數(shù)類型和找到的參數(shù)對象計算出來一個匹配值,值越小越匹配(Lenient表示寬松模式)
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// 值越小越匹配
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
// 值相等的情況下,記錄一下匹配值相同的構造方法
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
// 遍歷結束
// 如果沒有可用的構造方法,就取記錄的最后一個異常并拋出
if (constructorToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw new BeanCreationException(...);
}
// 如果有可用的構造方法,但是有多個
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(...);
}
if (explicitArgs == null && argsHolderToUse != null) {
// 將解析的構造函數(shù)加入緩存
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
// 將構造的實例加入BeanWrapper中
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}發(fā)現(xiàn)說明
1.autowireConstructor()大體流程
?。?)先檢查是否指定了具體的構造方法和構造方法參數(shù)值,或者在BeanDefinition中緩存了具體的構造方法或構造方法參數(shù)值,如果存在那么則直接使用該構造方法進行實例化
?。?)如果沒有確定的構造方法或構造方法參數(shù)值,那么
1)如果沒有確定的構造方法,那么則找出類中所有的構造方法
2)如果只有一個無參的構造方法,那么直接使用無參的構造方法進行實例化
3)如果有多個可用的構造方法或者當前Bean需要自動通過構造方法注入
4)根據(jù)所指定的構造方法參數(shù)值,確定所需要的最少的構造方法參數(shù)值的個數(shù)
5)對所有的構造方法進行排序,參數(shù)個數(shù)多的在前面
6)遍歷每個構造方法
7)如果不是調用getBean方法時所指定的構造方法參數(shù)值,那么則根據(jù)構造方法參數(shù)類型找值
8)如果時調用getBean方法時所指定的構造方法參數(shù)值,就直接利用這些值
9)如果根據(jù)當前構造方法找到了對應的構造方法參數(shù)值,那么這個構造方法就是可用的,但是不一定這個構造方法就是最佳的,所以這里會涉及到是否有多個構造方法匹配了同樣的值,這個時候就會用值和構造方法類型進行匹配程度的打分,找到一個最匹配的
2.為什么分越少優(yōu)先級越高?
(1)主要是計算找到的bean和構造方法參數(shù)類型匹配程度有多高。
?。?)示例:假設bean的類型為A,A的父類是B,B的父類是C,同時A實現(xiàn)了接口D 如果構造方法的參數(shù)類型為A,那么完全匹配,得分為0 如果構造方法的參數(shù)類型為B,那么得分為2 如果構造方法的參數(shù)類型為C,那么得分為4 如果構造方法的參數(shù)類型為D,那么得分為
Object[] objects = new Object[]{new A()};
// 0
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{A.class}, objects));
// 2
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{B.class}, objects));
// 4
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{C.class}, objects));
// 1
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{D.class}, objects));?。?)所以,我們可以發(fā)現(xiàn),越匹配分數(shù)越低
5)無參構造方法instantiateBean方法分析
//AbstractAutowireCapableBeanFactory類#instantiateBean方法
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged( (PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this), getAccessControlContext());
}
else {
//獲取實例化策略并且進行實例化操作
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
}
// 包裝成BeanWrapper
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
//SimpleInstantiationStrategy類#instantiate方法
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// bd對象定義中,是否包含MethodOverride列表,spring中有兩個標簽參數(shù)會產(chǎn)生MethodOverrides,分別是lookup-method,replaced-method
// 沒有MethodOverrides對象,可以直接實例化
if (!bd.hasMethodOverrides()) {
// 實例化對象的構造方法
Constructor<?> constructorToUse;
// 鎖定對象,使獲得實例化構造方法線程安全
synchronized (bd.constructorArgumentLock) {
// 查看bd對象里使用否含有構造方法
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
// 如果沒有
if (constructorToUse == null) {
// 從bd中獲取beanClass
final Class<?> clazz = bd.getBeanClass();
// 如果要實例化的beanDefinition是一個接口,則直接拋出異常
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
// 獲取系統(tǒng)安全管理器
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged((PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
// 獲取默認的無參構造器
constructorToUse = clazz.getDeclaredConstructor();
}
// 獲取到構造器之后將構造器賦值給bd中的屬性
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 通過反射生成具體的實例化對象
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// 必須生成cglib子類
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException { checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
return getConstructor0(parameterTypes, Member.DECLARED);
}
private Constructor<T> getConstructor0(Class<?>[] parameterTypes, int which) throws NoSuchMethodException {
//獲取所有的構造器
Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
//遍歷構造器,匹配的返回
for (Constructor<T> constructor : constructors) {
if (arrayContentsEq(parameterTypes,
constructor.getParameterTypes())) {
return getReflectionFactory().copyConstructor(constructor);
}
}
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
}beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new CircularRefA());
到此這篇關于Spring啟動過程中實例化部分代碼的分析之Bean的推斷構造方法的文章就介紹到這了,更多相關Spring Bean的推斷構造方法內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java過濾器與監(jiān)聽器間區(qū)別與聯(lián)系
監(jiān)聽器是一個接口內容由我們實現(xiàn),會在特定時間被調用,監(jiān)聽器用于監(jiān)聽web應用中三大域對象(request,session,application),信息的創(chuàng)建,銷毀,增加,修改,刪除等動作的發(fā)生,然后做出相應的響應處理2023-01-01
SpringBoot打印系統(tǒng)執(zhí)行的sql語句及日志配置指南
這篇文章主要給大家介紹了關于SpringBoot打印系統(tǒng)執(zhí)行的sql語句及日志配置的相關資料,在Java SpringBoot項目中如果使用了Mybatis框架,默認情況下執(zhí)行的所有SQL操作都不會打印日志,需要的朋友可以參考下2023-10-10

