Spring框架

简介

  Spring 是分层的 full-stack(全栈) 轻量级开源框架,以 IoC 和 AOP 为内核,提供了展现层 SpringMVC 和业务层事务管理等众多的企业级应⽤技术,还能整合开源世界众多著名的第三⽅框架和类库,已经成为使⽤最多的 Java EE 企业应⽤开源框架。

主要优势

  • 方便解耦简化开发
  • AOP编程支持
  • 声明式事务
  • 方便程序的测试
  • 方便集成各种优秀框架

核心思想

   在Spring中拥有许多的组件,但核心部分主要为:Beans、Core、Context、Expression,其中最为主的为Core、与Beans,它们提供了最为核心的IOC和依赖注入功能。

核心结构

image.png
框架设计理念:
在Spring框架中,其最核心组件应属Beans,Spring-Beans模块是所有应用都必须使用的,它包含了访问配置文件、创建和管理Bean以及进行控制反转(IOC,Inversion of Control)、依赖注入(DI,Dependency Injection)操作相关的所有类。Spring是面向Bean编程,Bean 在 Spring 中才是真正的主角。

IOC

  IOC,Inversion of Control (控制反转/反转控制),注意它是⼀个技术思想,不是⼀个技术实现。  

为什么叫做控制反转?

  • 控制:指的是对象创建(实例化、管理)的权利
  • 反转:控制权交给外部环境了(spring框架、IoC容器)

image.png

IOC解决什么问题?
解决对象之间的耦合问题。

IOC 与 DI 的区别?
DI:Dependancy Injection(依赖注⼊),IOC和DI描述的是同⼀件事情,只是理解角度不一样。
image.png

初始化主体流程

  Spring 提供了很多的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化,它定义了所有 IoC 容器 必须遵从的⼀套原则,具体的容器实现可以增加额外的功能,⽐如我们常⽤到的ApplicationContext,其下更具体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等⼀系列的内容。 
   BeanFactory 容器继承体系如下图

image.png
Spring IOC 容器初始化的关键环节在 AbstractApplicationContext#refresh() ⽅法中,如下所示

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 第⼀步:刷新前的预处理
prepareRefresh();
/*
第⼆步:
获取BeanFactory;默认实现是DefaultListableBeanFactory
加载BeanDefition 并注册到 BeanDefitionRegistry
*/
    
ConfigurableListableBeanFactory beanFactory =
obtainFreshBeanFactory();
// 第三步:BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加
载器等)
prepareBeanFactory(beanFactory);
try {
// 第四步:BeanFactory准备⼯作完成后进⾏的后置处理⼯作
postProcessBeanFactory(beanFactory);
// 第五步:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean
invokeBeanFactoryPostProcessors(beanFactory);
// 第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执registerBeanPostProcessors(beanFactory);
// 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
initMessageSource();
// 第⼋步:初始化事件派发器
initApplicationEventMulticaster();
// 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
onRefresh();
// 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器
bean
registerListeners();
/*
第⼗⼀步:
初始化所有剩下的⾮懒加载的单例bean
初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)
填充属性
初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、init-method⽅法)
调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处
*/
finishBeanFactoryInitialization(beanFactory);
/*
第⼗⼆步:
完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事
件 (ContextRefreshedEvent)
*/
finishRefresh();
 }
 ......
 }
}

循环依赖

 循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。⽐如A依赖于B,B依赖于C,C⼜依赖于A。

image.png
Spring中循环依赖场景有:

  • 构造器的循环依赖(构造器注⼊)
  • Field 属性的循环依赖(set注⼊)

处理机制

  • 单例 bean 构造器参数循环依赖(⽆法解决)
  • prototype 原型 bean循环依赖(⽆法解决)
  • 单例bean通过setXxx或者@Autowired进⾏循环依赖

三级缓存

  首先看下Spring创建一个bean的基本流程:

