Spring推断构造方法源码深度解析

news2024/10/6 1:38:28

文章目录

  • 前言
  • 思考
  • 目标
  • 一、bean的实例化入口-createBeanInstance
    • 1、源码逻辑思路**核心点,主要做了几件事情**
    • 2、instantiateBean-默认无参实例化
    • 3、instantiate-实例化
    • 4、instantiateClass-实例化类
  • 二、获取构造函数候选数组-determineConstructorsFromBeanPostProcessors
    • 1、确定构造方法的核心方法-determineCandidateConstructors
      • 主要做了几件事情
    • 2、推断构造方法简易流程图
  • 三、确定最终构造函数并实例化-autowireConstructor
    • 主要做了几件事情
  • 结论


前言

Spring中的一个bean,需要实例化得到一个对象,而实例化就需要用到构造方法。

默认是采用无参的构造方法去进行实例化,那如果一个类有多个构造方法,他是怎么选择的?

对要看源码的小伙伴说声,如果要自己去看spring源码,这一块比较绕,最好是有目标的去看,不容易迷失方向


思考

@Component
public class UserService  {
	
	// 构造方法0
    public UserService(){
        System.out.println(0);
    }

	// 构造方法1
    public UserService(OrderService orderService) {
        this.orderService = orderService;
        System.out.println(1);
    }
	// 构造方法2
    public UserService(OrderService orderService,OrderService orderService1) {
        this.orderService = orderService;
        System.out.println(2);
    }
public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService userSerivce = (UserService) context.getBean("userService");
}

上面代码

1、多个构造函数下,获取到的bean是采用的哪一个构造方法?答案是构造方法0(采用无参构造方法)

2、如果把上面的无参构造方法注释掉,这时候会采用哪一个构造方法?答案是在没有特殊处理的情况下,会报错

但是如果上面这种情况,添加了@Autowired注解,他会采用带@Autowired注解的构造方法(当然此外还有很多场景,暂不一一描述)

在这里插入图片描述

3、如果把构造方法0和构造方法1都注释掉,会采用构造方法2吗?答案是


目标

先定个小目标,本章尽量说明白上面列出的正常情况下的源码处理解析


一、bean的实例化入口-createBeanInstance

// 使用适当的实例化策略为指定的bean创建一个新实例:工厂方法、构造函数自动装配或简单实例化。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// 获取Bean定义的class
		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());
		}
    	// BeanDefinition中添加的Supplier,调用Supplier对象来得到对象
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}
		// @Bean对应的BeanDefiniton的实现
		if (mbd.getFactoryMethodName() != null) {
			// 核心方法之一
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		// 一个原型BeanDefinition,会多次创建Bean,所以会把该BeanDefiniton缓存起来使用,避免每次都进行构造方法的推断
		boolean resolved = false;
		boolean autowireNecessary = false;
		// args表示传进来的构造方法的带参的参数
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				// 缓存构造函数,只能缓存一个,在确认构造函数后缓存的
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					// autowireNecessary表示有没有必要注入,比如当前构造方法是无参的,那么autowireNecessary为空
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			// 如果确定了BeanDefintion的构造方法,那么需要判断是否需要进行有参构造方法的参数的依赖注入
			if (autowireNecessary) {
				// 方法内会拿到缓存好的构造方法入参
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				// 构造方法已经找到了,但是没有参数,就认为是无参构造方法,直接进行实例化即可
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
		// 自动装配的候选构造函数? 如果没找到,从这里开始寻找构造方法
		// 提供一个扩展点,可以利SmartInstantiationAwareBeanPostProcessor来控制beanClass中的哪些构造方法
		// 比如AutowiredAnnotationBeanPostProcessor会把加@Autowired注解的构造方法找出来,具体看代码实现会更复杂一点
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		
		// 如果推断出来了构造方法,则需要给构造方法赋值,也就是给构造方法参数赋值,也就是构造方法注入
		// 如果没有推断出来构造方法,但是autowiremode 为AUTOWIRE_CONSTRUCTOR,则也可能需要给构造方法财值,因为不确定是用无参还是有参
		// 如果通过BeanDefinition指定了构造方法参数值,那肯定就是要进行构造方法注入了
		// 如果调用getBean的时候传入了构造方法参数值,那肯定就是要进行构造方法注入了
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		// 默认是null
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		// 上面条件都不满足,使用默认无参构造函数
		return instantiateBean(beanName, mbd);
	}

1、源码逻辑思路核心点,主要做了几件事情

1、获取beanClass

2、方法带@bean的构造函数处理

3、如果args入参为空,则看有没有缓存过构造函数

4、如果有缓存过
4.1、则看有没有缓存的入参参数,有的话则执行autowireConstructor去创建bean
4.2、如果没有缓存入参,则直接执行无参构造方法

5、如果没有缓存过构造函数,则通过determineConstructorsFromBeanPostProcessors去寻找类可用的构造函数

6、如果找到了可用的构造函数,则执行autowireConstructor去创建bean

7、如果上述条件都不满则,则执行无参构造函数生成实例


2、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);
		}
	}

