SpringBoot(十二) springBoot

springBoot

一、概述

1.什么是spring boot

Spring Boot是Spring项目中的一个子工程,与我们所熟知的Spring-framework 同属于spring的产品:

其最主要作用就是帮助开发人员快速的构建庞大的spring项目,并且尽可能的减少一切xml配置,做到开箱即用,迅速上手,让开发人员关注业务而非配置。

2.spring boot的特点

1.自动配置:不需要再关注各个框架的整合配置,springboot全部都已经配置好了。

2.起步依赖:我们在需要使用某个框架的时候,直接添加这个框架的启动器依赖即可,不需要在关注jar包的冲突和整合。

3.目的

用来简化spring应用的初始搭建以及开发过程。

  1. 为所有spring开发提供一个更快更广泛的入门体验。
  2. 零配置。没有冗余代码生成和xml强制配置,遵循“约定大于配置”
  3. 集成了大量常用的第三方库的配置,spring boot应用为这些第三方库提供了几乎可以零配置的开箱即用的能力。
  4. 提供一系列大型项目常用的非功能性,如嵌入服务器等。

4.好处

简单、快速、方便

5.优势

使用Java开发程序 , 一直困扰我们的就是臃肿、麻烦。搭建项目的过程相当复杂 , 我们需要考虑很多问题 , 主要的问题有如下两点 :

  1. 复杂的配置
  2. 混乱的依赖管理

Spring Boot帮我们解决了这个些, 我们在使用Spring Boot开发时, 不需要关注各种复杂的整合配置 , 也不用关注各个库之间的依赖及冲突问题 , Spring Boot已经默认帮我们整合配置好了 !

二、springboot之helloworld

1.需求

访问 http://localhost:8080/hello输出 “Hello Spring Boot”

2.步骤

  1. 创建Maven工程
  2. 加依赖(springboot父工程依赖 , web启动器依赖)
1
2
3
4
5
6
7
8
9
10
11
12
13
xml复制代码<!--spring boot 父工程依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<!--web 启动器-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

配置jdk版本

1
2
3
xml复制代码<properties>
<java.version>1.8</java.version>
</properties>

思考: 为什么我们这里仅仅配置了这么一个变量 , 项目的JDK版本就会改变呢 ?

因为jdk插件已经在父工程中定义好了 , 默认会读取${java.version}变量值
3. 写启动引导类(springboot项目运行的入口)

1
2
3
4
5
6
7
8
9
java复制代码import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
  1. 编写处理器Controller
1
2
3
4
5
6
7
8
9
java复制代码import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String sayHello(){
return "hello spring boot!!" ;
}
}
  1. 启动项目

运行启动类的main方法

3.问题

1.为什么我们在添加启动器的时候不需要在启动器的坐标中指定版本?

答案:因为我们指定了项目的父工程,在spring-boot-starter-parent中已经通过Maven的版本锁定了Jar包的版本,所以就不需要再指定了。

2.为什么我们就添加一个启动器依赖,项目就可以运行起来了,运行项目所需要的Jar包从何而来?

答案:因为我们添加了这个启动器的依赖,它已经把自己运行所需要的必要包集成在这个启动器中,通过Maven的依赖传递性,将这些包都依赖到咱们的项目里了。

4.配置文件详解

springboot支持两种类型的配置文件

  • properties属性配置文件
  • yaml配置文件

配置文件必须放在项目的类加载目录下, 并且名字必须是application开头

springboot项目在运行的时候会自动加载这些配置文件。

可以在spring-boot-autoconfigure-2.2.2.RELLEASE.jar的META-INF目录下找到additional-spring-configuration-metadata.json搜索server.port,显示默认的端口是8080.

为什么可以在resources下创建application.properties文件?

我们查看springboot的启动依赖

按住ctrl键点击spring-boot-starter-parent

可以在父工程中看到

1
2
3
4
5
6
7
8
9
10
11
12
13
> xml复制代码<build>
> <resources>
> <resource>
> <filtering>true</filtering>
> <directory>${basedir}/src/main/resources</directory>
> <include>**/application*.yml</include>
> <include>**/application*.yaml</include>
> <include>**/application*.properties</include>
> </resource>
> </resources>
> </build>
>
>

5.如何主动读取配置文件到类变量

要使用@Value(“${属性名}”)

如下:

resource 文件夹下面新建 application.properties 配置文件

1
2
3
4
ini复制代码spring.jdbc.datasource.driverClassName=com.mysql.jdbc.driver
spring.jdbc.datasource.url=jdbc:mysql:///springboot_01
spring.jdbc.datasource.username=root
spring.jdbc.datasource.password=123456

创建类 DataSourceProperties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class DataSourceProperties {

@Value("${spring.jdbc.datasource.driverClassName}")
private String driverClassName;
@Value("${spring.jdbc.datasource.url}")
private String url;
@Value("${spring.jdbc.datasource.username}")
private String username;
@Value("${spring.jdbc.datasource.password}")
private String password;

// 生成get set 和 toString方法
}

三、YAML配置文件

1.什么是YAML?

YAML是一种配置文件格式

2.语法

1.数据结构用树形结构呈现,通过缩进来表示层级,

2.连续的项目通过减号 ” - ” 来表示

