spring 源码概述


                                                                              

spring 大致分为IOC和AOP,如下图:

IoC:通过容器去控制业务对象之间的依赖关系。控制权由应用代码中转到了外部容器,控制权的转移就是反转。控制权转移的意义是降低了类之间的耦合度。

创建对象的时候,向类里面的属性设置值。spring依赖注入主要是两种方式:

(1)使用set方法(常用)

(2)使用带参的构造函数

spring的IOC简单的理解大致就是如下过程:

其实最核心的就是IOC容器,就是用来存放Bean或者BeanDefintion信息的容器,我们一般会想到Map,用来做存储,常见的容器存储K‘、V值,如下:

这里的ObjectFacotry,主要用来解决循环依赖的,后续再细聊这一块。

继续说Bean的定义信息,常见的有xml,注解,properties,yaml等,我们需要把各种定义bean信息的格式文件统一读取,解析成BeanDefintion信息,那么就需要一个统一的接口,BeanDefinitionReader.,如:下图

查看源码,实现的子类:

除了实现BeanDefinitionReader接口以外,spring还有一些其他的BeanDefinitionReader,虽然没有实现BeanDefinitionReader,其功能大致都是一直的,只是原理不同罢了。如:AnnotatedBeanDefinitionReader,ConfigurationClassBeanDefinitionReader,JdbcBeanDefinitionReader, 这里不具体讲,后续单独讲。

说到这里有必要说一下,BeanFactory,

Bean工厂, 整个容器的根接口,也是整个容器的入口.

通过反射实例化对象,如下:

Constructor ctor= clazz.getConstructior();

Object obj =ctor.newInstance();

还有必要提一下:bean的作用域,scope,常用的singleton,prototype.

singleton是默认的作用域,当定义Bean时,如果没有指定scope配置项,Bean的作用域被默认为singleton。singleton属于单例模式,在整个系统上下文环境中,仅有一个Bean实例。也就是说,在整个系统上下文环境中,你通过Spring IOC获取的都是同一个实例。

当一个Bean的作用域被定义prototype时,意味着程序每次从IOC容器获取的Bean都是一个新的实例。因此,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。

Spring IOC容器创建一个Bean实例时,可以为Bean指定实例的作用域,作用域包括singleton(单例模式)、prototype(原型模式)、request(HTTP请求)、session(会话)、global-session(全局会话)。

创建对象可以分为两个部分,实例化和初始化。

实例化,在堆中开辟一块内存空间,同时给对象的属性值赋默认值,比如基本属性,int 赋值为0,对象属性赋值为null.

初始化,给属性赋值,填充属性值,执行初始化方法,init-method.

在容器创建过程中,需要改变bean的定义信息怎么办?

比如:我们有时候配置数据库的连接信息,如下图:

在这里要说到一个知识点,幕后的操作者就是 Spring 中后置处理器(PostProcessor)

后置处理器分为两种:BeanFactoryPostProcessor(Bean 工厂后置处理器) 和 BeanPostProcessor(Bean 后置处理器)

BeanFactoryPostProcessor 接口里面只有一个 postProcessBeanFactory 方法,结合接口的注释和接口里的方法注释,可以得出,这个接口是一个 BeanFactory 钩子接口,实现该接口,可以通过 postProcessBeanFactory 方法在 BeanFactory 实例化后,Bean 实例化前调用该接口,对 BeanFactory 中的 BeanDefinition 或 BeanDefinition 的元数据进行修改。

BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor 继承了 BeanFactoryPostProcessor,在 Bean 实例化和检测之前,实现了一个非常重要的功能,动态注册一个 BeanDefinition,除此之外,你还可以修改已注册的 BeanDefinition 信息。

BeanPostProcessor

BeanPostProcessor 是 Bean 后置处理器接口,里面包含两个方法:postProcessBeforeInitialization 和 postProcessAfterInitialization。前者在 Bean 实例化前调用,后者则是在实例化后。比如生成一个 Bean 的代理类,就是其子类做的。

别小看上面三个接口,Spring 绝大部分重要技术都是这三个接口的子类来实现,它们也是扩展接口,可以自定义类来实现它们,以增强 Spring 功能或者是扩展 Spring 功能,又或是第三方框架。

后续再细聊这一块。

所以大致的流程就是:定位配置文件,加载bean的信息,读取解析bean的信息,转化为:BeanDefinition,在中间过程中可以对BeanDefinition进行修改或者增强,实例化对象,填充属性,设置 Aware接口的属性,对bean初始化之前增强,执行init-method,再bean的初始化后增强,最后生成完整的对象,存入容器中,需要用的时候,从容器中获取即可。

这里要特别说明一下:Aware接口,

Aware.java是个没有定义任何方法的接口,拥有众多子接口,在spring源码中有多处都在使用这些子接口完成各种场景下的回调操作,当业务有需要时,我们只需创建类来实现相关接口,再声明为bean,就可以被spring容器主动回调;

这里简单的举一个例子 :

比如:我们想要在一个类中获取ApplicationContext对象,怎么获取,定义一个类,实现ApplicationContextAware接口

实现setApplicationContext方法,定义一个私有ApplicationContext对象,在setApplicationContext方法中赋值即可,然后再定义一个getApplicationContext方法,提供对外使用。

需要获取容器中的其他属性或者对象,都可以通过实现Aware接口,让容器回调赋值获取。

容器中到底在哪里给我们调用我们定义的方法呢?看下源码:AbstractAutowireCapableBeanFactory类中的doCreateBean方法。

这里再看一个抽象类AbstractAutoProxyCreator,主要是用来实现AOP,创建动态代理对象的。

最后发现,就是cglib和jdk两种动态代理。

如果看源码,需要翻译,可以安装插件:如下图:

下面再继续聊一下bean的生命周期,可以先看下源码:BeanFactory

下面再提一个问题:如果 :在不同的阶段要处理不同的工作,应该怎么办?Spring里面是通过,观察者模式:监听器,监听事件,多播器(广播器)来实现的。AbstractApplicationContext的Refresh方法中,如下图:

如果看源码,可以注意一些关键的接口,如下:

这里可以看下Environment是什么时候创建的,

最后再来说说BeanFacotry和FactoryBean的区别,这里也是面试最喜欢问的

先来自定义一个类

如果需要获取工厂bean,需要加&符号

那到底在哪里调用了getObject()方法呢?

下面看下源码:从getBean方法开始找

找到doGetBean,中间有些步骤省去了

猜你喜欢

转载自blog.csdn.net/huzhiliayanghao/article/details/115014979