博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
springboot初探
阅读量:6221 次
发布时间:2019-06-21

本文共 8493 字,大约阅读时间需要 28 分钟。

hot3.png

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生成

73cceba34c57e75bfaec30eb05ae9aba2f1.jpg

下面介绍一下普通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 例如

94ef6260feb8433fd813f14f1b1be636e35.jpg

* 在item-hello的pom文件里添加启动器依赖【web依赖和测试依赖】

org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test

需要注意的是,我们并没有在这里指定版本信息。因为SpringBoot的父工程已经对版本进行了管理了。

这个时候,可以去项目中查看依赖,会发现springboot帮我们引入了web开发需要的大量的依赖。

0243f96bc964519f38f93dafd21a324de61.jpg

* 编写启动类和controller类

8db4717950d0f345eafc85f2f928316e1d6.jpg

 

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类

2d135148c12d70cd57a228125a2638ab00b.jpg

  • 1)监听的端口是8080
  • 2)SpringMVC的映射路径是:/

  • 3)/hello路径已经映射到了HelloController中的hello()方法

访问http://localhost:8080/hello

78801a4bc41059540546318ec93b8d86096.jpg

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文件

7dc239d3dab1ab0c3b0b8210bcf707e3887.jpg

*配置端口

server:  port: 8090

*启动SpringbootHelloApplication

*访问http://localhost:8090/hello

9397064e6beafc6824b63821894f0477d3c.jpg

 

4、springboot原理分析

使用SpringBoot之后,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这是如何做到的?

一切魔力的开始,都是从我们的main函数来的,所以我们再次来看下启动类:

71c75fdf7e5bcd6d2b3cac4491649ec2503.jpg

我们发现特别的地方有两个:

  • 注解:@SpringBootApplication

  • run方法:SpringApplication.run()

我们分别来研究这两个部分。

 

注解SpringBootApplication

212bb4ebcd5c09aacf658c7ab3f9dc0bf53.jpg

这个注解等价于去声明下面三个注解:

  • @SpringBootConfiguration

  • @EnableAutoConfiguration

  • @ComponentScan

 

注解SpringBootConfiguration

0f9c6fee602d35459f2f1ca035829183684.jpg

通过这段我们可以看出,在这个注解上面,又有一个@Configuration注解。通过上面的注释阅读我们知道:这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration的类,并且读取其中的配置信息。而@SpringBootConfiguration是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。

 

注解ComponentScan

356afdbdd39b8015f9174ac333302a4be25.jpg

大概的意思:

配置组件扫描的指令。提供了类似与<context:component-scan>标签的作用

通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包

而我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。

 

注解EnableAutoConfiguration

3ba217528ee78ad58ec469a2239ab0c3e53.jpg

简单翻译以下:

第二级的注解@EnableAutoConfiguration,告诉SpringBoot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了spring-boot-starter-web,而这个启动器中帮我们添加了tomcatSpringMVC的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!

SpringBoot内部对大量的第三方库或Spring内部库进行了默认配置,这些配置是否生效,取决于我们是否引入了对应库所需的依赖,如果有那么默认配置就会生效。

所以,我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了。除非你不希望使用SpringBoot的默认配置,这时候就需要在配置文件里配置,就像前面的端口号配置成8090。

在@EnableAutoConfiguration注解内使用到了@import注解来完成导入配置类的功能,

而EnableAutoConfigurationImportSelector内部则是使用了SpringFactoriesLoader,
loadFactoryNames方法进行扫描所有jar包中META-INF/spring.factories文件,把spring.factories文件里的类注册到spring容器中。

bb5523a7315ea54c7277f6baf609a7cf436.jpg

可以查看依赖包spring-boot-autoconfigure,该包里定义了springboot自动装配的所有组件(这里只截取了部分)。

89912d0dbef5192002d01f5f9dd63c83194.jpg

几乎涵盖了现在主流的开源框架,例如:

  • redis

  • jms

  • amqp

  • jdbc

  • jackson

  • mongodb

  • jpa

  • solr

  • elasticsearch

下面介绍一下springboot是如何改变默认的端口配置?

我们在spring.factories可以发现类ServletWebServerFactoryAutoConfiguration。

查看ServletWebServerFactoryAutoConfiguration类,会发现该类导入了ServletWebServerFactoryConfiguration类里的静态内部类。

168be5e77eb2c449391988ecf861748e001.jpg

查看ServletWebServerFactoryConfiguration 类,会发现该类注册了TomcatServletWebServerFactory 实例。

8ded23c8718ad49e7b44d097994ced82118.jpg

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.

b0dd5b11a29118785e690ca1ca5de10fc59.jpg

 

customize方法的调用是在WebServerFactoryCustomizerBeanPostProcessor处理器中的postProcessBeforeInitialization方法中

463b9029162e71939058e66278dbc8410f4.jpg

ba5d2be4feb77ff2339e827ede2bbe68a1d.jpg

 

 

run方法简要分析:

run方法会把SpringbootHelloApplication当前类作为参数传入,springboot就会根据该类上的注解信息,把bean注册到spring容器中,一切都交给spring容器了。

不断的跟进run方法,打一个断点,debug运行,我们可以看到springboot内部创建了一个AnnotationConfigServletWebServerApplicationContext类。

5eb0ba8b284f436319c1b6b56e88e6d3e54.jpg

查看整个AnnotationConfigServletWebServerApplicationContext类的继承关系,如下图:

可以看到AnnotationConfigServletWebServerApplicationContext 继承ServletWebServerApplicationContext。

上面的代码截图中有个方法refreshContext(context);  该方法用来刷新spring容器,不断的跟进方法,可以看到熟悉的spring容器初始化过程:

5d6aac26901ade65c363a20b76796e33be0.jpg

该方法中在调用完initApplicationEventMulticaster()【初始化事件派发器】后会执行子类的onRefresh()方法。查看

ServletWebServerApplicationContext里的onRefresh()方法,可以看到createWebServer方法【创建web服务】。

4b5d690fb8a5c50300105fd6487cf27bc84.jpg

查看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的调用】

7e3646862de696d11428df336c58bc160db.jpg

 

总结

SpringBoot为我们提供了默认配置,而默认配置生效的条件一般有两个:

  • 你引入了相关依赖
  • 你自己没有配置

1)启动器

所以,我们如果不想配置,只需要引入依赖即可,而依赖版本我们也不用操心,因为只要引入了SpringBoot提供的stater(启动器),就会自动管理依赖及版本了。

因此,玩SpringBoot的第一件事情,就是找启动器,SpringBoot提供了大量的默认启动器。

2)全局配置

另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义application.yml (application.properties)文件来进行覆盖。

因此,玩SpringBoot的第二件事情,就是通过application.yml (application.properties)来覆盖默认属性值,形成自定义配置。

转载于:https://my.oschina.net/suzheworld/blog/2992514

你可能感兴趣的文章
Maven创建web工程报错
查看>>
[Android 之美] 那些你不知道的APK 瘦身,让你的APK更小
查看>>
Android Arcface 2.0人脸识别注册失败问题
查看>>
MySql ZIP 包 安装 的详细步骤以及可能的错误
查看>>
ROW_NUMBER() OVER函数的基本用法
查看>>
Hadoop LineRecordReader实现分析
查看>>
Android利用Fiddler进行网络数据抓包
查看>>
我的友情链接
查看>>
百度8秒君:文件存网盘真的靠谱么?
查看>>
TCP/IP参考模型
查看>>
linux基础_根文件系统
查看>>
一个奇葩常见的问题 nginx 403 forbidden错误
查看>>
Hibernate查询方式汇总
查看>>
hpux filecache问题
查看>>
下一代太阳自适应光学技术让太空“天气预报”更精准
查看>>
气象与情绪有何联系?低温天气比恐袭更容易令人抑郁
查看>>
使用Jmeter对mysql进行性能测试入门
查看>>
用java在图片上写字
查看>>
spring的成功配置样式
查看>>
spring注解之 @profile
查看>>