【spring源碼系列】之【Bean的實例化】


人生需要探索的熱情、堅持的勇氣以及熱愛生活熱愛自己的力量。

1. Bean的實例化

上一篇講述了bean的生命周期,其中第一步就涉及到了bean的實例化,本文重點分析bean實例化,先進入源碼中的AbstractAutowireCapableBeanFactory類中的createBeanInstance方法。

2. 流程概覽

上述圖描述了bean的實例化過程中的主要步驟:

  1. 如果存在 Supplier 回調,則調用 obtainFromSupplier() 進行初始化;
  2. 如果存在工廠方法,則使用工廠方法進行初始化;
  3. 如果構造函數參數不為空,則先獲取autowired注解的構造函數,再獲取構造函數里面的參數,參數是引用類型的話,再次循環調用容器去獲取,最后通過反射完成實例化;
  4. 如果構造函數無參,則使用默認無參構造函數實例化;
  5. 最后將bean添加到一級緩存,並清除二級三級緩存里的bean。

3. 源碼分析

3.1 createBeanInstance概覽

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		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());
		}

		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		// 使用Supplier接口獲取
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		// 使用FactoryMethod方法實例化
		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?
		// 構造函數有參autowired修飾
		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);
}

3.1 使用Supplier接口

Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		// 使用Supplier接口獲取
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

進入obtainFromSupplier方法

protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
		Object instance;

		String outerBean = this.currentlyCreatedBean.get();
		this.currentlyCreatedBean.set(beanName);
		try {
                        // 從instanceSupplier獲取
			instance = instanceSupplier.get();
		}
		finally {
			if (outerBean != null) {
				this.currentlyCreatedBean.set(outerBean);
			}
			else {
				this.currentlyCreatedBean.remove();
			}
		}

		if (instance == null) {
			instance = new NullBean();
		}
                // 包裝成BeanWrapper
		BeanWrapper bw = new BeanWrapperImpl(instance);
                // 初始化BeanWrapper
		initBeanWrapper(bw);
		return bw;
	}

上述源碼顯示從從instanceSupplier獲取,而instanceSupplier是一個函數式接口:

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

那在何時對該instanceSupplier進行設值的呢?不妨來看一下RootBeanDefinition:

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

	return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}

由此可見,在初始化BeanDefinition的時候,就已經將instanceSupplier設值, 隨后從instanceSupplier.get()獲取,最后包裝成BeanWrapper對象后,對其初始化。

3.2 使用FactoryMethod方法實例化

如果工廠方法不為空,則使用工廠方法實例化:

// 使用FactoryMethod方法實例化
if (mbd.getFactoryMethodName() != null) {
    return instantiateUsingFactoryMethod(beanName, mbd, args);
}

下面進入instantiateUsingFactoryMethod方法:

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

    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;
		// 獲取工廠bean
		String factoryBeanName = mbd.getFactoryBeanName();
		// RootBeanDefinition的factory-bean屬性不為空
		if (factoryBeanName != null) {
			if (factoryBeanName.equals(beanName)) {
				throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
						"factory-bean reference points back to the same bean definition");
			}
			factoryBean = this.beanFactory.getBean(factoryBeanName);
			if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
				throw new ImplicitlyAppearedSingletonException();
			}
			factoryClass = factoryBean.getClass();
			isStatic = false;
		}
		// RootBeanDefinition的factory-bean屬性為空,需要靜態方法初始化
		else {
			// It's a static factory method on the bean class.
			if (!mbd.hasBeanClass()) {
				throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
						"bean definition declares neither a bean class nor a factory-bean reference");
			}
			factoryBean = null;
			factoryClass = mbd.getBeanClass();
			isStatic = true;
		}
		// 工廠方法與參數
		Method factoryMethodToUse = null;
		ArgumentsHolder argsHolderToUse = null;
		Object[] argsToUse = null;

		if (explicitArgs != null) {
			argsToUse = explicitArgs;
		}
		else {
			// 首先嘗試從緩存中獲取參數
			Object[] argsToResolve = null;
			synchronized (mbd.constructorArgumentLock) {
				factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
				if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
					// Found a cached factory method...
					argsToUse = mbd.resolvedConstructorArguments;
					if (argsToUse == null) {
						argsToResolve = mbd.preparedConstructorArguments;
					}
				}
			}
			if (argsToResolve != null) {
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
			}
		}

		if (factoryMethodToUse == null || argsToUse == null) {
			// Need to determine the factory method...
			// Try all methods with this name to see if they match the given arguments.
			// 獲取工廠類全名
			factoryClass = ClassUtils.getUserClass(factoryClass);

			List<Method> candidates = null;
			if (mbd.isFactoryMethodUnique) {
				if (factoryMethodToUse == null) {
					factoryMethodToUse = mbd.getResolvedFactoryMethod();
				}
				if (factoryMethodToUse != null) {
					candidates = Collections.singletonList(factoryMethodToUse);
				}
			}
			if (candidates == null) {
				candidates = new ArrayList<>();
				Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
				for (Method candidate : rawCandidates) {
					// 如果有static 且為工廠方法,則添加到 candidates 中
					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;
					}
                                        // 初始化bean
					bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
					return bw;
				}
			}

			// 工廠類有多個工廠方法,按照參數數量降序排列
			if (candidates.size() > 1) {  // explicitly skip immutable singletonList
				candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);
			}

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

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

			LinkedList<UnsatisfiedDependencyException> causes = null;
			// 遍歷工廠方法
			for (Method candidate : candidates) {
				int parameterCount = candidate.getParameterCount();

				if (parameterCount >= minNrOfArgs) {
					ArgumentsHolder argsHolder;

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

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

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

			if (explicitArgs == null && argsHolderToUse != null) {
				mbd.factoryMethodToIntrospect = factoryMethodToUse;
				argsHolderToUse.storeCache(mbd, factoryMethodToUse);
			}
		}
                // 初始化bean
		bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
		return bw;
	}

