随着业务的增长,需要进行分表、分库,甚至拆分应用演化成微服务。
因此一次交易需要跨库、跨服务保证每个系统中的交易要么全部成功,否则全部回滚。这里就涉及到分布式事务。

XA协议时一个基于数据库的分布式事务协议,其分为两部分:事务管理器和本地资源管理器。
事务管理器作为一个全局调度着,负责对各个本地资源管理器统一发送提交或者回滚命令。
二阶段提交和三阶段提交都是根据此协议衍生而来,Oracle和Mysql均已实现了XA接口。
除了二阶段提交和三阶段提交外还有Try Confirm Cancel (TCC)、本地消息队列等分布式事务解决方案。

二阶段提交 2PC

二阶段提交需要进行两个阶段的操作,准备阶段和提交阶段。

准备阶段就是事务管理器(协调者)分别给不同的系统发送“准备”命令,这些系统出了提交数据库事务之外的所有操作,都要在准备阶段操作完成。

提交阶段就是事务管理器(协调者)给不同的系统发送“提交”命令,每个系统提交自己的数据库事务,然后给协调者返回“提交成功”, 协调者收到所有响应以后,返回给客户端成功响应。
如果遇到异常情况提交不成功,需要做一些补偿机制来保证成功。

二阶段提交

对于二阶段提交:
如果准备阶段全部返回成功, 那么进入提交阶段,该必须保证成功。
如果准备阶段有一个失败,那么协调者通知每个系统回滚。

二阶段提交保证了原子性与隔离性。所以2PC适合对数据一致性高的场景。

缺陷:
性能低:整个事务的执行过程需要阻塞服务端线程和数据库会话。
协调者单点故障:一旦协调者宕机,就会导致事务回话一致处于等待提交阶段,直到事务超时自动回滚。
超时导致同步阻塞:当某个参与者节点通信处于超时,其余参与者都会被懂阻塞导致占用的资源不能释放。

适合场景:只有病发量不大且需要强一致的情况下才考虑使用2PC。

三阶段提交 3PC

三阶段提交是对二阶段提交的一种升级优化,它在二阶段提交的中间增加了precommit阶段。保证了在最后提交阶段之前,各个参与者节点状态都一致。
同时在协调者与参与者中都引入超时机制,当参与者由于各种原因未收到协调者的commit请求后,会对本地事务进行commit,不会一直阻塞等待,解决了2pc的单点故障问题,但是3pc还是没有能从根本上解决数据一致性的问题。

三个阶段分别是can commit、Pre Commit 、Do Commit;

三阶段提交

CanCommit

类似于二阶段提交的准备阶段,协调者向所有参与者发送CanCommit命令,询问是否可以执行事务提交操作,如果可以提交就返回YES,否则返回NO。如果全部响应YES则进入下一个阶段。

PreCommit

协调者根据参与者的反应情况来决定是否可以进行事务的PreCommit操作。根据响应情况,有两种可能

所有参与者的反馈都是YES那么执行事务的预执行:
1)发送于提交请求,协调者向参与者发送Precommit请求,并进入Prepared阶段。
2)事务预提交,参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。
3)响应反馈:如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。

假如任何一个参与者向协调者发送了NO响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
1)发送终端请求: 协调者向所有参与者发送abort请求。
2)中断事务:参与者收到来自协调者的abort请求之后(或者超时之后,仍未收到协调者的请求)执行事务的中断。

DoCommit

该阶段进行真正的事务提交,也分为两种情况。

执行提交

发送提交请求: 协调者接收到参与者发送的ACK响应,那么它将从预提交状态进入到提交状态。
并向所有参与者发送doCommit请求。
事务提交:参与者收到docommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有的事务资源。
响应反馈:参与者事务提交之后,向协调者发送ACK请求
完成事务: 协调者接收到所有参与者的ACK响应之后,完成事务。

中断事务

协调者没有接收到参与者发送的ACK响应(可能是参与者发送的不是ACK响应,也可能是响应超时),那么就会执行中断事务。

发送中断请求:协调者向所有参与者发送abort请求。
事务回滚:参与者接收到abort请求后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
反馈结果:参与者完成事务回滚之后,向协调者发送ACK信息
中断事务:协调者接收到参与者反馈的ACK消息之后,执行事务的中断操作。

