Skip to content

Commit ecf122f

Browse files
committed
添加 banner 怎么加载的源码分析
1 parent 1a44a4f commit ecf122f

19 files changed

Lines changed: 249 additions & 0 deletions

‎.DS_Store‎

0 Bytes
Binary file not shown.

‎Algorithm/.DS_Store‎

0 Bytes
Binary file not shown.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
2+
3+
4+
5+
我们来看下 mybatis 是怎么在 springboot 中被初始化的
6+
7+
# 怎么找到入口
8+
9+
10+
11+
这个是我自己摸索的方法,仅供参考
12+
13+
但是我们从哪里入手呢?mybatis最早是在哪里被初始化的呢?我们都不知道、
14+
15+
我们之前看 源码知道,他有一个模块是 `parsing`,这个里面有解析 xml 文件的方法,和解析动态sql 占位符的方法和类
16+
17+
那么在 springboot 启动的时候,他肯定会调用这个类 XPathParser
18+
19+
我们进入这个类中,找到他的构造方法,因为要调用,肯定会调用他的构造方法来进行初始化
20+
21+
```java
22+
// XPathParser.java
23+
24+
public XPathParser(InputStream inputStream, boolean validation, Properties variables) {
25+
commonConstructor(validation, variables, null);
26+
this.document = createDocument(new InputSource(inputStream));
27+
}
28+
29+
public XPathParser(Document document, boolean validation, Properties variables) {
30+
commonConstructor(validation, variables, null);
31+
this.document = document;
32+
}
33+
34+
public XPathParser(String xml, boolean validation, Properties variables, EntityResolver entityResolver) {
35+
commonConstructor(validation, variables, entityResolver);
36+
this.document = createDocument(new InputSource(new StringReader(xml)));
37+
}
38+
39+
public XPathParser(Reader reader, boolean validation, Properties variables, EntityResolver entityResolver) {
40+
commonConstructor(validation, variables, entityResolver);
41+
this.document = createDocument(new InputSource(reader));
42+
}
43+
44+
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
45+
commonConstructor(validation, variables, entityResolver);
46+
this.document = createDocument(new InputSource(inputStream));
47+
}
48+
49+
public XPathParser(Document document, boolean validation, Properties variables, EntityResolver entityResolver) {
50+
commonConstructor(validation, variables, entityResolver);
51+
this.document = document;
52+
}
53+
```
54+
55+
但是我们看到,上面的构造方法实在是太多了,但是他们大多数都调用了 `createDocument()`方法,我们就进入这个方法中,在第一行打上断点,进入之后我们就可以看这边的调用栈。
56+
57+
我们找到和 Mybatis相关的最早的调用栈
58+
59+
![](img/Xnip2020-05-20_16-07-41.jpg)
60+
61+
![](img/Xnip2020-05-20_16-14-26.jpg)
62+
63+
我们发现这个类是在`package tk.mybatis.mapper.autoconfigure;`不是 Mybatis 的最初的类,最初的类是这个包开头的`package org.apache.ibatis.XXX`,这个是`mybatis-spring`的自动装配的包,但是他返回的`SqlSessionFactory`,却是ibatis的,那我们再往下找,
64+
65+
![](img/Xnip2020-05-21_09-39-13.jpg)
66+
67+
![](img/Xnip2020-05-21_19-03-09.jpg)
68+
69+
这里就是我们开始对文件进行处理,调用 ibatis 的各种方法,比如解析xml文件啊,绑定mapper啊,确定返回类型啊,提取他的 `namespace`啊,等等
70+
71+
# 初始化
72+
73+
## 入口
74+
969 KB
Loading
1.03 MB
Loading
1.43 MB
Loading
281 KB
Loading
707 KB
Loading
655 KB
Loading
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# 前言
2+
3+
我们肯定很好奇,当我们启动 springboot 的时候,这个下面的 banner 是怎么打印出来的呢?
4+
5+
![](img/Xnip2020-06-28_09-48-50.jpg)
6+
7+
以及我们可不可以定制我们自己的banner,那我们就进入一下 SpringBoot 的源码,看下他是怎么加载的吧
8+
9+
10+
11+
# 源码分析
12+
13+
14+
15+
## 项目结构
16+
17+
![](img/Xnip2020-06-28_10-32-58.jpg)
18+
19+
## 入口
20+
21+
![](img/Xnip2020-06-28_10-33-48.jpg)
22+
23+
![Xnip2020-06-28_10-34-10](img/Xnip2020-06-28_10-34-10.jpg)
24+
25+
![Xnip2020-06-28_10-34-19](img/Xnip2020-06-28_10-34-19.jpg)
26+
27+
![](img/Xnip2020-06-28_10-34-43.jpg)
28+
29+
```java
30+
private Banner printBanner(ConfigurableEnvironment environment) {
31+
// 判断是否关闭了 banner 打印模式
32+
if (this.bannerMode == Banner.Mode.OFF) {
33+
return null;
34+
}
35+
// 初始化资源加载器
36+
ResourceLoader resourceLoader = (this.resourceLoader != null)
37+
? this.resourceLoader : new DefaultResourceLoader(getClassLoader());
38+
// 初始化 banner 打印对象
39+
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
40+
resourceLoader, this.banner);
41+
// 如果在 log中打印 banner
42+
if (this.bannerMode == Mode.LOG) {
43+
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
44+
}
45+
// 如果在 控制台打印banner
46+
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
47+
}
48+
```
49+
50+
```java
51+
// 只有三种模式,关闭 控制台 和log文件中
52+
enum Mode {
53+
54+
/**
55+
* Disable printing of the banner.
56+
*/
57+
OFF,
58+
59+
/**
60+
* Print the banner to System.out.
61+
*/
62+
CONSOLE,
63+
64+
/**
65+
* Print the banner to the log file.
66+
*/
67+
LOG
68+
69+
}
70+
```
71+
72+
73+
74+
75+
76+
```java
77+
public Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
78+
// 获取banner,看了这个我们就知道怎么去更改 banner了
79+
Banner banner = getBanner(environment);
80+
// 打印 banner
81+
banner.printBanner(environment, sourceClass, out);
82+
return new PrintedBanner(banner, sourceClass);
83+
}
84+
```
85+
86+
```java
87+
private Banner getBanner(Environment environment) {
88+
// 创建一个局部对象 Banners ,这个对象继承自 Banner接口,内容很简单,保存banner信息,添加banner方法,打印banner方法
89+
Banners banners = new Banners();
90+
// 添加banner ,这个里面还有些道道
91+
banners.addIfNotNull(getImageBanner(environment));
92+
banners.addIfNotNull(getTextBanner(environment));
93+
if (banners.hasAtLeastOneBanner()) {
94+
return banners;
95+
}
96+
if (this.fallbackBanner != null) {
97+
return this.fallbackBanner;
98+
}
99+
// 如果都没有,那么就会打印默认的 banner, 我们都见过
100+
return DEFAULT_BANNER;
101+
}
102+
```
103+
104+
```java
105+
// 获取 图像banner 信息
106+
private Banner getImageBanner(Environment environment) {
107+
// 获取配置文件中的 banner 位置信息
108+
String location = environment.getProperty(BANNER_IMAGE_LOCATION_PROPERTY);
109+
if (StringUtils.hasLength(location)) {
110+
Resource resource = this.resourceLoader.getResource(location);
111+
return resource.exists() ? new ImageBanner(resource) : null;
112+
}
113+
// 如果配置文件中没有指明,我们就读取默认的配置,banner前缀开头的,挨个遍历匹配。按照 gif。jpg、png的顺序,所以如果匹配到前面的图片,后面的就不会显示
114+
for (String ext : IMAGE_EXTENSION) {
115+
Resource resource = this.resourceLoader.getResource("banner." + ext);
116+
if (resource.exists()) {
117+
return new ImageBanner(resource);
118+
}
119+
}
120+
return null;
121+
}
122+
```
123+
124+
```java
125+
// 默认的 banner
126+
class SpringBootBanner implements Banner {
127+
128+
private static final String[] BANNER = { "",
129+
" . ____ _ __ _ _",
130+
" /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\",
131+
"( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
132+
" \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )",
133+
" ' |____| .__|_| |_|_| |_\\__, | / / / /",
134+
" =========|_|==============|___/=/_/_/_/" };
135+
136+
private static final String SPRING_BOOT = " :: Spring Boot :: ";
137+
138+
private static final int STRAP_LINE_SIZE = 42;
139+
140+
@Override
141+
public void printBanner(Environment environment, Class<?> sourceClass,
142+
PrintStream printStream) {
143+
for (String line : BANNER) {
144+
printStream.println(line);
145+
}
146+
String version = SpringBootVersion.getVersion();
147+
version = (version != null) ? " (v" + version + ")" : "";
148+
StringBuilder padding = new StringBuilder();
149+
while (padding.length() < STRAP_LINE_SIZE
150+
- (version.length() + SPRING_BOOT.length())) {
151+
padding.append(" ");
152+
}
153+
154+
printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT,
155+
AnsiColor.DEFAULT, padding.toString(), AnsiStyle.FAINT, version));
156+
printStream.println();
157+
}
158+
159+
}
160+
```
161+
162+
# 实验
163+
164+
我们准备了 四个文件,gif、jpg、png、txt。打印出来是这样的,上面是 gif的内容,下面是 txt的内容
165+
166+
![](img/Xnip2020-06-28_11-23-06.jpg)
167+
168+
169+
170+
我们在配置文件中指定文件,就不会按照默认的来进行显示了
171+
172+
![](img/Xnip2020-06-28_11-32-29.jpg)
173+
174+
![Xnip2020-06-28_11-32-50](img/Xnip2020-06-28_11-32-50.jpg)
175+

0 commit comments

Comments
 (0)