bean的加载(八)创建bean的实例

下面我们一步步分析doCreatBean方法,首先从createBeanInstance开始。

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

		if (mbd.getFactoryMethodName() != null)  {
			//如果存在工厂方法则使用工厂方法进行初始化
			//如果在RootBeanDefinition中存在factoryMethodName属性,或者说在配置文件中配置了
			//factory-method,那么Spring会尝试使用instantiateUsingFactoryMethod(beanName, mbd, args)
			//方法根据RootBeanDefinition中的配置生成bean的实例。
			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;
				}
			}
		}
		//如果已经解析过则使用解析好的构造函数方法不需要再次锁定
		//一个类中有多个构造函数,判断使用哪个构造函数实例化过程比较耗性能,所以采用缓存机制,如果已经解析过则不需要
		//重复解析而是直接从RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod缓存的值去取,否则需要
		//再次解析,并将解析的结果添加至RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod中。
		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.
		//如果既不存在工厂方法也不存在带有参数的构造函数,则使用默认的构造函数进行bean实例化。
		return instantiateBean(beanName, mbd);
	}

1,autowireConstructor

   对于实例的创建Spring中分成了两种情况,一种是通用的实例化,另一种是带有参数的实例化。带有参数的实例化过程相当复杂,因为存在着不确定性,所以在判断对应参数上做了大量工作。

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;
		//explicitArgs通过getBean方法传入
		//如果getBean方法调用的时候指定方法参数那么直接使用
		if (explicitArgs != null) {
			argsToUse = explicitArgs;
		}
		else {
			//如果getBean方法时候没有指定则尝试从配置文件中解析
			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) {
				//解析参数类型,如给定方法的构造函数A(int,int)则通过此方法后就会把配置中的("1","1")转换为(1,1)
				//缓存中的值可能是原始值也可能是最终值
				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);
				}
			}
			//排序给定的构造函数,public构造函数优先参数数量降序/非public构造函数参数数量降序
			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) {
					//如果已经找到选用的构造函数或者需要的参数个数小于当前的构造函数则终止,
					//因为已经按照参数个数降序排列
					break;
				}
				if (paramTypes.length < minNrOfArgs) {
					//参数个数不对等
					continue;
				}

				ArgumentsHolder argsHolder;
				if (resolvedValues != null) {
					//有参数则根据值构造对应参数类型的参数
					try {
						String[] paramNames = null;
						if (constructorPropertiesAnnotationAvailable) {
							//注解上获取参数名称
							paramNames = ConstructorPropertiesChecker.evaluate(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);
			}
			//将构建的实例加入BeanWrapper中
			bw.setWrappedInstance(beanInstance);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}

这一段逻辑很复杂,代码量也很大,Spring一般都会进行代码封装,将一个功能封装成一个个短小的方法,但这次有些不同。这些代码慢慢看完,多花点时间不要紧,但要理解了最为重要

2.instantiateBean

经历了有参的实例构造,不带参数的构造函数的实例化过程就容易理解多了

//如果已经解析过则使用解析好的构造函数方法不需要再次锁定
		//一个类中有多个构造函数,判断使用哪个构造函数实例化过程比较耗性能,所以采用缓存机制,如果已经解析过则不需要
		//重复解析而是直接从RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod缓存的值去取,否则需要
		//再次解析,并将解析的结果添加至RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod中。
		if (resolved) {
			if (autowireNecessary) {
				//构造函数自动注入
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				//使用默认构造函数构造
				return instantiateBean(beanName, mbd);
			}
		}
/**
	 * Instantiate the given bean using its default constructor.
	 * @param beanName the name of the bean
	 * @param mbd the bean definition for the bean
	 * @return BeanWrapper for the new instance
	 */
	protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
		try {
			Object beanInstance;
			final BeanFactory parent = this;
			if (System.getSecurityManager() != null) {
				beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
					public Object run() {
						return getInstantiationStrategy().instantiate(mbd, beanName, parent);
					}
				}, getAccessControlContext());
			}
			else {
				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
			}
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}

这个方法中并没有什么实质性的逻辑,带有参数的实例构造中,Spring把精力都放在了构造函数以及参数匹配上,如果没有参数的话,直接调用实例化策略进行实例化就可以了

3.实例化策略

实例化过程中,反复提到了实例化策略,这是做什么的呢?其实,经过前面的分析,我们已经得到了足以实例化的相关信息,完全可以使用最简单的反射方法来构造实例对象,但Spring却没有这么做public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner)
{

		// Don't override the class with CGLIB if no overrides.
		//如果没有需要动态改变的方法,为了方便直接放射就可以了
		if (beanDefinition.getMethodOverrides().isEmpty()) {
			Constructor<?> constructorToUse;
			synchronized (beanDefinition.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class<?> clazz = beanDefinition.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
								public Constructor<?> run() throws Exception {
									return clazz.getDeclaredConstructor((Class[]) null);
								}
							});
						}
						else {
							constructorToUse =	clazz.getDeclaredConstructor((Class[]) null);
						}
						beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Exception ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// Must generate CGLIB subclass.
			//如果有需要覆盖或者动态替换的方法则当然需要使用cglib进行动态代理,因为可以在创建代理的
			//同时将动态方法植入类中
			return instantiateWithMethodInjection(beanDefinition, beanName, owner);
		}
	}