三阶段提交状态图

如果已经完成了Precommit进入到Docommit阶段,有的参与者由于超时没有收到Docommit请求时,会自动提交本地事务,并且释放资源。

三阶段提交解决了二阶段提交无法释放资源的问题。
也保证了在提交事务之前所有参与者的状态都一致

补偿事务(TCC)

针对每个操作都要注册一个与其对应的确认和补偿(撤销操作)

它分为三个操作:

Try阶段

主要针对业务系统做检测以及资源预留。

Confirm阶段

确认执行业务操作。

Cancel阶段

取消执行业务操作。

TCC处理流程与2PC类似,不过2PC通常是在跨库的DB层面,TCC本质上就是一个应用层面的2PC,需要通过业务逻辑来实现。这种分布式事务的实现方式的优势在于,可以让应用自己定义数据库操作的粒度,是的降低锁冲突、提高吞吐量成为可能。

不足之处在于对应用的侵入性非常强,业务逻辑的每个分支都需要实现try、confirm、cancel三个操作。
此外其实现难度也比较大,需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。
为了满足一致性的要求,confirm和cancel必须实现幂等。

TCC(图片来源于网络)

本地消息队列

如果只需要保证数据的最终一致性,那么可以使用消息队列来解决。

什么是事务Transaction

Transaction一词在英语的翻译中还有一次交易、业务、事务、办理、处理;

对于一次账户充值100元的操作,其中就有多个环节。
1)检查账户的有效性,查询账户余额;
2)记录充值流水;
3)为账户余额增加100元。

对于这三个操作来讲,他是一个Transaction, 要么都成功,只要有一个失败,就必须整个Transaction失败,不允许记录了充值流水成功,但是余额增加失败。这三个是一个整体,是不可分割的工作单元。

事务的特性

原子性 Atomic:要么都成功,只要有一个步骤失败,整个步骤必须回滚(失败)。
一致性 Consistency:事务保证读取到的数据总是一致的,如(不存在100元的充值流水时金额为100元, 存在100元的充值流水时金额为200元)。
但是对于这个充值过程来讲,肯定是先记录了充值记录,后增加100元余额。可以查到充值记录,但余额是100是客观存在的。
隔离性Isolation:为了保证一致性,事务执行过程中的中间状态不对外部可见,事务需要对整个过程进行隔离。
持久性 Durability:只要事务一经提交,就一定会被持久化到磁盘中。

Transaction 阶段

Transaction 需要有开始和结束,标记一个Transaction的开始和截止;
当所有的操作都成功的时候,需要Commit;
当其中某个操作失败的时候,之前的操作需要Rollback;

Transaction Start;
Transaction Commit Or Rollback;
Transaction End;

脏读

假如业务员给账户A增加100元的操作的同时(记录了充值流水100元,流水号为666),对账系统也在同时运行同时读取到了这一笔流水号为666的流水记录。但是后续的为余额增加100元的操作失败了,整个Transaction RollBack。 导致账户余额比对账系统少了100元。

在这里,对账系统看到了业务系统Transaction未提交时的数据,叫脏读。
也就是说当前事务的中间状态,对其他事务时可见的。

事务的最低隔离级别是未提交读(Read Uncommitted),因此会发生脏读的现象。
为了解决脏读的现象,需要将事务隔离起来,只允许读到已提交的数据。 Read Committed.

不可重复读

假如业务员A给用户增加100元。

开启事务;
查询账户余额 100元;
有其他事情去忙……

此时业务员B也给用户增加100元。
开启事务;
查询账户余额 100元
增加流水记录;
增加账户余额100元,变为200元;
结束事务;

业务员A回来为A增加100元:
查询账户余额 200元;

不可重复读就是业务员A在同一个事务内,先后两次读取同一条数据的结果可能不一样。
可重复读就是业务员A在同一个事务内,先后两次读取同一条数据的结果总是相同的,无论其他会话是否已经更新了这条数据。

为了保障在同一事务下,先后两次读取到的同一条数据结果一致,需要将事务的隔离级别调整为可重复读(Repeatable Read)。

幻读