這個方法體太多if條件,通過拆解主要流程可以歸納為以下步驟:
step1:獲取工廠bean的名字;
step2:判斷工廠bean名字是否為空,如果不為空,從容器中獲取工廠bean,並將非靜態方法設為false;
step3:如果工廠bean的名字為空,則使用靜態方法實例化。
上述其他代碼都是初始化前工廠方法的遍歷,工廠方法的排序、以及參數的獲取,最終再調用instantiate方法完成初始化;而instantiate的核心代碼就一句話

return this.beanFactory.getInstantiationStrategy().instantiate(
						mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args);

getInstantiationStrategy()獲取實例化的策略,這里是使用工廠方法來實例化bean,進入instantiate方法:

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

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

			Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
			try {
				currentlyInvokedFactoryMethod.set(factoryMethod);
                                // 核心代碼就是通過反射完成實例化
				Object result = factoryMethod.invoke(factoryBean, args);
...

最終是通過反射完成bean的實例化。

3.3 有參構造函數實例化

如果沒有通過工廠方法完成實例化,那么繼續玩下走如下代碼:

                // 尋找實例化的bean中有@Autowired注解的構造函數
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			// 如果ctors不為空,就說明構造函數中有@Autowired注解
			return autowireConstructor(beanName, mbd, ctors, args);
		}

有參構造函數的實例化過程,通過determineConstructorsFromBeanPostProcessors這個方法完成,同時也是BeanPostProcessor接口類的應用,最終會調到 AutowiredAnnotationBeanPostProcessor類的方法,在方法中會掃描有注解的構造函數然后完成裝配過程。然后把有@Autowired 注解的構造函數返回。

上面已經拿到了構造函數,autowireConstructor就是獲取參數的過程,其方法比較復雜,跟之前的instantiateUsingFactoryMethod類似,不再細究,把主要核心代碼拿出來分析:

// 獲取構造函數參數的值
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,

createArgumentArray方法,獲取構造函數參數的值,進入方法,找到核心代碼:

// 解析所有構造函數的參數值
Object autowiredArgument = resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter, fallback);

resolveAutowiredArgument方法解析構造函數參數的值,再進入:

// 解析依賴
return this.beanFactory.resolveDependency(new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);

再次進入:

// 執行解析依賴
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
// 解析candidate
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
beanFactory.getBean(beanName)

最終會感覺眼前一亮,通過非常熟悉的getBean獲取實例,然后會走到普通情況下的getBean方法,通過上面得到一個結論,不管是 Field、Method、還是構造函數中有@Autowired 注解引入的類,都是通過getBean方法進行實例化獲取bean的實例的。

3.4 無參構造函數實例化

無參構造函數的實例化過程 instantiateBean(beanName, mbd)這就是簡單的反射實例化。大部分類的實例化都會走這個邏輯。進入實現類的方法:

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) {
					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();
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
                        // 反射調用
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// Must generate CGLIB subclass.
                        // 創建cglib子類后在實例化
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

3.5 bean實例化后的收尾工作

當創建完后,回到上一篇講的getSingleton方法:

// 創建bean實例
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

再來回顧一下該方法:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				// bean單例創建前
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// 調用createBean方法創建bean
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					// 創建完成后要從正在實例化的bean集合singletonsCurrentlyInCreation中刪除該bean
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					// bean加入緩存
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

以及addSingleton相關代碼如下:

	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			// 一級緩存存放bean
			this.singletonObjects.put(beanName, singletonObject);
			// 三級緩存移除bean
			this.singletonFactories.remove(beanName);
			// 二級緩存移除bean
			this.earlySingletonObjects.remove(beanName);
			//
			this.registeredSingletons.add(beanName);
		}
	}

可以看出getSingleton方法總共做了如下幾件事:

  1. bean創建前,將正在創建的bean放入singletonsCurrentlyInCreation集合;
  2. bean創建過程中,就是上一篇寫的bean的創建整個過程,本篇只是涉及建實例這一個環節;
  3. bean創建后,從集合singletonsCurrentlyInCreation中移除正在創建的bean;
  4. bean加入一級緩存,同時移除三級緩存與二級緩存中的bean。

4. 案例

4.1 使用工廠方法創建bean