3.键值结构里面的key/value对用冒号 ” : ” 来分隔,冒号后要加上一个空格才能跟属性值。

4.YAML配置文件的扩展名是yaml 或 yml

如果要修改前面那个properties文件为yaml文件

1
2
3
4
5
6
7
yaml复制代码spring:
jdbc:
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql:///springboot_01
username: root
password: 123456

yml配置文件的特征

  1. 树状层级结构展示配置项
  2. 配置项之间如果有关系的话需要分行,空两格
  3. 配置项如果有值的话,那么需要在:之后空一格再写配置项值;

yaml与peoperties配置文件处理展示像是不相同以外,其他功能和作用都是一样的。

3.多环境profile切换配置

在实际开发中,因为开发环境的变化,我们需要修改配置文件中某一个配置项的值(比如之前himysql数据库,切换成oracle数据库)

项目开发完成需要上线时,需要把一些环境改成正式环境(开发,测试,上线,多环境切换)

解决方案:使用profiles拆分配置

spring boot项目中允许使用多个yaml配置文件。

这些文件名称必须为**application-***.yml**,并且在application.yml中激活。

具体实施

创建application-dev.yml文件如下:

1
2
3
4
5
6
7
yaml复制代码spring:
jdbc:
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql:///springboot
username: root
password: 123456

创建application-pro.yml文件如下:

1
2
3
4
5
6
7
yaml复制代码spring:
jdbc:
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql:///business
username: business
password: business

在application.yml文件中添加如下配置:

1
2
3
yml复制代码spring:
profiles:
active: dev

此时生效的文件就是application-dev.yml配置文件。

注意:

如果properties和yml文件都存在,不存在spring.profiles.active设置,如果有重叠属性,默认以properties文件优先.

如果设置了spring.profiles.active,并且有重叠属性,以active设置优先。

可以在两种文件中分别增加server.port属性指定不同的端口,启动项目查看控制台端口号进行测试。

四、Spring Boot 的自动配置原理

1.@SpringBootApplication注解

①@SpringBootConfiguration

含义:代表这个类就是一个配置类,本质上就是一个@Configuration注解

②ComponentScan

组件扫描,默认扫描启动类所在包以及子包的类身上的注解。

③EnableAutoConfiguration

自动配置注解,添加了此注解会自动去读取spring.factories配置文件中的自动配置类。

2.@ConfigurationProperties注解

@ConfigurationProperties是SpringBoot提供的重要注解,他可以将一些配置属性批量注入到bean对象

注入配置属性

方式一:使用@Value一个个注入

这种方式,如果属性特别多,一个一个注入非常麻烦。

方式二:使用@ConfigurationProperties批量注入【和@EnableConfigurationProperties配合使用】

1
2
3
4
5
6
7
8
9
10
11
java复制代码@Component
@ConfigurationProperties(prefix = "spring.jdbc.datasource")
public class DataSourceProperties2 {

private String driverClassName;
private String url;
private String username;
private String password;

// 省略getter和setter.....
}
  1. 在类上通过@ConfigurationProperties注解声明该类要读取属性配置。
  2. prefix=”spring.jdbc.datasource”读取属性文件中前缀为spring.jdbc.datasource的值。前缀和属性名称和配置文件中的key必须要一致才能注入成功
  3. Spring Boot默认读取application.properties属性文件

开启@ConfigurationProperties注解使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java复制代码@Controller
@EnableConfigurationProperties(DataSourceProperties2.class)
public class HelloController {

@Autowired
private DataSourceProperties2 dataSourceProperties2 ;

@RequestMapping(path = "/hello")
@ResponseBody
public String sayHello(){
System.out.println(dataSourceProperties2);
return "hello spring boot";
}
}
使用@EnableConfi

使用@EnableConfigurationProperties(DataSourceProperties2.class),开启DataSoutceProperties2身上的@ConfigurationProperties注解,他就会生效了,就能够帮我们注入数据了。

可能出现错误Spring Boot Configuration Annotation Processor not found in classpath

解决方法:

在pom文件中加入依赖

1
2
3
4
5
6
7
> xml复制代码<dependency>
> <groupId>org.springframework.boot</groupId>
> <artifactId>spring-boot-configuration-processor</artifactId>
> <optional>true</optional>
> </dependency>
>
>

3.条件化配置注解

​ 我们看到自动配置类上有一些ConditionalXxx注解,这些注解的作用就是进行条件化选择。

​ 所谓条件化选择就是如果满足条件,该配置类就生效,如果不满足该配置类就不生效。

常用的条件化选座注解如下:

注解 作用
@ConditionalOnBean 如果存在某个Bean, 配置类生效
@ConditionalOnMissingBean 如果不存在某个Bean, 配置类生效
@ConditionalOnClass 如果存在某个类, 配置类生效
@ConditionalOnMissingClass 如果不存在某个类, 配置类生效
@ConditionalOnProperty 如果存在某个属性配置, 配置类生效
@ConditionalOnWebApplication 如果是一个web应用, 配置类生效
@ConditionalOnNotWebApplication 如果不是一个web应用, 配置类生效

因为我们配置了DispatcherServlet满足上面定义的条件,所以WebMvcAutoConfiguration会生效,那么WebMvcAutoConfiguration自动配置类中帮我们配置了什么?

  1. 视图解析器(触发public InternalResourceViewResolver defaultViewResolver()public BeanNameViewResolver beanNameViewResolver()方法)
  2. 处理器适配器(public RequestMappingHandlerAdapter requestMappingHandlerAdapter()方法)

这些配置都是我们之前在学习SpringMVC时需要自己配置的,现在Spring Boot框架都已经帮我们提前配置好了,所以我们才能使用的那么方便。

4.自动配置原理

1.加载spring.factories

在SpringApplication类构建的时候,有这样一段初始化代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
java复制代码    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}

注意 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));点击进入getSpringFactoriesInstances方法

1
2
3
java复制代码    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}

紧接着跟入getSpringFactoriesInstances方法

1
2
3
4
5
6
7
java复制代码    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

可以看到Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));这条代码。能够发现loadFactoryNames()尝试加载一些FactoryName,然后利用createSpringFactoriesInstances将这些加载到的类名进行实例化。然后继续跟进loadFactoryNames方法:

1
2
3
4
java复制代码    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

观察返回时调用的loadSpringFactories方法

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
java复制代码private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();

while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();

while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;

for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}

cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}

发现此处会利用类加载器加载一个文件:META-INF/factories。我们知道,ClassLoader默认是从classpath下读取的文件,因此,SpringBoot会在初始化的时候,加载所有classpath:META-INF/spring.factories文件,包括jar包当中的。而在Spring的一个依赖包:spring-boot-autoconfigure中,就有这样一个文件。

image-20211029163735112

springboot-1.png
我们引入的任何第三方启动器,只要实现自动配置,也都会有类似文件。

2.读取自动配置类

打开这个spring.factories

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
ini复制代码# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# 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,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
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.ClientHttpConnectorAutoConfiguration,\
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,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

可以发现以EnableAutoConfigutation接口为key的一系列配置,key所对应的值,就是所有的自动配置类,可以在当前的jar包中找到这些自动配置类:

springboot-2.png
几乎涵盖了现在主流的开源框架,我们可以从这里查看SpringMVC的自动配置类。

springboot-3.png
我们就找到了springmvc的自动配置类

3.默认属性配置

配置类找到了,那么这些默认配置的属性来自哪里?

例如:我们配置视图解析器的时候需要配置前缀后后缀,那么这些配置在哪里?

1
2
3
4
5
6
7
8
9
java复制代码
@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.mvcProperties.getView().getPrefix());
resolver.setSuffix(this.mvcProperties.getView().getSuffix());
return resolver;
}

通过这段源码发现,这个配置是this.mvcProperties.getView()中获取的。查看这个方法。

1
2
3
csharp复制代码public WebMvcProperties.View getView() {
return this.view;
}

发现读取的是类变量

1
arduino复制代码    private final WebMvcProperties.View view;

这个View类型封装着前缀和后缀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typescript复制代码public static class View {
private String prefix;
private String suffix;

public View() {
}

public String getPrefix() {
return this.prefix;
}

public void setPrefix(String prefix) {
this.prefix = prefix;
}

public String getSuffix() {
return this.suffix;
}

public void setSuffix(String suffix) {
this.suffix = suffix;
}
}

可以看到,前缀和后缀变量的值默认是null。

4.覆盖默认属性配置

如果我们想要自己指定视图的前缀和后缀?

我们可以再看WebMvcAutoConfiguration这个类的静态内部类WebMvcAutoConfigurationAdapter上一个声明,发现这个类上面有这样一个注解@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
java复制代码@Configuration(
proxyBeanMethods = false
)
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
private final ResourceProperties resourceProperties;
private final WebMvcProperties mvcProperties;
private final ListableBeanFactory beanFactory;
private final ObjectProvider<HttpMessageConverters> messageConvertersProvider;
final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;

public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) {
this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
}

public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
this.messageConvertersProvider.ifAvailable((customConverters) -> {
converters.addAll(customConverters.getConverters());
});
}

public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
if (this.beanFactory.containsBean("applicationTaskExecutor")) {
Object taskExecutor = this.beanFactory.getBean("applicationTaskExecutor");
if (taskExecutor instanceof AsyncTaskExecutor) {
configurer.setTaskExecutor((AsyncTaskExecutor)taskExecutor);
}
}

Duration timeout = this.mvcProperties.getAsync().getRequestTimeout();
if (timeout != null) {
configurer.setDefaultTimeout(timeout.toMillis());
}

}

public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
configurer.setUseRegisteredSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
}

public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
Contentnegotiation contentnegotiation = this.mvcProperties.getContentnegotiation();
configurer.favorPathExtension(contentnegotiation.isFavorPathExtension());
configurer.favorParameter(contentnegotiation.isFavorParameter());
if (contentnegotiation.getParameterName() != null) {
configurer.parameterName(contentnegotiation.getParameterName());
}

Map<String, MediaType> mediaTypes = this.mvcProperties.getContentnegotiation().getMediaTypes();
mediaTypes.forEach(configurer::mediaType);
}

@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.mvcProperties.getView().getPrefix());
resolver.setSuffix(this.mvcProperties.getView().getSuffix());
return resolver;
}