假如业务员A给用户增加100元。

开启事务;
查询流水中是否有ID为1000的流水记录,不存在;

业务员B给用户增加100元;
开启事务;
查询流水中是否有ID为1000的流水记录,不存在;
插入流水记录;
更新账户余额为200;
提交事务;

业务员A开始执行;
插入流水记录,此时已经有ID为1000的流水记录,系统异常;
可以开启重试机制;
由于隔离性,查询是否有ID为1000的流水记录时还是不存在,重试插入时还是异常。

为了解决幻读的问题,需要将所有的事务和操作进行串行化。这也是Database的最高隔离级别,性能也最差。

事务的隔离级别以及解决的问题

对于账户充值来讲,交易的原子性以及持久性是最重要的。可以适当牺牲一些一致性和隔离性。

以下操作在 ReadCommitted 和 Repeatable Read下是安全的。
1)给账户余额表增加一个log_id属性,记录最后一笔交易的流水号。
2)首先开启事务,查询并记录当前账户的余额和最后一笔交易的流水号。
3)写入流水记录。
4)更新账户余额以及流水记录ID,需要在更新语句的Where条件中限定,只有流水好等于之前查询出的流水号时才能更新。
update account_balance set amount = amount + 100 , log_id = 2 where user_id = 0 and log_id = 1;
5)检查更新余额的返回值,如果为1 提交事务,否则回滚。

refresh()

AbstractApplicationContext#refresh()

该方法是线程安全的方法,在startupShutdownMonitor的锁同步块中。

prepareRefresh()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}

// Initialize any placeholder property sources in the context environment.
initPropertySources();

// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();

// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}

// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}

obtainFreshBeanFactory()

This implementation performs an actual refresh of this context’s underlying bean factory, shutting down the previous bean factory (if any) and initializing a fresh bean factory for the next phase of the context’s lifecycle.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) { //如果存在beanfactory, 则关闭
destroyBeans();
closeBeanFactory();
}
try {
//为上下文生命周期的下个阶段初始化一个新的beanfactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
//指定ID
beanFactory.setSerializationId(getId());
//设置是否允许被覆盖,是否允许循环引用
customizeBeanFactory(beanFactory);
//从Xml、Annotation、Groovy中读取Bean信息并注册。
loadBeanDefinitions(beanFactory);
//set the refrences to this.beanFactory.
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

prepareBeanFactory(beanFactory)

Prepare the bean facotry for use in this context.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* Configure the factory's standard context characteristics,
* such as the context's ClassLoader and post-processors.
* @param beanFactory the BeanFactory to configure
*/
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}

postProcessBeanFactory(beanFactory)

Allows post-processing of the bean factory in context subclasses.

Modify the application context’s internal bean factory after its standard initialization.
All bean definitions will have bean loaded, but no beans have been instantiated yet.
This alllows for registering special BeanPostProcessors etc in certain Applicationcontext implementations.

invokeBeanFactoryPostProcessors(beanFactory);

invoke factory processors registered as beans in the creation.

Instantiate and invoke all registered BeanFactoryPostProcessor beans,
respecting explicit order if given. Must be called before singleton instantiation.

要设计一个内存型数据库需要考虑哪些?

0)终端连接

1)存储的数据结构(需要支持多样的数据类型、数据结构)

哈希表

Hash冲突:Key的Hash值冲突,导致一个桶挂了多个元素,Hash表退化成了链表,查找耗时。
rehash:为了解决Hash冲突的问题,需要rehash操作,增加现有的Hash桶数量。
渐进式Rehash:每操作一次迁移一个Entry,避免rehash造成的阻塞。

双向链表

整数数组

压缩队列

类似于一个数组,数组中的每一个元素都对应保存一个数据。
压缩列表表头有三个字段zlbytes 列表长度, zltail 列表尾部偏移量, zllen 列表中entry的个数, 压缩列表再表尾还有一个zlend,表示列表结束。

跳表

加速队列和数组的访问。

简单动态字符串

byte   1字节
boolean 1字节
char   2字节,只要是字符无论是英文还是汉字,都占2个字节。
short  2字节
int    4字节
long   8字节
float 4字节
double  8字节


