spring笔记⑮——bean初始化(实例化)详解

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_35262405/article/details/101175991

springIOC容器宏观上是spring的整个环境,微观上来看就是一个map,存放着bean的名字和对应的bean对象

FactoryMethod

FactoryMethod顾名思义就是工厂方法的意思,如果配置了工厂方法,那么spring就会通过这个工厂方法去实例化bean。

在xml配置文件中可以配置FactoryMethod,如果配置了FactoryMethod,在初始化bean对象的时候会直接调用FactoryMethod方法来实例化bean
在这里插入图片描述

public class RealDao {
	public void test(){
		System.out.println("RealDao");
	}
}

注意工厂方法必须是static方法

public class TestDao {

	public void test(){
		System.out.println("TestDao");
	}


	// 工厂方法必须是static方法
	// spring会直接调用这个方法来初始化bean
	public static RealDao initFactoryMethod(){
		return new RealDao();
	}

}
public static void main(String[] args) {
	AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);

	//可以看到拿到的是工厂方法返回的bean对象
	RealDao testDao = (RealDao) annotationConfigApplicationContext.getBean("testDao");

	testDao.test();
	// RealDao
}

输出

RealDao

在spring源码中是在下面的位置判断bean是否配置了工厂方法并调用工厂方法
在这里插入图片描述
调用链如下
在这里插入图片描述

在配置类中@Bean注解的方法如果是static修饰的,那么这种bean的实例化就是通过FactoryMethod实现的。

bean的初始化

bean的实例化过程是在refresh中执行的,具体来说是在finishBeanFactoryInitialization这个方法中执行的
在这里插入图片描述

调用链

直到一个普通的bean被反射实例化(使用的默认构造器)的调用链如下
在这里插入图片描述
这里我会分析一些比较重要的方法其中干了什么,其中一些只是单纯的包装调用其他方法的方法就不会分析了。

preInstantiateSingletons

这个方法在初始化bean之前对bean做了一些初始化之前的准备
在这里插入图片描述
源码如下,这里是getBean方法去执行真正的bean实例化,在此之前会判断bean是否是抽象类、单例、懒加载,如果是的话就会直接跳过实例bean,之后还要判断是不是factorybean,同样如果是的话也不会通过上面的调用链实例化bean。

@Override
public void preInstantiateSingletons() throws BeansException {
	if (logger.isDebugEnabled()) {
		logger.debug("Pre-instantiating singletons in " + this);
	}

	// Iterate over a copy to allow for init methods which in turn register new bean definitions.
	// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
	// 得到所有的beanName
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	for (String beanName : beanNames) {
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		//判断是否是抽象类、单例、懒加载
		//只有非抽象类、单例、非懒加载的类才会进入if去实例化bean
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			//判断是不是factorybean
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					final FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
										((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			}
			else {
				// 真正非factorybean的bean的实例化方法
				getBean(beanName);
			}
		}
	}

	// Trigger post-initialization callback for all applicable beans...
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			}
			else {
				smartSingleton.afterSingletonsInstantiated();
			}
		}
	}
}

doGetBean

这个方法相当重要,因为不如是普通类的实例化过程还是spring内部的一些类的实例化过程都是通过此方法实现的,就连之后已经初始化完成后我们使用者得到bean都是通过此方法实现的。

