5.5 准备创建bean

5.5  准备创建bean

 

  我们不可能指望在一个函数中完成一个复杂的逻辑,而且我们跟踪了这么多Spring代码,经历了这么多函数,或多或少也发现了一些规律:一个真正干活的函数其实是以do开头的,比如doGetObjectFromFactoryBean;而给我们错觉的函数,比如getObjectFromFactoryBean,其实只是从全局角度去做些统筹的工作。这个规则对于createBean也不例外,那么让我们看看在createBean函数中做了哪些准备工作。

 

 1 protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)    throws BeanCreationException {
 2 
 3          if (logger.isDebugEnabled()) {
 4              logger.debug("Creating instance of bean '" + beanName + "'");
 5          }
 6          //锁定class,根据设置的class属性或者根据className来解析Class
 7          resolveBeanClass(mbd, beanName);
 8 
 9          //验证及准备覆盖的方法
10          try {
11              mbd.prepareMethodOverrides();
12          }
13          catch (BeanDefinitionValidationException ex) {
14              throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
15                      beanName, "Validation of method overrides failed", ex);
16          }
17 
18          try {
19              //给BeanPostProcessors一个机会来返回代理来替代真正的实例
20              Object bean = resolveBeforeInstantiation(beanName, mbd);
21              if (bean != null) {
22                  return bean;
23              }
24          }
25          catch (Throwable ex) {
26              throw new BeanCreationException(mbd.getResourceDescription(), beanName,
27                      "BeanPostProcessor before instantiation of bean failed", ex);
28          }
29 
30          Object beanInstance = doCreateBean(beanName, mbd, args);
31          if (logger.isDebugEnabled()) {
32              logger.debug("Finished creating instance of bean '" + beanName + "'");
33          }
34          return beanInstance;
35      }

 

从代码中我们可以总结出函数完成的具体步骤及功能。

1)根据设置的class属性或者根据className来解析Class

2)对override属性进行标记及验证。

很多读者可能会不知道这个方法的作用,因为在Spring的配置里面根本就没有诸如override-method之类的配置,那么这个方法到底是干什么用的呢?

其实在Spring中确实没有override-method这样的配置,但是如果读过前面的部分,可能会有所发现,在Spring配置中是存在lookup-methodreplace-method的,而这两个配置的加载其实就是将配置统一存放在BeanDefinition中的methodOverrides属性里,而这个函数的操作其实也就是针对于这两个配置的。

3)应用初始化前的后处理器,解析指定bean是否存在初始化前的短路操作。

4)创建bean

我们首先查看下对override属性标记及验证的逻辑实现。

 

处理ovverride属性

 

查看源码中AbstractBeanDefinition类的prepareMethodOverrides方法:

 

 1 public void prepareMethodOverrides() throws BeanDefinitionValidationException {
 2          // Check that lookup methods exists.
 3          MethodOverrides methodOverrides = getMethodOverrides();
 4          if (!methodOverrides.isEmpty()) {
 5              for (MethodOverride mo : methodOverrides.getOverrides()) {
 6                  prepareMethodOverride(mo);
 7              }
 8          }
 9 }
10   protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
11      //获取对应类中对应方法名的个数
12          int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
13          if (count == 0) {
14              throw new BeanDefinitionValidationException(
15                      "Invalid method override: no method with name '" + mo.getMethodName() +
16                      "' on class [" + getBeanClassName() + "]");
17          }
18          else if (count == 1) {
19              //标记MethodOverride暂未被覆盖,避免参数类型检查的开销。
20              mo.setOverloaded(false);
21          }
22 }

 

  通过以上两个函数的代码你能体会到它所要实现的功能吗?之前反复提到过,在Spring置中存在lookup-methodreplace-method两个配置功能,而这两个配置的加载其实就是将配置统一存放在BeanDefinition中的methodOverrides属性里,这两个功能实现原理其实是在bean实例化的时候如果检测到存在methodOverrides属性,会动态地为当前bean生成代理并使用对应的拦截器为bean做增强处理,相关逻辑实现在bean的实例化部分详细介绍。

  但是,这里要提到的是,对于方法的匹配来讲,如果一个类中存在若干个重载方法,那么,在函数调用及增强的时候还需要根据参数类型进行匹配,来最终确认当前调用的到底是哪个函数。但是,Spring将一部分匹配工作在这里完成了,如果当前类中的方法只有一个,那么就设置重载该方法没有被重载,这样在后续调用的时候便可以直接使用找到的方法,而不需要进行方法的参数匹配验证了,而且还可以提前对方法存在性进行验证,正可谓一箭双雕。

5.5.2  实例化的前置处理

  在真正调用doCreate方法创建bean的实例前使用了这样一个方法resolveBeforeInstantiation (beanName, mbd)BeanDefinigiton中的属性做些前置处理。当然,无论其中是否有相应的逻辑实现我们都可以理解,因为真正逻辑实现前后留有处理函数也是可扩展的一种体现,但是,这并不是最重要的,在函数中还提供了一个短路判断,这才是最为关键的部分。

 