整数数组和压缩列表再查找时间复杂度方面并没有很大的优势,为什么Redis还会把他们作为底层数据结构?

1)内存利用率方面:数组和压缩列表都是非常紧凑的数据结构,它比链表占用的内存更少。
Redis是内存数据库,大量数据存储到内存中,此时需要做尽可能的优化,提高内存的利用率。
2)数组对CPU高速缓存支持更友好,所以Redis再设计师,集合数据元素较少情况下,默认采用内存紧凑排列的方式存储,同时利用CPU高速缓存不会降低访问速度。
当数据元素超过设定阈值后看,避免时间复杂度太高,转为Hash和跳表数据结构存储,保证查询效率。

数组对CPU缓存友好的原因是,CPU预读取一个CacheLine大小的数据,数组数据排列紧凑,相同大小空间保存的元素更多,访问下一个元素时、恰好已经在CPU缓存中了,如果是随机访问,就不能充分利用CPU缓存。

2)对数据的加工和操作

单个元素的查找、修改、删除对于Redis来讲会非常快(在没有Hash冲突的情况下)
LLEN、SCARD等操作时间复杂度为O(1), 集合类型采用压缩列表,双向链表,整数数组等数据结构时,这些结构中专门记录了元素的个数统计,因此可以高效的完成相关操作。
HGETALL、SMEMBERS、LRANGE、ZRANGE等复杂度为O(N)的操作要避免,使用HSCAN、SSCAN、ZSCAN来替代,SCAN操作实现了渐进式便利,每次只返回优先数量的数据。

3)数据的安全性:
1)数据的备份:
实时备份:
对数据进行操作后记录操作日志
定时备份
2)数据的恢复
4)服务的高可用
主从模式

5)服务的监控、故障恢复以及通知
哨兵模式
哨兵集群

6)数据分片
纵向扩展:扩大服务器的内存,但是当存储数据内容较多,需要RDS备份时,会影响到Redis的使用性能。

横向扩展

数据结构

高性能IO模型

多路复用

命令解析

命令处理

数据安全

AOF AppendOnlyFile

记录每一条日志
日志压缩

RDB 快照

数据同步/读写分离 主从/主从从

哨兵

监测

选举

通知

哨兵集群

扩容

纵向扩容

横向扩容/分片

Spring 注解驱动编程发展历程

1.2 @Transactional
@ManagedResource
2.0 @Component
@Repository
3.0 @Bean
@Import

4.0 @Profile
@Conditional
@Indexed
Spring 核心注解场景分类

|注解|场景说明|起始版本|
|---|---|---|
|@Repository| 数据仓储模式注解| 2.0|
|@Component| 通用组件模式注解| 2.5|
|@Service| 服务模式注解| 2.5|
|@Controller| Web控制器模式注解| 2.5|
|@Configuration| 配置类模式注解| 3.0|

装配注解

|注解|场景说明|起始版本|
|---|---|---|
|@ImportResource| 替换XML元素\<import\>| 2.5|
|@Import| 导入Configuration类,无论是否标记@Configuration| 2.5|
|@ComponentScan| 扫描指定package下标注Spring模式注解的类| 3.1|

依赖注入注解

|注解|场景说明|起始版本|
|---|---|---|
|@Autowired| Bean依赖注入,支持多种依赖查找方式| 2.5|
|@Qualifier| 细粒度的@Autowired查找| 2.5|

Spring 注解编程模型

元注解
Spring 模式注解
Spring 组合注解
Spring 注解属性别名/覆盖

Spring 元注解(Meta-Annotations)

A meta-annotation is an annotation that is declared on another annotation.
An annotation is therefore meta-annotated if it is annotated with another annotation. For example, any annotation that is declared to be documented is meta-annotated with @Documented from the java.lang.annotation package.

  • java.lang.annotation.Documented
  • java.lang.annotation.Inherited
  • java.lang.annotation.Repeatable

Spring 模式注解(Stereotype Annotations)

元标注@Component的注解在XML元素 context:component-scan 或 注解 @ComponentScan 扫描中派生了 @Component 特性, 并且从Spring Framework 4.0 开始支持多层次派生。

  • @Repository
  • @Service
  • @Controller
  • @Configuration
  • @SpringBootConfiguration