@Bean
@ConditionalOnBean({View.class})
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {
BeanNameViewResolver resolver = new BeanNameViewResolver();
resolver.setOrder(2147483637);
return resolver;
}

@Bean
@ConditionalOnBean({ViewResolver.class})
@ConditionalOnMissingBean(
name = {"viewResolver"},
value = {ContentNegotiatingViewResolver.class}
)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
resolver.setOrder(-2147483648);
return resolver;
}

@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(
prefix = "spring.mvc",
name = {"locale"}
)
public LocaleResolver localeResolver() {
if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
} else {
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
}

public MessageCodesResolver getMessageCodesResolver() {
if (this.mvcProperties.getMessageCodesResolverFormat() != null) {
DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();
resolver.setMessageCodeFormatter(this.mvcProperties.getMessageCodesResolverFormat());
return resolver;
} else {
return null;
}
}

public void addFormatters(FormatterRegistry registry) {
ApplicationConversionService.addBeans(registry, this.beanFactory);
}

public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}

String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}

}
}

private Integer getSeconds(Duration cachePeriod) {
return cachePeriod != null ? (int)cachePeriod.getSeconds() : null;
}

private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
if (this.resourceHandlerRegistrationCustomizer != null) {
this.resourceHandlerRegistrationCustomizer.customize(registration);
}

}

@Bean
@ConditionalOnMissingBean({RequestContextListener.class, RequestContextFilter.class})
@ConditionalOnMissingFilterBean({RequestContextFilter.class})
public static RequestContextFilter requestContextFilter() {
return new OrderedRequestContextFilter();
}
}

再点进去看这两个配置类WebMvcProperties.class, 配置类身上使用ConfigurationProperties读取配置,前缀是spring.mvc

1
2
3
4
5
6
java复制代码@ConfigurationProperties(
prefix = "spring.mvc"
)
public class WebMvcProperties {
//...
}

而ResourceProperties.class读取的配置前缀是spring.resources

1
2
3
4
5
6
7
java复制代码@ConfigurationProperties(
prefix = "spring.resources",
ignoreUnknownFields = false
)
public class ResourceProperties {
//...
}

所以如果我们再配置文件中配置spring.mvc前缀开头的配置,就可以将自己配置的数据注入到这个对象的属性中。注意,由于@ConfigurationProperties是批量注入,我们在写配置属性时,要和这个类的前缀+属性名完全一致,否则注入不成功。

例如

1
2
3
4
5
yaml复制代码spring:
mvc:
view:
prefix: /WEB-INF/
suffix: .jsp

或者修改端口号

1
2
yaml复制代码server:
port: 10000

5.自定义启动器

1.需求介绍

定义一个连接池启动器,当用户引入了连接池启动依赖之后,项目中就已经自动配置了连接池。

2.步骤分析

  1. 建启动器项目
  2. 添加启动器相关依赖
  3. 创建属性配置类
  4. 创建自动配置类
  5. 编写自动配置文件(spring.factories)
  6. 使用自定义的启动器

3.代码实现

1.创建项目,引入依赖

创建项目spring-boot-jdbc-starter

pom.xml

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
xml复制代码<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</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>
<!--引入spring‐boot‐starter;所有starter的基本配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<!--自动配置连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>

<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2.创建属性配置类
1
2
3
4
5
6
7
8
9
10
11
java复制代码import org.springframework.boot.context.properties.ConfigurationProperties;

@Component
@ConfigurationProperties(prefix = "spring.jdbc.datasource")
public class DataSourceProperties {
private String driverClassName ;
private String url;
private String username;
private String password;
// 生成set get toString方法
}
3.创建自动配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
java复制代码import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;

@SpringBootConfiguration
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {

@Autowired
private DataSourceProperties dataSourceProperties ;

@Bean
public DataSource createDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
dataSource.setUrl(dataSourceProperties.getUrl());
dataSource.setUsername(dataSourceProperties.getUsername());
dataSource.setPassword(dataSourceProperties.getPassword());
return dataSource;
}
}
4.编写自动配置属性文件

在resources文件夹下面新建META-INF/spring.factories

1
2
ini复制代码# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.dyy.autoconfig.DataSourceAutoConfiguration

做完之后要注意在Maven中执行install,安装项目。

5.使用自定义启动器

在新建的项目中引入我们自己的自定义启动器依赖

1
2
3
4
5
xml复制代码<dependency>
<groupId>com.dyy</groupId>
<artifactId>spring-boot-jdbc-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

配置连接池信息。

新建application-datasource.yml

1
2
3
4
5
6
7
yaml复制代码spring:
jdbc:
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql:///springboot_01
username: root
password: 123456

激活配置文件application.yml

1
2
3
yaml复制代码spring:
profiles:
active: datasource

进入连接池,查看连接池属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
java复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.sql.DataSource;

@RestController
public class HelloController {
@Autowired
private DataSource dataSource ;

@RequestMapping(path = "/hello")
public String sayHello() {
System.out.println(dataSource.getClass());//打印DruidDataSource数据源
return "Hello Spring Boot ! " ;
}
}
6.多种数据源

