配置原理解析
1. 启动配置原理
配置在META-INF/spring.factories中
ApplicationContextInitializer
SpringApplicationRunListener
添加到IoC容器中
AppllicationRunner
CommandLineRunner
1.1. 启动流程
1 2 3
| SpringApplication.run(BootdataApplication.class, args);
return new SpringApplication(primarySources).run(args);
|
1.1.1. 创建SpringApplication对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public SpringApplication(Class<?>... primarySources) { this(null, primarySources); }
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
|
1.1.1.1. ApplicationContextInitializer
从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer



1.1.1.2. ApplicationListener

1.1.1.3. deduceMainApplicationClass
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { } return null; }
|
1.1.2. 运行run方法
refreshContext(context);所有组件的加载
1.1.2.1. SpringApplicationRunListeners
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
| public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment);
context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context);
callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); }
try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
|
SpringApplicationRunListeners

2. 自定义starters
2.1. 自动配置
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Configuration
@ConditionalOnxxx
@AutoConfigureAfter
@Bean
@ConfigurationProperties(prefix = "")
@EnableConfigurationProperties
|
META-INF/spring.factories
1 2
| org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
2.2. 模式
启动器只用来做依赖导入
专门写一个自动配置模块
启动器依赖自动配置
xxx-spring-boot-starter
2.3. 创建项目
新建空项目
new Module:
Spring-Initalizer:hello-spring-boot-starter-autoconfigurer
仅添加spring-boot-starter
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
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.0.RELEASE</version> <relativePath/> </parent> <groupId>com.runaccpeted</groupId> <artifactId>hello-spring-boot-starter-autoconfigurer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>hello-spring-boot-starter-autoconfigurer</name> <description>Demo project for Spring Boot</description>
<properties> <java.version>1.8</java.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> </dependencies> </project>
|
Maven:hello-spring-boot-starter
添加hello-spring-boot-starter-autoconfigurer依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.runaccpeted.starter</groupId> <artifactId>hello-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version>
<dependencies> <dependency> <groupId>com.runaccpeted</groupId> <artifactId>hello-spring-boot-starter-autoconfigurer</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies>
</project>
|
HelloProperties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package com.runaccpeted.starter;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "runaccpeted.hello") public class HelloProperties {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; } }
|
HelloService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.runaccpeted.starter;
public class HelloService {
HelloProperties helloProperties;
public HelloService(HelloProperties helloProperties) { this.helloProperties = helloProperties; }
public String saySomething(String name) { return helloProperties.getName()+" "+name; } }
|
HelloAutoConfiguration
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
| package com.runaccpeted.starter;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration @ConditionalOnWebApplication @EnableConfigurationProperties(HelloProperties.class) public class HelloAutoConfiguration { @Autowired private HelloProperties helloProperties;
public HelloProperties getHelloProperties() { return helloProperties; }
public void setHelloProperties(HelloProperties helloProperties) { this.helloProperties = helloProperties; }
@Bean public HelloService helloService(){ HelloService service = new HelloService(helloProperties); return service; } }
|
2.5. spring.factories
1 2 3
| # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.runaccpeted.starter.HelloAutoConfiguration
|
2.6. 安装项目
无法安装 no test – 删除hello-spring-boot-starter-autoconfigurer 中的test文件夹

2.7. 运用到项目
1 2 3 4 5
| <dependency> <groupId>com.runaccpeted.starter</groupId> <artifactId>hello-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
|
TestController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.runaccpeted.controller;
import com.runaccpeted.starter.HelloService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
@RestController public class TestController { @Autowired HelloService service;
@RequestMapping("/starter") public String test(){ return service.saySomething("Hello"); } }
|
application.properties
1
| runaccpeted.hello.name=say:
|