Spring 组合注解(Composed Annotations)

A composed annotation is an annotation that is meta-annotated withy one or more annotations with the intent of combining the behavor associated with those meta-annotations into a single custom annotation.
For example, an annotation named @TransactionalService that is meta-annotation with Spring’s @Transactional and @Service annotations is a composed annotation that combines the semantics of @Transactional and @Service.
@TransactionalService is technically also a custom stereotype annotation.

基本定义:

spring组合注解中的元注解允许是Spring模式注解与其他Spring功能性注解的任意组合。

Spring 注解属性别名(Attribute Alias)

Spring 注解属性覆盖(Attribute Ovverides)

Spring @Enable 模块驱动

@Import(@Configuration)
@Import(ImportSelector)
@Import(ImportBeanDefinitionRegistrar)
AnnotatedBeanDefinition ad = new AnnotatedGenericBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(ad, register);

Spring 条件注解

上下文对象: org.springframework.context.annotation.ConditionContext
条件判断:org.springframework.context.annotation.ConditionEvaluator
配置阶段:org.sprignframework.context.annotation.ConfigurationCondition.ConfigurationPhase
判断入口:org.springframework.context.annotation.ConfigurationClassPostProcessor
org.springframework.context.annotation.ConfigurationClassPasser
ConditionContext
ConditionEvaluator

Spring 校验使用场景
Spring 常规校验 Validator
Spring 数据绑定 Databinder
Spring Web 参数绑定 WebDataBinder
Spring WebMVC/WebFlux 处理方法参数校验

Validator 接口设计

Errors 接口设计

Errors 文案来源

自定义Validator

Validator的救赎

面试题

引入冬季

Java标准资源管理

强大
|面向资源|文件系统、artifact(Jar、War、ear)、远程资源(HTTP/FTP)|
|API整合|java.lang.ClassLoader.getResource\ java.io.File / java.net.URL|
|资源定位|java.net.URL / java.net.URI|
|面向流存储|java.net.URLConnection|
|协议扩展|java.net.URLStreamHandler / java.net.URLStreamHandlerFactory|
扩展复杂

扩展协议

Spring资源接口

类型 接口
输入流 org.springframework.core.io.InputStreamSource
只读资源 org.springframework.core.io.Resource
可写资源 org.springframework.core.io.WritableResource
编码资源 org.springframework.core.io.EncodedResource
上下文资源 org.springframework.core.io.ContextResource

Spring InputStreamResource

Spring内建Resource实现

|Bean 定义|无|org.springframework.beans.factory.support.BeanDefinitionResource|
|字节码|无|org.springframework.core.io.ByteArrayResource|
|类路径|classpath:/|org.springframework.core.io.ClassPathResource|
|文件系统|file:/|org.springframework.core.io.FileSystemResource|
|URL|URL支持的协议|org.springframework.core.io.UrlResource|
|ServletContext|无|org.springframework.web.context.support.ServletContextResource|

Spring Resource 接口扩展
Spring 资源加载器

  • Resource 加载器
    • org.springframework.core.io.ResourceLoader
      • org.springframewor.core.io.DefaultResourceLoader
        • org.springframework.core.io.FileSystemResourceLoader
        • org.springframework.core.io.ClassRelativeResourceLoader
        • org.springframework.context.support.AbstractapplicationContext

Spring 通配路径资源加载器

  • 通配路径ResourceLoader
    • org.springframework.core.io.support.ResourcePatternResolver
      • org.springframework.core.io.support.PathMatchingResourcePatternResolver
  • 路径匹配起
    • org.springframework.util.PathMatcher
      • Ant模式匹配实现 - org.springframework.util.AntPathMatcher

Spring 通配路径资源扩展

依赖注入 Spring Resource

@Value(“classpath:/…”)
private Resource resource;

依赖注入 ResourceLoader

  • 实现 ResourceLoaderAware 回调
  • @Autowire 注入 ResourceLoader
  • 注入ApplicationContext 作为 ResourceLoader