如果想让我们的启动器支持多种数据源。例如C3P0和Druid,根据配置进行选择,就可以使用条件选择进行实现。例如:如下配置中,有两个创建连接池的配置,一个是C3p0,一个是Druid,如何能够根据配置文件自动选择呢?

修改配置文件application-datasource.yml

1
2
3
4
5
6
7
8
yaml复制代码spring:
jdbc:
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql:///springboot_01
username: root
password: root
type: druid # 数据源类型
  • 如果配置文件中配置了spring.jdbc.datasource.type=c3p0使用c3p0数据源
  • 如果配置文件中配置了spring.jdbc.datasource.type=druid使用druid数据源。

在项目 spring-boot-jdbc-starter , 添加创建 c3p0 方法

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
java复制代码package com.dyy.autoconfig;

import com.alibaba.druid.pool.DruidDataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;

@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguratioin {

@Autowired
private DataSourceProperties dataSourceProperties ;

@Bean
@ConditionalOnProperty(value = "spring.jdbc.datasource.type",havingValue = "druid")
public DataSource createDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
dataSource.setUrl(dataSourceProperties.getUrl());
dataSource.setUsername(dataSourceProperties.getUsername());
dataSource.setPassword(dataSourceProperties.getPassword());
return dataSource;
}

@Bean
@ConditionalOnProperty(value = "spring.jdbc.datasource.type",havingValue = "c3p0")
public DataSource createC3P0DataSource() throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(dataSourceProperties.getDriverClassName());
dataSource.setJdbcUrl(dataSourceProperties.getUrl());
dataSource.setUser(dataSourceProperties.getUsername());
dataSource.setPassword(dataSourceProperties.getPassword());
return dataSource;
}
}

我们可以使用条件选择实现 , 如下图所示

@ConditionalOnProperty(value = “spring.jdbc.datasource.type”,havingValue = “druid”)
install安装spring-boot-jdbc-starter, 运行springboot_01

修改配置文件,重新install,再次请求。

五、spring boot常用启动器

1.SpringBoot整合MVC

创建项目 springboot_02_mvc

1.依赖

1
2
3
4
5
6
7
8
9
10
11
12
xml复制代码    <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

2.新建入口程序类

1
2
3
4
5
6
7
8
9
typescript复制代码package com.dyy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}

3.新建javabean

1
2
3
4
5
6
7
java复制代码public class User {
private String username ;
private String password ;
private Integer age ;
private String sex ;

}

4.新建UserController

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
java复制代码import com.dyy.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.List;

@Controller
@RequestMapping(path = "/user")
public class UserController {

@RequestMapping(path = "/findAll")
@ResponseBody
public List<User> findAll(){
//查询所有
List<User> users = new ArrayList<User>();

User user1 = new User();
user1.setUsername("杨过");
user1.setPassword("123456");
user1.setAge(18);
user1.setSex("男");

User user2 = new User();
user2.setUsername("杨过");
user2.setPassword("123456");
user2.setAge(18);
user2.setSex("男");

User user3 = new User();
user3.setUsername("杨过");
user3.setPassword("123456");
user3.setAge(18);
user3.setSex("男");

users.add(user1);
users.add(user2);
users.add(user3);

return users ;
}
}

运行程序。

2.静态资源目录

之前,开发web项目,如果是普通的项目金泰资源可以放在项目的webapp目录下。

现在使用Spring Boot做开发,项目中没有webapp目录,我们的项目是一个jar工程,那么就没有webapp,我么的静态资源该放哪里?

在springboot 中有一个叫做ResourceProperties得类,里面就定义了静态资源的默认查找路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
java复制代码@ConfigurationProperties(
prefix = "spring.resources",
ignoreUnknownFields = false
)
public class ResourceProperties {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
private String[] staticLocations;
private boolean addMappings;
private final ResourceProperties.Chain chain;
private final ResourceProperties.Cache cache;

public ResourceProperties() {
this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
this.addMappings = true;
this.chain = new ResourceProperties.Chain();
this.cache = new ResourceProperties.Cache();
}
//...
}

可以看到默认的静态资源路径为:

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public

只要静态资源放在这些目录中的任何一个,SpringMVC都会帮我们处理。我们习惯会把静态资源放在classpath:/static/目录下。在resources目录下创建index.html文件。

打开浏览器输入 : http://localhost:8080/index.html

如果想要修改默认的静态资源路径,需要在application.yml中添加

1
2
3
4
5
> javascript复制代码spring:
> resources:
> static-locations: classpath:/webapp/
>
>

重新安装启动后生效。

3.自定义的拦截器

web开发中的拦截器也是我们经常需要使用的组件,可以帮我们完成一些日志记录,数据过滤,请求过滤等等很多功能,那么在SpringBoot中该怎么配置?

在SpringMVC中配置拦截器的步骤:

  1. 编写一个拦截器(需要实现HandlerInterceptor接口)
  2. 注册拦截器(xml配置mvc:interceptors)
1
2
3
4
5
6
7
8
9
10
11
12
xml复制代码ml
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--配置拦截路径-->
<mvc:mapping path="/user/**"/>
<!--配置不拦截路径:不拦截路径是指从拦截路径中排除-->
<mvc:exclude-mapping path="/user/sayByby"></mvc:exclude-mapping>
<!--配置拦截器bean-->
<bean class="com.dyy.interceptor.LogInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>

