1、springboot特点
1、约定大于配置。不需要XML配置 ,可以非常快速的构建spring应用程序。
2、内嵌servlet容器。传统的项目采用war包的方式,由外部servlet容器(tomcat...)去加载war包。
而springboot的项目是引用了tomcat-embed的jar包,通过main方法的方式是去运行。
也就是说,tomcat是springboot应用程序的一个组件而已。
3、自动配置,可以快速的整合第三方库,比如redis,rabbitmq,elasticsearch等
4、Spring Boot允许你外部化你的配置,以便你可以在不同的环境中使用相同的应用程序代码。
比如:java -jar app.jar --spring.profiles.active=dev
java -jar app.jar --spring.profiles.active=test
java -jar app.jar --spring.profiles.active=pro
同一个jar包,只需要修改spring.profiles.active的属性,即可切到不同的环境。
5、整合了开发中常用的各种组件,优雅地处理了它们之间的版本兼容性问题 。
6、Spring Boot提供了Actuator 监控管理应用程序。
2、快速开始
可以通过地址:生成模板项目,也可以通过idea生成
下面介绍一下普通maven工程搭建boot应用
1、新建maven父项目springboot-item
- 在pom文件中添加父工程坐标
org.springframework.boot spring-boot-starter-parent 2.0.3.RELEASE
- 添加sprinboot maven 打包插件
org.springframework.boot spring-boot-maven-plugin
- * 添加属性
UTF-8 UTF-8 1.8
2、新建module工程item-hello 例如
* 在item-hello的pom文件里添加启动器依赖【web依赖和测试依赖】
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test
需要注意的是,我们并没有在这里指定版本信息。因为SpringBoot的父工程已经对版本进行了管理了。
这个时候,可以去项目中查看依赖,会发现springboot帮我们引入了web开发需要的大量的依赖。
* 编写启动类和controller类
SpringbootHelloApplication :
package com.suzhe.hello;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class SpringbootHelloApplication { public static void main(String[] args) { SpringApplication.run(SpringbootHelloApplication.class, args); }}
HelloController:
import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class HelloController { @GetMapping("hello") public String hello(){ return "world"; }}
* 运行SpringbootHelloApplication类
- 1)监听的端口是8080
-
2)SpringMVC的映射路径是:/
-
3)
/hello
路径已经映射到了HelloController
中的hello()方法
访问http://localhost:8080/hello
3、修改端口号
在 spring boot 中,有两种配置文件:application.properties和application.yml。下面是两种方式的比较【修改端口号和配置tomcat最大线程】:
application.properties:
server.port=8090server.tomcat.max-threads=200
application.yml
server: port: 8080 tomcat: max-threads: 200
从配置比较可以发现,yml有采用树形结构的这种方式,有更强的层次感。
*在项目中新建yml文件
*配置端口
server: port: 8090
*启动SpringbootHelloApplication
*访问http://localhost:8090/hello
4、springboot原理分析
使用SpringBoot之后,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这是如何做到的?
一切魔力的开始,都是从我们的main函数来的,所以我们再次来看下启动类:
我们发现特别的地方有两个:
-
注解:@SpringBootApplication
-
run方法:SpringApplication.run()
我们分别来研究这两个部分。
注解SpringBootApplication
这个注解等价于去声明下面三个注解:
-
@SpringBootConfiguration
-
@EnableAutoConfiguration
-
@ComponentScan
注解SpringBootConfiguration
通过这段我们可以看出,在这个注解上面,又有一个@Configuration
注解。通过上面的注释阅读我们知道:这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration
的类,并且读取其中的配置信息。而@SpringBootConfiguration
是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。
注解ComponentScan
大概的意思:
配置组件扫描的指令。提供了类似与
<context:component-scan>
标签的作用通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包
而我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。
注解EnableAutoConfiguration
简单翻译以下:
第二级的注解
@EnableAutoConfiguration
,告诉SpringBoot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了spring-boot-starter-web
,而这个启动器中帮我们添加了tomcat
、SpringMVC
的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!
SpringBoot内部对大量的第三方库或Spring内部库进行了默认配置,这些配置是否生效,取决于我们是否引入了对应库所需的依赖,如果有那么默认配置就会生效。
所以,我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了。除非你不希望使用SpringBoot的默认配置,这时候就需要在配置文件里配置,就像前面的端口号配置成8090。
在@EnableAutoConfiguration注解内使用到了@import注解来完成导入配置类的功能,
而EnableAutoConfigurationImportSelector内部则是使用了SpringFactoriesLoader, loadFactoryNames方法进行扫描所有jar包中META-INF/spring.factories文件,把spring.factories文件里的类注册到spring容器中。
可以查看依赖包spring-boot-autoconfigure,该包里定义了springboot自动装配的所有组件(这里只截取了部分)。
几乎涵盖了现在主流的开源框架,例如:
-
redis
-
jms
-
amqp
-
jdbc
-
jackson
-
mongodb
-
jpa
-
solr
-
elasticsearch
下面介绍一下springboot是如何改变默认的端口配置?
我们在spring.factories可以发现类ServletWebServerFactoryAutoConfiguration。
查看ServletWebServerFactoryAutoConfiguration类,会发现该类导入了ServletWebServerFactoryConfiguration类里的静态内部类。
查看ServletWebServerFactoryConfiguration 类,会发现该类注册了TomcatServletWebServerFactory 实例。
ConditionalOnClass 存在指定的class 才会注册该bean
ConditionalOnMissingBean,是说环境中没有指定类型的Bean这个才注册该bean
@EnableConfigurationProperties(ServerProperties.class) 来声明要使用ServerProperties这个类的对象,
然后把ServerProperties的对象注入到ServletWebServerFactoryCustomizer 中
进入ServerProperties 类
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)public class ServerProperties { /** * Server HTTP port. */ private Integer port; /** * Network address to which the server should bind. */ private InetAddress address; @NestedConfigurationProperty private final ErrorProperties error = new ErrorProperties(); /** * Whether X-Forwarded-* headers should be applied to the HttpRequest. */ private Boolean useForwardHeaders; /** * Value to use for the Server response header (if empty, no header is sent). */ private String serverHeader; /** * Maximum size, in bytes, of the HTTP message header. */ private int maxHttpHeaderSize = 0; // bytes /** * Time that connectors wait for another HTTP request before closing the connection. * When not set, the connector's container-specific default is used. Use a value of -1 * to indicate no (that is, an infinite) timeout. */ private Duration connectionTimeout; @NestedConfigurationProperty private Ssl ssl; @NestedConfigurationProperty private final Compression compression = new Compression(); @NestedConfigurationProperty private final Http2 http2 = new Http2(); private final Servlet servlet = new Servlet(); private final Tomcat tomcat = new Tomcat(); private final Jetty jetty = new Jetty(); private final Undertow undertow = new Undertow();..........}
在类上通过@ConfigurationProperties注解声明当前类为属性读取类 ,prefix="server"
读取属性文件中,
前缀为server的值,比如配置了server.port=8090, springboot会自动将配置文件的8090 自动注入
到port属性中。
继续查看ServletWebServerFactoryCustomizer ,可以看到该类的customize方法,该方法将ServerProperties里的属性port注入到了tomcat工厂类中的port,到此,springboot就把我们配置的端口号8090覆盖了默认的端口号8080.
customize方法的调用是在WebServerFactoryCustomizerBeanPostProcessor处理器中的postProcessBeforeInitialization方法中
run方法简要分析:
run方法会把SpringbootHelloApplication当前类作为参数传入,springboot就会根据该类上的注解信息,把bean注册到spring容器中,一切都交给spring容器了。
不断的跟进run方法,打一个断点,debug运行,我们可以看到springboot内部创建了一个AnnotationConfigServletWebServerApplicationContext类。
查看整个AnnotationConfigServletWebServerApplicationContext类的继承关系,如下图:
可以看到AnnotationConfigServletWebServerApplicationContext 继承ServletWebServerApplicationContext。
上面的代码截图中有个方法refreshContext(context); 该方法用来刷新spring容器,不断的跟进方法,可以看到熟悉的spring容器初始化过程:
该方法中在调用完initApplicationEventMulticaster()【初始化事件派发器】后会执行子类的onRefresh()方法。查看
ServletWebServerApplicationContext里的onRefresh()方法,可以看到createWebServer方法【创建web服务】。
查看createWebServer方法
private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); if (webServer == null && servletContext == null) { //从spring容器中获取ServletWebServerFactory实例,该实例是在ServletWebServerFactoryConfiguration来注入的。 ServletWebServerFactory factory = getWebServerFactory(); //从工厂中获取webServer实例,典型的工厂方法模式 this.webServer = factory.getWebServer(getSelfInitializer()); } else if (servletContext != null) { try { getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources(); }
这里首先会获取servlet容器工厂,也就是前面注册的TomcatServletWebServerFactory,然后从工场里获取一个实例。
当spring容器初始化完成后,会启动servlet容器【startWebServer方法】,【详细可以跟进startWebServer,会发现tomcat api的调用】
总结
SpringBoot为我们提供了默认配置,而默认配置生效的条件一般有两个:
- 你引入了相关依赖
- 你自己没有配置
1)启动器
所以,我们如果不想配置,只需要引入依赖即可,而依赖版本我们也不用操心,因为只要引入了SpringBoot提供的stater(启动器),就会自动管理依赖及版本了。
因此,玩SpringBoot的第一件事情,就是找启动器,SpringBoot提供了大量的默认启动器。
2)全局配置
另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义application.yml (application.properties)文件来进行覆盖。
因此,玩SpringBoot的第二件事情,就是通过application.yml (application.properties)来覆盖默认属性值,形成自定义配置。