public Object instantiate(Constructor<?> ctor, Object[] args) {
			Enhancer enhancer = new Enhancer();
			enhancer.setSuperclass(this.beanDefinition.getBeanClass());
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			enhancer.setCallbackFilter(new CallbackFilterImpl());
			enhancer.setCallbacks(new Callback[] {
					NoOp.INSTANCE,
					new LookupOverrideMethodInterceptor(),
					new ReplaceOverrideMethodInterceptor()
			});

			return (ctor != null ? enhancer.create(ctor.getParameterTypes(), args) : enhancer.create());
		}

Spring可谓是用心良苦,为了能更方便的使用Spring,程序中首先判断如果beanDefinition.getMethodOverrides()为空,也就是用户没有使用replace或者lookup的配置方法,那么直接使用反射的方式,简单快捷,但如果使用了这两个特性,再直接使用反射的方式创建实例就不妥了,因为需要将这两个配置提供的功能切入进去,所以就必须要使用动态代理的方式将包含两个特性锁对应的逻辑的拦截增强器设置进去,这样才可以保证在调用方法的时候会被相应的拦截器增强,返回值为包含拦截器的代理实例。关于这一块,我们后面分析AOP的时候会进行分析。

时间: 2024-10-16 15:47:09

bean的加载(八)创建bean的实例的相关文章

【Spring源码分析系列】bean的加载

前言 以 BeanFactory bf  = new XmlBeanFactory(new ClassPathResource("beans.xml"));为例查看bean的加载过程. 一.首先来看Spring中是如何实现的 1 @Override 2 public Object getBean(String name) throws BeansException { 3 return getBean(name, Object.class); 4 } 5 6 @Override 7 p

【Spring】详解Spring中Bean的加载

之前写过bean的解析,这篇来讲讲bean的加载,加载要比bean的解析复杂些,该文之前在小编原文中有发表过,要看原文的可以直接点击原文查看,从之前的例子开始,Spring中加载一个bean的方式: TestBean bean = factory.getBean("testBean"); 来看看getBean(String name)方法源码, @Override public Object getBean(String name) throws BeansException { re

Spring 源码分析(六)--bean的加载整体分析

通过前面的分析,我们结束了对XML配置文件的解析,接下来将进行bean加载的分析.对于加载bean的功能,在Spring中的调用方式为: 或者   MyTestBean  tb = bf.getBean("myTestBean", MyTestBean.class); 一:整体分析 (1.1)AbstractBeanFactory 类 public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport

spring IOC之篇五 bean的加载

我们终于结束了对XML配置文件的解析,接下来我们要分析bean的加载,即对代码getBean的分析: People p = (People)ctx.getBean("cutesource"); @SuppressWarnings("unchecked") protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args,

Spring源码分析(十一)bean的加载

摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 经过前面的分析,我们终于结束了对XML配置文件的解析,接下来将会面临更大的挑战,就是对bean加载的探索.bean加载的功能实现远比bean的解析要复杂得多.同样,我们还是以最开始的示例为基础,对于加载bean的功能,在Spring中的调用方式是: MySpringBean bean = (MySpringBean) beanFactory.getBean("mySpr

spring源码-bean之加载-2

一.前面说了bean的容器初始化,后面当然是说bean的加载.这里还是不讲解ApplicationContext的bean的加载过程,还是通过最基础的XmlBeanFactory来进行讲解,主要是熟悉通过BeanFactory是怎么实现class的实例化的. 二.声明一下:XmlBeanFactory和ApplicationContext的不同在与,ApplicationContext在容器初始化的时候,就做了很多准备操作.而XmlBeanFactory是在获取bean的时候才会调用初始化的东西

spring源码深度解析— IOC 之 开启 bean 的加载

概述 前面我们已经分析了spring对于xml配置文件的解析,将分析的信息组装成 BeanDefinition,并将其保存注册到相应的 BeanDefinitionRegistry 中.至此,Spring IOC 的初始化工作完成.接下来我们将对bean的加载进行探索. 之前系列文章: spring源码深度解析— IOC 之 容器的基本实现 spring源码深度解析— IOC 之 默认标签解析(上) spring源码深度解析— IOC 之 默认标签解析(下) spring源码深度解析— IOC

Spring源码学习(五)bean的加载

加油加油 ?? bean加载的大致过程 1 /** 2 * Return an instance, which may be shared or independent, of the specified bean. 3 * 4 * @param name the name of the bean to retrieve 5 * @param requiredType the required type of the bean to retrieve 6 * @param args argume

C#加载dll 创建类对象

//加载dll 创建类对象string sqlightAssembly = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "system.data.sqlite.dll"); Assembly lib = Assembly.LoadFrom(sqlightAssembly); foreach (Type t in lib.GetExportedTypes()) { if(t.FullName == "System.Da

spring IOC之篇六 bean的加载---bean的创建

之前我们讲解了缓存中单例的获取,解下来需要讲解缓存中不存在该如何处理 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "'beanName' must not be null"); // 全局变量需要同步 synchronized (this.singletonObjects) { // 先从单例缓存池获取,以便