将自己创建的对象放入spring容器管理_Spring源码分析(一)Spring容器及Spring Bean...

(一)Spring 容器及 Spring Bean

1.Spring 容器

1.1 什么是容器

官网中有一句话

The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans.

翻译下来的意思是:

  1. Spring IOC 容器就是一个 org.springframework.context.ApplicationContext 的实例化对象
  2. 容器负责实例化,配置以及装配 bean

那么我们可以这样理解:

  1. 从代码层次来看,Spring 容器就是一个实现了 ApplicationContext 接口的对象
  2. 从功能上来看,Spring 容器是 Spring 框架的核心,用来管理对象的。容器将创建的对象,把它们连接在一起,配置它们,并管理它们的整个生命周期从创建到销毁

1.2 容器如何工作

官网上一张图如下:

c48f53aa4d82f85212a290beb9512887.png

图可以理解为,Spring 容器通过我们提交的 POJO 对象(Your Business Objects(POJOs))以及配置元数据(Configuration Metadata)产生一个充分配置的可以使用的系统

这里说的配置元数据,实际上就是我们提供的 XML 配置文件,或者通过注解方式提供的一些配置信息

2.Spring bean

2.1 如何实例化一个 bean

从官网上来看,主要有三种方法:

651871824434897594514ef25b665e0c.png
  1. 构造方法
  2. 静态工厂方法
  3. 实例工厂方法

这三种例子官网都有具体的演示,可以通过注解查阅部分源码来验证官网的结论

从代码角度进行分析,这里我们直接定位到

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

通过运行下面这行代码

public 

在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance 这个方法的入口打一个端点,如图:

65b974ee6011a24b0fcf279e3e59776e.png

接下来我们通过代码来分析

6f1e95e3b64898b772903f963f373942.png

我们主要关注进行实例化的几个方法:

  1. 通过 Supplier 创建 Bean

通过 BeanDefinition 中的 instanceSupplier 直接获取一个是实例化的对象,这个 instanceSupplier 属性我不是很理解,在 XML 标签中以及注解的方式都没有找到方法配置这个属性,后来在 org.springframework.context.support.GenericApplicationContext 这个类中找到了以下两个方法

21cf90f2ffc7e565a3eaa208d578be5c.png

经过断点测试,发现这种情况下,在实例化对象时会进入上面的 supplier 方法。下面是测试代码

// AnnotationConfigApplicationContext 是 GenericApplicationContext 的一个子类

这个方法一般不常用,这是 Spring 提供的一种方便外部扩展的手段,让开发者能够更加灵活的实例化一个 bean

2. 通过注解的方式来创建 Bean

@Compent,@Service 等注解方式

测试代码:

public 

观察 debug:

ac6e6d3a0dd657de6ee5ef07c4a508ae.png

可以发现,代码执行到最后一行,同时我们看代码上面的注释可以知道,当没有进行特殊处理的时候,默认会使用无参构造函数进行对象的实例化

3. 通过普通 XML 的方式

同@Component 注解

4. 通过@Configuration 注解的方式

public 

11aea38baf3badf264cd51dea867311a.png

同样,断点也进入了最后一行

5. 通过@Bean 方式

public 

在方法入口打个断点如图:

60c999a93e47c131328b8764534931de.png

断点结果:

1b918c9efb9eb0c70915afb702637c61.png

可以发现,通过@Bean方法创建对象时,Spring底层是通过factoryMethod方法进行实例化对象的,Spring会在我们需要实例化这个对象对应的BeanDefinition中记录factoryBeanName是什么(factoryBeanName就是AppConfig),同时记录这个factoryBean中创建对象的factoryMethodName是什么,最后通过factoryBeanName获取一个Bean然后反射调用factoryMethod实例化一个对象。

这里需要注意几个概念:

  1. 这里所说的通过静态工厂方式通过factoryBeanName获取一个Bean,注意这个Bean,不是一个FactoryBean,也就是说不是一个实现了org.springframework.beans.factory.FacrotyBean接口的Bean。
  2. 提到一个概念BeanDefinition,它就是Spring对自己所管理的Bean的一个抽象。之后会出一个专题专门讲解

6. 通过静态工厂方法的方式

测试代码:

public 

application.xml:

<?

断点如下:

b5675976d3fc16a4967e9589ee5c8c9d.png

可以发现,这种情况也进入了insrantiateUsingFactoryMethod方法中。通过静态工厂方法的方式特殊之处在于,包含了这个静态方法的类,不需要被实例化,不需要被Spring管理,Spring的调用逻辑大概是:

  1. 通过<bean>标签中的class属性得到一个Class对象
  2. 通过Class对象获取到对应的方法名称得到Method对象
  3. 最后反射调用Method.invoke(null, args)

因为是静态方法,方法在执行时,不需要一个对象

7.通过实例工厂方法的方式

测试代码,配置文件不变:

ClassPathXmlApplicationContext 

断点如下:

81d1a48922ac7131a4c65c406fcc2b63.png

还是执行这个方法,这个方法的执行过程和@Bean方式执行的流程是一样的

到这里,这段代码我们算是结合了官网大致过了一遍,其实还遗留了几个问题:

  1. Spring是如何推断构造函数的?我们在上面验证的都是无参的构造函数,并且只提供了一个构造函数
  2. Spring是如何推断方法的?不管是静态工厂方法还是实例化工厂方法,我们都只在类中提供了一个和配置匹配的方法名,假设我们对方法进行了重载呢?

要说清楚这两个问题需要比较深入的研究代码,同时进行测试。

总结

  1. 对象实例化,只是得到一个对象,还不是一个完全的Spring中的bean,我们实例化后的这个对象还没有完成依赖注入,没有走完一系列的生命周期
  2. Spring官网上说到,在Spring实例化一个对象有三种方式:

构造函数

实例化工厂方法

静态工厂方法

3.自己总结如下结论:

Spring通过解析我们的配置元数据,以及我们提供的类对象得到一个BeanDefiniton对象,通过这个对象可以实例化一个java bean对象。主要流程图如下:

bea6c02f924561853b4398654564f8a6.png

不吃竹子的滚滚:Spring源码分析(十四)Spring中的BeanWrapper及类型转换

不吃竹子的滚滚:Spring源码分析(十二)ApplicationContext详解(中)

不吃竹子的滚滚:Spring源码分析(十一)ApplicationContext详细介绍(上)

不吃竹子的滚滚:Spring源码分析(十)Spring中Bean的生命周期(下)

不吃竹子的滚滚:Spring源码分析(九)Spring中Bean的生命周期(上)

不吃竹子的滚滚:Spring源码分析(八)容器的扩展点(BeanPostProcessor)

不吃竹子的滚滚:Spring源码分析(七)容器的扩展点(FactoryBean)

不吃竹子的滚滚:Spring源码分析(六)容器的扩展点(BeanFactoryPostProcessor)

不吃竹子的滚滚:Spring源码分析(五)BeanDefinition(下)

不吃竹子的滚滚:Spring源码分析(四)BeanDefinition(上)

不吃竹子的滚滚:Spring源码分析(三)自动注入与精确注入

不吃竹子的滚滚:Spring源码分析(二)依赖注入及方法注入

不吃竹子的滚滚:Spring源码分析(一)Spring容器及Spring Bean

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值