因为Spring Boot没有XML配置文件了,所以在SpringBoot中使用拦截器注册的方式就不太一样了,需要借助一个WebMvcConfigurer类帮助我们注册拦截器,实现拦截器的具体步骤如下:

  1. 编写一个拦截器(实现HandlerInterceptor接口)
  2. 通过WebMvcConfigurer注册拦截器(自定义类是实现WebMvcConfigurer接口中public void addInterceptors(InterceptorRegistry registry)方法)

具体步骤如下

1.编写拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
java复制代码
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor拦截器的preHandle方法执行....");
return false;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor拦截器的postHandle方法执行....");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor拦截器的afterCompletion方法执行....");
}
}

2.注册拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
java复制代码
import com.dyy.interceptor.MyInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {

@Autowired
private MyInterceptor myInterceptor ;

/**
* /** 拦截当前目录及子目录下的所有路径 /user/** /user/findAll /user/order/findAll
* /* 拦截当前目录下的以及子路径 /user/* /user/findAll
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor).addPathPatterns("/**");
}
}

打开浏览器输入 http://localhost:8888/user/findAll观察控制台。

4.整合Spring Data JPA

1.新建项目 springboot_jpa

2.添加Spring Data JPA的起步依赖

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
xml复制代码    <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.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-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!-- springBoot JPA的起步依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- MySQL连接驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

<!-- 配置使用redis启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

</dependencies>

3.在application.yml中配置数据库和jpa的相关属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
yml复制代码logging:
level:
com.dyy.dao: debug # 配置日志
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/springboot?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
database: mysql
show-sql: true
generate-ddl: true
hibernate:
ddl-auto: update
naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy
server:
port: 18081

注意:Mysql8.x版本,连接时url需要指定时区,并且驱动类包名发生了变化。

4.创建实体类配置属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
java复制代码
import javax.persistence.*;

@Entity
@Table(name = "user")
public class User{

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@Column(name = "name")
private String name;

//此处省略setter和getter方法... ...
}

5.编写UserRepository

1
2
3
4
5
java复制代码import com.dyy.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserDao extends JpaRepository<User,Integer> {
}

6.编写service类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java复制代码
import com.dyy.domain.User;
import java.util.List;

public interface UserService {
List<User> findUsers();

User findUserById(Integer id);

void saveUser(User user);

void updateUser(User user);

void deleteUserById(Integer id);
}

7.service实现类

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
java复制代码
import com.dyy.dao.UserDao;
import com.dyy.domain.User;
import com.dyy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserDao userDao;

/**
* 查询所有
* @return
*/
@Override
public List<User> findUsers() {
return userDao.findAll();
}
/**
* 根据id查询
* @return
*/
@Override
public User findUserById(Integer id) {
return userDao.findById(id).get();
}
/**
* 保存
* @return
*/
@Override
public void saveUser(User user) {
userDao.save(user);
}
/**
* 更新
* @return
*/
@Override
public void updateUser(User user) {
userDao.save(user);
}
/**
* 根据id删除
* @return
*/
@Override
public void deleteUserById(Integer id) {
userDao.deleteById(id);
}
}

8.编写Controller类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
java复制代码
import com.dyy.domain.User;
import com.dyy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {

@Autowired
private UserService userService;

@RequestMapping("/findAll")
public List<User> findAll(){
return userService.findUsers();
}
}

六、SpringBoot应用

1.环境搭建

1.数据库准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sql复制代码create database springboot character set utf8 ;

use springboot ;

CREATE TABLE `tb_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`gender` varchar(5) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`address` varchar(32) DEFAULT NULL,
`qq` varchar(20) DEFAULT NULL,
`email` varchar(50) DEFAULT NULL,
`username` varchar(20) NOT NULL,
`phone` varchar(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_username_uindex` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

INSERT INTO `tb_user` VALUES (1,'黄蓉','女',38,'桃花岛','212223390222','huangrong222@qq.com','huangrong','15600003333'),(2,'黄老邪','男',58,'湖北省武汉市','212223390','huanglaoxie@qq.com','huanglaoxie','15872320405'),(3,'小龙女','男',18,'湖北省荆门市','212223390','xiaolongnv@qq.com','xiaolongnv','15600004444'),(7,'杨过','男',30,'扬州','212223390','yangguo@qq.com','yangguo','15600005555');

2.创建项目以及包结构

创建项目springboot_case

3.导入依赖

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
xml复制代码<?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>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>

<dependencies>
<!--单元测试启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>

<!--通用mapper启动器依赖-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<!--JDBC启动器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--druid启动器依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--web启动器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--spring boot actuator依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!--编码工具包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>

<!—热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>

</dependencies>

<build>
<plugins>
<!--spring boot maven插件 , 可以将项目运行依赖的jar包打到我们的项目中-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

4.创建启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;

@SpringBootApplication
@MapperScan(basePackages = "com.dyy.dao")
@EnableTransactionManagement
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}

2.数据访问层

1.编写配置文件application.yml

1
2
3
4
5
6
7
8
9
10
11
yaml复制代码server:
port: 10001
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///springboot
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
mybatis:
type-aliases-package: com.dyy.pojo