创建该实例的原始对象 --> 进行自动装配 --> AOP代理处理 --> 完成bean的创建并加入单例池(即一级缓存)
但是当有循环依赖的时候,Spring是如何解决的呢?
主要原理是利用三级缓存机制:

  • singletonObjects: 一级缓存,也就是我们平常理解的单例池。
  • singletonFactories: 二级缓存,存储的是单例工厂。
  • earlySingletonObjects: 三级缓存,存储正在创建中的单例对象。

为什么要设立三级缓存呢?
其实当不需要实现AOP的时候,解决循环依赖不用三级缓存机制,也不用单例工厂,二级缓存就足以实现。
第一级:singletonObjects
第二级:earlySingletonObjects
不需要实现AOP时Spring解决循环依赖基本流程:
假设单例一与单例二相互依赖对方并且此时都没有加入到单例池

  1. 创建单例一
  2. 将单例一加入earlySingletonObjects缓存
  3. 自动装配单例二
  4. 判断单例二在earlySingletonObjects缓存是否存在
  5. 不存在则创建单例二
  6. 将单例二并且加入earlySingletonObjects缓存
  7. 自动装配单例一
  8. 判断单例一在earlySingletonObjects缓存是否存在
  9. 明显第2步已经加入earlySingletonObjects缓存
  10. 注入成功,单例2创建完成并加入singletonObjects单例池
  11. 注入成功,单例1创建完成并加入singletonObjects单例池

那为什么要设立三级缓存呢?
这是因为当需要使用AOP时,将会对原始对象进行代理,因此最后的对象将是代理对象而不是原始对象。
所以按照二级缓存的步骤进行创建的话将会造成一个问题:
第2步加入到二级缓存中的对象是原始对象,导致第7步自动装配到到单例2中的单例1对象是原始对象,这个对象还没有完成AOP的处理。如果此时完成单例2的创建,之后在完成进行单例1的创建时,单例1对原始对象进行AOP处理,将导致最终的单例1对象不是之前自动装配到单例2中的单例1对象。
Spring选择使用三级缓存来解决这个问题:singletonFactories缓存中的对象是一个单例工厂,该工厂可以将原始对象进行AOP处理。

  • singletonObjects: 一级缓存,也就是我们平常理解的单例池。
  • singletonFactories: 二级缓存,存储的是单例工厂。
  • earlySingletonObjects: 三级缓存,存储正在创建中的单例对象。

获取三级缓存的核心代码如下:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // Quick check for existing instance without full singleton lock
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                        synchronized (this.singletonObjects) {
                                // Consistent creation of early reference within full singleton lock
                                singletonObject = this.singletonObjects.get(beanName);
                                if (singletonObject == null) {
                                        singletonObject = this.earlySingletonObjects.get(beanName);
                                        if (singletonObject == null) {
                                                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                                                if (singletonFactory != null) {
                                                        singletonObject = singletonFactory.getObject();
                                                        this.earlySingletonObjects.put(beanName, singletonObject);
                                                        this.singletonFactories.remove(beanName);
                                                }
                                        }
                                }
                        }
                }
        }
        return singletonObject;
}

getSingleton方法的大概处理过程为:

  1. 判断singletonObjects单例池中是否存在,存在则返回
  2. 不存在则判断earlySingletonObjects缓存中是否存在,存在则返回
  3. 不存在则判断singletonFactories缓存中是否存在,不存在则返回null
  4. 存在则通过该存储工厂创建出最终的bean
  5. 将该bean加入earlySingletonObjects缓存并从singletonFactories缓存中中移除

存在三级缓存机制下处理流程如下:
假设单例1与单例2相互依赖对方并且此时都没有加入到单例池

  1. 创建单例一
  2. 创建单例一的工厂对象并且加入singletonFactories缓存
  3. 自动装配单例二
  4. 通过 getSingleton方法 判断单例二在三级缓存中是否存在
  5. 明显此时单例一不存在,所以创建单例二
  6. 创建单例二的工厂并且加入singletonFactories缓存
  7. 自动装配单例一
  8. 通过 getSingleton方法 判断单例一在三级缓存中是否存在
  9. 明显第2步已经加入singletonFactories缓存
  10. 单例二进行AOP处理
  11. 注入单例一成功,单例二创建完成并加入singletonObjects单例池
  12. 注入单例二成功,单例一创建完成并加入singletonObjects单例池