使用如下配置文件spring.xml,第一種是使用factory-bean屬性,bean后面不帶class屬性;第二種是bean使用class屬性,factory-method屬性后面是靜態工廠方法:

        <context:component-scan base-package="com.wzj"/>
	<bean id="factoryMethodbean" class="com.wzj.bean.FactoryMethodBean"/>
	<bean id="wzj" factory-bean="factoryMethodbean" factory-method="factoryMethod"/>

	<bean id="wzj2"  class="com.wzj.bean.Wzj" factory-method="factoryMethod"/>

FactoryMethodBean類如下,

public class FactoryMethodBean {

    public Object factoryMethod() {
        return new Wzj();
    }


    public Object factoryMethod(SC sc, CQ cq) {
        return new Wzj(sc,cq);
    }

}

實例化類如下:

public class Wzj {
    public static Wzj factoryMethod() {
        return new Wzj();
    }

    SC sc;

    public Wzj() {

    }

    public Wzj(SC sc, CQ cq) {
        this.sc = sc;
        this.cq = cq;
    }

    CQ cq;

}

依賴的屬性值分別代表四川、重慶,實現了Province接口:

@Component
public class CQ implements Province{

    private static String flag = "CQ";

    @Override
    public boolean support(String flag) {
        return CQ.flag.equalsIgnoreCase(flag);
    }

    @Override
    public String handler() {
        System.out.println("======CQ處理類處理");
        return null;
    }
}
@Component
public class SC implements Province{

    private static String flag = "SC";

    @Override
    public boolean support(String flag) {
        return SC.flag.equalsIgnoreCase(flag);
    }

    @Override
    public String handler() {
        System.out.println("======SC處理類處理");
        return null;
    }
}
public interface Province {

    public boolean support(String flag);

    public String handler();
}

測試類:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring.xml"})
public class TestSpring {
    @Test
    public void testCreateBeanInstance() {
        ClassPathXmlApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("spring.xml");
        Wzj wzj = (Wzj) applicationContext.getBean("wzj");
        Wzj wzj2 = (Wzj) applicationContext.getBean("wzj2");
        System.out.println(wzj.getClass().getName());
        System.out.println(wzj2.getClass().getName());
    }

最后結果:

com.wzj.bean.Wzj
com.wzj.bean.Wzj

4.2 帶有autowired的有參構造函數

測試示例代碼:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring.xml"})
public class TestSpring {
    @Test
    public void testCreateBeanInstance() {
        ClassPathXmlApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("spring.xml");
        AutowiredConstructorBean fmc = (AutowiredConstructorBean)applicationContext.getBean("autowiredConstructorBean");
        System.out.println(fmc.getClass().getName());
    }

實例化AutowiredConstructorBean的代碼:

@Component
public class AutowiredConstructorBean {

    @Autowired
    private SC sc;

    @Resource
    private CQ cq;

    @Autowired
    public AutowiredConstructorBean(SC sc,CQ cq) {
        System.out.println(sc);
        System.out.println(cq);
    }
}

結果會打印如下:

com.wzj.bean.AutowiredConstructorBean

如果再加一個帶@Autowired參數的構造函數:

@Component
public class AutowiredConstructorBean {

    @Autowired
    private SC sc;

    @Resource
    private CQ cq;

    @Autowired
    public AutowiredConstructorBean(SC sc,CQ cq) {
        System.out.println(sc);
        System.out.println(cq);
    }

    @Autowired(required = false)
    public AutowiredConstructorBean(SC sc) {
        System.out.println(sc);
    }
}

結果就會報錯:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'autowiredConstructorBean': Invalid autowire-marked constructor: public com.wzj.bean.AutowiredConstructorBean(com.wzj.strategy.SC). Found constructor with 'required' Autowired annotation already: public com.wzj.bean.AutowiredConstructorBean(com.wzj.strategy.SC,com.wzj.strategy.CQ)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:339)

通過調試,發現報錯的根源是在第二次拿構造函數的參數時,執行了AutowiredAnnotationBeanPostProcessor中determineCandidateConstructors方法的如下代碼:

						if (ann != null) {
							if (requiredConstructor != null) {
								throw new BeanCreationException(beanName,
										"Invalid autowire-marked constructor: " + candidate +
										". Found constructor with 'required' Autowired annotation already: " +
										requiredConstructor);
							}

提示已經有required修飾的構造函數存在,解決上述問題,如果有兩個@Autowired注解的有參構造函數,需要將兩個構造函數@Autowired都加上required = false)。只不過構造函數會根據參數個數的多少降序排序,參數多的構造函數會優先執行,后面的那個構造函數不會被執行。

4.3 不帶有autowired的有參構造函數

public class AutowiredConstructorBean {
    public AutowiredConstructorBean(SC sc,CQ cq) {
        System.out.println(sc);
        System.out.println(cq);
    }
}

最后也能完成初始化。

4.4 無參構造函數

public class AutowiredConstructorBean {
    
}

通過上面測試案例最后也能完成實例化。

5. 總結

本篇講述了bean實例化的多種方式,可以學到spring為用戶提供多種創建方式,從而看出spring創建bean方式的靈活性,在我們寫代碼時候,也可以考慮多種策略,來完成某種功能,提高可擴展性與靈活性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM