1-简介
Spring Boot是基于Spring框架开发的全新框架,其设计目的是简化Spring应用的初始化搭建和开发过程。
Spring Boot整合了许多框架和第三方库配置,几乎可以达到“开箱即用”。
优点
可快速构建独立的Spring应用
直接嵌入Tomcat、Jetty和Undertow服务器(无需部署WAR文件)
提供依赖启动器简化构建配置
极大程度的自动化配置Spring和第三方库
提供生产就绪功能
极少的代码生成和XML配置
2-环境准备
2-1-参考
2-2-工具
安装JDK 1.8.0_201(及以上版本)
classpath:.; %JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;%CATALINA_HOME%\lib\servlet-api.jar
安装Tomcat9
安装eclipse
安装spring Tools插件
打开eclipse----菜单----Help----Eclipse Marketplace----在Find搜索框中输入spring----回车搜索
可能会失败,多来几次,安装时间比较长。
安装Apache Maven 3.6.0
1.目前eclipse自带maven,也可以使用自己的maven,如下图所示
2.修改settings.xml,设置本地仓库位置和远程仓库镜像
<localRepository>D:/repository</localRepository>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
3.eclipse使用自己的settings.xml
3-入门程序
3-1-maven手动创建
创建Maven项目
在pom.xml中添加Spring Boot相关依赖
<!-- 引入Spring Boot依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.11</version>
</parent>
<dependencies>
<!-- 引入Web场景依赖启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
编写主程序启动类
@SpringBootApplication(scanBasePackages = "com.itheima")
public class ManualApp {
public static void main(String[] args) throws Exception {
SpringApplication.run(ManualApp.class, args);
}
}
创建一个用于Web访问的Controller
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello Spring Boot";
}
}
运行项目
在浏览器地址栏输入
http://localhost:8080/hello
即可看到运行结果
如果遇到端口占用,新建application.properties,设置端口号
# 应用服务 WEB 访问端口
server.port=8080
3-2-spring stater project创建
创建项目
设置Service URL
把Service URL设置为
https://start.aliyun.com/
如下图:
使用这个网址,创建项目更快。
选择Spring Web依赖
项目结构
mvnw和mvnw.cmd:这是maven包装器(wrapper)脚本,借助这些脚本,没有maven,也可以构建项目。
创建HelloController
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello Spring Boot";
}
}
测试同上
4-单元测试
在pom文件中添加spring-boot-starter-test测试启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
重命名自动创建的单元测试类
文件名改为HelloControllerTests
编写单元测试方法
@Autowired
private HelloController helloController;
@Test
public void testHello() {
String hello = helloController.hello();
System.out.println(hello);
Assert.isTrue("hello Spring Boot".equals(helloController.hello()), "helloController.hello()的返回值必须等于hello Spring Boot");
}
使用MockMvc来做单元测试
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import cn.zptc.autoapp.demos.web.HelloController;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(HelloController.class)
public class HelloControllerTest2 {
@Autowired
private MockMvc mockMvc;
@Test
public void whenGetGreeting_thenCorrectResponse() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("Hello, World!"));
}
}
这些测试通常运行得很快,因为它们不依赖于整个Spring应用程序的上下文启动。它们专注于测试Controller的逻辑,而不需要启动整个服务器或数据库连接。
启动tomcat来做单元测试
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyControllerTest {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testSayHello() {
String url = "http://localhost:" + port + "/hello";
String response = restTemplate.getForObject(url, String.class);
assertThat(response).isEqualTo("Hello, World!");
}
}
执行测试方法
光标定位到方法名称上,右键--》Run As --》JUnit Test。
5-Spring Boot 原理分析
以入门程序为例子,<spring-boot.version>2.4.3.RELEASE</spring-boot.version>
5-1-Spring Boot 依赖管理
spring-boot-starter-parent
配置文件管理
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/application*.yml</include>
<include>**/application*.yaml</include>
<include>**/application*.properties</include>
</includes>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
<excludes>
<exclude>**/application*.yml</exclude>
<exclude>**/application*.yaml</exclude>
<exclude>**/application*.properties</exclude>
</excludes>
</resource>
</resources>
spring-boot-dependencies
1.常用技术的版本号管理
<properties>
<activemq.version>5.15.14</activemq.version>
2.常用技术的依赖管理
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-amqp</artifactId>
<version>${activemq.version}</version>
</dependency>
3.插件管理
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>${build-helper-maven-plugin.version}</version>
</plugin>
spring-boot-starter-web
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.7.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.3.7.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.7.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.12.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
5-2-Spring Boot 自动配置
由@SpringBootApplication配置springboot
源码:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@SpringBootConfiguration
@Configuration
public @interface SpringBootConfiguration {
说明是一个配置类,相当于XML配置文件
@EnableAutoConfiguration
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
new PackageImports(metadata).getPackageNames().toArray(new String[0]):获取主程序启动类所在包
AutoConfigurationImportSelector.class中
有个方法getAutoConfigurationEntry()中
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);:获取自动配置类
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
。。。。。。
configurations = getConfigurationClassFilter().filter(configurations);:选出符合当前项目的自动配置类
@ComponentScan
扫描主程序启动类所在包下的组件
5-3-Spring Boot 执行流程
SpringApplication.run(Springboot11Application.class, args);
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
由上面代码看出,程序会创建SpringApplication实例并初始化和调用run方法启动项目
SpringApplication实例并初始化
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();//判断web应用类型,servlet应用还是reactive应用
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//设置SpringApplication应用的初始化器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//设置SpringApplication应用的监听器
this.mainApplicationClass = deduceMainApplicationClass();//推断主程序启动类
}
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
run方法
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);// Create and configure the environment
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 {
/**
* Called immediately before the run method finishes, when the application context has
* been refreshed and all {@link CommandLineRunner CommandLineRunners} and
* {@link ApplicationRunner ApplicationRunners} have been called.
* @param context the application context.
* @since 2.0.0
*/
listeners.running(context);//
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}