三级缓存的好处:

  • 通过单例工厂创建可以实现AOP创建最终对象
  • 加入earlySingletonObjects缓存不用每次都通过工厂创建

AOP

  Aspect oriented Programming ⾯向切⾯编程/⾯向⽅⾯编程,AOP是OOP的延续

image.png
OOP编程思想可以解决⼤多数的代码重复问题,但是有⼀些情况是处理不了的,⽐如下⾯的在顶级⽗类
Animal中的多个⽅法中相同位置出现了重复代码,OOP就解决不了。
AOP提出横向抽取机制,将横切逻辑代码和业务逻辑代码分离。
image.png
解决什么问题?
在不改变原有业务逻辑情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复。

  默认情况下,Spring会根据被代理对象是否实现接⼝来选择使⽤JDK还是CGLIB。当被代理对象没有实现任何接⼝时,Spring会选择CGLIB。当被代理对象实现了接⼝,Spring会选择JDK官⽅的代理技术,不过可以通过配置的⽅式,让Spring强制使⽤CGLIB。

Bean的生命周期

  在Spring中,Bean默认为单例模式,可以设置为多例。一个Bean从创建到销毁,大致经历以下步骤:
  1. 实例化Bean,根据Spring配置,执行包扫描操作,并对其进行实例化操作。
  2. 根据Spring上线文对实例化的Bean进行配置,其中包括依赖注入。
  3. 判断是否实现了BeanNameAware接口,如果有会执行setBeanName方法去设置这个Bean的id,即自己设置Bean在BeanFactory中的名字。
  4. 判断是否实现了BeanFactoryAware接口,如果有则执行setBeanFactory方法,使得Bean可以获取自己的工厂,从而可以使用工厂的getBean方法。
  5. 判断是否实现了ApplicationContextAware接口,如果有则执行setApplicationContext方法,使得在Bean中可以获取Spring上下文,从而可以获取通过上下文去getBean,该步骤与上一步作用大致相同,但通过该中方式能实现的功能却更加丰富。
  6. 判断是否实现了BeanPostProcessor接口,如果有则调用postProcessBeforeInitialization方法,这一步属于实例化Bean的前置操作,在经过该步骤后,即Bean实例化后同样也会执行一个操作。
  7. 判断Bean是否配置了init-method,如果有,在Bean初始化之后会默认执行一次init-method指定的方法。
  8. 判断Bean是否实现了BeanPostProcessor接口,如果有则调用postProcessAfterInitialization方法,该方法属于Bean实例化后的操作。在经过这个步骤后,Bean的初始化操作就完成了。
  9. 当Bean实例化完成后,当Bean不再被需要的时候会执行销毁操作。一般是在ApplicationContext执行close方法时会进行销毁操作。
  10. 在销毁过程中,判断是否实现了DisposableBean接口,如果有则执行destroy方法。
  11. 判断Bean是否配置了destroy-method,如果有,在销毁过程中会默认执行一次destroy-method方法。

BeanFactory与ApplicationContext区别

   BeanFactory是Spring框架中IoC容器的顶层接⼝,只是⽤来定义⼀些基础功能,定义⼀些基础规范,⽽ 

ApplicationContext是它的⼀个⼦接⼝,所以ApplicationContext是具备BeanFactory提供的全部功能的。 通常称BeanFactory为SpringIOC的基础容器,ApplicationContext是容器的⾼级接⼝,⽐BeanFactory要拥有更多的功能,⽐如说国际化⽀持和资源访问(xml,java配置类)等等。

FactoryBean 和 BeanFactory

 BeanFactory接⼝是容器的顶级接⼝,定义了容器的⼀些基础⾏为,负责⽣产和管理Bean的⼀个⼯⼚, 具体使⽤它下⾯的⼦接⼝类型,⽐如ApplicationContext。Spring中Bean有两种,⼀种是普通Bean,⼀种是⼯⼚Bean(FactoryBean),FactoryBean可以⽣成某⼀个类型的Bean实例,可以借助它⾃定义Bean的创建过程。

