SpringBoot 浅析

SpringBoot 使用已经有不短的时间了,这次来系统的过下,自动配置原理,和启动原理。

Spring Boot 优点

  • Spring Boot 首先还是Spring
  • 它减少了大量的开发时间并提高了生产力
  • 它避免了编写大量的样板代码,注释和XML配置
  • 它遵循“自用默认配置”方法,以减少开发工作量
  • 独立运行的Spring项目
  • 内嵌的Servlet容器
  • ….
  • 重点:自用默认配置,约定大于配置,开箱即用
  • 如何实现的?

    自动配置

  • @EnableAutoConfiguration
  • @Conditional

@EnableAutoConfiguration

  • 顾名思义,EnableAutoConguration是和自动化配置相关的东西。
  • Spring应用上下文的自动化配置,尝试去猜测和配置你需要的bean。这些被自动化配置的类通常在classpath路径下,或者是你自己定义的bean。
  • 可以使用exclude来排除那些你不想被自动化配置的类。
  • 被EnableAutoConfiguration注解的类所在的包有着特殊的意义,他们通常被认为是默认的包,并对其及下属的包进行扫描。
  • 自动配置的类通常是在@Configuration里面配置的类
  • AutoConfigurationImportSelector 类提供支持,从 META-INF/spring.factories 中获取配置类

@Conditional

  • @Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean
  • Spring Boot 对在这个注解的基础上进行扩充了许多的@ConditionalOnXXXXXX
  • @ConditionalOnBean(某个Bean是否存在)
  • @ConditionalOnClass(类是否存在)
  • @ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
  • 参考 HttpEncodingAutoConfiguration

启动原理

我们从一个简单的SpringBoot入手

1
2
3
4
5
6
7
8
@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

}

进来以后 先 new SpringApplication(primarySources)对象,看下他的构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
		
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//记录主资源
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断启动类型,这里是SERVLET
this.webApplicationType = deduceWebApplicationType();
//从 META-INF/spring.factories 收集 ApplicationContextInitializer,并实例化
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//从 META-INF/spring.factories 收集 ApplicationListener,并实例化
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//判断主类
this.mainApplicationClass = deduceMainApplicationClass();
}

进入run方法

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
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//声明了一个ApplicationContext 容器
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//从 META-INF/spring.factories 收集SpringApplicationRunListener,并实例化
SpringApplicationRunListeners listeners = getRunListeners(args);
//调用 SpringApplicationRunListener.starting()
listeners.starting();
try {
//参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备环境 并调用 SpringApplicationRunListener.environmentPrepared()
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
//打印Banner
Banner printedBanner = printBanner(environment);
//根据类型创建一个Spring容器
context = createApplicationContext();
//异常报告
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备Spring容器环境,调用ApplicationContextInitializer.initialize()
//调用SpringApplicationRunListener.contextPrepared
//调用SpringApplicationRunListener.contextLoaded
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//刷新容器
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//调用SpringApplicationRunListener.started
listeners.started(context);
//调用 ApplicationRunner CommandLineRunner
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}

try {
//调用SpringApplicationRunListener.running
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

具体的东西还是跟代码看几遍,并实现下这几个接口