写在前面
鉴于有人留言说想要学习SpringBoot相关的知识,我这里打算写一个SpringBoot系列的相关博文,目标呢是想让看了这一系列博文的同学呢,能够对SpringBoot略窥门径,这一系列的博文初步都定下来包括SpringBoot介绍、入门、配置、日志相关、web开发、数据访问、结合docker、缓存、消息队列、检索、任务安全、分布式等等一系列的博文,工作量很大,是个漫长的过程,每一步我都尽量详细,配上截图说明,也希望对看的同学真的有用。
单纯就是想分享技术博文,还想说一句就是,如果觉得有用,请点个关注、给个赞吧,也算对我来说是个宽慰,毕竟也得掉不少头发,嘿嘿嘿
系列文章传送条
详细SpringBoot教程之入门(一)
详细SpringBoot教程之入门(二)
详细SpringBoot教程之配置文件(一)
详细SpringBoot教程之配置文件(二)
详细SpringBoot教程之日志框架
详细SpringBoot教程之Web开发(一)
详细SpringBoot教程之Web开发(二)
详细SpringBoot教程之Web开发(三)
详细SpringBoot教程之数据访问
详细SpringBoot教程之启动配置原理
详细SpringBoot教程之缓存开发
启动配置原理
到这里,我们讲解的只是其实已经够我们开发一些比较小的SpringBoot应用了,但是我们随着在使用的过程中,可以对SpringBoot进行底层原理分析,这样我们才能真正将SpringBoot使用的得心应手,然后我们还可以自己开发自己的starter场景启动器,是不是很刺激,后面我们会将,而我这里首先要几个重要的事件回调机制
我们之前也提到过,一般我们的配置核心是在各个配置的META-INF/spring.factories中,而我们SpringBoot的启动相关是
- ApplicationContextInitializer
- SpringApplicationRunListener
只需要放在ioc容器中
- ApplicationRunner
- CommandLineRunner
启动流程
创建SpringApplication对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| initialize(sources); private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } this.webEnvironment = deduceWebEnvironment(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); 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
| public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); Banner printedBanner = printBanner(environment); context = createApplicationContext(); analyzers = new FailureAnalyzers(context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); listeners.finished(context, null); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } }
|
事件监听机制
配置在META-INF/spring.factories
ApplicationContextInitializer
1 2 3 4 5 6 7
| public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("ApplicationContextInitializer...initialize..."+applicationContext); } }
|
SpringApplicationRunListener
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
| public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {
public HelloSpringApplicationRunListener(SpringApplication application, String[] args){
}
@Override public void starting() { System.out.println("SpringApplicationRunListener...starting..."); }
@Override public void environmentPrepared(ConfigurableEnvironment environment) { Object o = environment.getSystemProperties().get("os.name"); System.out.println("SpringApplicationRunListener...environmentPrepared.."+o); }
@Override public void contextPrepared(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener...contextPrepared..."); }
@Override public void contextLoaded(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener...contextLoaded..."); }
@Override public void finished(ConfigurableApplicationContext context, Throwable exception) { System.out.println("SpringApplicationRunListener...finished..."); } }
|
配置(META-INF/spring.factories)
1 2 3 4 5
| org.springframework.context.ApplicationContextInitializer=\ com.atguigu.springboot.listener.HelloApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\ com.atguigu.springboot.listener.HelloSpringApplicationRunListener
|
只需要放在ioc容器中
ApplicationRunner
1 2 3 4 5 6 7
| @Component public class HelloApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("ApplicationRunner...run...."); } }
|
CommandLineRunner
1 2 3 4 5 6 7
| @Component public class HelloCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("CommandLineRunner...run..."+ Arrays.asList(args)); } }
|
自定义starter
我们在之前的SpringBoot中,引入依赖的starter是不是很舒服,那么我们现在来学着怎么开发自己的starter,其实也非常简单,具体操作如下,首先我们使用Idea创建一个空项目
然后我们会到这里的界面,在这里,我们可以给空项目创建模块,我们如果要自己的启动器的话,那么最基本需要两个模块,不过是哪两个模块呢?这里我们要来讲讲。
我们需要搞清楚两个问题,如下
这个场景需要使用到的依赖是什么?
如何编写自动配置
我们找个starter来进行分析,如下
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Configuration @ConditionalOnXXX @AutoConfigureAfter @Bean
@ConfigurationPropertie @EnableConfigurationProperties
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
|
现在我们
所以我们应该符合以下模式:
又到了我们熟悉的界面,我们要创建两个,一个是啥都不勾选的SpringBoot项目,还有一个只勾选web模块,创建好了之后,在pom.xml中进行如下更改
启动器模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?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.atguigu.starter</groupId> <artifactId>atguigu-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version>
<dependencies>
<dependency> <groupId>com.atguigu.starter</groupId> <artifactId>atguigu-spring-boot-starter-autoconfigurer</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies>
</project>
|
自动配置模块
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
| <?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.atguigu.starter</groupId> <artifactId>atguigu-spring-boot-starter-autoconfigurer</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging>
<name>atguigu-spring-boot-starter-autoconfigurer</name> <description>Demo project for Spring Boot</description>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.10.RELEASE</version> <relativePath/> </parent>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties>
<dependencies>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
</dependencies>
</project>
|
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
| package com.atguigu.starter;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "atguigu.hello") public class HelloProperties {
private String prefix; private String suffix;
public String getPrefix() { return prefix; }
public void setPrefix(String prefix) { this.prefix = prefix; }
public String getSuffix() { return suffix; }
public void setSuffix(String suffix) { this.suffix = suffix; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.atguigu.starter;
public class HelloService {
HelloProperties helloProperties;
public HelloProperties getHelloProperties() { return helloProperties; }
public void setHelloProperties(HelloProperties helloProperties) { this.helloProperties = helloProperties; }
public String sayHellAtguigu(String name){ return helloProperties.getPrefix()+"-" +name + helloProperties.getSuffix(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.atguigu.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 HelloServiceAutoConfiguration {
@Autowired HelloProperties helloProperties; @Bean public HelloService helloService(){ HelloService service = new HelloService(); service.setHelloProperties(helloProperties); return service; } }
|
下一篇
SpringBoot官网其实给了很多案例给我们参考,集成了很多模块的示例代码,SpringBoot放在GitHub上可以下载运行然后研究,下一遍对缓存进行讲解。
Author:
DengBoCong
Permalink:
http://dengbocong.cn/Spring-Boot/a9afbec9ed9f/
License:
Licensed under the Apache License, Version 2.0 (the "License")
Slogan:
Stay hungry, Stay foolish.