源码如下,这里只是分析到初始化bean的过程,所以只是分析到调用getSingleton方法,当然是第二个getSingleton方法。

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
		@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	/**
	 * 下面总共调用了两次getSingleton方法,但是两次的目的是不一样的
	 * 因为不论是初始化还是之后getbean都是调用的doGetBean此方法得到bean对象的
	 * 所以这个方法是属于复用的,第一个getSingleton方法是对于初始化之后直接拿到bean对象的,后面的初始化流程也就不会执行了
	 * 而且如果bean对象是lazy的,也可以通过这个判断来实现初始化
	 * 第一个getSingleton方法如果没有初始化就会返回null,如果已经实例化了就会返回bean对象,在这个方法里面有一个判断,判断一个set集合中是否包含beanname
	 * 如果是第一次进入这个方法自然是没有,这个集合会在第二个getSingleton方法中加入当前的beanname并完成实例化bean对象
	 */

	final String beanName = transformedBeanName(name);
	Object bean;

	// Eagerly check singleton cache for manually registered singletons.
	// 先从容器中拿到实例,看是否已经实例化了
	// 但是初始化的一般情况下都是拿不出来的
	// 至于为什么要作这个判断是因为在初始化完成后拿到bean对象的方法也是通过这个方法实现的
	// 这样做就可以实现方法的复用
	Object sharedInstance = getSingleton(beanName);

	if (sharedInstance != null && args == null) {
		if (logger.isDebugEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	else {
		// Fail if we're already creating this bean instance:
		// We're assumably within a circular reference.

		// 判断这个bean是不是原型的(多例的)
		// 如果是的话就会抛出异常
		// 当然一般都是不会进的
		// 因为前面已经判断了
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		// Check if bean definition exists in this factory.
		BeanFactory parentBeanFactory = getParentBeanFactory();
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// Not found -> check parent.
			String nameToLookup = originalBeanName(name);
			if (parentBeanFactory instanceof AbstractBeanFactory) {
				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
						nameToLookup, requiredType, args, typeCheckOnly);
			}
			else if (args != null) {
				// Delegation to parent with explicit args.
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else {
				// No args -> delegate to standard getBean method.
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
		}

		if (!typeCheckOnly) {
			markBeanAsCreated(beanName);
		}

		try {
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);

			// Guarantee initialization of beans that the current bean depends on.
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				for (String dep : dependsOn) {
					if (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
					}
					registerDependentBean(dep, beanName);
					try {
						getBean(dep);
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}

			// Create bean instance.
			/**
			 * 真正实例化bean地方
			 */
			if (mbd.isSingleton()) {
				sharedInstance = getSingleton(beanName, () -> {
					try {
						// 真正的实例化bean的方法
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						// Explicitly remove instance from singleton cache: It might have been put there
						// eagerly by the creation process, to allow for circular reference resolution.
						// Also remove any beans that received a temporary reference to the bean.
						destroySingleton(beanName);
						throw ex;
					}
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}

			else if (mbd.isPrototype()) {
				// It's a prototype -> create a new instance.
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}

			else {
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
				}
				try {
					Object scopedInstance = scope.get(beanName, () -> {
						beforePrototypeCreation(beanName);
						try {
							return createBean(beanName, mbd, args);
						}
						finally {
							afterPrototypeCreation(beanName);
						}
					});
					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
				}
				catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName,
							"Scope '" + scopeName + "' is not active for the current thread; consider " +
							"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
							ex);
				}
			}
		}
		catch (BeansException ex) {
			cleanupAfterBeanCreationFailure(beanName);
			throw ex;
		}
	}

	// Check if required type matches the type of the actual bean instance.
	if (requiredType != null && !requiredType.isInstance(bean)) {
		try {
			T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
			if (convertedBean == null) {
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
			return convertedBean;
		}
		catch (TypeMismatchException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Failed to convert bean '" + name + "' to required type '" +
						ClassUtils.getQualifiedName(requiredType) + "'", ex);
			}
			throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
		}
	}
	return (T) bean;
}

需要注意的就是这两个getSingleton方法的区别,因为不论是初始化还是之后getbean都是调用的doGetBean此方法得到bean对象的所以这个方法是属于复用的,第一个getSingleton方法是对于初始化之后直接拿到bean对象的,后面的初始化流程也就不会执行了,而且如果bean对象是lazy的,也可以通过这个判断来实现初始化,第一个getSingleton方法如果没有初始化就会返回null,如果已经实例化了就会返回bean对象,在这个方法里面有一个判断,判断一个set集合中是否包含beanname,如果是第一次进入这个方法自然是没有,这个集合会在第二个getSingleton方法中加入当前的beanname并完成实例化bean对象。

