《spring設計思想》8-BeanDefinition中的beanClass從String轉換爲Class

上一節梳理了一下BeanDefinition的合併過程,而且講到BeanDefinition中的基本屬性


	@Nullable
	private volatile Object beanClass;

beanClass屬性描述的是Bean的類型,而且很特殊的設置爲Object類型,java中萬物皆是對象,但是我們在讀取xml或者propeties時,賦值的是什麼類型呢,斷點調試發現是Sting類型的對象,

但是在執行過getBean方法之後,會調用上一節的mergeBeanDefinition方法,這個時候的beanFactory中有屬性:mergedBeanDefinitions,其中的user的beanDefinition中的beanClass是Class對象

其中到底發生了什麼?

在mergeBeanDefinition之後,bean的屬性已經全部被準備完畢,那麼createBean中的時候有個方法,把beanClass的轉換完成:

/ Make sure bean class is actually resolved at this point, and
		// clone the bean definition in case of a dynamically resolved Class
		// which cannot be stored in the shared merged bean definition.
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

具體的實現方法

	@Nullable
	protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
			throws CannotLoadBeanClassException {

		try {
			if (mbd.hasBeanClass()) {
				return mbd.getBeanClass();
			}
			if (System.getSecurityManager() != null) {
				return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
					doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
			}
			else {
				return doResolveBeanClass(mbd, typesToMatch);
			}
		}
		catch (PrivilegedActionException pae) {
			ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
			throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
		}
		catch (ClassNotFoundException ex) {
			throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
		}
		catch (LinkageError err) {
			throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
		}
	}

1:首先會校驗mbd.hasBeanClass()這個方法校驗了beanClass是否爲Class對象,如果不是,繼續,

2:會校驗java安全是否開啓

3:解析beanClass

第三步的過程很奇妙

會調用BeanDefinition中的方法:

	/**
	 * Determine the class of the wrapped bean, resolving it from a
	 * specified class name if necessary. Will also reload a specified
	 * Class from its name when called with the bean class already resolved.
	 * @param classLoader the ClassLoader to use for resolving a (potential) class name
	 * @return the resolved bean class
	 * @throws ClassNotFoundException if the class name could be resolved
	 */
	@Nullable
	public Class<?> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {
		String className = getBeanClassName();
		if (className == null) {
			return null;
		}
		Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
		this.beanClass = resolvedClass;
		return resolvedClass;
	}

利用Spring的工具類 ClassUtils方法獲取resolvedClass;

classLoader是獲取的BeanFactory中的AppClassLoader

ClassUtils中的方法實現

try {
                    return Class.forName(name, false, clToUse);
                } catch (ClassNotFoundException var9) {
                    int lastDotIndex = name.lastIndexOf(46);
                    if (lastDotIndex != -1) {
                        String innerClassName = name.substring(0, lastDotIndex) + '$' + name.substring(lastDotIndex + 1);

                        try {
                            return Class.forName(innerClassName, false, clToUse);
                        } catch (ClassNotFoundException var8) {
                            ;
                        }
                    }

是調用了java.lang中的Class.forName方法。這個時候,就完成了String類型到Class類型的轉換。

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