spring源码解读第二版(一文看懂Spring核心概念和源码解读)
- 一、Spring框架的模块组成
- 二、Spring的核心原理
- 三、Spring的两大核心接口:BeanFactory和ApplicationContext
- 四、Spring容器中的Bean
- 五、单例Bean的线程安全和并发问题(重点)
- 六、Spring的事务处理
- 七、Spring框架中用到的设计模式
- 八、Spring框架的事件类型
1. 核心组件
1. 核心容器(Core Container)
2. AOP(Aspect Oriented Programming)
3. 设备支持(Instrument)
4. 数据访问及集成(Data Access/Integratioin)
5. Web
6. 报文发送(Messaging)
7. Test等模块。
2. Spring的优点1. 低侵入式
2. DI机制减少组件耦合性
3. AOP
4. 扩展性
## 二、Spring的核心原理Spring框架最核心的原理:IOC 和 AOP。IOC让相互协作的组件保持松散的耦合,而AOP编程允许把遍布于应用各层的功能分离出来形成可重用的功能组件。
### 1. 控制反转 IOC1. 容器控制创建对象,降低对象之间耦合性,利于功能复用
2. 创建对象不需要new,而是利用JAVA反射机制根据配置文件动态创建对象和管理对象
3. Spring中三种注入方式:
- 1. 构造器注入
- 2. setter方法注入
- 3. 基于注解注入(@Autowire)
抽取并封装多个对象的公共行为和逻辑成一个可重用的模块`切面(Aspect)`
2. 静态代理(AspectJ)和动态代理(Spring AOP)
- 1. `静态代理`:AspectJ是静态代理的增强,编译时将AspectJ植入Java字节码中,运用时就是增强后的代理对象
- 2. `动态代理`:动态代理不会修改Java字节码,是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法
- 1. `JDK`:JDK动态代理只提供接口的代理,不支持类的代理。
- 2. `CGLIB`:是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。
- 3. GLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
4. AOP的核心概念
1. `切面(Aspect)`:被抽取的公共模块,可能会横切多个对象。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。
2. `连接点(Join point)`:指方法,在Spring AOP中,一个连接点 总是 代表一个方法的执行。
3.`通知(Advice)`:在切面的某个特定的连接点(Join point)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。
4. `切入点(Pointcut)`:切入点是指 我们要对哪些Join point进行拦截的定义。通过切入点表达式,指定拦截的方法,比如指定拦截add*、search*。
5. `引入(Introduction)`:(也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。
6. `目标对象(Target Object)`: 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(adviced) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。
7. `织入(Weaving)`:指把增强应用到目标对象来创建新的代理对象的过程。Spring是在运行时完成织入。
8. 切入点(pointcut)和连接点(join point)匹配的概念是AOP的关键,这使得AOP不同于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。
5. AOP的应用场景
6. AOP的实战场景
7. 使用SpringAop的注意事项
参考[探秘Spring AOP](https://www.imooc.com/learn/869)课程截图
### 三、Spring的两大核心接口:BeanFactory和ApplicationContext
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
1. ApplicationContext 是 BeanFactory 的子接口,功能更全
- 1. BeanFactory是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext是BeanFactory的派生接口,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
- 2. 继承MessageSource,因此支持国际化。
- 3. 统一的资源文件访问方式。
- 4. 提供在监听器中注册bean的事件。
- 5. 同时加载多个配置文件。
- 6. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
2. 加载方式
- 1. `BeanFactroy` 采用的是延迟加载形式来注入Bean,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常
- 2. `ApplicationContext` 是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。
3. 创建方式
- 1. BeanFactory 通常以编程的方式被创建。
- 2. ApplicationContext 除了编程方式,还能以声明的方式创建,如使用ContextLoader。
4. 注册方式
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
### 四、Spring容器中的Bean#### 1. Bean的作用域1. `singleton(单例)`,在spring容器中仅存在一个Bean实例,Bean以单例方式存在,bean作用域范围的默认值。
2. `prototype(原型)`,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()。
3. `request`,每次HTTP请求都会创建一个新的Bean,该作用域仅适用于web的WebApplicationContext环境。
4. `session`,同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。该作用域仅适用于web的WebApplicationContext环境。
5. `globalSession`,同一个全局 Session 共享一个 bean,用于 Portlet, 该作用域仅用于 WebApplication 环境。
#### 2. Bean注入的几种方式1. 基于注解 @Autowired 的自动装配(最常用)
- 1. authwire3个属性值:constructor、byName、byType
- 2. 匹配多个Bean如何注入:DefaultListableBeanFactory 的 determineAutowireCandidate
2. 基于构造方法注入
3. 基于Setter方法注入
#### 3. Bean的自动装配在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用autowire来配置自动装载模式
1. 自动装配种类
- 1. no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。
- 2. byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。
- 3. byType:通过参数的数据类型进行自动装配。
- 4. constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
- 5. autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用
- 6. byType的方式自动装配。
2. @Autowired和@Resource之间的区别
- 1. @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
- 2. @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。
Spring Bean 的生命周期分为四个阶段和多个扩展点。扩展点又可以分为影响多个Bean和影响单个Bean。实例化和属性赋值对应构造方法和setter方法的注入,初始化和销毁是用户能自定义扩展的两个阶段。
1. 四个阶段(实例化 -> 属性赋值 -> 初始化 -> 销毁)
- 1. 实例化 Instantiation
- 2. 属性赋值 Populate
- 3. 初始化 Initialization
- 4. 销毁 Destruction
2. 多个扩展点
- 1. 影响多个Bean
1. BeanPostProcessor
2. InstantiationAwareBeanPostProcessor
- 2. 影响单个Bean
1. Aware
1. Aware Group1
1. BeanNameAware
2. BeanClassLoaderAware
3. BeanFactoryAware
1. Aware Group2
1. EnvironmentAware
2. EmbeddedValueResolverAware
3. ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)
3. 生命周期
- 1. InitializingBean,初始化Bean
- 2. DisposableBean,销毁Bean
1. Spring启动加载流程
- 1. XML加载
- 2. 解析
- 3. 创建实例
- 4. 使用
- 5. 销毁
2. 容器的作用
- 1. 存放bean
- 2. bean的数据结构
- 3. list
- 4. set
- 5. map(K-V)
3. IOC容器
- 1. `BeanDefinition`的定义信息
- 2. 抽象定义规范接口`BeanDefinitionReader`
4. 创建对象方式
- 1. new
- 2. 反射如何创建对象
- 3. 工厂模式
- 4. Spring中bean的默认scope是单例的
5. xml和注解中定义的是bean的定义信息,通过抽象定义接口解析到BeanDefinition
6. BeanDefinition通过new反射到实例化
- 1. 实例化:在堆中开辟一块空间,属性都是默认值
- 2. 初始化:给属性赋值
1. 填充属性
2. 执行初始化方法`init-method`
7. 初始化到完整对象
8. Spring的扩展性设计
9. BeanDefinition到BeanFactory
10. PostProcessor增强器,进行扩展实现
11. BeanFactoryPostProcessor
- 1. 解析配置文件,处理占位符`placeholderConfigrerSupport`
- 2. 可以自行继承PostProcessor
- 3. `registerListeners`
12. bean的生命周期
- 1. 实例化`反射`
- 2. 填充属性`populateBean`
- 3. 执行aware接口需要实现的方法`invokeAwareMethods`
- 1. aware接口存在的意义是方便spring中的bean对象获取容器对象中的属性值
- 4. BeanPostProcessor
- 1. before
- 2. init-method`invokeInitMethods`
- 3. after
- 4. aop扩展
- 5. 完整对象
- 6. 销毁流程
13. Environment
- 1. System.getEnv()
- 2. System.getProperties()
14. 如果我想在spring生命周期的不同阶段做不同的处理工作?
1. 观察者模式:监听器、监听时间、多播器
15. spring中的do方法
## 五、单例Bean的线程安全和并发问题(重点)单例Bean是Spring容器默认的方式,所有线程都共享一个单例实例Bean,确实会存在并发的问题。对于原型Bean,每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。
### 1、单例Bean的线程安全问题1. 无状态对象(Stateless Bean)(`线程安全`)
- 1. 没有实例变量的对象,不能保存数据,是不变类,是线程安全的。
- 2. bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean 的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。
- 3. 由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean。
- 4. 无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。
2. 有状态对象(Stateful Bean)(`线程不安全`) :
- 1. 就是有实例变量的对象,可以保存数据,是非线程安全的。
- 2. 每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束。
- 3. 即每个用户最初都会得到一个初始的bean。
1. 解决方案
- 1. 尽量避免在Bean对象中定义可变的成员变量,避免有状态的Bean。
- 2. 如果确实需要使用状态的Bean,则在Bean对象中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中。
- 3. 也可以通过加锁的方法来解决线程安全,这种以时间换空间的场景在高并发场景下显然是不实际的,还是优先推荐使用ThreadLocal。
2. 多线程相同变量访问冲突问题:ThreadLocal和线程同步机制
- 1. 线程同步:`时间换空间`
- 2. ThreadLocal:`空间换时间`
- 3. ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。
- 4. ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal.
1. 编程式事务,使用TransactionTemplate。
2. 声明式事务,建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
3. 区别:声明式事务最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别
### 2、Spring事务的隔离级别(5种)1. 事务的隔离级别
### 3、Spring事务的传播行为(7种)1. Spring事务的传播行为说的是,当多个事务同时存在的时候,Spring如何处理这些事务的行为
## 七、Spring框架中用到的设计模式### 1. 工厂模式1. Spring使用工厂模式可以通过 BeanFactory 或 ApplicationContext 创建 bean 对象。两者的区别,
- 1. BeanFactory :延迟注入(使用到某个 bean 的时候才会注入),占用更少的内存,程序启动速度更快。
- 2. ApplicationContext :容器启动的时候,一次性创建所有 bean 。ApplicationContext除了BeanFactory的功能,还有额外更多功能,实际开发中,ApplicationContext更常用。
2. ApplicationContext的三个实现类:
- 1. ClassPathXmlApplication:把上下文文件当成类路径资源。
- 2. FileSystemXmlApplication:从文件系统中的 XML 文件载入上下文定义信息。
- 3. XmlWebApplicationContext:从Web系统中的XML文件载入上下文定义信息。
Spring 中 Bean 的默认作用域就是 singleton(单例)的。使用单例模式的好处
- 1. 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;
- 2. 由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。
Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术。
### 4. 模板方法用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate等。
### 5. 观察者模式定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现:ApplicationListener。
## 八、Spring框架的事件类型1. 上下文更新事件(ContextRefreshedEvent)
2. 上下文开始事件(ContextStartedEvent)
3. 上下文停止事件(ContextStoppedEvent)
4. 上下文关闭事件(ContextClosedEvent)
5. 请求处理事件(RequestHandledEvent)
## 参考资料- [一招带你搞定Spring源码,小白也能听懂的spring源码过程](https://www.ixigua.com/6898673954483864077)
- [Spring框架小白的蜕变](https://www.imooc.com/learn/1108)
- [探秘Spring AOP](https://www.imooc.com/learn/869)
- [2021最新Java面经整理 | 框架篇(一)Spring框架](https://blog.csdn.net/shipfei_csdn/article/details/109530018)
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com