这个方法主要用来处理多种情况的调用,实现方法的复用性,因为有多情况会调用这个方法,我个人认为主要有如下的情况:

  • 初始化spring内部的类
  • 第一次初始化bean(包括自身的和spring的,就是目前我们分析的情况)
  • 初始化后使用者通过getBean拿到bean,这里还有两种情况,拿到原型(多例)的或者单例的

为了使用这一个方法共同处理这些情况所以spring在这个调用了两次getSingleton方法(虽然这两个方法只是重载方法并不是同一个方法),并且做了一些判断。

getSingleton

这里的getSingleton方法是第二个getSingleton方法,里面的代码并不是很重要,主要是说明一下它是如何调用下一个方法的。

这里是调用的入口,当然真正的执行方法并不在这,这个singletonFactory对象在外面是通过一个labmbda表达式传递过来的。
在这里插入图片描述
所以真正的执行代码在这,通过调用createBean方法完成进一步初始化
在这里插入图片描述

createBean

这个方法也没什么好说的,主要是执行了一个后置处理器,当然这个后置处理器并不是对所有的bean有作用,只有实现了InstantiationAwareBeanPostProcessor接口的类才会被这个后置处理器处理。

这个后置处理器的具体源码就不再分析,只要明白这个后置处理器会将bean直接实例化出来,但是这个bean中的依赖不会交给spring去维护,只是单纯的将bean放到spring容器中。

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {

	if (logger.isDebugEnabled()) {
		logger.debug("Creating instance of bean '" + beanName + "'");
	}
	RootBeanDefinition mbdToUse = mbd;

	// 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);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	// Prepare method overrides.
	try {
		mbdToUse.prepareMethodOverrides();
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
				beanName, "Validation of method overrides failed", ex);
	}

	try {
		// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
		// 实现InstantiationAwareBeanPostProcessor这个后置处理器的类会在这个方法中通过这个后置处理器直接生成一个bean对象并返回
		// 否则返回为null
		// 这样就不会执行后面的代码了
		// 这样生成的bean对象是没有依赖注入的,是一个寡对象
		// 这个接口spring也不提倡使用,是spring内部使用的
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}
	catch (Throwable ex) {
		throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
				"BeanPostProcessor before instantiation of bean failed", ex);
	}

	try {

		// 在这个方法中实例化了bean
		// 返回的也是一个代理方法
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isDebugEnabled()) {
			logger.debug("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}
	catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
		// A previously detected exception with proper bean creation context already,
		// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
	}
}

doCreateBean

这个方法也没有什么可以分析的,主要是将创建了一个bean的包装类BeanWrapper,这个包装类里面封装了bean对象和bean的一些其他信息。
在这里插入图片描述

createBeanInstance

这个方法非常重要,主要的作用是实现了通过FactoryMethod方式实例化bean选择实例化时使用的构造器

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable 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());
	}

	Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
	if (instanceSupplier != null) {
		return obtainFromSupplier(instanceSupplier, beanName);
	}

	// 如果有FactoryMethod就会用FactoryMethod来创建bean对象
	// 可以在xml中配置factory-method属性
	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) {
			// 判断是不是存在FactoryMethod,存在就进入if
			if (mbd.resolvedConstructorOrFactoryMethod != null) {
				resolved = true;
				autowireNecessary = mbd.constructorArgumentsResolved;
			}
		}
	}
	// 只有存在FactoryMethod才会进入
	if (resolved) {
		if (autowireNecessary) {
			return autowireConstructor(beanName, mbd, null, null);
		}
		else {
			return instantiateBean(beanName, mbd);
		}
	}

	//这里通过后置处理器得到bean的构造方法
	// 总的来说除非只有一个构造器(非默认构造器)的情况下,都会返回null
	// 如果存在一个非默认构造器,而且默认构造器是非显示的,那么非返回这个构造器
	// Candidate constructors for autowiring?
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {

		//使用有参的构造方法来初始化bean
	return autowireConstructor(beanName, mbd, ctors, args);

	}

	// No special handling: simply use no-arg constructor.
	//执行默认构造方法创建bean
	return instantiateBean(beanName, mbd);
}

