spring源碼:bean加載之創建bean-創建BeanWrapper

一、介紹

  BeanWrapper是對bean實例的一層包裝,目前在spring中有四種實例化bean的方式,分別爲:supplier、工廠方法、有參構造函數、無參構造函數。

二、bean加載流程

  1. 獲取用戶傳入name對應的beanName
  2. 嘗試從緩存中獲取bean實例
  3. 緩存中不存在,加載bean實例
    3.1. 檢查循環依賴
    3.2 處理parentBeanFactory
    3.3 處理依賴的bean(dependsOn)
    3.4 三種bean實例的創建
     3.4.1 單例bean的創建
      3.4.1.1 獲取單例bean,getSingleton()方法
      3.4.1.2 準備創建bean,createBean()方法
      3.4.1.3 創建bean,doCreateBean()方法
       3.4.1.3.1 創建BeanWrapper(本章解析
     3.4.2 原型bean的創建
     3.4.3 根據scope策略創建bean
  4. 從bean實例中獲取真正的對象
  5. 轉換對象類型
  6. 返回對象實例

三、相關類及方法

  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance:創建bean實例整體流程的方法
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#obtainFromSupplier:supplier方式創建bean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod:使用工廠方法創建bean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor:有參構造方法創建bean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateBean:無參構造方法創建bean

四、創建beanWrapper的整體流程

	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// 1. 解析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());
		}

		// 2. 使用supplier方式初始化bean(方式一)
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		// 3. 使用工廠方法初始化bean(方式二)
		if (mbd.getFactoryMethodName() != null)  {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// 4. 使用構造函數創建bean
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				// 已解析出對應的構造函數
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		// 4.1 已解析出對應的構造函數
		if (resolved) {
			if (autowireNecessary) {
				// 有參構造函數初始化bean(方式三)
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				// 無參構造函數初始化bean(方式四)
				return instantiateBean(beanName, mbd);
			}
		}

		// 4.2 需要根據參數解析構造函數
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
			// 有參構造函數初始化bean
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// 無參構造函數初始化bean
		return instantiateBean(beanName, mbd);
	}

在這裏插入圖片描述
可以看到有四種(圖中的粉色方塊)方式可以創建bean實例,優先級爲:initSupplier方式 > 工廠方法方式 > 無參構造函數方式 = 有參構造函數方式,其中無參、有參構造函數是根據條件來選擇使用哪種方式創建bean實例的。下面來分別分析這四種方式

1. initSupplier方式創建bean:obtainFromSupplier(spring5.0新增)
1.1 使用方式
一般使用在用戶註冊自定義的BeanDefinition的場景中,這樣對bean實例的初始化,增加了極大的靈活性。以往beanName基本都是寫死在xml或者註解中的,有了initSupplier就可以設置通過計算得到的beanName、構造函數中的參數等等。

    @Test
    public void registerBeanDefinition() {
        // 1. 創建DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory(null);

        // 2. 通過BeanDefinitionBuilder把創建Person的方式設置到initSupplier
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Person.class,
            Person::new);

        // 3. 註冊beanDefinition(beanName可靈活設置)
        defaultListableBeanFactory.registerBeanDefinition("supplierPerson",
            beanDefinitionBuilder.getBeanDefinition());

        // 4. 獲取bean
        Object supplierPerson = defaultListableBeanFactory.getBean("supplierPerson");
        System.out.println(supplierPerson);
    }

第2步,可以通過initSupplier可靈活編寫創建Person的代碼;第3步,可靈活設置beanName。

除了DefaultListableBeanFactory有註冊beanDefinition的方法,GenericApplicationContextSimpleBeanDefinitionRegistry兩個類也有同樣的功能。

1.2 initSupplier初始化bean源碼

	protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
		String outerBean = this.currentlyCreatedBean.get();
		this.currentlyCreatedBean.set(beanName);
		Object instance;
		try {
			// 調用用戶自定義的代碼
			instance = instanceSupplier.get();
		}
		finally {
			if (outerBean != null) {
				this.currentlyCreatedBean.set(outerBean);
			}
			else {
				this.currentlyCreatedBean.remove();
			}
		}
		BeanWrapper bw = new BeanWrapperImpl(instance);
		initBeanWrapper(bw);
		return bw;
	}