后置处理器

  Spring提供了两种后处理bean的扩展接⼝,分别为 BeanPostProcessor 和 BeanFactoryPostProcessor,两者在使⽤上是有所区别的。 ⼯⼚初始化(BeanFactory)—> Bean对象 

在BeanFactory初始化之后可以使⽤BeanFactoryPostProcessor进⾏后置处理做⼀些事情
在Bean对象实例化(并不是Bean的整个⽣命周期完成)之后可以使⽤BeanPostProcessor进⾏后置处理做⼀些事情。

Bean初始化过程

    Spring初始化过程中最后执行的核心方法是AbstractRefreshableApplicationContext类的refresh方法。
public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
               // 1.为应用上下文的刷新做准备--设置时间、记录刷新日志、初始化属性源中的占位符(事实上什么都没做)和验证必要的属性等
			// Prepare this context for refreshing.
			prepareRefresh();
			// 2.让子类刷新内部的bean factory
			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            //3.为上下文准备bean factory
			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);
			try {
                 // 4.bean factory 后置处理
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);
				// 5.调用应用上下文中作为bean注册的工厂处理器
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);
				// 6.注册拦截创建bean的bean处理器
				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);
				 // 7.初始化消息源
				// Initialize message source for this context.
				initMessageSource();
				 // 8.初始化事件广播
				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();
				// 9.初始化特定上下文子类中的其它bean
				// Initialize other special beans in specific context subclasses.
				onRefresh();
				 // 10.注册监听器bean
				// Check for listener beans and register them.
				registerListeners();
				// 11.实例化所有的单例bean
				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);
 				// 12.发布相应的事件
				// Last step: publish corresponding event.
				finishRefresh();
			}catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}
				 //销毁错误的资源
				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();
				//重置刷新标志
				// Reset 'active' flag.
				cancelRefresh(ex);
				//主动抛出异常
				// Propagate exception to caller.
				throw ex;
			}
			finally {
                //重置内存缓存
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}
  通过源码可以看出该方法是构建整个IOC容器的完成过程。其中每一行代码都是创建容器的一个流程。其中主要包括以下几个步骤:
  1. 构建BeanFactory
  2. 添加事件处理
  3. 创建 Bean 实例对象并构建Bean关系
  4. 触发被监听的事件

构建BeanFactory

      在第二步中,obtainFreshBeanFactory方法主要调用了AbstractRefreshableApplicationContext#refreshBeanFactory方法:
protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
    以上是BeanFactory的创建过程,首先判断当前容器是否存在BeanFactory,如果有则销毁后在进行创建。BeanFactory的是DefaultListableBeanFactory的实例对象,类图如下:

image.png
从这个图中发现除了 BeanFactory 相关的类外,还发现了与 Bean 的 register 相关。这在 refreshBeanFactory 方法中有一行 loadBeanDefinitions(beanFactory) 这个方法将开始加载、解析 Bean 的定义,也就是把用户定义的数据结构转化为 Ioc 容器中的特定数据结构。对于WEB应用而言,其调用的是XmlWebApplicationContext#loadBeanDefinitions方法。在BeanFactory创建成功后,Spring将创建的对象交于第三步,即prepareBeanFactory方法为其添加一些 Spring 本身需要的一些工具类。

