Spring 中 initializeBean 详解

267 阅读4分钟

「这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战

1.前言

主要作用:初始化给定的bean实例,应用工厂回调以及初始化方法和bean后处理器。

这个方法在spring 容器初始化调用的位置: org.springframework.context.support.AbstractApplicationContext#refresh --》 org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization --》 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons --》 org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String) --》 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean --》 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[]) --》 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean --》 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)

2.源码讲解

2.1 initializeBean 方法

图片.png

  • 首先它会判断 系统的安全管理器是不是为null,如果不为null 调用 AccessController.doPrivileged(...)(这里它的主要作用,就是获取一个特权,绕开权限检查)。然后执行 invokeAwareMethods(beanName, bean),如果是null,则直接调用 invokeAwareMethods(beanName, bean)
  • invokeAwareMethods(beanName, bean) :这里主要处理,实现Aware接口对bean的设置,详解见 2.2
  • 获取bean 的 副本 wrapperBean
  • 判断当 mbd == null || mbd的定义不是合成的,即程序本身定义的
    • 执行 applyBeanPostProcessorsBeforeInitialization:主要就是执行指定bean实例,执行postProcessBeforeInitialization 方法,详解见 2.3
  • 执行 invokeInitMethods(beanName,wrappedBean,mbd) 方法:如果bean实现了InitializingBean或者用户自定义的init方法方法,那么调用这些初始化方法对bean的属性进行一些个性化设置,详解见 2.4
  • 最后判断当 mbd == null || mbd的定义不是合成的,即程序本身定义的
    • 执行 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName):主要执行后置处理器的postProcessAfterInitialization方法 详解见 2.5

2.2 invokeAwareMethods(beanName, bean)

这里主要就是处理实现了 Aware 接口 对bean的设置 图片.png 其实这部分代码也很简单,我们可以看到主要就是 bean 实现了不同类型的 aware 接口,就给他做一些对应的处理。如实现了 BeanNameAware 就设置一下 它的beanName。 如实现了 BeanClasssLoaderAware 就对应的设置一下 bean 的classLoader。如实现了 BeanFactoryAware 就设置一下bean 的 BeanFactory。这些相当于是对bean 做了一个增强处理。

2.3 applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)

图片.png 这里就是取出所有的 BeanPostProcessors 调用它们的 postProcessBeforeInitialization(主要是用来做一些bean 初始化前的操作) 方法,返回一个 current 对象,当 current 不为null 则把它赋给 result,接着遍历调用,否则返回 result。

下图列举了一些 ,spring中 BeanPostProcessor,这里不同类型的 BeanPostProcessor 对该方法有不同的实现。我们也可以重写这个方法,做一些自定义的设置 图片.png

2.4 invokeInitMethods(beanName,wrappedBean,mbd)

图片.png

  • 首先 判断bean 是不是 InitializingBean 的实例类: initMethodName &&
  • mbd.isExternallyManagedInitMethod("afterPropertiesSet") : 判断有没有名为 afterPropertiesSet 这个外部管理的初始化方法 图片.png 图片.png
  • 当 bean 是 InitializingBean 的实例类 && mbd没有名为 afterPropertiesSet 的外部管理的初始化方法
    • 如果系统安全策略管理器不为null,给它开个特权,执行 ((InitializingBean) bean).afterPropertiesSet() 这个方法,主要作用 : 在 bean 属性设置后调用,此方法允许bean实例对其整体性能进行验证,设置所有bean属性后的配置和最终初始化,在配置错误时会抛出异常。
    • ((InitializingBean) bean).afterPropertiesSet()的实现有很多这里截取一小部分。 图片.png
  • 当 mbd != null && bean的类型不是 NullBean
    • 获取mbd 的初始化方法的方法名:initMethodName
    • 当 initMethodName 不是(null或"") && !( initMethodName && initMethodName不等于"afterPropertiesSet") && initMethodName不是 mbd 的外部管理初始化方法
      • 执行 invokeCustomInitMethod(beanName, bean, mbd) 方法。
      • invokeCustomInitMethod:在给定bean上调用指定的自定义init方法。详解见 2.6

2.5 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)

主要执行后置处理器的postProcessAfterInitialization方法 图片.png 这里就是取出所有的 BeanPostProcessors 调用它们的 postProcessAfterInitialization(主要是用来做一些bean 初始化前的操作) 方法,返回一个 current 对象,当 current 不为null 则把它赋给 result,接着遍历调用,否则返回 result。

主要实现类如下: 图片.png

2.6 invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)

在给定bean上调用指定的自定义init方法。由invokeInitMethods调用。 可以在子类中重写以自定义init解析,具有参数的方法。

图片.png

  • 首先获取它的初始化方法名 : initMethodName

  • isNonPublicAccessAllowed():返回是否允许访问非公共构造函数和方法。 图片.png

  • 如果允许的话调用 BeanUtils.findMethod(bean.getClass(), initMethodName) 不允许的话调用 ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName)

  • BeanUtils.findMethod(bean.getClass(), initMethodName) :查找具有给定方法名和给定参数类型的方法,该方法在给定类或其超类之一上声明。首选公共方法,但也会返回一个受保护的、包访问或私有方法。 图片.png

  • ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName):确定给定类是否有带有给定签名的公共方法,并在可用时返回该方法 图片.png

  • 当 initMethod 为null时

    • isEnforceInitMethod():表示配置的init方法是否为默认方法。 图片.png
    • 如果mbd.isEnforceInitMethod() == true 则抛出异常,即没找到可使用的初始化方法
    • 否则直接返回,外面使用配置的初始化方法
  • ClassUtils.getInterfaceMethodIfPossible(initMethod):为给定的方法句柄确定相应的接口方法。这对于在Jigsaw上获得一个公共导出类型特别有用,该类型可以反射调用,而不会发出非法访问警告。 图片.png

Jigsaw是OpenJDK项目下的一个子项目,旨在为Java SE平台设计、实现一个标准的模块系统,并应用到该平台和JDK中

  • 这里还是判断系统安全管理器是不是null,若不是null,给下面两个方法开个特权。
  • ReflectionUtils.makeAccessible(methodToInvoke):使给定的方法具有可访问性,必要时显式地将其设置为可访问性。(jdk 9 中 过期)
  • methodToInvoke.invoke(bean):执行bean 的初始化方法