2.编写实体类User

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java复制代码
import java.io.Serializable;

@Entity
@Table(name = "tb_user")
public class User implements Serializable {
private Integer id;
private String name;
private String gender;
private Integer age;
private String address;
private String qq;
private String email;
private String username;
private String phone;
//getter setter toString…
}

3.mapper接口和映射配置

1
2
3
4
5
6
java复制代码
import tk.mybatis.mapper.common.Mapper;
import java.util.List;

public interface UserMapper extends Mapper<User> {
}

4.编写测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {

@Autowired
private UserMapper userMapper ;

@Test
public void findAll() {
List<User> users = userMapper.selectAll();
System.out.println(users);
}
}

3.业务层

1.编写接口

1
2
3
4
5
6
7
8
java复制代码public interface UserService {

/**
* 查询所有用户信息
* @return
*/
public List<User> findAll();
}

2.编写实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
java复制代码
import com.dyy.dao.UserMapper;
import com.dyy.pojo.User;
import com.dyy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;

@Override
@Transactional(readOnly = true ,propagation = Propagation.SUPPORTS)
public List<User> findAll() {
return userMapper.selectAll();
}
}

3.编写测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {

@Autowired
private UserService userService;

@Test
public void findAll() {
List<User> users = userService.findAll();
System.out.println(users);
}
}

Spring Boot整合单元测试,需要在测试类上添加两个注解:

  1. @RunWith(SpringRunner.class)指定Junit核心运行类
  2. @SpringBootTest指定这是一个Spring Boot的测试类,运行时会自动加载Spring Boot运行环境

4.表现层

1.引入依赖

1
2
3
4
5
6
7
8
9
10
11
xml复制代码<!--Web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--编码工具包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>

2.新建工具类

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
java复制代码
import java.io.Serializable;

public class Result implements Serializable {
private boolean status ; //响应状态 true false
private String msg ; // 响应信息
private Object data ; //处理成功的响应数据

public static Result ok(Object data){
Result result = new Result();
result.setStatus(true);
result.setData(data);
return result ;
}

public static Result error(String msg){
Result result = new Result();
result.setStatus(false);
result.setMsg(msg);
return result ;
}

// 生成set get tostring方法

}

3.编写表现层代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码@Controller
@RequestMapping(path = "/user")
public class UserController {

@Autowired
private UserService userService;

/**
* 查询所有用户信息
* @return
*/
@RequestMapping(path = "/findAll")
@ResponseBody
public Result findAll() {
List<User> users = userService.findAll();
return Result.ok(users);
}
}

4.代码测试

使用postman进行测试

5.页面展示

resources目录下创建static目录 , 创建页面展示、list.html:

  • 页面异步请求的端口和服务器端口一致
  • 页面异步请求访问的路径和对应的表现层控制方法路径要致
  • 页面异步请求参数名称和和对应的表现层控制方法参数一致

修改之后, 访问页面即可 : localhost:10001/list.html

6.缓存优化

1.缓存需求

问题:用户数据是不经常变化的数据,如果这些数据每次都去数据库中进行查询,效率比较低,对数据库造成很大的压力。

解决:缓存,用户第一次查询数据的时候,京数据存入到缓存中,之后再查询数据直接从缓存中获取即可,不需要再查询数据库。【此处使用redis缓存数据库存储数据】

2.依赖

1
2
3
4
5
xml复制代码<!--springboot整合redis启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

3.编写配置文件

1
2
3
4
yml复制代码spring:
redis: # 配置redis
host: localhost
port: 6379

4.修改业务层实现类代码

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
java复制代码
import com.dyy.mapper.UserMapper;
import com.dyy.pojo.User;
import com.dyy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserMapper userMapper ;
@Autowired
private RedisTemplate redisTemplate ;

@Override
@Transactional(readOnly = true ,propagation = Propagation.SUPPORTS)
public List<User> findAll() {
//从缓存中查询数据 规定存储用户信息使用string类型进行存储, 存储的key就是userList
List<User> userList = (List<User>) redisTemplate.boundValueOps("userList").get();
//如果缓存中没有数据, 查询数据库 , 将查询到的数据放入缓存
if(userList==null){
userList = userMapper.findAll();
redisTemplate.boundValueOps("userList").set(userList);
System.out.println("从数据库中查询...");
}else {
System.out.println("从缓存中查询.....");
}

//如果缓存中有数据, 直接返回
return userList ;
}
}

七、SpringBoot其他组件

1.SpringBoot Actuator组件

作用

Spring Boot Actuator是SpringBoot自带的一个组件 , 可以帮助我们监控和管理Spring Boot应用,比如健康检查、审计、统计和HTTP追踪等。

如何使用

1.引入SpringBoot Actuator起步依赖
1
2
3
4
xml复制代码<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.配置SpringBoot Actuator参数
1
2
3
4
5
6
7
8
9
10
11
yml复制代码management:
endpoints:
web:
exposure:
include: '*' # 对外暴露的访问入口 , 默认是/health和/info
base-path: /monitor # 默认是actuator
endpoint:
health:
show-details: ALWAYS # 显示所有健康状态
server:
port: 9999
3.启动项目获取系统信息