Java 标准资源管理扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
public class XURLConnection extends URLConnection{

private final UrlResource resource;

protected XURLConnection(URL url){
super(url);
this.resource = new ClassPathResource(url.getPath());
}

public InputStream getInputStream() throws IOException{
return resource.getInputStream();
}
}
1
2
3
4
5
public class Handler extends URLStreamHandler{
protected URLConnection openConnection(URL u) throws IOException{
return new XURLConnection(u);
}
}
1
2
3
URL url = new URL("x:///META-INF/default.properties");
InputStream is = url.openStream();
System.out.println(StreamUtils.copyString(is, Charset.forName("UTF-8")));
  • 实现URLStreamHandler, 添加 -Djava.protocal.handler.pkgs 启动参数,指向URLStreamHandler 实现类的包

  • 实现URLStreamHandlerFactory 并传递到URL之中

Spring 配置元信息

Bean配置元信息:BeanDefinition
Bean属性元信息:PropertyValues
容器配置元信息
外部化配置元信息: PropertySource
Profile 元信息: @Profile

Spring Bean 配置元信息

GenericBeanDefinition
RootBeanDefinition
AnnotatedBeanDefinition

Spring Bean 属性元信息
PropertyValues
MutablePropertyValues
PropertyValue
Bean 属性上下文存储
AttributeAccessor
Bean 元信息元素
BeanMetadataElement

Spring 容器配置元信息

beans 元素

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<!-- outter -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
profile="dev" default-lazy-init="default" default-merge="default" default-autowire="default"
default-autowire-candidates="" default-init-method="" default-destroy-method=""
>
<!-- inner -->
<import resource="applicationContext-lookup.xml"/>
<bean id="userRepository" class="com.github.springframework.repository.UserRepository" autowire="byType"></bean>
</beans>
Beans元素属性 默认值 使用场景
profile null(留空) SpringProfiles 配置值
default-lazy-init default 当outter Beans “default-lazy-init”属性存在时,继承该值,否则为false
default-merge default 当outter beans ‘default-merge’ 属性存在时,继承该值,否则为“false”
default-autowire default 当outter beans “default-autowire”存在时,继承该值,否则为no
default-autowire-candidates null 默认SpringBean名称的pattern
default-init-method null 默认springBeans 自定义初始化方法
default-destroy-method null 默认SpringBean自定义的销毁方法

Spring Xml 配置元信息

xml元素 使用场景
<context:annotation-config/> 激活Spring注解驱动
<context:component-scan/> Spring @Component 以及自定义注解扫描
<context:load-time-weaver /> 激活Spring LoadTimeWeaver
<context:mbean-export /> 暴露Springbeans 做为JMX beans
<context:mbean-server /> 将当前平台作为MBeanServer
<context:property-placeholder /> 加载外部化配置资源作为Spring属性配置
<context:property-override /> 利用外部化配置资源覆盖Spring属性值

底层实现 BeanDefinitionParserDelegate

基于XML文件装载

Spring Bean 配置元信息

xml元素 使用场景
<beans:beans /> 单XML资源下的多个SpringBean配置
<beans:bean /> 单个SpringBean定义Beandefinition 配置
<beans:alias /> 为SpringBean 定义(BeanDefinition)映射别名
<beans:import /> 加载外部SpringXML 配置资源

底层实现 XmlBeanDefinitionReader BeanDefinitionDocumentReader BeanDefinitionHolder

基于Properties文件装载

Spring Bean 配置元信息

Properties 属性名 使用场景
(class) Bean类全称限定名
(abstract) 是否为抽象的BeanDefinition
(parent) 指定 parent BeanDefinition
(lazy-init) 是否延迟初始化
(ref) 引用其他Bean的名称
(scope) 设置Bean的scope属性
${n} n标示第n个构造器参数
底层实现PropertiesBeanDefinitionReader

基于Java注解装载SpringBean的配置元信息

Spring注解 场景说明
@Repository 数据仓储模式
@Component 通用组建模式
@Service 服务模式
@Controller Web控制器模式
@Configuration 配置类模式
@Autowired Bean依赖注入,支持多种依赖查找方式
@Qualifier 细粒度的@Autowired 依赖查找
@Resource Java注解,类似于@Autowired
@Inject Java注解,类似于@Autowired
@Profile 配置话条件装配
@Conditional 编程条件装配
@PostConstructor 替换XML元素 <bean init-method=” /> 或者 initializingBean
@PreDestroy 替换XML元素 或者 DisposableBean