這裏我們看到,只是簡單的調用了用戶自定義的方法。

2. 工廠方法創建bean:instantiateUsingFactoryMethod
2.1 使用方式

  • 工廠類
public class MyFactory {

    public static Person staticMethod(String name, Integer age){
        System.out.println("靜態工廠方法創建方式");
        return new Person(name, age);
    }

    public Person factoryMethod(String name, Integer age){
        System.out.println("普通工廠方法創建方式");
        return new Person(name, age);
    }
}
  • 配置(兩種方式:實例方法和靜態方法)
    <!--工廠方法爲實例方法時,需要創建工廠實例-->
    <bean id="myFactory" class="com.kaka.spring.pojo.factory.MyFactory"/>
    <bean id="personByFactory" factory-bean="myFactory" factory-method="factoryMethod">
        <constructor-arg index="0" value="personByFactory"/>
        <constructor-arg index="1" value="22"/>
    </bean>

    <!--工廠方法爲靜態方法時,class指定爲工廠類,直接使用靜態方法即可-->
    <bean id="staticPerson" class="com.kaka.spring.pojo.factory.MyFactory" factory-method="staticMethod">
        <constructor-arg name="name">
            <value type="java.lang.String">staticPerson</value>
        </constructor-arg>
        <constructor-arg name="age" value="9"/>
    </bean>
  • 工廠方法爲實例方法時,需要把工廠類配置爲一個bean,然後對應的bean通過factory-bean指定該工廠類bean,factory-method指定創建bean使用的實例方法名稱;
  • 工廠方法爲靜態方法時,僅需要配置一個factory-method指定創建bean使用的靜態方法名稱即可
  • 獲取bean
	@Test
	public void factoryMethod(){
		// 1. 創建bean工廠
		Resource classPathResource = new ClassPathResource("applicationContext.xml");
		BeanFactory xmlBeanFactory = new XmlBeanFactory(classPathResource);
		
		// 測試獲取bean(工廠方法爲實例方法方式)
		Person personByFactory = xmlBeanFactory.getBean("personByFactory", Person.class);
		System.out.println(personByFactory);

		// 測試獲取bean(工廠方法爲靜態方法方式)
		Person staticPerson = xmlBeanFactory.getBean("staticPerson", Person.class);
		System.out.println(staticPerson);

	}