目启动之后就可以通过发送http请求获取系统健康数据了 , 例如 : http://localhost:9999/monitor/health , 返回数据如下 :

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
json复制代码{
"status": "UP",
"details": {
"db": {
"status": "UP",
"details": {
"database": "MySQL",
"hello": 1
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 355816562688,
"free": 129251151872,
"threshold": 10485760
}
},
"redis": {
"status": "UP",
"details": {
"version": "2.8.9"
}
}
}
}

常用的访问路径

HTTP 方法 路径 描述
GET /autoconfig 提供了一份自动配置报告,记录哪些自动配置条件通过了,哪些没通过
GET /configprops 描述配置属性(包含默认值)如何注入Bean
GET /beans 描述应用程序上下文里全部的Bean,以及它们的关系
GET /dump 获取线程活动的快照
GET /env 获取全部环境属性
GET /env/{name} 根据名称获取特定的环境属性值
GET /health 报告应用程序的健康指标,这些值由HealthIndicator的实现类提供
GET /info 获取应用程序的定制信息,这些信息由info打头的属性提供
GET /mappings 描述全部的URI路径,以及它们和控制器(包含Actuator端点)的映射关系
GET /metrics 报告各种应用程序度量信息,比如内存用量和HTTP请求计数
GET /metrics/{name} 报告指定名称的应用程序度量值
POST /shutdown 关闭应用程序,要求endpoints.shutdown.enabled设置为true
GET /trace 提供基本的HTTP请求跟踪信息(时间戳、HTTP头等)

我们可以通过发送这些请求,获取系统状态信息。

2.SpringBoot Admin组件

上面我们讲了Spring Boot Actuator , 可以通过http协议获取系统状态信息 , 但是返回的是JSON格式数据, 看起来不太方面, 而且还需要记忆路径, 比较麻烦 , Spring Boot Admin给我们提供了更加友好的可视化界面来查看这些信息 !

Spring Boot Admin是一个开源社区项目,用于管理和监控SpringBoot应用程序。 应用程序作为Spring Boot Admin ClientSpring Boot Admin Server注册 , Client会定时向Server发送数据, Server使用友好的界面展示数据。

1.SpringBoot Admin服务端

1.创建项目springboot-admin-server
2.依赖
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
xml复制代码<?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>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>

<groupId>com.dyy</groupId>
<artifactId>springboot-admin-server</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
</project>
3.配置application.yml
1
2
3
4
5
yml复制代码spring:
application:
name: admin-server
server:
port: 8769

我们将Spring Boot Admin端口号设置为8769.

4.启动类
1
2
3
4
5
6
7
java复制代码@SpringBootApplication
@EnableAdminServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}

@EnableAdminServer的作用是开启管理服务。

2.SpringBoot Admin客户端

1.创建springboot-admin-client
2.依赖
1
2
3
4
5
xml复制代码<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.2.0</version>
</dependency>
3.配置

向admin-server注册的地址为http://localhost:8769,最后暴漏自己的actuator所有的端口信息,具体配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
yml复制代码server:
port: 9999
spring:
application:
name: admin-client
boot:
admin:
client:
url: http://localhost:8769 # 指定注册地址 , Spring Boot Admin Server地址
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: ALWAYS

这个注册的地址一定要和SpringBoot Admin Server地址匹配。

4.启动测试

分别开启客户端(应用程序)和服务端,访问http://localhost:8769,可以看到这样一个界面。

springboot-4.png

八、Spring Boot项目打包部署

1.项目打包

1.在pom中配置Spring Boot 项目的maven插件

1
2
3
4
5
6
7
8
9
xml复制代码<build>
<plugins>
<!-- 打jar包时如果不配置该插件,打出来的jar包没有清单文件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

2.运行maven的打包命令

3.打包之前我们需要跳过测试

如果不跳过测试,那么我们编写的测试类都会被maven自动执行,可能会出现错误,导致打包不成功。

springboot-5.png

4.执行之后可以在控制台看到打包的日志信息,其中有生成的包的位置

打开指定目录就可以发现有一个jar包存在 , 仔细观察其实我们会发现 , 在target目录下其实会存在二个jar包 , 一个是springboot_02-1.0-SNAPSHOT.jar一个是springboot_02-1.0-SNAPSHOT.jar.original , 那么这两个jar包有什么区别呢?

我们如果是普通项目打包那么就只会得到一个jar包 , 这个jar包中不包含项目的一些依赖jar包

但是我们现在是一个Spring Boot项目 , 我们希望打完的包能够直接运行, 所以项目中就必须包含他的依赖jar包 , 我们之前在pom.xml中配置一个Spring Boot的maven插件可以在普通包的基础上将我们项目的一些运行及依赖信息打进jar包里面 , 打完包之后将原来的普通包改名为xxx.jar.original , 新打的包为xxx.jar .

也就是说

  1. .jar.original 是普通jar包,不包含依赖
  2. .jar 是可执行jar包,包含了pom中的所有依赖,可以直接用java -jar 命令执行
  3. 如果是部署,就用.jar , 如果是给别的项目用,就要给.jar.original这个包

2.项目运行

打开命令行运行打出来的包:使用命令:java -jar包全名

1
复制代码java -jar springboot_02-1.0-SNAPSHOT.jar

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%