Spring框架源码解析

导读:本篇文章讲解 Spring框架源码解析,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录

对spring的理解

Spring的优势

什么是IOC

Spring的AOP的底层实现原理

bean的生命周期

如何解决循环依赖

为什么需要三级缓存

三级缓存分别什么作用

Spring中支持几种作用域

Bean Factory与FactoryBean区别

Spring框架中用到了哪些设计模式 

单例模式

原型模式

模板模式

观察者模式

工厂模式

适配器模式

装饰者模式

代理模式

策略模式

责任链默认

委托者模式

Spring的事务是如何回滚 事务的实现原理

事务的传播行为 事务的注解属性

Spring中有哪些通知类型(Advice)


对spring的理解

Spring从之前单纯的xml的配置方式,到现在的完全基于注解的编程方式发展,

  Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。常见的配置方式有三种:基于XML的配置、基于注解的配置、基于Java的配置.

主要由以下几个模块组成:

  • Spring Core:核心类库,提供IOC服务;
  • Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
  • Spring AOP:AOP服务;
  • Spring DAO:对JDBC的抽象,简化了数据访问异常的处理;
  • Spring ORM:对现有的ORM框架的支持;
  • Spring Web:提供了基本的面向Web的综合特性,例如多方文件上传;
  • Spring MVC:提供面向Web应用的Model-View-Controller实现。

Spring框架源码解析

Spring的优势

 Spring框架源码解析

什么是IOC

对SpringIOC模块的理解:

控制反转:理论思想,原来的对象是由使用者来进行控制,有了spring之后,可以把整个对象交给spring来帮我们进行管理

​DI:依赖注入,把对应的属性的值注入到具体的对象中,@Autowired,populateBean完成属性值的注入

容器:存储对象,使用map结构来存储,在spring中一般存在三级缓存,singletonObjects存放完整的bean对象,

