bean 的加载(二)
之前文章主要对 getBean 方法进行简单的介绍,和 FactoryBean 的作用,以及是如何从缓存中获取 bean。本文继续讲解 bean 的加载流程。
从 bean 的实例中获取对象
在 getBean 方法里,getObjectForBeanInstance()
是个常用的方法,无论是从缓存中获取 bean 还是根据不同 scope 策略来加载 bean。总而言之,我们在获取到 bean 实例后第一步就是调用这个方法来检测正确性,其实就是检测当前 bean 是否为 FactoryBean 类型的 bean,如果是则调用 FactoryBean 实例的 getObject()作为返回值。
需要注意的是无论是缓存中获取到的 bean 还是通过 scope 策略加载的 bean 都是原始的 bean 状态,我们需要的是工厂 bean 中定义 factory-method 方法中返回的 bean,而 getObjectForBeanInstance 方法就是完成这个工作的。
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { //如果指定的name是工厂相关以"&"为前缀,并且beanInstance又不是FactoryBean则校验不通过 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; } //现在我们有了这个bean实例,这个实例可能是FactoryBean,也可能是正常的bean //如果是FactoryBean的话,我们使用它创建实例,但如果是用户想要直接获取工厂实例而不是工厂的getObject方法则需要在BeanName前加上"&" if (!(beanInstance instanceof FactoryBean)) { return beanInstance; } //加载FactoryBean Object object = null; if (mbd != null) { mbd.isFactoryBean = true; } else { //尝试从缓存中加载bean object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // 执行到这里表明beanInstance一定是一个FactoryBean FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // containsBeanDefinition检测BeanDefinitionMap中也就是在所有一键加载的类中检测是否定义beanName if (mbd == null && containsBeanDefinition(beanName)) { //将GenericBeanDefinition转换为RootBeanDefinition,如果指定BeanName是子bean的话同时会合并父类的属性 mbd = getMergedLocalBeanDefinition(beanName); } //是否是用户定义的而不是应用程序本身定义的 boolean synthetic = (mbd != null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; }
我们先看一下 getObjectForBeanInstance 主要做了什么:
- 对 FactoryBean 正确性进行验证
- 对非 FactoryBean 不作任何处理
- 对 bean 进行转换
- 将从 Factory 中解析 bean 的工作委托给了
getObjectFromFactoryBean
。
该段代码大多都是辅助代码,真正的核心代码委托给了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) { //重点方法 doGetObjectFromFactoryBean object = doGetObjectFromFactoryBean(factory, beanName); //...省略 } else { //重点方法 doGetObjectFromFactoryBean 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; } }
这段代码就是返回的 bean 如果是单例的则需要保证全局唯一,也正因为是单例的所以不必重复创建,可以用缓存来提高性能。
我们进入doGetObjectFromFactoryBean
方法中。
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final 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 { //直接调用getObject方法(重点) 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); } // Do not accept a null value for a FactoryBean that's not fully // initialized yet: Many FactoryBeans just return null then. 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; }
在该方法中,我们终于看到了想要看到的代码,也就是object = factory.getObject()
。之前我们已经讲过了 FactoryBean 的调用方法,如果 bean 是 FactoryBean 类型,则当提取 bean 时提取的并不是 factoryBean 而是 factoryBean 的 getObject 方法的返回值。
获取单例
之前我们说过如果缓存中不存在已经加载的 bean 则需要重头开始 bean 的加载,在 Spring 中使用 getSingleton 的重载方法实现了 bean 的加载过程。
getBean 方法:
// 实例化依赖的bean后就可以实例化mbd本身了 // 如果BeanDefinition为单例 if (mbd.isSingleton()) { //创建Bean实例对象,并且注册给所依赖的对象 sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { //从单例缓存中删除bean实例 //因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁 destroySingleton(beanName); throw ex; } }); //如果是普通bean,直接返回,如果是FactoryBean,则返回它的getObject bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
进入 getSingleton 方法:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); //加锁 synchronized (this.singletonObjects) { //首先检查对应的bean是否已经加载过, Object singletonObject = this.singletonObjects.get(beanName); //如果为空则需要进行singleton的bean初始化 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 + "'"); } //代码(1) beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 通过回调方式获取bean实例。 singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. 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; } //代码(2) afterSingletonCreation(beanName); } if (newSingleton) { //加入缓存 代码(3) addSingleton(beanName, singletonObject); } } return singletonObject; } }
上述代码使用了回调方法,在单例创建的前后做了些准备及处理操作,而真正获取单例 bean 的方法是在 ObjectFactory 类型的实例 singletonFactory 中。我们先看一下 getSingleton 方法主要做了什么:
- 检查缓存是否已经加载过
- 若没有加载,则记录 beanName 为正在加载状态
- 加载单例前记录加载状态,代码(1)
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
这个方法主要做的就是记录加载状态,this.singletonsCurrentlyInCreation.add(beanName)
将当前正要创建的 bean 记录在缓存中,这样就可以对循环依赖进行检测。
- 获取 bean 实例
- 调用加载单例后的处理方法,代码(2)
protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } }
和上述类似,只是这里是从缓存中移除 bean 的正在加载状态。
- 将 bean 加入缓存,并删除加载 bean 过程中所记录的各种辅助状态。
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 的逻辑架构,但是 bean 的加载逻辑是在传入 ObjectFactory 类型的参数 singletonFactory 中定义的。
//创建Bean实例对象,并且注册给所依赖的对象 sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { //从单例缓存中删除bean实例 //因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁 destroySingleton(beanName); throw ex; } });
我们进入 createBean 方法中继续查看。
准备创建 bean
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; // 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,根据设置的class属性或者根据className来解析Class 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. //给BeanPostProcessors一个机会来返回代理用于替代真正的实例 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 { //代码(1) Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("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); } }
- 根据设置的 class 属性或者根据 className 来解析 Class
- 对 override 属性进行标记及验证
我们知道在 Spring 的配置中并没有类似于 override-methdo 之类的配置,那么该方法的作用是什么?
我们之前说过 Spring 配置中存在 lookup-method 和 replace-method 的,这两个配置的加载就是将配置统一存放在 BeanDefinition 中的 methodOverrides 属性中,而这个函数其实也就是针对这两个配置的。
- 应用初始化前的后处理器,解析指定 bean 是否存在初始化前的短路操作
- 创建 bean
我们先看一下 override 属性标记及验证的逻辑实现
处理 override 属性
进入 prepareMethodOverrides 方法:
public void prepareMethodOverrides() throws BeanDefinitionValidationException { // Check that lookup methods exist and determine their overloaded status. if (hasMethodOverrides()) { getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride); } }
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException { // 获取对应类中对应方法名的个数 int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName()); if (count == 0) { throw new BeanDefinitionValidationException( "Invalid method override: no method with name '" + mo.getMethodName() + "' on class [" + getBeanClassName() + "]"); } else if (count == 1) { // Mark override as not overloaded, to avoid the overhead of arg type checking. // 标记MethodOverride暂未被覆盖,避免参数类型检查的开销 mo.setOverloaded(false); } }
刚才说到 lookup-method 和 replace-method 两个配置功能是统一存放在 BeanDefinition 中的 methodOverrides 属性中,这两个功能实现原理就是在 bean 实例化的时候如果检测到存在 methodOverrides 属性,就会动态地为当前 bean 生成代理并使用对应的拦截器对 bean 做增强处理。
需要提到的是,对于方法的匹配来说,如果一个类中有多个重载方法则需要根据参数类型进行匹配。如果类中只有方法只有一个那么就设置该方法没有被重载,这样在后续时候可以直接使用找到的方法,不需要进行方法的参数匹配验证,而且还可以提前对方法存在性进行验证,所谓一箭双雕。
实例化的前置处理
在调用 doCreateBean 之前,还使用了 resolveBeforeInstantiation(beanName, mbdToUse)方法对 BeanDefinition 中的属性做些前置处理。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; }
该段代码的重点就是这个 if 条件,当处理结果不为 null 的时候就会跳过后续 bean 的创建直接返回结果。我们熟知的 AOP 功能就是基于这里判断的。
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { Object bean = null; //如果还没被解析过,则解析 if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { // Make sure bean class is actually resolved at this point. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<?> targetType = determineTargetType(beanName, mbd); if (targetType != null) { //代码(1) bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); if (bean != null) { //代码(2) bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean != null); } return bean; }
该方法中的重点就是这两个方法:applyBeanPostProcessorsBeforeInstantiation、applyBeanPostProcessorsAfterInitialization。这两个方法实现都很简单,就是对后处理器中所有的 InstantiationAwareBeanPostProcessor 类型的后处理器进行 postProcessBeforeInstantiation 方法和 BeanPostProcessor 的 postProcessAfterInitialization 方法的调用。
1. 实例化前的后处理器应用
bean 的实例化前调用,也就是将 AbstractBeanDefinition 转换为 BeanWrapper 前的处理。给子类一个修改 BeanDefinition 的机会,也就是调用这个方法后 bean 就有可能产生变化,有可能是经过处理的代理 bean,也可能是 cglib 生成的。后续会详细介绍,现在只需要明白在 bean 实例化前会调用后处理器的方法进行处理。
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null) { return result; } } } return null; }
2. 实例化后的后处理器应用
Spring 的规则是在 bean 初始化后尽可能保证将注册的后处理器 postProcessAfterInitialization 方法应用到 bean 中,如果返回的 bean 不为空,则不需要再经历 bean 的创建过程。
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }