Skip to content

Commit b28c649

Browse files
author
曾梓健
committed
自定义starter
1 parent 8843c20 commit b28c649

File tree

11 files changed

+156
-1
lines changed

11 files changed

+156
-1
lines changed

myTest/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
<artifactId>spring-boot-starter-test</artifactId>
2828
<scope>test</scope>
2929
</dependency>
30+
31+
<dependency>
32+
<groupId>com.hand</groupId>
33+
<artifactId>zzj-spring-boot-stater</artifactId>
34+
<version>1.0-SNAPSHOT</version>
35+
</dependency>
3036
</dependencies>
3137

3238
<build>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
server.port=8082
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1+
server.port=8081
12

3+
simplebean.id=1
4+
simplebean.name=zzj
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
package com.hand.mytest;
22

3+
import com.hand.pojo.SimpleBean;
34
import org.junit.jupiter.api.Test;
5+
import org.junit.runner.RunWith;
6+
import org.springframework.beans.factory.annotation.Autowired;
47
import org.springframework.boot.test.context.SpringBootTest;
8+
import org.springframework.test.context.junit4.SpringRunner;
59

10+
@RunWith(SpringRunner.class)
611
@SpringBootTest
712
class MyTestApplicationTests {
813

14+
@Autowired
15+
private SimpleBean simpleBean;
16+
917
@Test
1018
void contextLoads() {
19+
System.out.println(simpleBean);
1120
}
1221

1322
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/BeanDefinitionLoader.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ class BeanDefinitionLoader {
7979
Assert.notNull(registry, "Registry must not be null");
8080
Assert.notEmpty(sources, "Sources must not be empty");
8181
this.sources = sources;
82+
// 注解形式的bean定义读取器,比如: 读取 @Configuration @Bean @Component @Controller 等等
8283
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
84+
// xml形式的bean定义读取器
8385
this.xmlReader = new XmlBeanDefinitionReader(registry);
8486
if (isGroovyPresent()) {
8587
this.groovyReader = new GroovyBeanDefinitionReader(registry);
@@ -132,7 +134,9 @@ int load() {
132134

133135
private int load(Object source) {
134136
Assert.notNull(source, "Source must not be null");
137+
// source是主类: run方法的主类
135138
if (source instanceof Class<?>) {
139+
// 从Class加载
136140
return load((Class<?>) source);
137141
}
138142
if (source instanceof Resource) {
@@ -149,11 +153,14 @@ private int load(Object source) {
149153

150154
private int load(Class<?> source) {
151155
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
156+
// 这个条件不满足,不会执行
152157
// Any GroovyLoaders added in beans{} DSL can contribute beans here
153158
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
154159
load(loader);
155160
}
161+
// 判断主类是否有标注@Component注解
156162
if (isComponent(source)) {
163+
// 将启动类的beanDefinition注册进beanDefinitionMap
157164
this.annotatedReader.register(source);
158165
return 1;
159166
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ public class SpringApplication {
179179
* environments.
180180
*/
181181
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
182-
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
182+
+ "boot.web.reactive.context .AnnotationConfigReactiveWebServerApplicationContext";
183183

184184
/**
185185
* Default banner location.
@@ -265,12 +265,17 @@ public SpringApplication(Class<?>... primarySources) {
265265
*/
266266
@SuppressWarnings({ "unchecked", "rawtypes" })
267267
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
268+
// 设置资源加载器为null
268269
this.resourceLoader = resourceLoader;
269270
Assert.notNull(primarySources, "PrimarySources must not be null");
270271
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
272+
// 1.推断应用类型,后面会根据类型初始化对应的环境,常用的一般都是servlet环境
271273
this.webApplicationType = WebApplicationType.deduceFromClasspath();
274+
// 2.根据ApplicationContextInitializer为key从classPath 下spring.factories配置文件中获取实例化的类
272275
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
276+
// 3.根据ApplicationListener为key从从classPath下spring.factories配置文件中获取实例化的类
273277
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
278+
// 4.根据调用栈,推断出main方法的类名
274279
this.mainApplicationClass = deduceMainApplicationClass();
275280
}
276281

@@ -296,24 +301,34 @@ private Class<?> deduceMainApplicationClass() {
296301
* @return a running {@link ApplicationContext}
297302
*/
298303
public ConfigurableApplicationContext run(String... args) {
304+
// 记录程序运行时间
299305
StopWatch stopWatch = new StopWatch();
300306
stopWatch.start();
307+
// ConfigurableApplicationContext接口 继承了 ApplicationContext接口,在ApplicationContext基础上增加了配置上下文的工具
301308
ConfigurableApplicationContext context = null;
302309
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
303310
configureHeadlessProperty();
311+
// 1.获取并启动监听器
304312
SpringApplicationRunListeners listeners = getRunListeners(args);
305313
listeners.starting();
306314
try {
307315
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
316+
// 2.构造应用上下文环境
308317
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
309318
configureIgnoreBeanInfo(environment);
310319
Banner printedBanner = printBanner(environment);
320+
// 3.初始化应用上下文
311321
context = createApplicationContext();
322+
// 实例化SpringBootExceptionReporter,用来支持报告关于启动的错误
312323
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
313324
new Class[] { ConfigurableApplicationContext.class }, context);
325+
// 4.刷新应用上下文的准备工作
314326
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
327+
// 5.刷新应用上下文
315328
refreshContext(context);
329+
// 6.刷新应用上下文的扩展接口
316330
afterRefresh(context, applicationArguments);
331+
// 时间记录停止
317332
stopWatch.stop();
318333
if (this.logStartupInfo) {
319334
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
@@ -339,9 +354,12 @@ public ConfigurableApplicationContext run(String... args) {
339354
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
340355
ApplicationArguments applicationArguments) {
341356
// Create and configure the environment
357+
// 创建并配置相应的环境
342358
ConfigurableEnvironment environment = getOrCreateEnvironment();
359+
// 根据用户配置,配置environment系统环境
343360
configureEnvironment(environment, applicationArguments.getSourceArgs());
344361
ConfigurationPropertySources.attach(environment);
362+
// 启动相应的监听器,其中重要的一个监听器就是 configFileApplicationListener,就是加载项目配置文件的监听器
345363
listeners.environmentPrepared(environment);
346364
bindToSpringApplication(environment);
347365
if (!this.isCustomEnvironment) {
@@ -365,20 +383,26 @@ private Class<? extends StandardEnvironment> deduceEnvironmentClass() {
365383

366384
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
367385
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
386+
// 设置容器环境
368387
context.setEnvironment(environment);
388+
// 执行容器后置处理
369389
postProcessApplicationContext(context);
370390
applyInitializers(context);
391+
// 向各个监听器发送容器已经准备好的事件
371392
listeners.contextPrepared(context);
372393
if (this.logStartupInfo) {
373394
logStartupInfo(context.getParent() == null);
374395
logStartupProfileInfo(context);
375396
}
376397
// Add boot specific singleton beans
398+
// 拿到容器对象
377399
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
378400
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
379401
if (printedBanner != null) {
402+
// 将 printedBanner 也封装成单例,注册进容器
380403
beanFactory.registerSingleton("springBootBanner", printedBanner);
381404
}
405+
// 下面这个条件是符合的
382406
if (beanFactory instanceof DefaultListableBeanFactory) {
383407
((DefaultListableBeanFactory) beanFactory)
384408
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
@@ -389,7 +413,9 @@ private void prepareContext(ConfigurableApplicationContext context, Configurable
389413
// Load the sources
390414
Set<Object> sources = getAllSources();
391415
Assert.notEmpty(sources, "Sources must not be empty");
416+
// 加载我们的启动类,将启动类注入容器
392417
load(context, sources.toArray(new Object[0]));
418+
// 发布容器已加载事件
393419
listeners.contextLoaded(context);
394420
}
395421

@@ -412,6 +438,8 @@ private void configureHeadlessProperty() {
412438

413439
private SpringApplicationRunListeners getRunListeners(String[] args) {
414440
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
441+
// SpringApplicationRunListener 负责在springboot启动的不同阶段广播出不同的消息,传递给ApplicationListener监听器实现类
442+
// org.springframework.boot.context.event.EventPublishingRunListener 就这一个实例
415443
return new SpringApplicationRunListeners(logger,
416444
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
417445
}
@@ -423,8 +451,12 @@ private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
423451
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
424452
ClassLoader classLoader = getClassLoader();
425453
// Use names and ensure unique to protect against duplicates
454+
// 通过指定的classLoader从MEATA-INF/spring.factories 中读取key为 type.getName()的value
455+
// 一共有七个
426456
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
457+
// 创建七个spring工厂实例
427458
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
459+
// 对七个spring工厂实例排序()
428460
AnnotationAwareOrderComparator.sort(instances);
429461
return instances;
430462
}
@@ -435,6 +467,7 @@ private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] par
435467
List<T> instances = new ArrayList<>(names.size());
436468
for (String name : names) {
437469
try {
470+
// 根据全路径名实例化
438471
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
439472
Assert.isAssignable(type, instanceClass);
440473
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
@@ -454,6 +487,7 @@ private ConfigurableEnvironment getOrCreateEnvironment() {
454487
}
455488
switch (this.webApplicationType) {
456489
case SERVLET:
490+
// 该应用如果是servlet类型的应用,走这里的逻辑
457491
return new StandardServletEnvironment();
458492
case REACTIVE:
459493
return new StandardReactiveWebEnvironment();
@@ -478,7 +512,9 @@ protected void configureEnvironment(ConfigurableEnvironment environment, String[
478512
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
479513
environment.setConversionService((ConfigurableConversionService) conversionService);
480514
}
515+
// 将main函数的args封装成 SimpleCommandLinePropertySource加入环境中
481516
configurePropertySources(environment, args);
517+
// 激活相应的配置文件
482518
configureProfiles(environment, args);
483519
}
484520

@@ -678,6 +714,7 @@ protected void load(ApplicationContext context, Object[] sources) {
678714
if (logger.isDebugEnabled()) {
679715
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
680716
}
717+
// 创建BeanDefinitionLoader 创建了注解形式的bean定义读取器
681718
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
682719
if (this.beanNameGenerator != null) {
683720
loader.setBeanNameGenerator(this.beanNameGenerator);
@@ -1212,6 +1249,7 @@ public Set<ApplicationListener<?>> getListeners() {
12121249
* @return the running {@link ApplicationContext}
12131250
*/
12141251
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
1252+
// 调用重载方法
12151253
return run(new Class<?>[] { primarySource }, args);
12161254
}
12171255

@@ -1223,6 +1261,7 @@ public static ConfigurableApplicationContext run(Class<?> primarySource, String.
12231261
* @return the running {@link ApplicationContext}
12241262
*/
12251263
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
1264+
// 两件事:初始化SpringApplication,然后调用run方法
12261265
return new SpringApplication(primarySources).run(args);
12271266
}
12281267

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/WebApplicationType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ static WebApplicationType deduceFromClasspath() {
6868
return WebApplicationType.NONE;
6969
}
7070
}
71+
// 走这里
7172
return WebApplicationType.SERVLET;
7273
}
7374

zzj-spring-boot-stater/pom.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.hand</groupId>
8+
<artifactId>zzj-spring-boot-stater</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<properties>
12+
<maven.compiler.source>8</maven.compiler.source>
13+
<maven.compiler.target>8</maven.compiler.target>
14+
</properties>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>org.springframework.boot</groupId>
19+
<artifactId>spring-boot-autoconfigure</artifactId>
20+
<version>2.2.9.RELEASE</version>
21+
</dependency>
22+
</dependencies>
23+
24+
</project>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.hand.config;
2+
3+
import com.hand.pojo.SimpleBean;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
7+
/**
8+
* @author zijian.zeng@hand-china.com
9+
* @since 2023-01-27
10+
*/
11+
@Configuration
12+
public class MyAutoConfiguration {
13+
14+
static {
15+
System.out.println("MyAutoConfiguration init...");
16+
}
17+
18+
@Bean
19+
public SimpleBean simpleBean() {
20+
return new SimpleBean();
21+
}
22+
23+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.hand.pojo;
2+
3+
import org.springframework.boot.context.properties.ConfigurationProperties;
4+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
5+
import org.springframework.context.annotation.Configuration;
6+
7+
/**
8+
* @author zijian.zeng@hand-china.com
9+
* @since 2023-01-27
10+
*/
11+
@EnableConfigurationProperties
12+
@ConfigurationProperties(prefix = "simplebean")
13+
public class SimpleBean {
14+
15+
private int id;
16+
private String name;
17+
18+
public int getId() {
19+
return id;
20+
}
21+
22+
public void setId(int id) {
23+
this.id = id;
24+
}
25+
26+
public String getName() {
27+
return name;
28+
}
29+
30+
public void setName(String name) {
31+
this.name = name;
32+
}
33+
34+
@Override
35+
public String toString() {
36+
return "SimpleBean{" +
37+
"id=" + id +
38+
", name='" + name + '\'' +
39+
'}';
40+
}
41+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.hand.config.MyAutoConfiguration

0 commit comments

Comments
 (0)