if (bean != null) {return bean;
}

 

  当经过前置处理后返回的结果如果不为空,那么会直接略过后续的Bean的创建而直接返回结果。这一特性虽然很容易被忽略,但是却起着至关重要的作用,我们熟知的AOP功能就是基于这里的判断的。

 

 1 protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
 2          Object bean = null;
 3 //如果尚未被解析
 4          if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
 5              // Make sure bean class is actually resolved at this point.
 6              if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAware BeanPostProcessors()) {
 7                  bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);
 8                  if (bean != null) {
 9                      bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
10                  }
11              }
12              mbd.beforeInstantiationResolved = (bean != null);
13          }
14          return bean;
15      }

 

  此方法中最吸引我们的无疑是两个方法applyBeanPostProcessorsBeforeInstantiation以及applyBeanPostProcessorsAfterInitialization。两个方法实现的非常简单,无非是对后处理器中的所有InstantiationAwareBeanPostProcessor类型的后处理器进行postProcessBeforeInstantiation方法和BeanPostProcessorpostProcessAfterInitialization方法的调用。

1.实例化前的后处理器应用

  bean的实例化前调用,也就是将AbsractBeanDefinition转换为BeanWrapper 前的处理。给子类一个修改BeanDefinition的机会,也就是说当程序经过这个方法后,bean可能已经不是我们认为的bean了,而是或许成为了一个经过处理的代理bean,可能是通过cglib生成的,也可能是通过其它技术生成的。这在第7章中会详细介绍,我们只需要知道,在bean的实例化前会调用后处理器的方法进行处理。

 

 1   protected Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName)
 2              throws BeansException {
 3 
 4          for (BeanPostProcessor bp : getBeanPostProcessors()) {
 5              if (bp instanceof InstantiationAwareBeanPostProcessor) {
 6                  InstantiationAwareBeanPostProcessor ibp = (Instantiation AwareBean PostProcessor) bp;
 7                  Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
 8                  if (result != null) {
 9                      return result;
10                  }
11              }
12          }
13          return null;
14      }

 

2.实例化后的后处理器应用

  在讲解从缓存中获取单例bean的时候就提到过,Spring中的规则是在bean的初始化后尽可能保证将注册的后处理器的postProcessAfterInitialization方法应用到该bean中,因为如果返回的bean不为空,那么便不会再次经历普通bean的创建过程,所以只能在这里应用后处理器的postProcessAfterInitialization方法。

 

 1 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
 2              throws BeansException {
 3 
 4          Object result = existingBean;
 5          for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
 6              result = beanProcessor.postProcessAfterInitialization(result, beanName);
 7              if (result == null) {
 8                  return result;
 9              }
10          }
11          return result;
12      } 

 

 

 

 

 

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/299983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

***教程十:数据库注入(上)

这一段的教程是笔者(这里应该叫整理者)由《***X档案》的教程中整理改编而来。不知道是什么时候,B/S结构的软件越来越普及。工程师们为了应对“用户皆白痴”的服务理念(就是把用户想像成什么都不会),所以更加…

服务器精益改善系列,精益生产改善的内容是什么?

精益生产管理改善的内容包含了生产管理过程中的方方面面,如果可以准确理解的话,请从以下三个方面来理解:首先是精益生产管理六大产出,即PQCDSM,就是精益生产管理改善的第一层内容。其中PQCDSM分别代表了P:P…

当代大学查寝奇葩操作大赏 | 今日最佳

全世界只有3.14 %的人关注了青少年数学之旅(图源 阿粪青,侵权删)

mysql学习笔记之mysqlparameter(摘)

在.net中操作数据库的时候。 大家都喜欢用sqlparameter。 parameter是预编译的,可以加快速度,也可以防注入。 在使用mssql的时候用sqlparameter。 在使用mysql的时候使用mysqlparameters。 第一次使用mysql的时候,都经常犯一个错误 比如在使用…

.net LTS3.1升5.0和LTS6.0隐蔽的坑

下面这段代码就是把ascll为0到127值 &#xff0c;转成string&#xff0c;并判断在字符串中的位置&#xff0c;第5&#xff0c;6行代码分别用了两种IndexOf方法的重载。for (var i 0; i < 128; i) {var str1 ((char)i).ToString();var str2 $"---------------{str1}-…

Java正则表达式获取网页所有网址和链接文字

/*获取网址首页的所有网址和链接文字*/import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.MalformedURLException;import java.net.URL;import java.util.ArrayList;import java.util.HashMap;import java.util.Lis…

戴尔服务器远程管理卡端口修改,dell服务器远程管理卡的配置和应用(10页)-原创力文档...

DELL服务器远程管理卡的配置和应用适用于DELL PowerEdge 2950及以上机型目标一&#xff1a;停电或者断电后&#xff0c;通电自动启动设置方法&#xff1a;开机按F2键&#xff0c;在CMOS中找到AC Power Recovery "选项设置为 ON ”。意思说 把服务器的开机选项设置为一通电…

