我們一般是通過調用一個類的構造函數完成實例化的工作,spring當然也不例外。然而相比於直接通過構造函數對類進行實例化,spring的實例化過程要複雜得多。
在之前的博客中,本人曾經說過,任何一個JavaBean都有一個beandefinition。然而beandefinition並沒有規定一個類的構造函數是哪個。原因很簡單,因爲在xml文件中沒有規定構造函數的方法。spring只能通過<constructor-arg/>標籤中的信息去“猜測”哪一個構造函數最合適。而“猜測構造函數”這個工作並不適合在構建beandefinition時完成,其更適合在實例化JavaBean的時候進行。在合適的時間做合適的事情,spring很好地把握了這一點。
spring通過AbstractAutowireCapableBeanFactory類中的createBeanInstance完成類的實例化。其代碼如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, 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());
}
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);
}
}
// Need to determine the constructor...
Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
對於被<constructor-arg/>修飾的JavaBean,其最終歸宿是在autowireConstructor這個函數中,而該函數則調用了其他類的autowireConstructor,而該方法的具體實現如下所示。
public BeanWrapper autowireConstructor(
final String beanName, final RootBeanDefinition mbd, Constructor[] chosenCtors, final Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
if (constructorToUse == null) {
// Need to resolve the constructor.
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// Take specified constructors, if any.
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);
}
}
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor> ambiguousConstructors = null;
List<Exception> causes = null;
for (int i = 0; i < candidates.length; i++) {
Constructor<?> candidate = candidates[i];
Class[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
if (paramTypes.length < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
try {
String[] paramNames = null;
if (constructorPropertiesAnnotationAvailable) {
paramNames = ConstructorPropertiesChecker.evaluateAnnotation(candidate, paramTypes.length);
}
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
argsHolder = createArgumentArray(
beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (this.beanFactory.logger.isTraceEnabled()) {
this.beanFactory.logger.trace(
"Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
if (i == candidates.length - 1 && constructorToUse == null) {
if (causes != null) {
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
}
throw ex;
}
else {
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<Exception>();
}
causes.add(ex);
continue;
}
}
}
else {
// Explicit arguments given -> arguments length must match exactly.
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
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<Constructor>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
if (constructorToUse == null) {
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.storeCache(mbd, constructorToUse);
}
}
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
final Constructor ctorToUse = constructorToUse;
final Object[] argumentsToUse = argsToUse;
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, beanFactory, ctorToUse, argumentsToUse);
}
}, beanFactory.getAccessControlContext());
}
else {
beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
bw.setWrappedInstance(beanInstance);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
上面的代碼很長,但通過分析,其主要包含以下幾段代碼:
代碼段1:該段代碼比較了candidate參數與<constructor-arg/>中規定參數之間的差異值,並將差異值最小的那一個賦予給constuctorToUse,並將參數列表賦予給argsToUse對象,在該段代碼之外包裹了一個for循環,該循環會遍歷類的所有構造函數。
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;
}
代碼段2:該段代碼調用類的構造函數完成類的實例化,參數列表作爲函數的入參。
beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
beanfactory調用getInstantiationStrategy方法,該方法主要決定了類的反射策略,默認是cglib。
除了通過<constructor-arg />標籤,spring也能夠使用@Autowired註解控制構造函數的入參。而解析被@Autowired修飾的構造函數這一任務由determineCandidateConstructors完成,該函數在autowireConstructor之前被執行。而該函數一旦成功解析出了構造函數,那麼就不再執行autowireConstructor方法。determineCandidateConstructors具體代碼如下:
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
synchronized (this.candidateConstructorsCache) {
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
Constructor<?>[] rawCandidates = beanClass.getDeclaredConstructors();
List<Constructor<?>> candidates = new ArrayList<Constructor<?>>(rawCandidates.length);
Constructor<?> requiredConstructor = null;
Constructor<?> defaultConstructor = null;
for (Constructor<?> candidate : rawCandidates) {
Annotation annotation = findAutowiredAnnotation(candidate);
if (annotation != null) {
if (requiredConstructor != null) {
throw new BeanCreationException("Invalid autowire-marked constructor: " + candidate +
". Found another constructor with 'required' Autowired annotation: " +
requiredConstructor);
}
if (candidate.getParameterTypes().length == 0) {
throw new IllegalStateException(
"Autowired annotation requires at least one argument: " + candidate);
}
boolean required = determineRequiredStatus(annotation);
if (required) {
if (!candidates.isEmpty()) {
throw new BeanCreationException(
"Invalid autowire-marked constructors: " + candidates +
". Found another constructor with 'required' Autowired annotation: " +
requiredConstructor);
}
requiredConstructor = candidate;
}
candidates.add(candidate);
}
else if (candidate.getParameterTypes().length == 0) {
defaultConstructor = candidate;
}
}
if (!candidates.isEmpty()) {
// Add default constructor to list of optional constructors, as fallback.
if (requiredConstructor == null && defaultConstructor != null) {
candidates.add(defaultConstructor);
}
candidateConstructors = candidates.toArray(new Constructor[candidates.size()]);
}
else {
candidateConstructors = new Constructor[0];
}
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
}
}
}
return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
仔細閱讀代碼,我們可以發現其主要過程就是遍歷所有的構造函數,找到被@Autowired修飾的那一個並返回。同時,對於多個構造函數被@Autowired修飾的情況以及構造函數沒有參數的情況,spring會拋出異常。spring實例化JavaBean存在一個隱患,即無論JavaBean是通過xml配置還是註解配置,其都有可能導致構造函數的循環依賴。
什麼是構造函數的循環依賴?假設我們有兩個類,分別是A和B,其定義如下:
A:
public class A{
public A(B b){
//some code
}
}
B:
public class B{
public B(A a){
//some code
}
}
在代碼中無法直接通過構造函數完成類A的實例化,因爲這會導致無窮的遞歸,其結果如下一行代碼所示:
A a=new A(new B(new A(new B(.......))))
對於循環依賴,構造函數的代碼根本無法繼續書寫,更別說變成字節碼供JVM調用了。但是,由於spring允許通過<constructor-arg/>標籤對構造函數入參進行配置,因此在spring的世界裏,循環依賴能夠被人爲的構造出來。spring中的循環依賴例子如下所示:<bean id="test1" class="com.tan.tool.Test1" >
<constructor-arg ref="test"/>
</bean>
<bean id="test" class="com.tan.tool.Test" >
<constructor-arg ref="test1"/>
</bean>
爲了避免這一問題,spring會在實例化的過程中檢測是否存在循環依賴,其具體實現方法是在beanfactory調用creatBean函數之前會調用isPrototypeCurrentlyInCreation(beanName)函數,該函數具體實現如下:
protected final boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}
其中prototypesCurrentlyIncreation是一個ThreadLocal<Object>類,該對象保存了所有正在被實例化的JavaBean。一旦出現重複的beanname,該函數會返回true,並導致拋出BeanCurrentlyInCreationException異常類。其具體代碼在AbstractBeanFactory的doGetBean函數中:
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}