3、instantiate-实例化

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				// 获取构造函数的缓存
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					// 获取class
					final Class<?> clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(
									(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
						}
						else {
							// 拿到类的构造方法
							constructorToUse = clazz.getDeclaredConstructor();
						}
						// 构造方法缓存,方便原型bean的时候,直接走缓存
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			// 实例化
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// Must generate CGLIB subclass.
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

4、instantiateClass-实例化类

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			ReflectionUtils.makeAccessible(ctor);
			if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
				return KotlinDelegate.instantiateClass(ctor, args);
			}
			else {
				// 获取参数类型数组
				Class<?>[] parameterTypes = ctor.getParameterTypes();
				Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
				Object[] argsWithDefaultValues = new Object[args.length];
				// 获取入参,用于后续实例化时使用
				for (int i = 0 ; i < args.length; i++) {
					if (args[i] == null) {
						Class<?> parameterType = parameterTypes[i];
						argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
					}
					else {
						argsWithDefaultValues[i] = args[i];
					}
				}
				// 实例化结束、
				return ctor.newInstance(argsWithDefaultValues);
			}
		}
		catch (Exception ex) {
			throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
		}
	}

二、获取构造函数候选数组-determineConstructorsFromBeanPostProcessors

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
			throws BeansException {

		if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					// 只有AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors有进行实现
					Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
					if (ctors != null) {
						return ctors;
					}
				}
			}
		}
		return null;
	}

1、确定构造方法的核心方法-determineCandidateConstructors

调用地址:
AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
			throws BeanCreationException {

		// 1、从method中寻中Lookup
		if (!this.lookupMethodsChecked.contains(beanName)) {
			if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
				try {
					Class<?> targetClass = beanClass;
					do {
						ReflectionUtils.doWithLocalMethods(targetClass, method -> {
							Lookup lookup = method.getAnnotation(Lookup.class);
							if (lookup != null) {
								Assert.state(this.beanFactory != null, "No BeanFactory available");
								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,
											"Cannot apply @Lookup to beans without corresponding bean definition");
								}
							}
						});
						targetClass = targetClass.getSuperclass();
					}
					while (targetClass != null && targetClass != Object.class);

				}
				catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
				}
			}
			this.lookupMethodsChecked.add(beanName);
		}

		// 2、从候选构造缓存中,获取匹配的构造函数数组
		Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
		if (candidateConstructors == null) {
			// Fully synchronized resolution now...
			synchronized (this.candidateConstructorsCache) {
				candidateConstructors = this.candidateConstructorsCache.get(beanClass);
				if (candidateConstructors == null) {
					Constructor<?>[] rawCandidates;
					try {
						// 3、获取类下的所有构造函数
						rawCandidates = beanClass.getDeclaredConstructors();
					}
					catch (Throwable ex) {
						throw new BeanCreationException(beanName,
								"Resolution of declared constructors on bean Class [" + beanClass.getName() +
								"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
					}
					List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
					Constructor<?> requiredConstructor = null;
					Constructor<?> defaultConstructor = null;
					Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
					int nonSyntheticConstructors = 0;
					for (Constructor<?> candidate : rawCandidates) {
						if (!candidate.isSynthetic()) {
							nonSyntheticConstructors++;
						}
						else if (primaryConstructor != null) {
							continue;
						}
						// 4、遍历构造函数上面是否有@Autowired
						MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
						if (ann == null) {
							Class<?> userClass = ClassUtils.getUserClass(beanClass);
							// 正常情况是相等的, 所以不深究里面if逻辑
							if (userClass != beanClass) {
								try {
									Constructor<?> superCtor =
											userClass.getDeclaredConstructor(candidate.getParameterTypes());
									ann = findAutowiredAnnotation(superCtor);
								}
								catch (NoSuchMethodException ex) {
									// Simply proceed, no equivalent superclass constructor found...
								}
							}
						}
						// 5、有@autowreid或者@value的会进if
						if (ann != null) {
							// 循环第一次肯定为空 ,不会进,如果有多个@autowreid且required为true的则异常
							if (requiredConstructor != null) {
								throw new BeanCreationException(beanName,
										"Invalid autowire-marked constructor: " + candidate +
										". Found constructor with 'required' Autowired annotation already: " +
										requiredConstructor);
							}
							// 6、获取注解的required属性值
							boolean required = determineRequiredStatus(ann);
							// 7、缓存required的构造函数
							if (required) {
								if (!candidates.isEmpty()) {
									throw new BeanCreationException(beanName,
											"Invalid autowire-marked constructors: " + candidates +
											". Found constructor with 'required' Autowired annotation: " +
											candidate);
								}
								requiredConstructor = candidate;
							}
							candidates.add(candidate);
						}
						else if (candidate.getParameterCount() == 0) {
							defaultConstructor = candidate;
						}
					}
					
					// 8.1 、指定带@autowreid注解的构造函数
					// 8.2 、只有一个构造函数,且带参数
					// 8.3 、8.4 用不到的场景
					// 8.5 、以上都不满足,就返回空
					if (!candidates.isEmpty()) {
						// Add default constructor to list of optional constructors, as fallback.
						if (requiredConstructor == null) {
							if (defaultConstructor != null) {
								candidates.add(defaultConstructor);
							}
							else if (candidates.size() == 1 && logger.isInfoEnabled()) {
								logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
										"': single autowire-marked constructor flagged as optional - " +
										"this constructor is effectively required since there is no " +
										"default constructor to fall back to: " + candidates.get(0));
							}
						}
						candidateConstructors = candidates.toArray(new Constructor<?>[0]);
					}
					else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
						candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
					}
					else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
							defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
						candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
					}
					else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
						candidateConstructors = new Constructor<?>[] {primaryConstructor};
					}
					else {
						candidateConstructors = new Constructor<?>[0];
					}
					this.candidateConstructorsCache.put(beanClass, candidateConstructors);
				}
			}
		}
		// 多个构造函数,或者只有一个无参这里会返回null
		return (candidateConstructors.length > 0 ? candidateConstructors : null);
	}

主要做了几件事情

1、从method中寻中Lookup

2、从候选构造缓存中,获取匹配的构造函数数组

3、获取类下的所有构造函数

4、遍历构造函数上面是否有@Autowired

5、有@autowreid或者@value的会进if(主要判断是否有多个@autowreid)

6、获取注解的required属性值

7、缓存required的构造函数(用于步骤5判断处理)

8、返回构造函数数组 or null

8.1 、指定带@autowreid注解的构造函数
8.2 、只有一个构造函数,且带参数
8.3 、8.4 用不到的场景
8.5 、以上都不满足,就返回空

下面的流程图对应上面的代码


2、推断构造方法简易流程图

在这里插入图片描述


三、确定最终构造函数并实例化-autowireConstructor

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
			@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {

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

		Constructor<?> constructorToUse = null;
		ArgumentsHolder argsHolderToUse = null;
		Object[] argsToUse = null;

		// 默认进if
		if (constructorToUse == null || argsToUse == null) {
			// 获取指定的构造函数
			Constructor<?>[] candidates = chosenCtors;
			if (candidates == null) {
				Class<?> beanClass = mbd.getBeanClass();
				try {
					candidates = (mbd.isNonPublicAccessAllowed() ?
							beanClass.getDeclaredConstructors() : beanClass.getConstructors());
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Resolution of declared constructors on bean Class [" + beanClass.getName() +
							"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
				}
			}
			
			// 1、如果构造函数只有一个,并且该构造函数的入参为null,直接去实例化
			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;
				}
			}

			// 2、获取是否有指定AUTOWIRE_CONSTRUCTOR,
			boolean autowiring = (chosenCtors != null ||
					mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
			ConstructorArgumentValues resolvedValues = null;

			int minNrOfArgs;
			// 3、构造函数的入参如果不为空,则获取入参数量
			if (explicitArgs != null) {
				minNrOfArgs = explicitArgs.length;
			}
			else {
				// 4、从bean定义里获取缓存过的构造函数的入参
				ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
				resolvedValues = new ConstructorArgumentValues();
				minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
			}
			// 5、构造函数排序(降序,数量越多的最前面),用于后面找到最合适匹配度最高的构造函数
			AutowireUtils.sortConstructors(candidates);
			int minTypeDiffWeight = Integer.MAX_VALUE;
			Set<Constructor<?>> ambiguousConstructors = null;
			LinkedList<UnsatisfiedDependencyException> causes = null;
				
			// 6、开始遍历构造函数数组
			for (Constructor<?> candidate : candidates) {
				// 获取构造函数的参数数量
				int parameterCount = candidate.getParameterCount();
				
				// 7、如果是之前已经缓存过的构造函数,且传递构造函数入参也不为空,并且传递的参数大于当前构造函数的参数个数,则直接结束循环(因为没必要在循环,因为传递的参数已经大于数组里最多的参数数量了)
				if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
					// Already found greedy constructor that can be satisfied ->
					// do not look any further, there are only less greedy constructors left.
					break;
				}
				// 8、小于当前构造函数结束本次循环
				if (parameterCount < minNrOfArgs) {
					continue;
				}

				int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
						argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
				// Choose this constructor if it represents the closest match
				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(mbd.getResourceDescription(), beanName,
						"Could not resolve matching constructor " +
						"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
			}
			else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Ambiguous constructor matches found in bean '" + beanName + "' " +
						"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
						ambiguousConstructors);
			}

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

		Assert.state(argsToUse != null, "Unresolved constructor arguments");
		bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
		return bw;
	}

主要做了几件事情

1、如果构造函数只有一个,并且该构造函数的入参为null,直接去实例化

2、获取是否有指定AUTOWIRE_CONSTRUCTOR

3、构造函数的入参如果不为空,则获取入参数量

4、从bean定义里获取缓存过的构造函数的入参

5、构造函数排序(降序,数量越多的最前面),用于后面找到最合适匹配度最高的构造函数

6、开始遍历构造函数数组(选出最匹配的构造函数)

7、如果是之前已经缓存过的构造函数,且传递构造函数入参也不为空,并且传递的参数大于当前构造函数的参数个数,则直接结束循环(因为没必要在循环,因为传递的参数已经大于数组里最多的参数数量了)

8、小于当前构造函数结束本次循环

9、把遍历里拿到的构造函数进行实例化


结论

正常情况下(不添加注解等其他因素)

1、如果有无参,默认采用无参构造方法

2、如果有多个构造方法,并且也有无参构造方法,也是采用无参构造方法

3、如果没有无参构造方法,且有多个不同带参构造方法会报错

4、如果没有无参构造方法,且只有一个带参构方法,就会采用唯一构造方法

带@Autowired注解情况下

1、只有一个@Autowired的required为true的,就构造

2、多个@Autowire的required为true,报错

3、多个@Autowire的required为false,就循环遍历,找到构造函数参数最多的那个

4、如果构造函数有相同的,则进行权重打分,分越低 优先级越高

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/81123.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

这十套练习,教你如何用Pandas做数据分析(04)

练习4-Apply函数 探索1960 - 2014 美国犯罪数据 步骤1 导入必要的库 运行以下代码 import numpy as np import pandas as pd 步骤2 从以下地址导入数据集 运行以下代码 path4 ‘…/input/pandas_exercise/pandas_exercise/exercise_data/US_Crime_Rates_1960_2014.csv’…

微信小程序|入门进阶

接下来点击新建项目就可以在主界面中预览到我们的豆瓣电影示例了 小程序开发初体验 Hello world 希望是一个从零到一的转换过程~ 创建项目 接下来创建一个新的项目,理解小程序项目的基本结构和一些基础语法。 官方的开发工具为此准备了一个QuickStart项目。在创建过程中,…

利用jrebel与arthas在centos7 springboot热部署

jrebel 热部署 jrebel在本地是可以class xml一起热部署&#xff0c;但是远程热部署xml不行&#xff0c;所以用arthas代替去热部署xml 1.jrebel 反向代理 因为jrebel是收费插件&#xff0c;所以要高一些小动作咱们才能‘正常’使用&#xff0c;当然你也可以拿别人代理好的操作…

并发基础(五):ThreadPoolExecutor源码解析

尺有所短&#xff0c;寸有所长&#xff1b;不忘初心&#xff0c;方得始终。 请关注公众号&#xff1a;星河之码 在JDK提供的几种线程池技术&#xff0c;除了JDK8新加的newWorkStealingPool之外&#xff0c;其余的几种线程池都是通过ThreadPoolExecutor 来实现线程池技术&#x…

本周大新闻|FDA公布XR认证医疗名单,索尼推数字孪生平台Mapray

本周大新闻&#xff0c;AR方面&#xff0c;苹果首款MR头显或推迟至2023年下半年发布&#xff1b;FDA官网公布经过认真的AR/VR医疗方案名单&#xff1b;索尼预测AR/VR光学发展路径&#xff1b;索尼公布3D数字孪生平台Mapray&#xff1b;索尼公布ToF AR SDK。 VR方面&#xff0c…

Docker简介与安装

一、Docker 简介 1.1 为什么选择Docker? 更高效的利用系统资源更快速的启动时间一致的运行环境持续交付和部署更轻松的迁移更轻松的维护和扩展 1.2 Docker组件 1.2.1 Docker服务器与客户端 Docker是一个客户端-服务器&#xff08;cs&#xff09;架构程序。Docker客户端只…

linux下共享内存和消息队列实现多进程间数据收发

linux下进程通信的方式有很多&#xff0c;共享内存&#xff0c;消息队列&#xff0c;管道等。共享内存可以传输大量数据&#xff0c;但是多个进程同时读取共享内存就会出现脏读&#xff0c;可以借助消息队列实现多进程消息发送和接收。这种组合方式在实际开发中应用还是很多的&…

计算机网络复习(五)

考点&#xff1a;UDP 拥塞控制 TCP三次握手四次握手 P247 熟知端口号 P215 TCP报文计算5-36.假定TCP采用一种仅使用线性增大和乘法减小的简单拥塞控制算法&#xff0c;而不使用慢开始。发送窗口不采用字节为计算单位&#xff0c;而是使用分组pkt为计算单位。在一开始发送窗口为…

时序预测 | MATLAB实现VAR和GARCH时间序列预测

时序预测 | MATLAB实现VAR和GARCH时间序列预测 目录 时序预测 | MATLAB实现VAR和GARCH时间序列预测预测效果基本介绍程序设计VARGARCH参考资料预测效果 基本介绍 机器学习可其用于时间序列问题的分类和预测。在探索时间序列的机器学习方法之前,尝试统计时间序列预测方法,它列…

SQL开窗函数之percent_rank、first_value、nth的用法