用IStateManager管理状态

/Files/nanshouyong326/CumstomControlIstaeManager.rar 还有Bug就是不能用VS的设计器Html方式声明控件&#xff0c;郁闷&#xff01;

学习烂到留级,却凭着正经发表的第一篇论文,优雅斩获诺贝尔奖

全世界只有3.14 %的人关注了青少年数学之旅照片里的男人&#xff0c;得意但很谦逊&#xff0c;他是诺贝尔化学奖创设以来最年轻得主——田中耕一。诺贝尔奖通知的那一天 叮铃叮铃叮铃......正在加班的田中耕一掏出手机&#xff0c;这是一个陌生的跨洋电话。电话那头的外国人…

CakePHP Pagination (分頁功能) 加入自己的參數

如果還不知道什麼是 Pagination 或者還不了解如何使用&#xff0c;請參考&#xff1a; CakePHP Pagination (分頁功能) 。通常在管理後台實作時&#xff0c;常設定許多查詢條件來查詢資料&#xff0c;比如&#xff1a;起始、結束時間。通常這些參數都是用GET的方式在傳遞。以下…

基于事件驱动架构构建微服务第2部分:领域对象和业务规则

原文链接&#xff1a;https://logcorner.com/building-microservices-through-event-driven-architecture-part2-domain-objects-and-business-rules/在本文中&#xff0c;我将实现领域模型&#xff1a;EduSync.Speech.Domain这是包含核心域的最内层。它包含我们的领域对象和业…

/etc/sudoers中的含义

Sudo 是允许系统管理员让普通用户执行一些或者全部的root 命令的一个工具&#xff0c;如halt&#xff0c;reboot&#xff0c;su 等等。这样不仅减少了root 用户的登陆 和管理时间&#xff0c;同样也提高了安全性。Sudo 不是对shell 的一个代替&#xff0c;它是面向每个命令的。…

qt客户端连接服务器不响应,qt判断tcp客户端是否连接服务器

qt判断tcp客户端是否连接服务器 内容精选换一换本章节指导您使用MongoDB客户端&#xff0c;通过弹性云服务器内网方式连接GaussDB(for Mongo)集群实例。操作系统使用场景&#xff1a;弹性云服务器的操作系统以Linux为例&#xff0c;客户端本地使用的计算机系统以Windows为例。目…

asp版新闻发布今日弄好

感谢组长帮忙弄好了新闻发布的删除功能&#xff0c;组长自己那么多事&#xff0c;而且又是凌晨二点&#xff0c;仍过来帮我解决问题。太感激了。。。。最近特别忙&#xff0c;也让我多了些怨天尤人的感慨。其实还是自己的原因&#xff0c;如果我能力足够强的话&#xff0c;会轻…

谈谈为什么我们需要云原生架构?

未来的软件&#xff0c;从诞生起&#xff0c;就是生在云上&#xff0c;长在云上的。这个说法绝对不是没有根据的&#xff0c;看看现在的互联网大厂在做的事情&#xff0c;你就知道了&#xff1a;阿里宣布成立云原生技术委员会&#xff0c;并投入数十亿大力推动阿里经济体全面云…

用SQL Server Compact Edition创建移动应用程序 【转载】

本文转载自 http://www.bccn.net/Article/sjk/sqlserver/jszl/200709/6545.html 这个文档比较完整地介绍了在移动开发中&#xff0c;如何实现对SQL Server数据库的合并订阅。收藏一下先&#xff0c;在用的时候仔细看一下即可。转载于:https://www.cnblogs.com/chenxizhang/arch…

服务器系统设计方案,服务器集群方案设计

当前主流的集群方式包括以下几种&#xff1a;1.服务器主备集群方式服务器主-备方式由一台服务器在正常运行状态提供对外服务&#xff0c;其它集群节点作为备份机&#xff0c;备份机在正常状态下不接受外部的应用请求&#xff0c;实时对生产机进行检测&#xff0c;当生产机停机时…

第2天.make的学习(第二部分)对伪目标的理解

一、目标&#xff0c;依赖&#xff0c;命令也许大家觉得这个不重要&#xff0c;但今天我有了新的认识&#xff0c;所以写了下来。这三个就是Makefile的全部&#xff0c;但今天我要重点说一下它的执行顺序。每个Makefile都有且只有一个终极目标&#xff0c;下设若干子目标&#…

ASP.NET(c#)常用类函数

常用函数系列: public static string Get_ClientIP() 得到客户端IP public static string Get_CMac(string IP) 得到客户端 CMac 地址 public static string RequestF(string xPName,string xPType,int xLenDef) 安全接收数据系列 public static string Show_Cont(string xStr)…

快别发语音了! | 今日最佳

全世界只有3.14 %的人关注了青少年数学之旅&#xff08;图源千叶的堕天使绅士猫_呜喵0w0&#xff0c;侵权删&#xff09;我们无论遇到什么困难&#xff0c;都不要怕&#xff0c;微笑着面对它&#xff01;消除恐惧的最好方法就是面对恐惧&#xff01;