这里就不再详细分析FactoryMethod的调用过程,详细分析如下

FactoryMethod详细分析

至于构造器的选择则是通过determineConstructorsFromBeanPostProcessorsfang方法是实现的。

走进这个方法,方法里面又是通过determineCandidateConstructors方法得到的构造器,这是一个接口方法,真正调用的是AutowiredAnnotationBeanPostProcessor中的determineCandidateConstructors方法,这个方法中代码很多但是我们可以只关心最后几行代码,对于spring是怎么拿到构造器的我们不关心,主要是spring是如何选择使用哪一个构造器的。
在这里插入图片描述
因为还不知道primaryConstructor是如何设置的,而且默认是null。

总的来说排除这个primaryConstructor,除非只有一个构造器(非默认构造器)的情况下,都会使用默认构造器,而且这个默认构造器是非显示的。

			/**
			 * 上面关于构造器如何得到和一些处理不做分析
			 * 这里得到rawCandidates和nonSyntheticConstructors
			 * rawCandidates里面装着所有的构造器(一般情况下)
			 * 至于rawCandidates都有哪些构造器这里会有几种情况
			 *
			 * 1.只有默认构造器,这种情况下不论显不显示地写出默认构造器rawCandidates中都会有默认构造器
			 *
			 * 2.存在非默认构造器
			 * 	a.显示地写出默认构造器,那么rawCandidates就会有默认构造器
			 * 	b.不显示地写出默认构造器,那么rawCandidates就不会有默认构造器
			 *
			 * 这里的primaryConstructor目前并不清楚如何设置
			 * 默认是没有设置的,就是null
			 *
			 * 排除这个primaryConstructor
			 * 总的来说除非只有一个构造器(非默认构造器)的情况下,都会使用默认构造器
			 * 而且这个默认构造器是非显示的
			 */
			// 如果只有一个构造器就会返回这个构造器(非默认构造器)
			else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
				candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
			}
			// 如果有两个构造器(含默认构造器)且存在primary设置的构造器就返回此构造器
			else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
					defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
				candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
			}
			// 如果有一个构造器且存在primary设置的构造器就返回此构造器
			else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
				candidateConstructors = new Constructor<?>[] {primaryConstructor};
			}
			else {
				// 如果进入此语句代表最终将返回null
				// 也就是使用默认构造器初始化bean
				candidateConstructors = new Constructor<?>[0];
			}
			this.candidateConstructorsCache.put(beanClass, candidateConstructors);
		}
	}
}
return (candidateConstructors.length > 0 ? candidateConstructors : null);

如果在上面选择构造器的时候真的找到了初始化时使用的会默认构造方法的话会执行下面的方法初始化bean
在这里插入图片描述
在上面就分析过了,如果无法设置主要构造器的话,除了返回null之外只会返回一个构造器,自然就是通过这个构造器实例化的bean,当然如果返回了多个构造器spring也会在这个方法中进行选择一个匹配度最高的构造器来初始化bean。

我们可以通过spring的扩展点设置需要注入的属性的类型,如下所示,mybatis也正是通过这种方法是实现实例化mapper接口。
在这里插入图片描述
下面是spring内部拿到我们注入的属性
在这里插入图片描述
然后spring会通过这些需要注入的属性来选择构造器,这个是属于spring内部的算法选择,具体是如何选择的就不具体分析了,类似于编辑距离算法。

下面是通过选择的构造方法初始化bean的方法
在这里插入图片描述

instantiateBean&instantiate&instantiateClass

上面这三个方法并没有做出什么实质性的操作,只是在instantiateClass方法中通过传进来的默认构造方法反射调用newInstance真正意义实例化bean对象。
在这里插入图片描述
到这里bean也就真正被实例化出来了

流程图

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_35262405/article/details/101175991
今日推荐