如果没有用Spring框架,程序员创建对象的方式有以下5种方式:
- 使用new关键字。
- 使用Class的newInstance()方法。
- 使用Constructor的newInstance()方法。
- 使用clone()方法。
- 使用反序列化。
虽然这些方式都能实现创建一个对象,但在当今的应用开发中对于频繁使用到的类(比如dao层对象),如果频繁的创建对象,无形中会加剧内存的产生,对系统性能产生影响,而且也是不利于管理的。为了解决上述提到的痛点,Spring就应运而生,并且业界在进行企业级开发的时候,都会把它引入到自己的项目中。我们知道Spring在创建对象的时候,有两种方式,一种是singleton(单例),一种是prototype(原型)。默认是singleton的。那么Spring是如何创建对象的呢?我们下面就来聊聊Spring对象创建流程。
Spring加载bean的功能,在代码中可以这样调用:
UserService userService = (UserService) applicationContext.getBean("userService");
下面是getBean方法的源代码,你可以看一下代码里面的注释。
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// name有可能是 &xxx 或者 xxx,如果name是&xxx,那么beanName就是xxx
// name有可能传入进来的是别名,那么beanName就是id
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 如果sharedInstance是FactoryBean,那么就调用getObject()返回对象
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
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.
// &&&&xxx---->&xxx
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 if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查BeanDefinition是不是Abstract的
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
// dependsOn表示当前beanName所依赖的,当前Bean创建之前dependsOn所依赖的Bean必须已经创建好了
for (String dep : dependsOn) {
// beanName是不是被dep依赖了,如果是则出现了循环依赖
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// dep被beanName依赖了,存入dependentBeanMap中,dep为key,beanName为value
registerDependentBean(dep, beanName);
// 创建所依赖的bean
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
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;
}
});
beanInstance = 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);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try { // session.getAttriute(beaName) setAttri
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
// 检查通过name所获得到的beanInstance的类型是否是requiredType
return adaptBeanInstance(name, beanInstance, requiredType);
}
这句代码实现了什么样的功能呢?我们可以先看一下这个程序代码的流程图。
从上面这个流程图可以看出获取bean经历了一个相当复杂的流程,对于获取bean的过程所涉及的步骤大致如下。
- 转换对应beanName
方法入参传入的name,不一定是对应的beanName,有可能是别名,也可能是FactoryBean,所以需要进行一系列的解析。主要的处理逻辑是:
- 去除FactoryBean的修饰符,也就是如果传入的name为&aa,那么会首先去掉“&”字符,返回aa。
- 如果传入的name是一个alias,要取得最终指向的真实bean。例如别名A指向名称为B的bean,则返回B;若别名A指向别名B,别名B又指向名称为C的bean,则返回C。
- 尝试从缓存中获取bean对象
如果使用Spring创建的Bean是单例模式,那么同一个容器只会创建一次。后续在获取相同的bean对象,就直接从单例缓存中获取了。这首先尝试从缓存中获取bean对象,如果获取不到,则再次从singletonFactories中获取。因为创建单例bean的时候,会存在循环依赖的问题,为了避免循环依赖,Spring中创建bean的原则是不等bean创建完成,就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦bean创建时候需要依赖上一个bean,则直接使用ObjectFactory。
这部分的代码在下面,你可以看一下。
public Object getSingleton(String beanName) {
//true表示允许早期的依赖引用。
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//检查缓存中是否存在对象。
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//如果为空,则锁定singletonObjects,并进行处理。
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
//当某些方法需要提前初始化的时候会调用addSingletonFactory方法将对应
//的ObjectFactory初始化策略存储在singletonFactories中。
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//调用预先设定的getObject方法。
singletonObject = singletonFactory.getObject();
//记录在缓存中,earlySingletonObjects和singletonFactories互斥。
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
这个方法首先尝试从singletonObjects获取对象实例,如果获取不到再从earlySingletonObjects里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject来创建bean,并放入earlySingletonObjects里面去,并且从singletonFactories里面删除掉这个ObjectFactory。
这个方法里面引用了几个map,下面分别说明一下。
- singletonObjects:用于保存BeanName和创建bean实例之间的关系。
- singletonFactories:用于保存BeanName和创建bean的工厂之间的关系。
- earlySingletonObjects:也是保存BeanName和创建bean实例之间的关系,与singletonObjects的不同之处在于,当一个单例bean被放进到这里面后,那么当其他bean创建时需要这个bean,可以通过getSingleton方法直接获得,解决循环依赖的问题。
- bean的实例化
从缓存中获得的是bean的原始状态,则需要对bean进行实例化。而getObjectForBeanInstance就是完成这个工作的。第一步调用这个方法来检测正确性。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
//如果指定的name是工厂相关例如&xxx
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
//单例池中的对象不是FactoryBean,则直接返回
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
//从factoryBeanObjectCache中直接拿对象
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
//到这里已经明确知道beanInstance一定是FactoryBean类型。
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
//containsBeanDefinition检测beanDefinitionMap是否定义beanName。
if (mbd == null && containsBeanDefinition(beanName)) {
//将存储XML配置文件到GernericBeanDefinition转换为RootBeanDefinition,
//如果指定BeanName是子Bean的话同时会合并父类的相关属性。
mbd = getMergedLocalBeanDefinition(beanName);
}
//synthetic为true,表示这个Bean不是正常的一个Bean,可能只是起到辅助作用的,所以这种Bean就不用去执行PostProcessor了
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
这个方法主要做的事情就是beanInstance的name是&aa这样的,并且不是FactoryBean实例,则直接报错,如果是FactoryBean类型的实例,则直接返回。
对于name不是&开头的名字,判断如果不是FactoryBean类型的实例,则直接返回,如果是FactoryBean类型的实例,则交给getObjectFromFactoryBean方法来创建实例对象。
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 如果是单例模式
if (factory.isSingleton() && containsSingleton(beanName)) {
// 多个线程同时来创建就要进行控制,保证单例
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 执行getObject()方法,返回的object不可能为null(会返回NullBean)
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
return object;
}
beforeSingletonCreation(beanName);
try {
// getObject()方法返回的对象进行后置处理
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
在上面这个方法中判断如果是单例模式,则调用
doGetObjectFromFactoryBean方法创建一次实例对象,之后则是从factoryBeanObjectCache缓存对象中获取,以便于下次复用。接下来判断如果需要后置处理,那么则根据单例创建前、创建单例、单例创建后的顺序,依次执行后置处理逻辑。
doGetObjectFromFactoryBean又把创建对象的责任下派到doGetObjectFromFactoryBean方法。
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
最终看到Spring使用的是实现FactoryBean接口的实现类的getObject方法来获取对象。
- 获取单例
在doGetBean方法中首先使用getSingleton(String beanName)获取beanName对应类型的实例对象。如果没有从缓存中获取到beanName对应类型的实例对象,则执行对象创建逻辑。其中在创建单例的时候,使用重载方法getSingleton(String beanName, ObjectFactory<?> singletonFactory)来获取单例对象。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
// 单例池对象需要同步锁定。
synchronized (this.singletonObjects) {
// 检查单例池中是否已经创建过。
Object singletonObject = this.singletonObjects.get(beanName);
// 如果没有创建过,才执行创建逻辑。
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
// 添加到单例池
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
这个代码使用到了回调方法,使得可以在单例创建前beforeSingletonCreation(beanName)把当前创建的beanName加入到
singletonsCurrentlyInCreation这个变量中,singletonsCurrentlyInCreation作用就是在于判断是否产生了循环依赖。而真正创建单例对象不是在这个方法中实现的,是在ObjectFactory类型的实例singletonFactory中实现的。addSingleton(beanName, singletonObject)方法把创建的singletonObject放入单例池singletonObjects变量中,以及放入注册单例beanName的集合registeredSingletons中,并且从singletonFactories中删除beanName对应的ObjectFactory,删除earlySingletonObjects变量中beanName对应的对象。addSingleton相关代码如下:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
bean对象的创建是在getSingleton方法中传入的ObjectFactory类型的lamda表达式,重写的getObject方法中的createBean方法实现的。
- 准备创建bean
让我们看看createBean方法函数中做了哪些准备工作。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// 马上就要实例化Bean了,确保beanClass被加载了
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// 验证及准备覆盖的方法。
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// 实例化前
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 {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
这个方法主要做的工作如下:
- 把beanName对应的类加载到类加载器中,并且返回Class对象。
- 对override属性进行标记及验证。
对于方法的匹配来讲,如果一个类中存在若干个重载方法,在函数调用及增强的时候还要根据参数类型进行匹配,来最终确认当前调用的到底是哪个函数。Spring把其中一部分匹配工作在这个方法里完成了。如果当前类中的方法只有1个,那么就设置没有重载方法,这样在后续调用的时候就可以直接使用找到的方法,而不需进行方法的参数匹配验证了,而且还可以对方法的存在性进行验证,可谓是一箭双雕。
- 实例化的前置处理。
在真正调用doCreateBean方法创建bean的实例前调用了
resolveBeforeInstantiation(beanName, mbdToUse)这个方法,该方法可以在实例化前和初始化后对BeanDefinition中的属性做一些调整,用户可以通过实现Spring中开放的接口,来灵活配置自己的业务逻辑。这个函数中有一个很重要的短路判断。
if (bean != null) {
return bean;
}
当经过实例化前解析之后返回的bean对象不为空,那么将直接返回,忽略掉后续的doCreateBean的创建逻辑。
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// synthetic表示合成,如果某些Bean是合成的,那么则不会经过BeanPostProcessor的处理
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
这个方法中最重要的是
applyBeanPostProcessorsBeforeInstantiation和applyBeanPostProcessorsAfterInitialization这两个方法。它们分别对bean实例化前和初始化后进行一些处理。
- 循环依赖
Spring将循环依赖分为三种情况进行解决:构造器循环依赖、setter循环依赖、prototype范围的依赖处理。下面分别来分析一下:
- 构造器循环依赖
通过构造器注入产生的循环依赖是无法解决的,只能抛出
BeanCurrentlyInCreationException。Spring将当前正在创建的每一个bean,如果是单例放在singletonsCurrentlyInCreation变量中,如果是prototype放在prototypesCurrentlyInCreation中。程序判断如果这些变量里有记录,则认为依赖的实例还没有创建好。bean创建好之后,则会从这些变量中删除对应的记录。