开窗函数 当我们需要进行一些比较复杂的子查询时&#xff0c;聚合函数就会非常的麻烦&#xff0c;因此可以使用开窗函数进行分组再运用函数查询。窗口函数既可以显示聚集前的数据&#xff0c;也可以显示聚集后的数据&#xff0c;可以在同一行中返回基础行的列值和聚合后的结果…

微信小程序|反编译

一、下载网易模拟器 MuMu模拟器官网_安卓模拟器_网易手游模拟器 根据自己的系统选择对应的软件进行安装。 安装成功后,如下: 二、再模拟器上面安装对应的软件(微信、RE文件管理器) 1. 打开应用中心,搜索 RE文件管理器和微信,分别进行下载 2. 打开微信,输入帐号进行…

Windows 文件比较工具winmerge

今天下载了一个非常强大的文件比较工具推荐给大家。开源免费的&#xff01;&#xff01;&#xff01; 什么是WinMerge&#xff1f; WinMerge是Windows的开源差异和合并工具。WinMerge 可以比较文件夹和文件&#xff0c;以易于理解和处理的可视文本格式呈现差异。 官方下载地…

代码随想录算法训练营第六十天| LeetCode84. 柱状图中最大的矩形

一、LeetCode84. 柱状图中最大的矩形 1&#xff1a;题目描述&#xff08;84. 柱状图中最大的矩形&#xff09; 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大…

学习Typescript(第二弹)

接口 对象类型接口 先用interface定义一个List接口,成员有id时number类型&#xff0c;name是string类型再定义一个Result&#xff0c;成员是List数组定义一个render函数&#xff0c;接收参数是result // 先用interface定义一个List接口 interface List {id:number,name:strin…

安卓APP源码和设计报告——个人通讯录

摘 要 随着移动设备制造技术和移动通信网络的迅猛发展,全球手机用户日益增加,手机成为了很多人日常生活中必不可少的一部分,手机业在日益发展的同时,人们对手机的功能需求和体验需求也越来越高,因此各种智能手机相继而出&#xff0c;当前市场上最流行的智能手机的操作系统非An…

RabbitMQ--重试机制

原文网址&#xff1a;RabbitMQ--重试机制_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍RabbitMQ的重试机制。 问题描述 消费者默认是自动提交&#xff0c;如果消费时出现了RuntimException&#xff0c;会导致消息直接重新入队&#xff0c;再次投递&#xff08;进入队首&am…

【iOS】—— MVVM模式

MVVM模式 文章目录MVVM模式为什么使用MVVM&#xff1f;MVVM分别代表什么含义&#xff1f;MVVM通信关系MVVM模式的优缺点优点:缺点:概括总结MVVM文件分类为什么使用MVVM&#xff1f; iOS中&#xff0c;我们使用的大部分都是MVC架构。虽然MVC的层次明确&#xff0c;但是由于功能日…

C# 11新特性之file关键字

C#11 添加了文件作用域类型功能&#xff1a;一个新的 file 修饰符&#xff0c;可以应用于任何类型定义以限制其只能在当前文件中使用。这样&#xff0c;我们可以在一个项目中拥有多个同名的类。 目录示例file不可以与其他修饰符一起使用file可以修饰的类型file 不可修饰的类型f…

主流报表开发工具FastReport.Net全新发布,邀您体验最新版试用

FastReport .Net是一款适用于 WinForms、Blazor Server、ASP.NET、MVC、.NET 6 和 .NET Core 的报告生成工具。FastReport代表着“速度”、“可靠”和“品质”&#xff0c;是当今主流的报表开发工具。 该产品在本月进行了重大版本v2023的发布&#xff0c;接下来让我们一起看看…

【OpenCV-Python】教程:4-9 特征匹配 match

OpenCV Python 特征匹配 【目标】 特征匹配Brute-Force Matcher 和 FLANN Matcher 【理论】 Brute-Force Matcher字面意思是蛮力匹配器&#xff0c;所以它的过程也很简单&#xff0c;从一个集合里取出一个特征描述子&#xff0c;然后与第二个集合里的特征逐个的进行匹配比较…