3. 有參構造函數創建bean:autowireConstructor

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

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

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

		// 1. 獲取構造函數的參數:argsToUse
		// 1.1 explicitArgs通過getBean 方法傳入
		// 如果getBean 方法調用調用的時候指定方法參數那麼直接使用
		if (explicitArgs != null) {
			argsToUse = explicitArgs;
		}
		else {
			// 如果在getBean 方法沒有指定,則嘗試從配置文件中解析
			Object[] argsToResolve = null;
			// 1.2 嘗試從緩存中獲取構造函數的參數
			synchronized (mbd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
				// 構造函數已解析完成
				if (constructorToUse != null && mbd.constructorArgumentsResolved) {
					// 從RootBeanDefinition中取完全解析的構造函數參數
					argsToUse = mbd.resolvedConstructorArguments;
					if (argsToUse == null) {
						// 部分準備好的構造函數參數
						argsToResolve = mbd.preparedConstructorArguments;
					}
				}
			}
			// 如果緩存中存在
			if (argsToResolve != null) {
				// 解析緩存中的參數類型
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
			}
		}
		// 1.3 如果緩存中不存在確定的構造函數,需要解析構造函數和參數
		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 {
				// 提取配置文件中配置的構造函數參數(解析BeanDefinition的時候提到過)
				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);
				}
			}
			// 2. 確定構造函數
			// 排序給定的構造函數,public構造函數有限參數數量降序、非public構造函數參數數量降序
			AutowireUtils.sortConstructors(candidates);
			int minTypeDiffWeight = Integer.MAX_VALUE;
			Set<Constructor<?>> ambiguousConstructors = null;
			LinkedList<UnsatisfiedDependencyException> causes = null;

			for (Constructor<?> candidate : candidates) {
				Class<?>[] paramTypes = candidate.getParameterTypes();

				if (constructorToUse != null && argsToUse.length > paramTypes.length) {
					// 如果已經找到選用的構造函數或者需要的參數個數小於當前的構造函數參數個數則終止,
					// 因爲已經按照參數個數降序排列了,後面肯定找不到了
					break;
				}
				if (paramTypes.length < minNrOfArgs) {
					// 參數個數不相等
					continue;
				}

				// 3. 參數持有者的確定
				ArgumentsHolder argsHolder;
				if (resolvedValues != null) {
					try {
						// 有參數則根據值構造對應參數類型的參數
						String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
						if (paramNames == null) {
							// 獲取參數名稱探索器
							ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
							if (pnd != null) {
								// 獲取指定構造函數的參數名稱
								paramNames = pnd.getParameterNames(candidate);
							}
						}
						// 3.1 根據名稱和數據類型創建參數持有者
						argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
								getUserDeclaredConstructor(candidate), autowiring);
					}
					catch (UnsatisfiedDependencyException ex) {
						if (logger.isTraceEnabled()) {
							logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
						}
						// Swallow and try next constructor.
						if (causes == null) {
							causes = new LinkedList<>();
						}
						causes.add(ex);
						continue;
					}
				}
				else {
					// Explicit arguments given -> arguments length must match exactly.
					if (paramTypes.length != explicitArgs.length) {
						continue;
					}
					// 3.2 構造函數沒有參數的情況
					argsHolder = new ArgumentsHolder(explicitArgs);
				}

				// 4. 探測是否有不確定性的構造函數存在,例如不同構造函數的參數爲父子關係
				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.storeCache(mbd, constructorToUse);
			}
		}

		try {
			// 5. 實例化策略
			final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();
			Object beanInstance;

			if (System.getSecurityManager() != null) {
				final Constructor<?> ctorToUse = constructorToUse;
				final Object[] argumentsToUse = argsToUse;
				beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
						strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse),
						beanFactory.getAccessControlContext());
			}
			else {
				// 實例化bean(見5)
				beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
			}
			// 將構建的實例加入BeanWrapper中
			bw.setBeanInstance(beanInstance);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean instantiation via constructor failed", ex);
		}
	}

以上代碼比較長,但是要做的事情無非是確定構造函數和構造函數的參數。然後使用對應的實例化策略,來實例化bean。

4. 無參構造函數創建bean:instantiateBean

	protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
		try {
			Object beanInstance;
			final BeanFactory parent = this;
			if (System.getSecurityManager() != null) {
				beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
						getInstantiationStrategy().instantiate(mbd, beanName, parent),
						getAccessControlContext());
			}
			else {
				// 實例化bean(見5)
				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);
		}
	}

5. 實例化策略

	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// 如果有需要覆蓋或者動態替換的方法,則使用cglib進行動態代理,因爲可以在創建代理的同時將動態方法織入類中
		// 但是如果沒有需要動態改變的方法,爲了方便直接反射就可以了
		// 如果不存在replace或者lookup的方法配置,
		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);
					}
				}
			}
			// 直接反射實例化bean
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// Must generate CGLIB subclass.
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

		// cglib實例化bean
		public Object instantiate(@Nullable Constructor<?> ctor, @Nullable Object... args) {
			Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
			Object instance;
			if (ctor == null) {
				instance = BeanUtils.instantiateClass(subclass);
			}
			else {
				try {
					Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
					instance = enhancedSubclassConstructor.newInstance(args);
				}
				catch (Exception ex) {
					throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
							"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
				}
			}
			// SPR-10785: set callbacks directly on the instance instead of in the
			// enhanced class (via the Enhancer) in order to avoid memory leaks.
			Factory factory = (Factory) instance;
			factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
					new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
					new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
			return instance;
		}

如果用戶沒有使用replace或者lookup的配置,那麼直接使用反射的方式。但如果使用了這兩種方式,則需要使用cglib來把這些方法織入到實例的方法中了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章