ClassPathScanningCandidateComponentProvider
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor

SpringBean配置元信息底层实现

  • Xml资源 BeanDefinition解析与注册

    • 核心API: XmlBeanDefinitionReader
      • 资源: Resource
      • 底层: BeanDefinitionDocumentReader
        • XML 解析: JavaDOM Level 3 API
        • BeanDefinition 解析 BeanDefinitionParserDelegate
        • BeanDefinition 注册 BeanDefinitionRegistry
          DefaultBeanDefinitionDocumentReader
  • Properties 资源 BeanDefinition 解析与注册

    • 核心API:PropertiesBeanDefinitionReader
      • 资源
        • 字节流:Resource
        • 字符流:EncodeResource
      • 底层:
        • 存储:java.util.Properties
        • BeanDefinition 解析: API内部实现
        • BeanDefinition 注册: BeanDefinitionRegistry
  • Annotation 解析与注册

    • 核心API:AnnotatedBeanDefinitionReader
      • 资源
        • 类对象: java.lang.Class
      • 底层
        • 条件评估: ConditionEvaluator
        • Bean范围解析: ScopeMetadataResolver
        • BeanDefinition解析:内部API实现
        • BeanDefinition处理:AnnotationConfigUtils.processCommonDefinitionAnnotations
        • BeanDefinition注册:BeanDefinitionRegistry

基于XML文件装载SpringIOC容器配置元信息

命名空间 所属模块 Schema资源URL
beans spring-beans https://www.springframework.org/schema/beans/spring-beans.xsd
context spring-context https://www.springframework.org/schema/context/spring-context.xsd
aop spring-aop https://www.springframework.org/schema/aop/spring-aop.xsd
tx spring-tx https://www.springframework.org/schema/tx/spring-tx.xsd
util spring-util https://www.springframework.org/schema/util/spring-util.xsd
tool spring-tool https://www.springframework.org/schema/tool/spring-tool.xsd

基于Java注解装载SpringIOC容器配置元信息

Spring注解 场景说明 Since
@ImportResource 替换XML元素 </import> 3.0
@Import 导入Configuration Class 3.0
@ComponentScan 扫描指定package下标注Spring模式注解的类 3.1
@PropertySource 配置属性抽象 3.1
@PropertySources @PropertySource集合注解 4.0

基于ExtensibleXML authoring扩展Spring XML元素

  • 编写 XML Schema 文件,定义XML结构
  • 自定义NameSpaceHandler, 实现命名空间绑定
  • 自定义BeanDefinitionParser, 实现XML元素与BeanDefinition解析
  • 注册XML扩展:命名空间与XML Schema 映射

Extensible XML authoring扩展原理

  • AbstractApplicationcontext.obtainFreshBeanFactory
    • AbstractRefreshableApplicationContext.refreshBeanFactory
      • AbstractXmlApplicationContext.loadBeanDefinitions
        • XmlBeanDefinitionReader.doLoadBeanDefinitions
          • BeanDefinitionParserDelegate.parseCustomElement

BewanDefinitionParserDelegate.parseCustomElement(Element, BeanDefinition);

  • 获取namespace
  • 通过namespace 解析NamespaceHandler
  • 构造ParserContext
  • 解析元素,获取BeanDefinition

基于Properties文件装载外部化配置
基于YAML文件装载外部化配置

  • org.springfrmework.beans.factory.config.YamlProcessor
    • org.springframework.beans.factory.config.YamlMapFactoryBean
    • org.springframework.beans.factory.config.YamlPropertiesFactoryBean

SpringBean 元信息

BeanDefinition Class Diagram

元信息的配置

  • 通过资源的方式配置,如: XML、 Properties、Groovy
  • 通过注解配置 : @Bean
  • 通过API配置 :BeanDefinitionBuilder / GenericBeanDefinition

元信息的读取

1) Get beanDefinitionRegistry for registry beanDefinitions.
2) Get ResourceLoader
3) Get ClassLoader.

  • 读取通过资源方式配置,如:XmlBeanDefinitionReader、PropertiesBeanDefinitionReader、GroovyBeanDefinitionReader
  • 读取注解配置的Bean:AnnotatedBeanDefinitionReader

