项目
博客
文档
归档
资源链接
关于我
项目
博客
文档
归档
资源链接
关于我
【Spring】—— IoC 之加载 Bean:创建 Bean(六)之初始化 Bean 对象
2020-12-05
·
芋道源码
·
转载
·
·
本文共 607个字,预计阅读需要 3分钟。
> `转载`于【[芋道源码](http://svip.iocoder.cn/)】 > 本文主要基于 Spring 5.0.6.RELEASE 一个 bean 经历了 `#createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)` 方法,被创建出来,然后又经过一番属性注入,依赖处理,历经千辛万苦,千锤百炼,终于有点儿 bean 实例的样子,能堪大任了,只需要经历最后一步就破茧成蝶了。 这**最后一步**就是初始化,也就是 `#initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)` 方法。所以,这篇文章我们分析 `#doCreateBean(...)` 方法的中最后一步:初始化 bean 对象。 ## 1. initializeBean ``` // AbstractAutowireCapableBeanFactory.java protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { // 安全模式 AccessController.doPrivileged((PrivilegedAction
) () -> { // <1> 激活 Aware 方法,对特殊的 bean 处理:Aware、BeanClassLoaderAware、BeanFactoryAware invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { // <1> 激活 Aware 方法,对特殊的 bean 处理:Aware、BeanClassLoaderAware、BeanFactoryAware invokeAwareMethods(beanName, bean); } // <2> 后处理器,before Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } // <3> 激活用户自定义的 init 方法 try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } // <2> 后处理器,after if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; } ``` 初始化 bean 的方法其实就是三个步骤的处理,而这三个步骤主要还是根据**用户设定**的来进行初始化,这三个过程为: - `<1>` 激活 Aware 方法。 - `<3>` 后置处理器的应用。 - `<2>` 激活自定义的 init 方法。 ### 1.1 激活 Aware 方法 Aware ,英文翻译是意识到的,感知的。Spring 提供了诸多 Aware 接口,用于辅助 Spring Bean 以编程的方式调用 Spring 容器,通过实现这些接口,可以增强 Spring Bean 的功能。 Spring 提供了如下系列的 Aware 接口: - LoadTimeWeaverAware:加载Spring Bean时织入第三方模块,如AspectJ - BeanClassLoaderAware:加载Spring Bean的类加载器 - BootstrapContextAware:资源适配器BootstrapContext,如JCA,CCI - ResourceLoaderAware:底层访问资源的加载器 - BeanFactoryAware:声明BeanFactory - PortletConfigAware:PortletConfig - PortletContextAware:PortletContext - ServletConfigAware:ServletConfig - ServletContextAware:ServletContext - MessageSourceAware:国际化 - ApplicationEventPublisherAware:应用事件 - NotificationPublisherAware:JMX通知 - BeanNameAware:声明Spring Bean的名字 ------ `#invokeAwareMethods(final String beanName, final Object bean)` 方法,代码如下: ``` // AbstractAutowireCapableBeanFactory.java private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { // BeanNameAware if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } // BeanClassLoaderAware if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } // BeanFactoryAware if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } } ``` 这里代码就没有什么好说的,主要是处理 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 。 关于 Aware 接口,后面会专门出篇文章对其进行详细分析说明的。 ### 1.2 后置处理器的应用 BeanPostProcessor 在前面介绍 bean 加载的过程曾多次遇到,相信各位不陌生,这是 Spring 中开放式框架中必不可少的一个亮点。 BeanPostProcessor 的作用是:如果我们想要在 Spring 容器完成 Bean 的实例化,配置和其他的初始化后添加一些自己的逻辑处理,那么请使用该接口,这个接口给与了用户充足的权限去更改或者扩展 Spring,是我们对 Spring 进行扩展和增强处理一个必不可少的接口。 - `#applyBeanPostProcessorsBeforeInitialization(...)` 方法,代码如下: ``` // AbstractAutowireCapableBeanFactory.java @Override public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; // 遍历 BeanPostProcessor 数组 for (BeanPostProcessor processor : getBeanPostProcessors()) { // 处理 Object current = processor.postProcessBeforeInitialization(result, beanName); // 返回空,则返回 result if (current == null) { return result; } // 修改 result result = current; } return result; } ``` - `#applyBeanPostProcessorsAfterInitialization(...)` 方法,代码如下: ``` // AbstractAutowireCapableBeanFactory.java @Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; // 遍历 BeanPostProcessor for (BeanPostProcessor processor : getBeanPostProcessors()) { // 处理 Object current = processor.postProcessAfterInitialization(result, beanName); // 返回空,则返回 result if (current == null) { return result; } // 修改 result result = current; } return result; } ``` 其实,逻辑就是通过 `#getBeanPostProcessors()` 方法,获取定义的 BeanPostProcessor ,然后分别调用其 `#postProcessBeforeInitialization(...)`、`#postProcessAfterInitialization(...)` 方法,进行**自定义**的业务处理。 ### 1.3 激活自定义的 init 方法 如果熟悉 `
` 标签的配置,一定不会忘记 `init-method` 方法,该方法的执行就是在这里执行的。代码如下: ``` // AbstractAutowireCapableBeanFactory.java protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { // 首先会检查是否是 InitializingBean ,如果是的话需要调用 afterPropertiesSet() boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isTraceEnabled()) { logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { // 安全模式 try { AccessController.doPrivileged((PrivilegedExceptionAction
) () -> { // <1> 属性初始化的处理 ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { // <1> 属性初始化的处理 ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { // <2> 激活用户自定义的初始化方法 invokeCustomInitMethod(beanName, bean, mbd); } } } ``` - 首先,检查是否为 InitializingBean 。如果**是**的话,需要执行 `#afterPropertiesSet()` 方法,因为我们除了可以使用 `init-method` 来自定初始化方法外,还可以实现 InitializingBean 接口。接口仅有一个 `#afterPropertiesSet()` 方法。 - 两者的执行先后顺序是先 `<1>` 的 `#afterPropertiesSet()` 方法,后 `<2>` 的 `init-method` 对应的方法。 ## 2. 小结 关于这篇博客的三个方法,LZ 后面会单独写博客来进行分析说明。 经过六篇博客终于把 Spring 创建 bean 的过程进行详细说明了,过程是艰辛的,但是收获很大,关键还是要耐着性子看。