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

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

 [[346085]]

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

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

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

  • 实例化Bean对象,这个时候Bean的对象是非常低级的,基本不能够被我们使用,因为连最基本的属性都没有设置,可以理解为连Autowired注解都是没有解析的;
  • 填充属性,当做完这一步,Bean对象基本是完整的了,可以理解为Autowired注解已经解析完毕,依赖注入完成了;
  • 如果Bean实现了BeanNameAware接口,则调用setBeanName方法;
  • 如果Bean实现了BeanClassLoaderAware接口,则调用setBeanClassLoader方法;
  • 如果Bean实现了BeanFactoryAware接口,则调用setBeanFactory方法;
  • 调用BeanPostProcessor的postProcessBeforeInitialization方法;
  • 如果Bean实现了InitializingBean接口,调用afterPropertiesSet方法;
  • 如果Bean定义了init-method方法,则调用Bean的init-method方法;
  • 调用BeanPostProcessor的postProcessAfterInitialization方法;当进行到这一步,Bean已经被准备就绪了,一直停留在应用的上下文中,直到被销毁;
  • 如果应用的上下文被销毁了,如果Bean实现了DisposableBean接口,则调用destroy方法,如果Bean定义了destory-method声明了销毁方法也会被调用。

在实例化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. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans xmlns="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.     <bean id="factoryInstance" class="spring.service.instance.MyBeanFactory"  
  7.           factory-method="getInstanceStatic"/> 
  8. </beans> 

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

  1. public class MyBeanFactory { 
  2.  
  3.     /** 
  4.      * 实例工厂创建bean实例 
  5.      * 
  6.      * @return 
  7.      */ 
  8.     public FactoryInstance getInstance() { 
  9.         return new FactoryInstance(); 
  10.     } 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="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.     <bean id="myBeanFactory" class="MyBeanFactory"/>  
  7.     <bean id="factoryInstance" factory-bean="myBeanFactory" factory-method="getInstance"/>  
  8. </beans>  

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

  1. public class ConstructorInstance { 
  2.  
  3.     public ConstructorInstance() { 
  4.         System.out.println("ConstructorInstance none args"); 
  5.     } 
  6.  
  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans xmlns="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.     <bean id="constructorInstance" class="spring.service.instance.ConstructorInstance"/> 
  6. </beans> 

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

  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. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans xmlns="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.    <bean id="constructorInstance" class="spring.service.instance.ConstructorInstance"
  7.         <constructor-arg index="0" name="name" value="test constructor with args"/> 
  8.     </bean> 
  9. </beans> 

源码阅读

直接来看看doCreateBean方法

具体实现在AbstractAutowireCapableBeanFactory类里面。

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

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

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

  • instantiateUsingFactoryMethod 工厂方法实例化的具体实现
  • autowireConstructor 有参构造函数实例化的具体实现
  • instantiateBean 默认实例化具体实现(无参构造函数)

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

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

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


 

 

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

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

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

「选择使用反射还是cglib」

 

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

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

  1. <bean id="constructorInstance" class="spring.service.instance.ConstructorInstance" > 
  2.         <lookup-method name="getName" bean="xxx"/> 
  3.         <replaced-method name="getName" replacer="yyy"/> 
  4.     </bean> 

如果使用了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

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

 

责任编辑:武晓燕 来源: 月伴飞鱼
相关推荐

2012-01-12 14:37:34

jQuery

2011-11-29 12:17:00

2009-02-24 09:43:00

IP电话原理

2016-08-17 23:53:29

网络爬虫抓取系统

2021-02-08 21:40:04

SockmapBPF存储

2011-08-10 19:33:09

Cocoa对象

2016-08-18 00:04:09

网络爬虫抓取系统服务器

2013-04-07 14:09:55

Android应用基本

2010-08-20 13:29:33

OFDM

2019-11-28 10:45:28

ZooKeeper源码分布式

2020-03-21 14:57:14

手机定位智能手机APP

2010-03-17 13:35:02

2011-07-07 14:46:10

Cocoa Xcode

2010-03-18 20:13:03

Java socket

2011-07-07 14:10:21

Cocoa 内省 hash

2009-06-11 09:56:09

MySQL Repli原理

2020-12-29 16:55:44

ZooKeeper运维数据结构

2010-01-07 09:53:09

Winform多线程编

2012-09-28 10:12:55

2020-11-26 13:54:03

容器LinuxDocker
点赞
收藏

51CTO技术栈公众号