SpringBoot- SpringBoot基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换
- 全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率
SpringBoot的特点- 为基于Spring的开发提供更快的入门体验
- 开箱即用,没有代码生成,也无需XML配置。同时也可以修改默认值来满足特定的需求
- 提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全、指标,健康检测、外部配置等
- SpringBoot不是对Spring功能上的增强,而是提供了一种快速使用Spring的方式
SpringBoot的核心功能- 起步依赖
- 起步依赖本质上是一个Maven项目对象模型(POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能
- 简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能
- 自动配置
- Spring Boot的自动配置是一个运行时的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个
- 该过程是Spring自动完成的
SpringBoot快速入门- 创建maven工程(jar)
- 添加SpringBoot的起步依赖
- SpringBoot要求,项目要继承SpringBoot的起步依赖spring-boot-starter-parent
- SpringBoot要集成SpringMVC进行Controller的开发,所以项目要导入web的启动依赖
[XHTML] 纯文本查看 复制代码 <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
编写SpringBoot引导类 - 要通过SpringBoot提供的引导类起步SpringBoot才可以进行访问
[Java] 纯文本查看 复制代码 import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class);
}
}
[Java] 纯文本查看 复制代码 @RestController
public class QuickStartController {
@RequestMapping("/quick")
public String quick() {
return "springboot 访问成功!";
}
}
快速入门解析- SpringBoot代码解析
- @SpringBootApplication
- SpringApplication.run(MySpringBootApplication.class) 代表运行SpringBoot的启动类
- SpringBoot工程热部署
- 我们在开发中反复修改类、页面等资源,每次修改后都是需要重新启动才生效,这样很浪费时间
- 我们可以在修改代码后不重启就能生效
- 在 pom.xml 中添加如下配置就可以实现这样的功能,我们称之为热部署
- 注意:IDEA进行SpringBoot热部署失败原因
- 出现这种情况,并不是热部署配置问题
- 其根本原因是因为Intellij IEDA默认情况下不会自动编译
- settint-->compiler-->build project automatically
- 然后按快捷键: Shift+Ctrl+Alt+/,选择Registry
- 选中register
- 勾选compiler.automake.allow.when.app.running
[XHTML] 纯文本查看 复制代码 <!--热部署配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
SpringBoot原理分析分析spring-boot-starter-parent- 按住Ctrl点击pom.xml中的spring-boot-starter-parent,跳转到了spring-boot-starter-parent的pom.xml,xml配置如下
[XHTML] 纯文本查看 复制代码 <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
- 按住Ctrl点击pom.xml中的spring-boot-starter-dependencies,跳转到了 spring-boot-starter-dependencies的pom.xml,xml配置如下
[XML] 纯文本查看 复制代码 <properties>
<activemq.version>5.15.3</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.63</appengine-sdk.version>
<artemis.version>2.4.0</artemis.version>
<aspectj.version>1.8.13</aspectj.version>
<assertj.version>3.9.1</assertj.version>
<atomikos.version>4.0.6</atomikos.version>
<bitronix.version>2.1.4</bitronix.version>
<build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version>
……
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
……
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
</plugin>
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<version>${jooq.version}</version>
</plugin>
………
</plugins>
</pluginManagement>
</build>
- 从上面的spring-boot-starter-dependencies的pom.xml中我们可以发现,一部分坐标的版本、依赖管理、插件管理已经定义好,所以我们的SpringBoot工程继承spring-boot-starter-parent后已经具备版本锁定等配置了
spring-boot-starter-web- 按住Ctrl点击pom.xml中的spring-boot-starter-web,跳转到了spring-boot-starter-web的pom.xml,xml配置如下
[XML] 纯文本查看 复制代码 <?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starters</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.1.RELEASE</version>
<name>Spring Boot Web Starter</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.0.1.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.0.1.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.0.1.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.9.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.5.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.5.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
- 从上面的spring-boot-starter-web的pom.xml中我们可以发现,spring-boot-starter-web就是将web开发要使用的spring-web、spring-webmvc等坐标进行了“打包”
- 这样我们的工程只要引入spring-boot-starter-web起步依赖的坐标就可以进行web开发了,同样体现了依赖传递的作用
自动配置原理解析- 按住Ctrl点击查看启动类MySpringBootApplication上的注解@SpringBootApplication
[Java] 纯文本查看 复制代码 @SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class);
}
}
- 注解@SpringBootApplication的源码
[JavaFX] 纯文本查看 复制代码 @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
……
}
- @SpringBootConfiguration:等同与@Configuration,既标注该类是Spring的一个配置类
- @EnableAutoConfiguration:SpringBoot自动配置功能开启
- 按住Ctrl点击查看注解@EnableAutoConfiguration
[Java] 纯文本查看 复制代码 @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
………[mw_shl_code=java,true]@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
"List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);"
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
}[/mw_shl_code]
- 其中,@Import(AutoConfigurationImportSelector.class) 导入了AutoConfigurationImportSelector类
- 按住Ctrl点击查看AutoConfigurationImportSelector源码
[Java] 纯文本查看 复制代码 @Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
"List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);"
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
protected List<String> "getCandidateConfigurations"(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in 'META-INF/spring.factories'. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
- 其中,SpringFactoriesLoader.loadFactoryNames方法的作用就是从META-INF/spring.factories文件中读取指定类对应的类名称列表
- spring.factories 文件中有关自动配置的配置信息如下
[XML] 纯文本查看 复制代码 ……
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
……
- 上面配置文件存在大量的以Configuration为结尾的类名称,这些类就是存有自动配置信息的类,而 SpringApplication在获取这些类名后再加载
- 我们以ServletWebServerFactoryAutoConfiguration为例来分析源码
[Java] 纯文本查看 复制代码 @Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
"… … …"
}
- 其中,@EnableConfigurationProperties(ServerProperties.class)代表加载ServerProperties服务器配置属性类
- 进入ServerProperties.class源码如下
[Java] 纯文本查看 复制代码 @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;
… … …
}
|