添加事件处理

    在第4、5、6步中,这三行代码对 Spring 的功能扩展性起了至关重要的作用 。其中第4、5步的代码主要是让你可以在Bean已经被创建,但未被初始化之前对已经构建的 BeanFactory 的配置做修改;第6步代码主要是让你可以对以后再创建 Bean 的实例对象时添加一些自定义的操作 。
   第4步,即postProcessBeanFactory方法。主要功能为允许上下文能对BeanFactory做一些处理。比如:AbstractRefreshableWebApplicationContext抽象类实现了该方法,并在方法中对Servlet做了一些处理。
   第5步,即invokeBeanFactoryPostProcessors方法主要是获取实现 BeanFactoryPostProcessor 接口的子类。其中主要包括执行BeanDefinitionRegistryPostProcessor类型的postProcessBeanDefinitionRegistry方法,以及执行非BeanDefinitionRegistryPostProcessor类型的postProcessBeanFactory方法。当然,该方法传入的参数是ConfigurableListableBeanFactory 类型,我们仅能对BeanFactory的一些配置做修改。
   第6步,即registerBeanPostProcessors 方法也是可以获取用户定义的实现了 BeanPostProcessor 接口的子类,并执行把它们注册到 BeanFactory 对象中的 beanPostProcessors 变量中。BeanPostProcessor 中声明了两个方法:postProcessBeforeInitialization、postProcessAfterInitialization 分别用于在 Bean 对象初始化时执行。可以执行用户自定义的操作。
   第7、8、9、10步的方法主要是初始化监听事件和对系统的其他监听者的注册,监听者必须是 ApplicationListener 的子类。 在容器启动时,Spring会调用ApplicationStartListener的onApplicationEvent方法。

创建 Bean 实例对象并构建Bean关系

    Bean的实例化过程是第11步开始的,即finishBeanFactoryInitialization方法,而在finishBeanFactoryInitialization方法中核心方法又为preInstantiateSingletons(DefaultListableBeanFactory类)。在该方法中,首先拿到所有beanName,然后在实例化的时候会判断bean是否为FactoryBean,顾名思义,这是一个特殊的工厂Bean,可以产生Bean的Bean。
   这里的产生 Bean 是指 Bean 的实例,如果一个类继承 FactoryBean 用户只要实现他的 getObject 方法,就可以自己定义产生实例对象的方法。然而在 Spring 内部这个 Bean 的实例对象是 FactoryBean,通过调用这个对象的 getObject 方法就能获取用户自定义产生的对象,从而为 Spring 提供了很好的扩展性。Spring 获取 FactoryBean 本身的对象是在前面加上 & 来完成的。
   在Bean的实例化主要分两个步骤:
  • Bean不为抽象、单例、非懒加载。

     判断Bean是否为FactoryBean,是则执行FactoryBean相关的操作,否则直接调用getBean方法产生实例。
    
  • 在singleton的bean初始化完了之后调用SmartInitializingSingleton的afterSingletonsInstantiated方法。

      通过跟进Bean实例化代码可以发现getBean方法最后指向的是AbstractBeanFactory类的抽象方法createBean,其实现类为AbstractAutowireCapableBeanFactory。在该方法中有一个步骤会去查找Bean的依赖关系,并对其进行依赖注入操作。这里画一个时序图来作说明。
    

    image.png
    在resolveValueIfNecessary方法中,不仅有调用resolveReference,同样的还有resolveInnerBean,即解析内部的Bean引用。

触发被监听的事件

    在经历第11步后,上下文的创建就已经基本完成了,这时Spring会执行finishRefresh方法,完成此上下文的刷新。其中包括LifecycleProcessor的onRefresh方法,并执行ContextRefreshedEvent事件。例如:执行SpringMVC的事件。

总结

  在Bean声明周期中曾讲到,Spring在初始化Bean的时候先后对调用BeanPostProcessor接口的postProcessBeforeInitialization、postProcessAfterInitialization方法。利用这一特性我们可以在Bean中实现BeanPostProcessor接口,然后再方法体中加入自己的逻辑。
  对于Spring的IOC容器而言,除了BeanPostProcessor,还有BeanFactoryPostProcessor。BeanFactoryPostProcessor是在构建BeanFactory和构建Bean对象时调用。IOC容器允许BeanFactoryPostProcessor在容器初始化任何Bean之前对BeanFactory配置进行修改。
  在Spring的IOC容器中还有一个特殊的Bean,即FactoryBean,FactoryBean主要用于初始化其他Bean,我们可以自己实现一个FactoryBean,然后添加自定义实例化逻辑。在Spring中,AOP、ORM、事务管理等都是依靠FactoryBean的扩展来实现的。

渣渣海公众号
笔记不易,喜欢就关注一下我以及我的公众号吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值