文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Spring源码之Bean实例化基本原理

2024-12-03 19:19

关注

创建Spring Bean实例化是Spring Bean生命周期的第一阶段

Bean的生命周期主要有如下几个步骤:

「详细介绍:Spring In Action是这样讲的:」

在实例化Bean之前在BeanDefinition里头已经有了所有需要实例化时用到的元数据,接下来Spring只需要选择合适的实例化方法以及策略即可。

「BeanDefinition」

Spring容器启动的时候会定位我们的配置文件,加载文件,并解析成Bean的定义文件BeanDefinition

右边的Map里存储这bean之间的依赖关系的定义BeanDefinition,比如OrderController依赖OrderService这种

实例化方法有两大类分别是工厂方法和构造方法实例化,后者是最常见的。其中Spring默认的实例化方法就是无参构造函数实例化。

如我们在xml里定义的以及用注解标识的bean都是通过默认实例化方法实例化的

实例化方法

「使静态工厂方法实例化」

  1. public class FactoryInstance { 
  2.  
  3.     public FactoryInstance() { 
  4.         System.out.println("instance by FactoryInstance"); 
  5.     } 
  1. public class MyBeanFactory { 
  2.  
  3.     public static FactoryInstance getInstanceStatic(){ 
  4.         return new FactoryInstance(); 
  5.     } 
  1. "1.0" encoding="UTF-8"?> 
  2. "http://www.springframework.org/schema/beans" 
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  4.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
  5.  
  6.     "factoryInstance" class="spring.service.instance.MyBeanFactory"  
  7.           factory-method="getInstanceStatic"/> 
  8.  

「使用实例工厂方法实例化」

  1. public class MyBeanFactory { 
  2.  
  3.      
  4.     public FactoryInstance getInstance() { 
  5.         return new FactoryInstance(); 
  6.     } 
  1. "1.0" encoding="UTF-8"?>  
  2. "http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">  
  5.     -- 工厂实例 -- >     
  6.     "myBeanFactory" class="MyBeanFactory"/>  
  7.     "factoryInstance" factory-bean="myBeanFactory" factory-method="getInstance"/>  
  8.   

「使用无参构造函数实例化(默认的)」

  1. public class ConstructorInstance { 
  2.  
  3.     public ConstructorInstance() { 
  4.         System.out.println("ConstructorInstance none args"); 
  5.     } 
  6.  
  1. "1.0" encoding="UTF-8"?> 
  2. "http://www.springframework.org/schema/beans" 
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  4.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
  5.     "constructorInstance" class="spring.service.instance.ConstructorInstance"/> 
  6.  

「使用有参构造函数实例化」

  1. public class ConstructorInstance { 
  2.  
  3.     private String name
  4.      
  5.     public ConstructorInstance(String name) { 
  6.         System.out.println("ConstructorInstance with args"); 
  7.         this.name = name
  8.     } 
  9.  
  10.     public String getName() { 
  11.         return name
  12.     } 
  13.  
  14.     public void setName(String name) { 
  15.         this.name = name
  16.     } 
  17.  
  1. "1.0" encoding="UTF-8"?> 
  2. "http://www.springframework.org/schema/beans" 
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  4.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
  5.         
  6.    "constructorInstance" class="spring.service.instance.ConstructorInstance"
  7.         index="0" name="name" value="test constructor with args"/> 
  8.      
  9.  

源码阅读

直接来看看doCreateBean方法

具体实现在AbstractAutowireCapableBeanFactory类里面。

我们这里只需关注第一步创建bean实例的流程即可

  1. instanceWrapper = createBeanInstance(beanName, mbd, args); 

上面代码就是spring 实现bean实例创建的核心代码。这一步主要根据BeanDefinition里的元数据定义决定使用哪种实例化方法,主要有下面三种:

「实例化策略(cglib or 反射)」

❝工厂方法的实例化手段没有选择策略直接用了反射实现的,所以这个实例化策略都是对于构造函数实例化而言的❞

下面选一个instantiateBean的实现来介绍


 

 

上面说到的两构造函数实例化方法不管是哪一种都会选一个实例化策略进行,到底选哪一种策略也是根据BeanDefinition里的定义决定的。

下面这一行代码就是选择实例化策略的代码

  1. beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); 

「选择使用反射还是cglib」

 

先判断如果beanDefinition.getMethodOverrides()为空也就是用户没有使用replace或者lookup的配置方法,那么直接使用反射的方式,简单快捷

但是如果使用了这两个特性,在直接使用反射的方式创建实例就不妥了,因为需要将这两个配置提供的功能切入进去,所以就必须要使用动态代理的方式将包含两个特性所对应的逻辑的拦截增强器设置进去,这样才可以保证在调用方法的时候会被相应的拦截器增强,返回值为包含拦截器的代理实例-----Spring源码深度解析

  1. "constructorInstance" class="spring.service.instance.ConstructorInstance" > 
  2.         name="getName" bean="xxx"/> 
  3.         name="getName" replacer="yyy"/> 
  4.      

如果使用了lookup或者replaced的配置的话会使用cglib,否则直接使用反射。

  1. public static final String LOOKUP_METHOD_ELEMENT = "lookup-method"
  2.  
  3. public static final String REPLACED_METHOD_ELEMENT = "replaced-method"

觉得不错,点个赞再走吧,谢谢

参考:

Spring源码深度解析

Spring In Action

 

https://url.ms/owy8p

本文转载自微信公众号「月伴飞鱼」,可以通过以下二维码关注。转载本文请联系月伴飞鱼公众号。

 

来源:月伴飞鱼 内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