BeanDefinitionReader Class Diagram

1
2
3
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(beanFactory);
reader.register(Main.class);

元信息的解析

BeanDefinitionParser

图片版本的看不太清,整理一份文字版本的层级关系,除BeanDefinitionParser是顶层抽象接口外,其余Parser都是类或者抽象类。

  • BeanDefinitionParser
    • SpringConfiguredBeanDefinitionParser
    • AnnotationDrivenCacheBeanDefinitionParser
    • ScriptingDefaultsParser
    • ComponentScanBeanDefinitionParser
    • AnnotationConfigBeanDefinitionParser
    • AspectJAutoProxyBeanDewfinitionParser
    • SpringConfiguredBeanDefinitionParser
    • ConfigBeanDefinitionParser
    • AnnotationDrivenBeanDefinitionParser
    • AbstractBeanDefinitionParser
      • MBeanExportBeanDefinitionParser
      • MBeanServiceBeanDefinitionParser
      • ScriptBeanDefinitionParser
      • AbstractSingleBeanDefinitionParser
        • ExecutorBeanDefinitionParser
        • SchedulerBeanDefinitionParser
        • SetBeanDefinitionParser
        • AbstractPropertyLoadingBeanDefinitionParser
        • LoadTimeWeaverBeanDefinitionParser
        • CacheAdviceParser
        • ListBeanDefinitionParser
        • ScheduledTasksBeanDefinitionParser
        • MapBeanDefinitionParser
        • PropertiesBeanDefinitionParser
        • PropertyPathBeanDefinitionParser
        • AbstractSimpleBeanDefinitionParser
          • ConstantBeanDefinitionParser
          • AbstractJndiLocatingBeanDefinitionParser
            • JndiLookupBeanDefinitionParser
            • LocalStatelessSessionBeanDefinitionParser
            • RemoteStatelessSessionBeanDefinitionParser

SpringBean 注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {

BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}

if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}

Spring BeanDefinition 合并阶段

GenericBeanDefinition -> RootBeanDefinition

Spring Bean Class 加载阶段

BeanDefinition 中定义的Class名称加载具体的Class类。

ClassLoader 类加载
Java Security 安全控制
ConfigurableBeanFactory 临时 ClassLoader

Spring Bean 实例化
实例化前:
InstantiationAwareBeanProcessor.postProcessorBeforeInstantiation()
提前生成一些代理对象,替换掉默认的springIOC的实现内容。
实例化
传统实例化方式
+ 实例化策略 InstantiationStrategy

构造器依赖注入(根据类型来注入)

实例化后
InstantiationAwareBeanProcessor.postProcessorAfterInstantiation()

Spring Bean 属性赋值前阶段

Bean的属性值元信息: PropertyValues
构造器参数值:ConstructorValues

Bean属性赋值前回调
<= 5.0 InstantiationAwareBeanPostProcessor#postProcessorPropertyValues();
>= 5.1 InstantiationAwareBeanPostProcessor#postProcessorProperties();

Spring Bean Aware 接口回调阶段

Aware接口是一个标志接口,并没有提供任何实现。
BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
EnvironmentAware
EmbeddedValueResolverAware
ApplicationEventPublisherAware
MessageSourceAware
ApplicationContextAware

Spring Bean 初始化

初始化前
BeanPostProcessor#postProcessorBeforeInitialization
初始化
@PostConstructor
AfterPropertiesSet
init-method
初始化后
BeanPostProcessor#postProcessAfterInitialization
初始化完成
SmartinitializingSingleton#afterSingletonsInstanted

AbstractAutowireCapableBeanFactory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* <p>Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @return the initialized bean instance (potentially wrapped)
* @see BeanNameAware
* @see BeanClassLoaderAware
* @see BeanFactoryAware
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

return wrappedBean;
}

Spring Bean 销毁
销毁前
DestructionAwareBeanPostProcessor#postProcessorBeforeDestruction
销毁
@PreDestroy
实现DisposableBean接口的destroy方法
自定义销毁方法
垃圾回收
关闭Spring 容器
执行GC
SpringBean 覆盖finalize()方法被回调