​整个bean的生命周期,从创建到使用到销毁的过程全部都是由容器来管理(bean的生命周期

        1、先通过createBeanFactory创建出一个Bean工厂(DefaultListableBeanFactory)

        2、开始循环创建对象,因为容器中的bean默认都是单例的,所以优先通过getBean,doGetBean从容器中查找,找不到的话,

        3、通过createBean,doCreateBean方法,以反射的方式创建对象,一般情况下使用的是无参的构造方法(getDeclaredConstructor,newInstance)

        4、进行对象的属性填充populateBean

        5、进行其他的初始化操作(initializingBean)

Spring的AOP的底层实现原理

aop是ioc的一个扩展功能,先有的ioc,再有的aop,只是在ioc的整个流程中新增的一个扩展点而已:BeanPostProcessor

bean的创建过程中有一个步骤可以对bean进行扩展实现,aop本身就是一个扩展功能,所以在BeanPostProcessor的后置处理方法中来进行实现

​    1、代理对象的创建过程(advice,切面,切点)

​    2、通过jdk或者cglib的方式来生成代理对象

​    3、在执行方法调用的时候,会调用到生成的字节码文件中,直接回找到DynamicAdvisoredInterceptor类中的intercept方法,从此方法开始执行

​    4、根据之前定义好的通知来生成拦截器链

​    5、从拦截器链中依次获取每一个通知开始进行执行,在执行过程中,为了方便找到下一个通知是哪个,会有一个CglibMethodInvocation的对象,找的时候是从-1的位置一次开始查找并且执行的。

 

bean的生命周期

1、实例化bean:反射的方式生成对象

2、填充bean的属性:populateBean(),循环依赖的问题(三级缓存)

3、调用aware接口相关的方法:invokeAwareMethod(完成BeanName,BeanFactory,BeanClassLoader对象的属性设置)

4、调用BeanPostProcessor中的前置处理方法:使用比较多的有(ApplicationContextPostProcessor,设置 ApplicationContext,Environment,ResourceLoader,EmbeddValueResolver等对象)

5、调用initmethod方法:invokeInitmethod(),判断是否实现了initializingBean接口,如果有,调用afterPropertiesSet方法,没有就不调用

6、调用BeanPostProcessor的后置处理方法:spring的aop就是在此处实现的,AbstractAutoProxyCreator

​ 注册Destuction相关的回调接口:钩子函数

7、获取到完整的对象,可以通过getBean的方式来进行对象的获取

8、销毁流程,1;判断是否实现了DispoableBean接口,2,调用destroyMethod方法

如何解决循环依赖

循环依赖:

        1、先创建A对象,实例化A对象,此时A对象中的b属性为空,填充属性b

        ​ 2、从容器中查找B对象,如果找到了,直接赋值不存在循环依赖问题(不通),找不到直接创建B对象

​         3、实例化B对象,此时B对象中的a属性为空,填充属性a

​         4、从容器中查找A对象,找不到,直接创建

如果仔细观察的话,会发现A对象是存在的,只不过此时的A对象不是一个完整的状态,只完成了实例化但是未完成初始化,如果在程序调用过程中,拥有了某个对象的引用,能否在后期给他完成赋值操作,可以优先把非完整状态的对象优先赋值,等待后续操作来完成赋值,相当于提前暴露了某个不完整对象的引用,所以解决问题的核心在于实例化和初始化分开操作,这也是解决循环依赖问题的关键,

​ 当所有的对象都完成实例化和初始化操作之后,还要把完整对象放到容器中,此时在容器中存在对象的几个状态,完成实例化=但未完成初始化,完整状态,因为都在容器中,所以要使用不同的map结构来进行存储,此时就有了一级缓存和二级缓存,如果一级缓存中有了,那么二级缓存中就不会存在同名的对象,因为他们的查找顺序是1,2,3这样的方式来查找的。一级缓存中放的是完整对象,二级缓存中放的是非完整对象

​ 为什么需要三级缓存?三级缓存的value类型是ObjectFactory,是一个函数式接口存在的意义是保证在整个容器的运行过程中同名的bean对象只能有一个

​ 如果一个对象需要被代理,或者说需要生成代理对象,那么要不要优先生成一个普通对象?普通对象和代理对象是不能同时出现在容器中的,因此当一个对象需要被代理的时候,就要使用代理对象覆盖掉之前的普通对象,在实际的调用过程中,是没有办法确定什么时候对象被使用,所以就要求当某个对象被调用的时候,优先判断此对象是否需要被代理,类似于一种回调机制的实现,因此传入lambda表达式的时候,可以通过lambda表达式来执行对象的覆盖过程,getEarlyBeanReference()

​ 因此,所有的bean对象在创建的时候都要优先放到三级缓存中,在后续的使用过程中,如果需要被代理则返回代理对象,如果不需要被代理,则直接返回普通对象

缓存的放置时间和删除时间:

三级缓存:createBeanInstance之后:addSingletonFactory

​ 二级缓存:第一次从三级缓存确定对象是代理对象还是普通对象的时候,同时删除三级缓存 getSingleton

​ 一级缓存:生成完整对象之后放到一级缓存,删除二三级缓存:addSingleton

为什么需要三级缓存

三级缓存主要处理的是AOP的代理对象,存储的是一个ObjectFactory

三级缓存考虑的是带你对象,而二级缓存考虑的是性能-从三级缓存的工厂里创建出对象,再扔到二级缓存(这样就不用每次都要从工厂里拿)

三级缓存分别什么作用

一级缓存:正式对象

二级缓存:半成品对象

三级缓存:工厂

Spring框架源码解析 

Spring中支持几种作用域

Spring容器中的bean可以分为5个范围:

        prototype:为每一个bean请求提供一个实例。

        singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。

        request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。

        session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。

        global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。

 

Bean Factory与FactoryBean区别

使用BeanFactory创建对象的时候,必须要遵循严格的生命周期流程,太复杂了,,如果想要简单的自定义某个对象的创建,同时创建完成的对象想交给spring来管理,那么就需要实现FactroyBean接口了

​ isSingleton:是否是单例对象

​ getObjectType:获取返回对象的类型

​ getObject:自定义创建对象的过程(new,反射,动态代理)

Spring框架中用到了哪些设计模式 

单例模式

  单例模式应该是大家印象最深的一种设计模式了。在Spring中最明显的使用场景是在配置文件中配置注册bean对象的时候设置scope的值为singleton 。

原型模式

  原型模式也叫克隆模式,Spring中该模式使用的很明显,和单例一样在bean标签中设置scope的属性prototype即表示该bean以克隆的方式生成

模板模式

  模板模式的核心是父类定义好流程,然后将流程中需要子类实现的方法就抽象话留给子类实现,Spring中的JdbcTemplate就是这样的实现。我们知道jdbc的步骤是固定

  • 加载驱动,
  • 获取连接通道,
  • 构建sql语句.
  • 执行sql语句,
  • 关闭资源

  在这些步骤中第3步和第四步是不确定的,所以就留给客户实现,而我们实际使用JdbcTemplate的时候也确实是只需要构建SQL就可以了.这就是典型的模板模式。

观察者模式

  观察者模式定义的是对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。使用比较场景是在监听器中而spring中Observer模式常用的地方也是listener的实现。如ApplicationListener.

工厂模式

简单工厂模式

  简单工厂模式就是通过工厂根据传递进来的参数决定产生哪个对象。Spring中我们通过getBean方法获取对象的时候根据id或者name获取就是简单工厂模式了。

 

工厂方法模式

  在Spring中我们一般是将Bean的实例化直接交给容器去管理的,实现了使用和创建的分离,这时容器直接管理对象,还有种情况是,bean的创建过程我们交给一个工厂去实现,而Spring容器管理这个工厂。这个就是我们讲的工厂模式,在Spring中有两种实现一种是静态工厂方法模式,一种是动态工厂方法模式。

适配器模式

  将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。这就是适配器模式。在Spring中在AOP实现中的Advice和interceptor之间的转换就是通过适配器模式实现的。

装饰者模式

  装饰者模式又称为包装模式(Wrapper),作用是用来动态的为一个对象增加新的功能。装饰模式是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
  spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。
  具体的使用在Spring session框架中的SessionRepositoryRequestWrapper使用包装模式对原生的request的功能进行增强,可以将session中的数据和分布式数据库进行同步,这样即使当前tomcat崩溃,session中的数据也不会丢失。

代理模式

  代理模式应该是大家非常熟悉的设计模式了,在Spring中AOP的实现中代理模式使用的很彻底.

策略模式

  策略模式对应于解决某一个问题的一个算法族,允许用户从该算法族中任选一个算法解决某一问题,同时可以方便的更换算法或者增加新的算法。并且由客户端决定调用哪个算法,spring中在实例化对象的时候用到Strategy模式。XmlBeanDefinitionReader,PropertiesBeanDefinitionReader

责任链默认

AOP中的拦截器链

委托者模式

DelegatingFilterProxy,整合Shiro,SpringSecurity的时候都有用到。

Spring的事务是如何回滚 事务的实现原理

spring的事务是由aop来实现的,首先要生成具体的代理对象,然后按照aop的整套流程来执行具体的操作逻辑,正常情况下要通过通知来完成核心功能,但是事务不是通过通知来实现的,而是通过一个TransactionInterceptor来实现的,然后调用invoke来实现具体的逻辑.

1、先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务

​ 2、当需要开启的时候,获取数据库连接,关闭自动提交功能,开起事务

​ 3、执行具体的sql逻辑操作

​ 4、在操作过程中,如果执行失败了,那么会通过completeTransactionAfterThrowing看来完成事务的回滚操作,回滚的具体逻辑是通过doRollBack方法来实现的,实现的时候也是要先获取连接对象,通过连接对象来回滚

​ 5、如果执行过程中,没有任何意外情况的发生,那么通过commitTransactionAfterReturning来完成事务的提交操作,提交的具体逻辑是通过doCommit方法来实现的,实现的时候也是要获取连接,通过连接对象来提交

​ 6、当事务执行完毕之后需要清除相关的事务信息cleanupTransactionInfo

事务常见的注解:

REQUIRED — 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 

SUPPORTS — 支持当前事务,如果当前没有事务,就以非事务方式执行。 

MANDATORY — 支持当前事务,如果当前没有事务,就抛出异常。 

REQUIRES_NEW — 新建事务,如果当前存在事务,把当前事务挂起。 

NOT_SUPPORTED — 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 

NEVER — 以非事务方式执行,如果当前存在事务,则抛出异常。 

NESTED — 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与REQUIRED类似的操作。 

事务的传播行为 事务的注解属性

Spring框架源码解析

 

Spring中有哪些通知类型(Advice)

        前置通知:Before – 这些类型的 Advice 在 joinpoint 方法之前执行,并使用@Before 注解标记进行配置。
        后置通知:After Returning – 这些类型的 Advice 在连接点方法正常执行后执行,并使用@AfterReturning 注解标记进行配置。
        异常通知:After Throwing – 这些类型的 Advice 仅在 joinpoint 方法通过抛出异常退出并使用 @AfterThrowing 注解标记配置时执行。
        最终通知:After (finally) – 这些类型的 Advice 在连接点方法之后执行,无论方法退出是正常还是异常返回,并使用 @After 注解标记进行配置。
        环绕通知:Around – 这些类型的 Advice 在连接点之前和之后执行,并使用@Around 注解标记进行配置。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/116516.html

(0)
seven_的头像seven_bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!