本篇文章是“Spring IOC 容器源码分析”系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bean 作最后的初始化工做。相较于以前几篇文章所分析的源码,initializeBean 的源码相对比较简单,你们能够愉快的阅读。好了,其余的很少说了,咱们直入主题吧。java
本章咱们来分析一下 initializeBean 方法的源码。在完成分析后,仍是像往常同样,把方法的执行流程列出来。好了,看源码吧:app
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { // 若 bean 实现了 BeanNameAware、BeanFactoryAware、BeanClassLoaderAware 等接口,则向 bean 中注入相关对象 invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // 执行 bean 初始化前置操做 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { /* * 调用初始化方法: * 1. 若 bean 实现了 InitializingBean 接口,则调用 afterPropertiesSet 方法 * 2. 若用户配置了 bean 的 init-method 属性,则调用用户在配置中指定的方法 */ invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { // 执行 bean 初始化后置操做,AOP 会在此处向目标对象中织入切面逻辑 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
以上就是 initializeBean 方法的逻辑,很简单是否是。该方法作了以下几件事情:ide
在上面的流程中,咱们又发现了后置处理器的踪迹。若是你们阅读过 Spring 的源码,会发现后置处理器在 Spring 源码中屡次出现过。后置处理器是 Spring 拓展点之一,经过实现后置处理器 BeanPostProcessor 接口,咱们就能够插手 bean 的初始化过程。好比你们所熟悉的 AOP 就是在后置处理 postProcessAfterInitialization 方法中向目标对象中织如切面逻辑的。关于“前置处理”和“后置处理”相关的源码,这里就不分析了,你们有兴趣本身去看一下。接下来分析一下 invokeAwareMethods 和 invokeInitMethods 方法,以下:源码分析
private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { // 注入 beanName 字符串 ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { // 注入 ClassLoader 对象 ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader()); } if (bean instanceof BeanFactoryAware) { // 注入 BeanFactory 对象 ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } }
invokeAwareMethods 方法的逻辑很简单,一句话总结:根据 bean 所实现的 Aware 的类型,向 bean 中注入不一样类型的对象。post
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable { // 检测 bean 是不是 InitializingBean 类型的 boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { @Override public Object run() throws Exception { ((InitializingBean) bean).afterPropertiesSet(); return null; } }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { // 若是 bean 实现了 InitializingBean,则调用 afterPropertiesSet 方法执行初始化逻辑 ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null) { String initMethodName = mbd.getInitMethodName(); if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { // 调用用户自定义的初始化方法 invokeCustomInitMethod(beanName, bean, mbd); } } }
invokeInitMethods 方法用于执行初始化方法,也不复杂,就很少说了。this
本篇文章到这里差很少就分析完了,总的来讲本文的内容比较简单,很容易看懂。正如简介一章中所说,本篇文章是个人“Spring IOC 容器源码分析”系列文章的最后一篇文章。写完这本篇文章,有种如释重负的感受。我在5月15号写完 Java CAS 原理分析 文章后,第二天开始阅读 Spring IOC 部分的源码,阅读该部分源码花了大概两周的时间。而后在5月30号发布了“Spring IOC 容器源码分析”系列文章的第一篇文章 Spring IOC 容器源码分析系列文章导读。在写完第一篇文章后,就开启了快速更新模式,以平均2天一篇的速度进行更新。终于在今天,也就是6月11号写完了最后一篇。这一段时间写文章写的很累,常常熬夜。主要的缘由在于,在本身看懂源码的同时,经过写文章的方式尽可能保证别人也能看懂的话,这个就比较难了。好比我在阅读源码的时候,在源码上面写了一些简单的注释。这些注释我能够看懂,但若是想写成文章,则须要把注释写的尽可能详细,必要的背景知识也要介绍一下。总的来讲,认真写一篇技术文章仍是不容易的。写文章尚如此,那写书呢,想必更加辛苦了。我在阅读源码和写文章的过程当中,也参考了一些资料(相关资料在“导读”一文中指明了出处,本文就再也不次说明)。在这里,向这些资料的做者表示感谢!spa
好了,本篇文章就到这里了,感谢你们的阅读。debug
本文在知识共享许可协议 4.0 下发布,转载需在明显位置处注明出处
做者:coolblog.xyz
本文同步发布在个人我的博客: http://www.coolblog.xyz
更新时间 | 标题 |
---|---|
2018-05-30 | Spring IOC 容器源码分析系列文章导读 |
2018-06-01 | Spring IOC 容器源码分析 - 获取单例 bean |
2018-06-04 | Spring IOC 容器源码分析 - 建立单例 bean 的过程 |
2018-06-06 | Spring IOC 容器源码分析 - 建立原始 bean 对象 |
2018-06-08 | Spring IOC 容器源码分析 - 循环依赖的解决办法 |
2018-06-11 | Spring IOC 容器源码分析 - 填充属性到 bean 原始对象 |
2018-06-11 | Spring IOC 容器源码分析 - 余下的初始化工做 |
更新时间 | 标题 |
---|---|
2018-06-17 | Spring AOP 源码分析系列文章导读 |
2018-06-20 | Spring AOP 源码分析 - 筛选合适的通知器 |
2018-06-20 | Spring AOP 源码分析 - 建立代理对象 |
2018-06-22 | Spring AOP 源码分析 - 拦截器链的执行过程 |
更新时间 | 标题 |
---|---|
2018-06-29 | Spring MVC 原理探秘 - 一个请求的旅行过程 |
2018-06-30 | Spring MVC 原理探秘 - 容器的建立过程 |
本做品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。代理