本篇文章已经是此系列的第五篇了,我想改变一下套路,分析到这已经逐渐的进入到了容器创建的核心,代码的嵌套非常的深,如果在一点点分析源码,真是灰常的费劲。之前写过一篇文章,是跟随代码一点点分析,可以去看看。后边文章的代码将按照要点着重的进行分析。
创建bean总纲.png
每一个bean都有一个id(beanName), 这个id 在创建的过程中, 有着至关重要的作用。在创建的第一步就是进行beanName的转换。
-
转换对应的beanName
为什么要转化呢。此处的beanName代表多个含义,有可能是别名,也有可能是FactoryBean .- 去除FactoryBean的修饰符,也就是如果name="&xxx" , 解析为name="xx"
- 将别名转化为最终的beanName 。别名的父类是AliasRegistry
-
尝试从缓存中获取单例。
单例在同一个容器中只会创建一次,后续再创建bean。就直接从缓存中获取了。但是只是会尝试加载,如果缓存中没有则再次从singletonFactories 中加载。 -
createBean .
protected Object createBean(String beanName,RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
mbdToUse.prepareMethodOverrides();
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
}
下面简单概述一下,上面方法的功能。
- resolveBeanClass
- doCreateBean
resolveBeanClass方法: 其实在xml中配置的bean标签,有一个属性class 属性,里面配置了类的包名和类名。 这个方法执行的代码,总结一下话核心可能就一段代码 就是 Class.forName() . 当然了Spring并没有这么直白,在其之上有进行了代码的封装。 它就是 ClassUtils.forName() ,下面我们看一下代码 :
public static Class<?> forName(String name, @Nullable ClassLoader classLoader)throws ClassNotFoundException, LinkageError {
//断言 name 不能为空
Assert.notNull(name, "Name must not be null");
// 如果name指定是一个java的简单类型,那么就根据jvm的命名规范返回对应的类
Class<?> clazz = resolvePrimitiveClassName(name);
if (clazz == null) {
clazz = commonClassCache.get(name);
}
if (clazz != null) {
return clazz;
}
// "java.lang.String[]" style arrays
if (name.endsWith(ARRAY_SUFFIX)) {
String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
Class<?> elementClass = forName(elementClassName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
// "[Ljava.lang.String;" style arrays
if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
Class<?> elementClass = forName(elementName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
// "[[I" or "[[Ljava.lang.String;" style arrays
if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length());
Class<?> elementClass = forName(elementName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
ClassLoader clToUse = classLoader;
if (clToUse == null) {
clToUse = getDefaultClassLoader();
}
try {
return Class.forName(name, false, clToUse);
}
catch (ClassNotFoundException ex) {
int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
if (lastDotIndex != -1) {
String innerClassName = name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
try {
return Class.forName(innerClassName, false, clToUse);
}catch (ClassNotFoundException ex2) {
// Swallow - let original exception get through
}
}
throw ex;
}
}
如果不是基本类型,就会从commonClassCache里去取值,commonClassName存储了所有java.lang包中的类,显而易见我们这个不在 lang包里。则要判断对象是否为数组对象,二进制数组和二维数组对象进行判断。 如果类加载器为null ,则要获取一个默认的类加载器。
获取类加载器的三种方式:
- Thread.currentThread().getContextClassLoader()
- ClassUtils.class.getClassLoader()
- ClassLoader.getSystemClassLoader()
如果不是上面的几种类型,则来到了Class.forName(innerClassName, false, clToUse); 处 , 使用 Class.forName获取Class对象。
对象的创建来源于对象对应的Class对象,现在已经拿到了Class对象了,那么就可以为所欲为了。
下面 解析Object beanInstance = doCreateBean(beanName, mbdToUse, args); 这段代码 :
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
}
}
}
registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}
看一下上面这段代码主要干了些什么事?
image.png如果xml中配置的工厂方法初始化不为空,则使用工厂方法进行初始化,如果没有配置工厂方法,则在调用前,要解析构造函数,然后根据xml中配置的构造函数参数名称,确定使用哪个构造函数进行对象的初始化操作。如果解析则使用autowireConstructor()方法进行初始化,否则则使用默认的构造函数也就是无参的构造函数进行初始化的操作。后面的代码我就不展开细说了,说一下spring是如何根据xml配置的信息确定采用哪个构造函数进行初始化的。
上面解析获取了Class对象。 Spring 调用 Constructor<?>[] constructors
= clazz.getDeclaredConstructors() 获取到构造函数的数组。之后会遍历这个数组,与xml中配置的构造函数name 进行比较。如果参数名字对应上则使用该对应构造函数。并使用 ctor.newInstance(args) 创建实例。
实例已经创建了 ,剩下的就是注入属性了。其实属性的注入没有什么太多要说的。 PropertyDescriptor 来实现的。之前的代码有cglib来实现。
到此处呢 , 实例就创建完成了。
网友评论