Nothing that has meaning is easy. - 有意义的事从来都不是容易的。

Trace-Recorder V2.5.1

简单的, 可伸缩的, 高性能的。

trace-recorder 是一个跟踪记录仪,主要是为了更好的去进行源码流程的记录, 可以更好的获取源码执行的基础流程和全流程;通过可伸缩的插件体系可以更好的去管理记录。

一、快速开始

dependency(依赖)

gradle
1
2
3
4
5
6
7
8
9
10
11
// 核心包 - 必要
// https://mvnrepository.com/artifact/cn.xusc/trace-recorder-core
implementation 'cn.xusc:trace-recorder-core:2.5.1'

// echarts关系图 - 如需记录关系图化
// https://mvnrepository.com/artifact/cn.xusc/trace-recorder-chart-echarts-relation
implementation 'cn.xusc:trace-recorder-chart-echarts-relation:2.5.1'

// 内部运行日志 - 如需查看跟踪记录仪详情(遵循SLF4J日志规范,可以使用simple日志实现)
// https://mvnrepository.com/artifact/org.slf4j/slf4j-simple
implementation 'org.slf4j:slf4j-simple:2.0.3'
maven
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 核心包 - 必要
<!-- https://mvnrepository.com/artifact/cn.xusc/trace-recorder-core -->
<dependency>
<groupId>cn.xusc</groupId>
<artifactId>trace-recorder-core</artifactId>
<version>2.5.1</version>
</dependency>

// echarts关系图 - 如需记录关系图化
<!-- https://mvnrepository.com/artifact/cn.xusc/trace-recorder-chart-echarts-relation -->
<dependency>
<groupId>cn.xusc</groupId>
<artifactId>trace-recorder-chart-echarts-relation</artifactId>
<version>2.5.1</version>
</dependency>

// 内部运行日志 - 如需查看跟踪记录仪详情(遵循SLF4J日志规范,可以使用simple日志实现)
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.3</version>
</dependency>

coding(编码)

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
package cn.xusc;//注意包修改,切勿直接复制运行

import cn.xusc.trace.core.TraceRecorder;
import cn.xusc.trace.core.util.TraceRecorders;

/**
* 引导启动
*
* @author wangcai
*/
public class Bootstrap {

public static void main(String[] args) {
TraceRecorder recorder = new TraceRecorder();
recorder.log("hello TraceRecorder!");
welcomeEchartsRelationChart();
}

/**
* 欢迎echarts关系图化
*/
public static void welcomeEchartsRelationChart(){
TraceRecorders.get().log("welcome echarts relation chart");
}
}

console(控制台)

console info(控制台信息)
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
00:44:59: Executing ':Bootstrap.main()'...

> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE

> Task :Bootstrap.main()
[main] INFO cn.xusc.trace.core.TraceRecorder -
___
,--.'|_ ,---,
| | :,' __ ,-. __ ,-. ,---. __ ,-. ,---.'| __ ,-.
: : ' : ,' ,'/ /| ,' ,'/ /| ' ,'\ ,' ,'/ /| | | : ,' ,'/ /|
.;__,' / ' | |' | ,--.--. ,---. ,---. ' | |' | ,---. ,---. / / |' | |' | | | | ,---. ' | |' |
| | | | | ,'/ \ / \ / \ | | ,'/ \ / \. ; ,. :| | ,',--.__| | / \ | | ,'
:__,'| : ' : / .--. .-. | / / ' / / | ' : / / / | / / '' | |: :' : / / ,' | / / |' : /
' : |__ | | ' \__\/: . .. ' / . ' / | | | ' . ' / |. ' / ' | .; :| | ' . ' / |. ' / || | '
| | '.'|; : | ," .--.; |' ; :__ ' ; /| ; : | ' ; /|' ; :__| : |; : | ' ; |: |' ; /|; : |
; : ;| , ; / / ,. |' | '.'|' | / | | , ; ' | / |' | '.'|\ \ / | , ; | | '/ '' | / || , ;
| , / ---' ; : .' \ : :| : | ---' | : || : : `----' ---' | : :|| : | ---'
---`-' | , .-./\ \ / \ \ / \ \ / \ \ / \ \ / \ \ /
`--`---' `----' `----' `----' `----' `----' `----'

[main] INFO cn.xusc.trace.core.TraceRecorder - local thread enable share TraceRecorder [ TraceRecorder-1 ] successful!
[main] INFO cn.xusc.trace.core.TraceRecorder - TraceRecorder environment create successful!
[main] INFO cn.xusc.trace.core.TraceRecorder - init base environment successful!
[main] INFO cn.xusc.trace.core.TraceRecorder - enable spi components register
[main] INFO cn.xusc.trace.core.TraceRecorder - inner spi components register:
[main] INFO cn.xusc.trace.core.TraceRecorder - register InfoFilter component: cn.xusc.trace.core.filter.RecordLabelInfoFilter
[main] INFO cn.xusc.trace.core.TraceRecorder - register InfoEnhancer component: cn.xusc.trace.core.enhance.LineInfoEnhancer
[main] INFO cn.xusc.trace.core.TraceRecorder - register InfoEnhancer component: cn.xusc.trace.core.enhance.StackInfoEnhancer
[main] INFO cn.xusc.trace.core.TraceRecorder - register InfoEnhancer component: cn.xusc.trace.core.enhance.ShortClassNameInfoEnhancer
[main] INFO cn.xusc.trace.core.TraceRecorder - register InfoEnhancer component: cn.xusc.trace.core.enhance.ThreadInfoEnhancer
[main] INFO cn.xusc.trace.core.TraceRecorder - register InfoRecorder component: cn.xusc.trace.core.record.ConsoleInfoRecorder
[main] INFO cn.xusc.trace.core.TraceRecorder - external spi components register:
[main] INFO cn.xusc.trace.core.TraceRecorder - register InfoEnhancer component: cn.xusc.trace.chart.ChartEnhancer
---------------------------------------------------------
- Tomcat Server stared! -
- access: http://localhost:5729/trace-recorder/ -
- access: http://localhost:5729/trace-recorder/relation -
- close : http://localhost:5729/trace-recorder/close -
---------------------------------------------------------

main cn.xusc.Bootstrap.main()[16] - hello TraceRecorder!
main cn.xusc.Bootstrap.welcomeEchartsRelationChart()[24] - welcome echarts relation chart

page(页面)

需依赖trace-recorder-chart-echarts-relation包方可关系图化,可在dependency中查看依赖

二、新特性说明

待补充

三、特别说明

2.5版本去哪了?
1
2.5版本是不完整的版本,没有兼容windows,故已弃用。
下一个版本规划
1
暂无规划,想好了再修改

四、项目地址

github直链gitee直链

github: https://github.com/Cw404/trace-recorder
gitee:  https://gitee.com/Cw404/trace-recorder

五、历史版本

Trace-Recorder history

2.4 version

2.3 version补充: 废弃Recorders,由于该类只是为了兼容1.0的方便使用,请使用更灵活的方式TraceRecorder + TraceRecorderConfig

一、简介 2.4

Trace-Recorder 是笔者开源的一个简单的、可伸缩的、高性能的记录框架。

主要解决:看源码时记录不方便,没有一个清晰的流程能更直观了解到源码的步骤,重复看一个框架都觉得是一个新的。那么我想你可能需要它。

  • 使用简单,一行代码可搞定简单记录
  • 伸缩性强,可自定义扩展
  • 配置灵活,xml和properties两向曲
  • 性能高速,在并发的场景下记录处理更快速

二、使用 2.4

项目依赖

gradle

1
implementation 'cn.xusc:trace-recorder:2.4'

maven

1
2
3
4
5
<dependency>
<groupId>cn.xusc</groupId>
<artifactId>trace-recorder</artifactId>
<version>2.4</version>
</dependency>

跟踪记录仪属性-更灵活的配置

可以根据xml文件和properties文件进行灵活配置,并加载生成TraceRecorderConfig

目录结构

目录结构

PrefixInfoEnhancer

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
package cn.xusc.enhance;

import cn.xusc.trace.EnhanceInfo;
import cn.xusc.trace.enhance.InfoEnhancer;

/**
* 前缀信息增强器
*
* @author wangcai
*/
public class PrefixInfoEnhancer implements InfoEnhancer {

@Override
public EnhanceInfo enhance(EnhanceInfo eInfo) {
eInfo.setInfo("prefix:" + eInfo.getInfo());
return eInfo;
}

@Override
public EnhanceInfo setWriteInfo(EnhanceInfo eInfo) {
eInfo.setWriteInfo(eInfo.getInfo());
return eInfo;
}
}

TraceRecorderProperties.properties

1
2
3
4
5
6
# more see cn.xusc.trace.util.TraceRecorderProperties
cn.xusc.trace.config.TraceRecorderConfig.enableStack=true
cn.xusc.trace.config.TraceRecorderConfig.enableThreadName=true
cn.xusc.trace.config.TraceRecorderConfig.enableAsync=false
cn.xusc.trace.config.TraceRecorderConfig.infoEnhancers=cn.xusc.enhance.PrefixInfoEnhancer

TraceRecorderProperties.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>more see cn.xusc.trace.util.TraceRecorderProperties</comment>
<entry key="cn.xusc.trace.config.TraceRecorderConfig.enableStack">true</entry>
<entry key="cn.xusc.trace.config.TraceRecorderConfig.enableThreadName">true</entry>
<entry key="cn.xusc.trace.config.TraceRecorderConfig.enableAsync">false</entry>
<entry key="cn.xusc.trace.config.TraceRecorderConfig.infoEnhancers">
cn.xusc.enhance.PrefixInfoEnhancer
</entry>
</properties>

Bootstrap

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
package cn.xusc;

import cn.xusc.trace.TraceRecorder;
import cn.xusc.trace.config.TraceRecorderConfig;
import cn.xusc.trace.util.TraceRecorderProperties;

import java.io.IOException;

public class Bootstrap {

public static void main(String[] args) throws IOException {
// 构建跟踪记录仪属性
TraceRecorderProperties properties = new TraceRecorderProperties();
// 加载TraceRecorderProperties.properties配置
properties.load(ClassLoader.getSystemClassLoader().getResource("TraceRecorderProperties.properties"));
// 加载TraceRecorderProperties.xml配置
// properties.loadFromXML(ClassLoader.getSystemClassLoader().getResource("TraceRecorderProperties.xml"));
// 获取TraceRecorderConfig配置
TraceRecorderConfig config = properties.config();
// 构建配置相关性的跟踪记录仪
TraceRecorder recorder = new TraceRecorder(config);
// 记录消息
recorder.log("hello {}", "TraceRecorderProperties");
}
}
1
2
> Task :webflux:Bootstrap.main()
main cn.xusc.Bootstrap.main()[22] - prefix:hello TraceRecorderProperties

三、项目地址 2.4

github: https://github.com/Cw404/Trace-Recorder

2.2 version

一、简介 2.2

Trace-Recorder 是笔者开源的一个简单的、可伸缩的、高性能的记录框架。

主要解决:看源码时记录不方便,没有一个清晰的流程能更直观了解到源码的步骤,重复看一个框架都觉得是一个新的。那么我想你可能需要它。

  • 使用简单,一行代码可搞定简单记录
  • 伸缩性强,可自定义扩展
  • 性能高速,在并发的场景下记录处理更快速

二、使用 2.2

项目依赖

gradle

1
implementation 'cn.xusc:trace-recorder:2.2'

maven

1
2
3
4
5
<dependency>
<groupId>cn.xusc</groupId>
<artifactId>trace-recorder</artifactId>
<version>2.2</version>
</dependency>

关闭跟踪记录仪

关闭跟踪记录仪,只是释放了异步的资源,并未对其进行标记bug - fixup to V2.2.1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import cn.xusc.trace.TraceRecorder;
import cn.xusc.trace.config.TraceRecorderConfig;

import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class Bootstrap {

public static void main(String[] args) throws InterruptedException {
//构建异步跟踪记录仪
TraceRecorder recorder = new TraceRecorder(TraceRecorderConfig.builder().enableAsync(true).taskHandlerSize(1).build());
// 构建 provider 进行消息提供
new Thread(() -> {
IntStream.rangeClosed(1,10).forEach(i -> recorder.log("shutdown - {}" ,i));
},"provider").start();
// 为 provider 提供启动预热
TimeUnit.MILLISECONDS.sleep(6);
// 关闭记录仪
recorder.shutdown();
}
}
1
2
3
4
5
> Task :webflux:Bootstrap.main()
shutdown - 1

shutdown - 2

复位

重置特殊的结构,回到原始的组件模样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import cn.xusc.trace.TraceRecorder;
import cn.xusc.trace.constant.RecordLabel;
import cn.xusc.trace.filter.InfoFilter;

public class Bootstrap {

public static void main(String[] args) {
TraceRecorder recorder = new TraceRecorder();
recorder.log("success");
// 增加信息过滤器 -> 因为总是返回false,所以总是失败
recorder.addInfoFilter(new InfoFilter() {
@Override
public boolean isRecord(String info, RecordLabel label) {
return false;
}
});
recorder.log("failure");
// 重置特殊的结构(复位) -> 将添加的特殊组件丢弃,回到原始的组件结构
recorder.resetSpecial();
recorder.log("success");
}
}
1
2
3
> Task :webflux:Bootstrap.main()
main cn.xusc.Bootstrap.main()[11] - success
main cn.xusc.Bootstrap.main()[22] - success

三、项目地址 2.2

github: https://github.com/Cw404/Trace-Recorder

2.0 version

一、简介 2.0

Trace-Recorder 是笔者开源的一个简单的、可伸缩的、高性能的记录框架。

主要解决:看源码时记录不方便,没有一个清晰的流程能更直观了解到源码的步骤,重复看一个框架都觉得是一个新的。那么我想你可能需要它。

  • 使用简单,一行代码可搞定简单记录
  • 伸缩性强,可自定义扩展
  • 性能高速,在并发的场景下记录处理更快速

二、使用 2.0

项目依赖

gradle

1
implementation 'cn.xusc:trace-recorder:2.0'

maven

1
2
3
4
5
<dependency>
<groupId>cn.xusc</groupId>
<artifactId>trace-recorder</artifactId>
<version>2.0</version>
</dependency>

简单异步记录

简单的异步输出

1
2
3
4
5
6
7
8
9
10
import cn.xusc.trace.util.Recorders;

public class Bootstrap {
public static void main(String[] args) {
System.out.println("Hello world!");
// Trace-Recorder 使用
Recorders.enableAsync();
Recorders.log("hello {}", "world!");
}
}
1
2
3
> Task :webflux:Bootstrap.main()
Hello world!
TaskHandler-1 cn.xusc.Bootstrap.main()[10] - hello world!

配置化的记录

配置化的输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import cn.xusc.trace.config.TraceRecorderConfig;
import cn.xusc.trace.util.Recorders;

import java.util.stream.IntStream;

public class Bootstrap {
public static void main(String[] args) {
System.out.println("Hello world!");
// Trace-Recorder 使用
Recorders.config(
TraceRecorderConfig.builder()
.enableStack(true) // 启用栈信息
.enableThreadName(true) // 启用线程名信息
.enableAsync(true) // 启用异步
.taskHandlerSize(2) // 设置异步任务处理器数量
.build()
);
/*
构建三个记录
*/
IntStream.rangeClosed(1, 3).forEach(i -> Recorders.log("hello {}", "world!"));
}
}
1
2
3
4
5
> Task :webflux:Bootstrap.main()
Hello world!
TaskHandler-2 cn.xusc.Bootstrap.lambda$main$0()[20] - hello world!
TaskHandler-1 cn.xusc.Bootstrap.lambda$main$0()[20] - hello world!
TaskHandler-2 cn.xusc.Bootstrap.lambda$main$0()[20] - hello world!

三、项目地址 2.0

github: https://github.com/Cw404/Trace-Recorder

1.2 version

一、简介 1.2

在1.0版本上增加了信息格式化的功能

二、使用 1.2

项目依赖

gradle

1
implementation 'cn.xusc:trace-recorder:1.2'

maven

1
2
3
4
5
<dependency>
<groupId>cn.xusc</groupId>
<artifactId>trace-recorder</artifactId>
<version>1.2</version>
</dependency>

信息格式化记录

信息格式化的输出

1
2
3
4
5
6
7
8
9
import cn.xusc.trace.util.Recorders;

public class Bootstrap {
public static void main(String[] args) {
System.out.println("Hello world!");
// Trace-Recorder 使用
Recorders.log("hello {}", "world!");
}
}
1
2
3
> Task :webflux:Bootstrap.main()
Hello world!
cn.xusc.Bootstrap.main()[9] - hello world!

三、项目地址 1.2

github: https://github.com/Cw404/Trace-Recorder

1.0 version

一、简介 1.0

Trace-Recorder 是笔者开源的一个简单的、可伸缩的记录框架。

主要解决:看源码时记录不方便,没有一个清晰的流程能更直观了解到源码的步骤,重复看一个框架都觉得是一个新的。那么我想你可能需要它。

  • 使用简单,一行代码可搞定简单记录
  • 伸缩性强,可自定义扩展

二、使用 1.0

项目依赖

gradle

1
implementation 'cn.xusc:trace-recorder:1.0'

maven

1
2
3
4
5
<dependency>
<groupId>cn.xusc</groupId>
<artifactId>trace-recorder</artifactId>
<version>1.0</version>
</dependency>

简单记录

更详细的输出

1
2
3
4
5
6
7
8
9
import cn.xusc.trace.util.Recorders;

public class Bootstrap {
public static void main(String[] args) {
System.out.println("Hello world!");
// Trace-Recorder 使用
Recorders.log("Hello Trace-Recorder");
}
}
1
2
3
> Task :webflux:Bootstrap.main()
Hello world!
cn.xusc.Bootstrap.main()[8] - Hello Trace-Recorder

伸缩性的记录

更丰富的输出

1
2
3
4
5
6
7
8
9
10
11
import cn.xusc.trace.util.Recorders;

public class Bootstrap {
public static void main(String[] args) {
System.out.println("Hello world!");
// 添加一个通用统计信息增强器
Recorders.addCommonStatisticsInfoEnhancer();
// Trace-Recorder 使用
Recorders.log("The statistics are as follows:");
}
}
1
2
3
4
5
6
> Task :webflux:Bootstrap.main()
Hello world!
cn.xusc.Bootstrap.main()[11] - The statistics are as follows:
--------------------
cn.xusc.Bootstrap - 1
--------------------

自定义的记录

自定义的输出

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
import cn.xusc.trace.EnhanceInfo;
import cn.xusc.trace.enhance.InfoEnhancer;
import cn.xusc.trace.util.Recorders;

public class Bootstrap {
public static void main(String[] args) {
System.out.println("Hello world!");
// 添加一个自定义信息增强器
Recorders.addInfoEnhancer(new InfoEnhancer() {
@Override
public EnhanceInfo enhance(EnhanceInfo eInfo) {
// 做一些事
eInfo.setInfo(eInfo.getInfo().trim() + "_enhance");
return eInfo;
}

@Override
public EnhanceInfo setWriteInfo(EnhanceInfo eInfo) {
// 设置增强后的消息输出
eInfo.setWriteInfo(eInfo.getInfo());
return eInfo;
}
});
// Trace-Recorder 使用
Recorders.log("hello,custom InfoEnhance");
}
}
1
2
3
> Task :webflux:Bootstrap.main()
Hello world!
hello,custom InfoEnhance_enhance

三、项目地址 1.0

github: https://github.com/Cw404/Trace-Recorder

Springboot启动流程剖析

一、前言

Spring Framework的强大扩展点,赋予了对象丰富的生命周期;但是其配置繁琐,而且不太灵活,什么都需要自己来配置引入;简直就是优秀的架构,构造的噩梦。就在这过程中,官方Springboot以快速构建突破了这一痛点,也被开发者赋予Spring急行军的称号。通过下面3点我们将了解简单的Springboot:

本章不会涉及到springboot的自动装配,仅针对启动流程!!!

1.Springboot项目搭建
2.游走Springboot启动流程源码
3.Springboot启动流程图

二、Springboot急行军项目搭建

启动入口

1
2
3
4
5
6
@SpringBootApplication
public class SpringApplication {
public static void main(String[] args) {
org.springframework.boot.SpringApplication.run(SpringApplication.class,args);
}
}

依赖
maven

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.5.RELEASE</version>
</dependency>

gradle

1
2
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter
implementation group: 'org.springframework.boot', name: 'spring-boot-starter', version: '2.3.5.RELEASE'

执行输出结果

1
2
3
4
5
6
7
8
9
10
11
12

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.5.RELEASE)

2021-06-23 13:44:14.090 INFO [main] c.x.c.SpringApplication - [logStarting,55] - Starting SpringApplication on localhost with PID 49608 (/Users/wangcai/appData/development/projects/java/self/springboothome/cache/build/classes/java/main started by wangcai in /Users/wangcai/appData/development/projects/java/self/springboothome)
2021-06-23 13:44:14.096 INFO [main] c.x.c.SpringApplication - [logStartupProfileInfo,651] - No active profile set, falling back to default profiles: default
2021-06-23 13:44:14.646 INFO [main] c.x.c.SpringApplication - [logStarted,61] - Started SpringApplication in 0.832 seconds (JVM running for 1.884)

三、游走Springboot启动流程源码

简单了解@SpringBootApplication
@SpringBootApplication

完成扫描和启动自动装配

avatar
深入理解Springboot启动流程
SpringApplication
avatar
avatar

最终会进入主构造

avatar

真正的启动流程(只会针对重要的来进行说明)

avatar
1⃣️、创建合适的应用上下文
avatar
avatar
2⃣️、准备上下文

监听上下文、注册实例(run入口传入的类)

avatar
3⃣️、刷新上下文
avatar
avatar

四、Springboot启动流程图

avatar

Spring Framework集成之Mybatis

一、前言

mybatis作为ORM(Object Relational Mapping)首选框架,融入Spring Framework大家族自然是必要的,话不多说。通过下面3点我们将了解简单的Mybatis-Spring:

主要是做集成,了解其扫描运行机制,不会去往深处进行数据库查询

1.Mybatis-Spring的简单使用
2.游走Mybatis-Spring集成机制源码
3.游走Mybatis-Spring集成机制源码 - 番外篇(特殊的sqlSession)

二、Mybatis-Spring的简单使用

准备
类结构图
avatar
类包依赖
gradle

1
2
3
4
5
6
7
8
9
// ==================== spring framework ====================
testImplementation 'org.springframework:spring-context:5.3.5'
// ==================== mybatis ====================
testImplementation 'org.mybatis:mybatis:3.5.7'
testImplementation 'org.mybatis:mybatis-spring:2.0.6'
// ==================== spring tx ====================
testImplementation 'org.springframework:spring-tx:5.3.5'
// ==================== spring jdbc ====================
testImplementation 'org.springframework:spring-jdbc:5.3.5'

maven

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
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.5</version>
</dependency>

类结构

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
49
50
51
52
53
54
55
56
package mybatis.bean;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@Mapper
public interface MybatisBean {
@Select("select * from user")
List<Object> queryAll();
}
-------------------------------------------------------------
package mybatis.config;

import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
* mybatis配置类
*/
@Component
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionTemplate sqlSession() throws Exception {
return new SqlSessionTemplate(sqlSessionFactory(), ExecutorType.REUSE);
}

public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(new PooledDataSource());//mybatis的数据源池
return factoryBean.getObject();
}
}
-------------------------------------------------------------
package mybatis;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

@Component
@ComponentScan
@MapperScan
public class MybatisScanner {

}

junit代码块

1
2
3
4
5
6
7
8
9
10
@Test
public void Test(){
// 构建应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MybatisScanner.class);
// 刷新应用上下文
context.refresh();
Arrays.asList(context.getBeanDefinitionNames())
.forEach(System.out::println);
}

执行输出结果

1
2
3
4
5
6
7
8
9
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mybatisScanner
myBatisConfig
sqlSession
mybatis.MybatisScanner#MapperScannerRegistrar#0
mybatisBean

三、游走Mybatis-Spring集成机制源码

由于Mybatis-Spring是可插拔的数据库资源代理使用,所以需要手动注明,注解使用为@MapperScan和@MapperScans两种

@MapperScan
avatar

通过@Import会将MapperScannerRegistrar.class注入到Spring Framework中,这边直接看处理

MapperScannerRegistrar
avatar
avatar
MapperScannerConfigurer

类结构图

avatar

在获取Bean的时候,在initializeBean中回调ApplicationContextAware接口的setApplicationContext方法、BeanNameAware接口的setBeanName方法、InitializingBean接口的afterPropertiesSet方法(具体看Spring Framework的Bean生成)

avatar
avatar
avatar
Mybatis实现了自己的扫描器,作用域在refresh的invokeBeanFactoryPostProcessors方法中
avatar

ClassPathMapperScanner继承自ClassPathBeanDefinitionScanner,对其doScan进行了重写,使用父类的scan

ClassPathBeanDefinitionScanner
avatar
ClassPathMapperScanner
avatar

调用父类的doScan会触发findCandidateComponents方法,进行组件的查找和验证,Mybatis-Spring重写了组件的验证逻辑

avatar
avatar

四、游走Mybatis-Spring集成机制源码 - 番外篇(特殊的sqlSession)

总体释义:获取一个mybatis的接口bean,会使用sqlSessionTemplate代理的方式进行处理

代码块

1
context.getBean(MybatisBean.class);

由于Spring Framework对bean回去已做了充分说明,这边直接通过流程图进行说明

运行时流程图
avatar
MapperFactoryBean
avatar
SqlSessionTemplate
avatar
Configuration

此处就是调用mybatis的Configuration获取mapper的动态代理逻辑了,想获取更多看Mybatis的代理篇

avatar
通过获取bean使用
SqlSessionTemplate

构造生成的代理尤为重要,最终会走向SqlSessionInterceptor

avatar

Mybatis-Spring使用sqlSessionTemplate进行处理

avatar
SqlSessionInterceptor

最终走向,会通过事物同步管理器来复用session(复用有一定的条件),此时的sqlSession就是mybatis篇我们熟悉的DefaultSqlSession

avatar
avatar

Spring Framework集成之AOP

一、前言

使用过AOP,我们经常用来切包或者方法,然后会回调,有些许意思哈。通过下面4点我们将了解简单的SpringAOP:

前面2点为概念扫盲,不仅要知其然,更要知其所以然,本文不会说明扫描机制,如有需要请看Spring Framework扫描注册

1.AOP概念
2.SpringAOP的概念
3.SpringAOP的简单使用
4.游走SpringAOP集成机制源码

二、AOP概念

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 - 来自百度百科

补充:AOP 实现分类、AOP术语

AOP 实现分类

  • 静态 AOP 实现, AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。
  • 动态 AOP 实现, AOP 框架在运行阶段对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP。

AOP 领域中的特性术语:

  • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
  • 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
  • 切点(PointCut): 可以插入增强处理的连接点。
  • 切面(Aspect): 切面是通知和切点的结合。
  • 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
  • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。

来自SharpCJhttps://www.cnblogs.com/joy99/p/10941543.html

三、SpringAOP的概念

SpringAOP使用的是动态代理进行实现,借助aspectj包进行使用,aspectj支持字段、构造器和方法的连接点,SpringAOP只支持方法的连接点。

细节点:看了前面Spring Framework就知道,Bean对象的字段和构造都由Spring Framework上下文进行构建,对于第三方框架(aspectj)而言,方法切入点最合适。

四、SpringAOP的简单使用

关于Bean的注入在Spring Framework扫描加载有说明

准备
类结构图
avatar
类包依赖
gradle

1
2
3
4
5
6
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
// ==================== spring framework ====================
testImplementation 'org.springframework:spring-context:5.3.5'
// ==================== aspectj ====================
testImplementation 'org.aspectj:aspectjweaver:1.9.6'

maven

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
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.6.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>

类结构

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package aop.bean;

import org.springframework.stereotype.Component;

@Component
public class Bean {
String name = "I am Bean";

public String getName() {
System.out.println("getName");//为了在输出感受到调用
return name;
}
}
-------------------------------------------------------------
package aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AOPBean {

//切点
@Pointcut("execution(* aop.bean.*.*(..))")
private void pointCut(){

}

//环切
@Around(value = "pointCut()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("start aop");
Object retVal = pjp.proceed();//原方法回调
System.out.println("stop aop");
return "my name is SpringAOP!";//偷天换日
}

//切点执行前调用
@Before("pointCut()")
public void doBefore() {
System.out.println("before");
}

//切点执行后调用
@After("pointCut()")
public void doAfter() {
System.out.println("after");
}
}
-------------------------------------------------------------
package aop;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy//启动Aspect自动代理
public class AOPConfiguration {

}

junit代码块

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void Test2(){
// 构建应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AOPConfiguration.class);
// 刷新应用上下文
context.refresh();
Arrays.asList(context.getBeanDefinitionNames())
.forEach(System.out::println);
System.out.println("-------------------------");//上下文分割
//触发aop
System.out.println(context.getBean(Bean.class).getName());
}

执行输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
AOPConfiguration
AOPBean
bean
org.springframework.aop.config.internalAutoProxyCreator
-------------------------
start aop
before
getName
after
stop aop
my name is SpringAOP!

五、游走SpringAOP集成机制源码

由于AOP是可插拔的代理使用,所以需要手动注明,注解使用为@EnableAspectJAutoProxy

@EnableAspectJAutoProxy
avatar

通过@Import会将AspectJAutoProxyRegistrar.class注入到Spring Framework中,这边直接看处理

AspectJAutoProxyRegistrar
avatar
AopConfigUtils
avatar
avatar
avatar
AnnotationAwareAspectJAutoProxyCreator

类结构图

avatar

在获取Bean的时候,在initializeBean中回调BeanFactoryAware接口的setBeanFactory方法(具体看Spring Framework的Bean生成)

AbstractAdvisorAutoProxyCreator
avatar

在refresh刷新上下文中finishBeanFactoryInitialization方法完成最终代理对象生成

AbstractAutoProxyCreator

实例化之前,AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation方法中回调

avatar

实例化之后,AbstractAutowireCapableBeanFactory.initializeBean方法中回调

avatar
avatar
avatar
ProxyFactory
avatar
avatar
avatar

Spring Framework之扫描注册机制(五)

一、前言

声明:Spring Framework将以本篇带来末结

通过前面五篇,我们对Bean加载、Bean依赖都有了深刻的认识,关于扫描Spring Framework是怎么做的了?通过下面2点我们将了解简单的Spring:
1.扫描注册机制的应用
2.游走ClassPathBeanDefinitionScanner扫描机制源码

二、扫描注册机制的应用

下面将会给未接触过的人也能一眼看懂,给接触过的人一个简短的温故

准备
类结构图
avatar
类结构

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
package mybean;

import org.springframework.stereotype.Component;

@Component
public class Bean1 {

}
-------------------------------------------------------------
package mybean;

import org.springframework.stereotype.Component;

@Component
public class Bean2 {

}
-------------------------------------------------------------
package mybean;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan
public class ScanBean {

}

手动上下文扫描

  • junit代码块

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Test
    public void Test(){
    // 构建应用上下文
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.scan("mybean");
    // 刷新应用上下文
    context.refresh();
    Arrays.asList(context.getBeanDefinitionNames())
    .forEach(System.out::println);
    }
  • 执行输出结果

    缺少scanBean原因:Spring Framework是过滤掉了一些Bean,原生的默认支持@Component扫描自动注册

    1
    2
    3
    4
    5
    6
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    bean1
    bean2

自动Bean配置扫描

  • junit代码块

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Test
    public void Test(){
    // 构建应用上下文
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(ScanBean.class);
    // 刷新应用上下文
    context.refresh();
    Arrays.asList(context.getBeanDefinitionNames())
    .forEach(System.out::println);
    }
  • 执行输出结果

    1
    2
    3
    4
    5
    6
    7
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    scanBean
    bean1
    bean2

三、游走ClassPathBeanDefinitionScanner扫描机制源码

由于扫描注册有两套机制,下文呼应所有Spring Framework文章,全面对自动Bean配置扫描进行解析,其中手动上下文扫描也会走到其中,下面会重点说明;主要类为ConfigurationClassPostProcessor,执行时机为上下文刷新中invokeBeanFactoryPostProcessors(beanFactory);

ConfigurationClassPostProcessor结构图
avatar
ConfigurationClassPostProcessor

这是Spring的内置Bena配置对象,前文学了BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry();回调流程,这边直接跟进

avatar

由于processConfigBeanDefinitions代码过多,直接贴出源码(删除了一些不明确的源码)

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//处理配置bean定义
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();

//筛选配置Bean
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
//...
}
//检查配置bean
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//装载ScanBean
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}

//没有配置需要处理 -> 跳出
if (configCandidates.isEmpty()) {
return;
}

//优先级排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});

//为registry绑定BeanName生成器
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}

//共享环境绑定
if (this.environment == null) {
this.environment = new StandardEnvironment();
}

//配置类解析器 -> 解析配置
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);

Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
parser.parse(candidates);//解析ScanBean⬅️
parser.validate();//验证

Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);

if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//注册配置解析出来的Bean定义
this.reader.loadBeanDefinitions(configClasses);
//...
}
while (!candidates.isEmpty());

if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
//注册导入单例
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
//...
}

ConfigurationClassParser
avatar
avatar
avatar
avatar
ComponentScanAnnotationParser
avatar
ClassPathBeanDefinitionScanner

其中注册的逻辑就不进行说明了,可以看前面更系统的了解

avatar
ClassPathScanningCandidateComponentProvider

当前为单个包的扫描机制,与手动上下文扫描对应

avatar
avatar

Spring Framework之加载机制的内置接口Bean加载(四)

一、前言

声明:本章不会针对所有内置接口Bean进行解析,但会对主要的进行深度剖析

前文分别介绍了单例Bean单例循环依赖Bean,本章主要说明部分内置接口Bean的加载(接口Bean),这种Bean拥有着一系列的扩展点,使其在Spring Framework的中有着独特的生命周期,本章上下文刷新需要从前文得到概览图,通过下面2点我们讲了解简单的Spring加载:
1.内置接口Bean在Spring Framework中的意义
2.游走内置接口Bean加载源码

二、内置接口Bean在Spring Framework中的意义

一个内置接口Bean拥有着独特的生命周期,能逆天改命,也能做一切的事。

开源框架中通常使用这种内置接口Bean加载自己的特定类来与Spring完成集成。

三、游走内置接口Bean加载源码

BeanDefinitionRegistryPostProcessor接口,上下文刷新中invokeBeanFactoryPostProcessors(beanFactory);处理

代码块

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;

/*********************************************
* 我的Bean定义注表后置处理器构建器 *
*********************************************/
public class MyBeanDefinitionRegistryPostProcessorBuilder {
//为BeanFactoryPostProcessors而生
public static MyBeanDefinitionRegistryPostProcessor buildBeanFactoryPostProcessor(){return new MyBeanDefinitionRegistryPostProcessorOfAddBeanFactoryPostProcessor();}
//优先定制的
public static Class buildPriorityOrdered(){return MyBeanDefinitionRegistryPostProcessorPriorityOrdered.class;}
//定制的
public static Class buildOrdered(){return MyBeanDefinitionRegistryPostProcessorOrdered.class;}
//普通的
public static Class build(){return MyBeanDefinitionRegistryPostProcessor.class;}

}

class MyBeanDefinitionRegistryPostProcessorOfAddBeanFactoryPostProcessor extends MyBeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.print("postProcessBeanDefinitionRegistry()\t我最快\t");
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.print("postProcessBeanFactory()\t我最快\t");
}
}

class MyBeanDefinitionRegistryPostProcessorPriorityOrdered extends MyBeanDefinitionRegistryPostProcessor implements PriorityOrdered {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.print("我第一快\t");
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.print("我第一快\t");
}

@Override
public int getOrder() {
return 100;
}
}

class MyBeanDefinitionRegistryPostProcessorOrdered extends MyBeanDefinitionRegistryPostProcessor implements Ordered {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.print("我第二快\t");
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.print("我第二快\t");
}

@Override
public int getOrder() {
return 1;
}
}

class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.print("我最后\n");
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.print("我最后\n");
}
}

junit代码块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void Test(){
// 构建应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册
context.register(
MyBeanDefinitionRegistryPostProcessorBuilder.buildPriorityOrdered(),
MyBeanDefinitionRegistryPostProcessorBuilder.buildOrdered(),
MyBeanDefinitionRegistryPostProcessorBuilder.build()
);
context.addBeanFactoryPostProcessor(MyBeanDefinitionRegistryPostProcessorBuilder.buildBeanFactoryPostProcessor());
// 刷新应用上下文
context.refresh();
}

AbstractApplicationContext
avatar
PostProcessorRegistrationDelegate

代码实在太多,不好截图,直接放源码

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//BeanFactoryPostProcessor接口对象方法回调
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

//回调过的Bean集
Set<String> processedBeans = new HashSet<>();

//全面处理BeanDefinitionRegistryPostProcessor接口对象 和 beanFactoryPostProcessors的BeanFactoryPostProcessor方法回调
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//BeanFactoryPostProcessor处理集
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//BeanFactoryPostProcessor处理集
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

//beanFactoryPostProcessors回调,并按接口分层
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
//回调postProcessBeanDefinitionRegistry
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
//BeanFactoryPostProcessor
regularPostProcessors.add(postProcessor);
}
}

//当前处理集
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

//PriorityOrdered接口处理
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//回调postProcessBeanDefinitionRegistry
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();

//Ordered接口处理
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//回调postProcessBeanDefinitionRegistry
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();

//处理剩余的
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//回调postProcessBeanDefinitionRegistry
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}

//回调postProcessBeanFactory -> BeanDefinitionRegistryPostProcessor接口
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
//回调postProcessBeanFactory -> beanFactoryPostProcessors中为BeanFactoryPostProcessor接口的
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}

else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}

//全面处理BeanFactoryPostProcessor接口对象
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
//跳过上面上阶段处理的bean
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}

sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
//回调postProcessBeanFactory -> PriorityOrdered接口
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
//回调postProcessBeanFactory -> Ordered接口
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
//回调postProcessBeanFactory -> 剩余的
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

//清空bean工厂的元数据缓存
beanFactory.clearMetadataCache();
}

程序执行输出

1
2
postProcessBeanDefinitionRegistry()	我最快	我第一快	我第二快	我最后
postProcessBeanFactory() 我最快 我第一快 我第二快 我最后

BeanPostProcessor接口,上下文刷新中registerBeanPostProcessors(beanFactory);处理,特别注意:这个是在初始化的时候就会进行后置回调,所以要结合程序输出来看

代码块

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;

/*********************************************
* 我的Bean后置处理器构建器 *
*********************************************/
public class MyBeanPostProcessorBuilder {
//结合bean定义的后置处理器
public static Class buildMergedBeanDefinitionPostProcessor(){return MyMergedBeanDefinitionPostProcessor.class;}
//优先定制的
public static Class buildPriorityOrdered(){return MyBeanPostProcessorPriorityOrdered.class;}
//定制的
public static Class buildOrdered(){return MyBeanPostProcessorOrdered.class;}
//普通的
public static Class build(){return MyBeanPostProcessor.class;}

}

class MyBeanPostProcessorPriorityOrdered extends MyBeanPostProcessor implements PriorityOrdered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("-----------------------------");
System.out.println("PriorityOrdered\tBefore");
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("PriorityOrdered\tAfter");
return bean;
}

@Override
public int getOrder() {
return 100;
}
}

class MyBeanPostProcessorOrdered extends MyBeanPostProcessor implements Ordered {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Ordered\tBefore");
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Ordered\tAfter");
return bean;
}

@Override
public int getOrder() {
return 1;
}
}

class MyBeanPostProcessor implements BeanPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("common\tBefore");
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("common\tAfter");
return bean;
}
}

class MyMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("merged\tBefore");
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("merged\tAfter");
return bean;
}

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
System.out.println("merged\tunique");
}

@Override
public void resetBeanDefinition(String beanName) {
System.out.println("=============================");
System.out.println("merged\treset");
}
}

junit代码块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void Test(){
// 构建应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册
context.register(
MyBeanPostProcessorBuilder.buildMergedBeanDefinitionPostProcessor(),
MyBeanPostProcessorBuilder.buildPriorityOrdered(),
MyBeanPostProcessorBuilder.buildOrdered(),
MyBeanPostProcessorBuilder.build(),
String.class
);
// 刷新应用上下文
context.refresh();
// 重新注册(任意类注册),来进行resetBeanDefinition回调
context.register(MyBeanPostProcessorBuilder.buildMergedBeanDefinitionPostProcessor());
}

程序执行输出

在虚线后面是额外加的注释,来帮助理解

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
-----------------------------MyBeanPostProcessorOrdered初始化引起回调
PriorityOrdered Before
PriorityOrdered After
-----------------------------MyMergedBeanDefinitionPostProcessor初始化引起的回调
PriorityOrdered Before
Ordered Before
PriorityOrdered After
Ordered After
-----------------------------MyBeanPostProcessor初始化引起回调
PriorityOrdered Before
Ordered Before
PriorityOrdered After
Ordered After
//这里往下为一组,String初始化引起回调
merged unique
-----------------------------
PriorityOrdered Before
Ordered Before
common Before
merged Before
PriorityOrdered After
Ordered After
common After
merged After
=============================重新注册引起的回调
merged reset

AbstractApplicationContext
avatar
PostProcessorRegistrationDelegate

代码实在太多,不好截图,直接放源码

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//注册beanPostProcessor接口对象,并进行方法回调
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

//获取所有BeanPostProcessor接口beanName
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//实例化PriorityOrdered对象
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}

sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
//将实例化PriorityOrdered对象注册到BeanPostProcessors中
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);


List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
//实例化Ordered对象
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
//将实例化Ordered对象注册到BeanPostProcessors中
registerBeanPostProcessors(beanFactory, orderedPostProcessors);

List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
//实例化剩余的对象
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}

//将实例化剩余的对象注册到BeanPostProcessors中
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
sortPostProcessors(internalPostProcessors, beanFactory);
//将实例化MergedBeanDefinitionPostProcessor对象注册到BeanPostProcessors中
registerBeanPostProcessors(beanFactory, internalPostProcessors);

//添加ApplicationListenerDetector监听
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

回调机制

除重置其它的执行时间都在AbstractAutowireCapableBeanFactory的doCreateBean方法中,下面只列具体的执行时机代码点

AbstractAutowireCapableBeanFactory
MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition回调
avatar
avatar
BeanPostProcessor.postProcessBeforeInitialization回调
BeanPostProcessor.postProcessAfterInitialization回调
avatar
avatar
avatar
avatar

重置点,MergedBeanDefinitionPostProcessor.resetBeanDefinition();方法回调,直接定位DefaultListableBeanFactory.registerBeanDefinition();

DefaultListableBeanFactory
avatar
avatar

Spring Framework之加载机制的循环依赖单例Bean加载(三)

一、前言

声明:这个加载只适用循环依赖普通单例Bean加载流程,其它的bean流程只稍微有些差异

前文说明普通单例Bean的加载(忽略掉循环依赖、扩展、接口等),循环依赖也无异,通过下面3点我们讲了解简单的Spring加载:
1.Spring Framework中的循环依赖理论
2.游走循环依赖普通单列Bean加载源码
3、循环依赖最终图解

二、Spring Framework中的循环依赖理论

Bean的内部结构图
avatar
循环依赖
在Java层面

一个对象依赖另一个对象,只需要将Bean1对象地址赋给Bean2对象变量,Bean2对象地址赋给Bean1对象变量,以此达到对象间的循环依赖

在Spring framework层面

情况一(构造依赖):

Bean1未构建成功,立即构建Bean2,Bean2也未构建成功,立即构建Bean1,陷入循环,导致无法构建成功

Spring framework会抛出BeanCurrentlyInCreationException异常,Spring framework无法解决构造依赖

情况二(属性依赖):

Bean1构建时,会先将beanName放入当前创建的单列集中,并效验当前beanName是否存在单例工厂,使用构造函数完成构建,并添加到单例工厂,填充属性时,发现依赖Bean2,解决Bean2依赖时产生Bean1构建中断;

Bean2构建时,会先将beanName放入当前创建的单列集中,并效验当前beanName是否存在单例工厂,使用构造函数完成构建,并添加到单例工厂,填充属性时,发现依赖Bean1,解决Bean1依赖时产生Bean2构建中断;

Bean1构建时,发现当前beanName存在创建的单列集中,并且存在当前beanName的单例工厂,直接获取Bean并返回;

回到Bean2进行注入,回到Bean1进行注入

三、游走循环依赖普通单列Bean加载源码

属性依赖对象代码

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
//Bean1
public class SystemPrint {
@Autowired
SystemWrite systemWrite;
}

//Bean2
public class SystemWrite {
@Autowired
SystemPrint systemPrint;
}

//junit测试
@Test
public void Test(){
// 构建应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册一个SystemPrint bean 、SystemWrite bean
context.register(SystemPrint.class, SystemWrite.class);
// 刷新应用上下文
context.refresh();⬅️
// 获取IOC容器bean对象
Object bean = context.getBean(SystemPrint.class);
// 打印对象
log.info("{}",bean);
}

上下文刷新

具体参照前文Spring Framework之加载机制的单例Bean加载,本次获取的bean为SystemPrint对象,这里通过流程图来简略阐述上章流程

avatar
AbstractAutowireCapableBeanFactory

本章属性依赖重点类

avatar
avatar
AutowiredAnnotationBeanPostProcessor
avatar
InjectionMetadata
avatar
AutowiredFieldElement
avatar
DefaultListableBeanFactory
avatar
avatar
DependencyDescriptor
avatar

本次获取的是SystemWrite对象,重回流程图,AbstractBeanFactory.getBean(“systemWrite”);最终走先上图DependencyDescriptor,获取SystemPrint对象,重回流程图,AbstractBeanFactory.getBean(“systemPrint”);直到AbstractBeanFactory.doGetBean()方法

AbstractBeanFactory
avatar
DefaultSingletonBeanRegistry
avatar
avatar
程序输出

1
[Test worker] INFO SpringFrameworkTest - bean.SystemPrint@2fc749df

构造依赖对象代码

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
//Bean1
public class SystemPrint {
SystemWrite systemWrite;

public SystemPrint(SystemWrite systemWrite) {
this.systemWrite = systemWrite;
}
}

//Bean2
public class SystemWrite {
@Autowired
SystemPrint systemPrint;
}

//junit测试
@Test
public void Test(){
// 构建应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册一个SystemPrint bean 、SystemWrite bean
context.register(SystemPrint.class, SystemWrite.class);
// 刷新应用上下文
context.refresh();
// 获取IOC容器bean对象
Object bean = context.getBean(SystemPrint.class);
// 打印对象
log.info("{}",bean);
}

流程和属性一样,主要是实例化类的区别,直接定位AbstractAutowireCapableBeanFactory.doCreateBean()方法

AbstractAutowireCapableBeanFactory
avatar
avatar
avatar
ConstructorResolver

autowireConstructor()方法中定位

avatar

createArgumentArray()方法中定位

avatar
avatar

流程和 “ 构造依赖对象代码 ” 中 DefaultListableBeanFactory.resolveDependency()方法一直,急切获取属性SystemWrite对象,重回流程图,AbstractBeanFactory.getBean(“systemWrite”);最终走先上图DependencyDescriptor,获取SystemPrint对象,重回流程图,AbstractBeanFactory.getBean(“systemPrint”);直到DefaultSingletonBeanRegistry.getSingleton()方法

DefaultSingletonBeanRegistry
avatar
AbstractBeanFactory

doGetBean()方法中定位

avatar
DefaultSingletonBeanRegistry
avatar
avatar

经过一系列的抛出,最终定位ConstructorResolver.createArgumentArray()方法,抛出不满意的依赖异常,也就是循环依赖异常

ConstructorResolver
avatar

四、循环依赖最终图解

avatar

Spring Framework之加载机制的单例Bean加载(二)

一、前言

声明:这个加载只适用普通单例Bean加载流程

前文BeanDefinition建模基石说到Bean构建前的状态,本章主要说明普通单例Bean的加载(忽略掉循环依赖、扩展、接口等),通过下面3点我们讲了解简单的Spring加载:
1.单列Bean加载意味着什么?
2.游走普通单列Bean加载源码

二、单例Bean加载意味着什么

单例Bean最终会存入到DefaultListableBeanFactory的singletonObjects单例池(必须是单列bean才会入单例池),通过bean工厂即可获取到此bean。

三、游走普通单例Bean加载源码

上下文刷新

定位finishBeanFactoryInitialization()方法,实例化所有剩余的单例(未懒加载的)

avatar

AbstractApplicationContext
avatar

DefaultListableBeanFactory
avatar

AbstractBeanFactory
avatar
avatar

DefaultSingletonBeanRegistry
avatar

AbstractAutowireCapableBeanFactory
avatar
avatar
avatar
avatar
avatar

DefaultSingletonBeanRegistry
avatar

Spring Framework之BeanDefinition建模基石(一)

一、前言

声明:初识架构篇我们采用的是解析文件(ClassPathXmlApplicationContext)的方式,解析文件比较繁琐,本篇至以后采用注解(AnnotationConfigApplicationContext)的方式

通过初识架构篇我们了解了一个ioc容器,但Spring又是怎么做的呢?通过下面3点我们讲了解简单的Spring:
1.BeanDefinition是什么?
2.游走BeanDefinition源码
3.Spring通过BeanDefinition产生一个bean对象过程

二、BeanDefinition是什么

BeanDefinition就是bean对象的定义,Spring会根据该定义生成一个完整的bean,里面都是bean的描述信息(生成的bean类型、bean的作用域、是否懒加载、注入模型….),并注入ioc容器。
BeanDefinition关系图
avatar
BeanDefinition图解
avatar

三、游走BeanDefinition源码

源码解析导图
avatar
BeanDefinition
avatar
AbstractBeanDefinition
avatar
GenericBeanDefinition
avatar
AnnotatedGenericBeanDefinition
avatar

拓展知识

AnnotationMetadata
avatar
MethodMetadata
avatar

四、Spring通过BeanDefinition产生一个bean对象过程

代码区

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void Test(){
// 1⃣️:构建应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 2⃣️:注册一个SystemPrint bean
context.register(SystemPrint.class);
// 3⃣️:刷新应用上下文
context.refresh();
// 4⃣️:获取IOC容器bean对象
Object bean = context.getBean(SystemPrint.class);
// 触发懒加载
log.info("{}",bean);
}

1⃣️:构建应用上下文
avatar

2⃣️:注册一个SystemPrint bean
avatar
avatar
avatar
avatar
avatar

3⃣️:刷新应用上下文

只有懒加载的bean才不会在现在进行加载

avatar

4⃣️:获取IOC容器bean对象

获取Bean对象,如果是懒加载的Bean才会在获取的时候进行加载,本章不会深揪加载流程

avatar
程序执行输出

1
[Test worker] INFO SpringFrameworkTest - bean.SystemPrint@1fd53402

请我喝杯咖啡吧~

支付宝
微信