轻量级的开源框架。
SpringBoot和Spring之间有什么联系? SpringBoot本质上就是一个Spring框架,只不过它是站在Spring的肩膀上。简化了Spring的配置。
Spring 配置魔鬼
Java → SpringBoot
- 轻量级的开源框架,可以非常方便的整合其他框架
- 内置了JavaEE容器,不需要依赖于外部的JavaEE容器
- SpringBoot的应用不需要打成war,而是jar包,以jar包的方式来运行
- java -jar xxx.jar → 执行的是里面的main方法 → 作为SpringBoot应用程序的入口
- 约定大于配置(自动配置)
在你没有给你一个具体的配置之前,SpringBoot会给你一个默认的配置(约定);如果你给到一个具体的配置,才采用具体的配置。→ 给到亿些默认值
搭建SpringBoot应用
Maven工程
start.spring.io
packageName:包名 → 启动类(包含main方法的类,也是应用程序的入口)所在的包目录,这个包目录也是SpringBoot的扫描包目录
.mvn、mvnw、mvnw.cmd → maven的功能
.gitignore:要放在工作区的根目录才会生效 → 和.git文件夹放在同一级目录
在idea中创建
其实也是在start.spring.io下载应用程序,然后idea帮你解压
也可以从Maven工程改造为SpringBoot
只要包含pom.xml和启动类就行
如果你连接不到start.spring.io的时候可以采用
pom.xml → 父工程、dependencies
启动类
// 该注解就是SpringBoot应用启动类上的注解 → 会配置扫描包目录就是该类所处的包目录
@SpringBootApplication
public class Demo1FirstSbApplication {
// 启动类中一定会包含main方法 → 就是启动SpringBoot应用程序的入口
public static void main(String[] args) {
SpringApplication.run(Demo1FirstSbApplication.class, args);
}
}
pom.xml
parent标签
只要是SpringBoot应用一定会有这样的parent标签
- 项目构建的配置
- 依赖的配置
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!-- version标签里的值就是SpringBoot应用程序的版本 -->
<version>2.7.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
依赖
SpringBoot应用程序中引入的依赖中没有写版本号
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
在依赖中没有版本号,仍然能够引入对应的版本的依赖, 约定大于配置
因为父工程里管理了依赖的版本信息
父工程里还有一个父工程
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
因为父工程的父工程里管理了依赖的版本信息,在你SpringBoot应用没有写依赖的版本号时,会引入默认的版本信息,同时兼容性也更好
spring-boot-starter
要使用SpringBoot框架,就需要引入这个依赖spring-boot-starter
starter依赖
还有一类依赖
- spring-boot-starter-xxx → SpringBoot官方提供的,比如spring-boot-starter-web
- xxx-spring-boot-starter → 第三方框架对SpringBoot支持的依赖,比如mybatis-spring-boot-starter
当你需要引入新的框架的时候,通常引入该框架的starter依赖即可
- 引入该框架所必须的依赖
- 会引入autoconfigure依赖
SpringBoot的配置文件
properties格式的
application*.properties
application*.yml
application*.yaml
yml配置文件的语法,含义仍然配置的是键值对
cs.file.path=d:/spring/
cs.size=5
cs.file.size=1024
songge.name=yuanzhi
用yml文件来改造
- 点 变为 冒号、换行、空格缩进
- 等于 变为 冒号、一个空格
- 同一级对齐,缩进几个空格都行
cs:
file:
path: d:/spring/
size: 1024
size: 5
songge:
name: yuanzhi
SpringBoot对web的支持
tomcat的配置
server:
port: 8083 #Tomcat的端口号配置
servlet:
context-path: /demo1 # 应用程序的上下文配置(应用名)
静态资源映射
SpringBoot帮我们做了默认的静态资源映射的配置
mapping=/** location=classpath:/static/
其实我们并不用这个配置,因为他配置的这几个location并不是我们最终放静态资源的location,我们现在放静态资源放在文件路径下
所以需要我们自己来指定一些配置
这些配置SpringBoot仍然可以帮我们做,只不过你让SpringBoot帮你做你指定值的配置,在properties或yml文件中提供对应的值
# mapping
spring:
mvc:
static-path-pattern: /pic/**
# spring.resources 或 spring.web.resources
resources:
static-locations: file:d:/spring/
SpringMVC的配置类
SpringMVC的配置类仍然是可以使用的,把配置类放在启动类所在的扫描包范围就可以了。
配置类上可以使用@EnableWebMvc,也可以使用@Configuration;这两个注解都会让这个配置类生效,但是我们建议大家使用@Configuration
@EnableWebMvc → 意味着全面接管SpringMVC的相关配置
@Configuration → 意味着做的是配置项的补充
//@EnableWebMvc
@Configuration
//@ComponentScan("com.cs.controller")
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pic/**").addResourceLocations("file:d:/spring/");
}
// HandlerInterceptor → addInterceptors
// Converter → addFormatters
}
SpringMVC的一些配置
有一些配置可以通过配置文件来进行配置
spring.mvc作为前缀的配置
spring.web或spring.resources作为前缀的配置
MVC中配置起来更方便的配置项
Converter
请求参数接收过程中的类型转换器
在WebMvcConfigurer接口中的addFormatters方法使用registry调用addConverter方法就可以了
在SpringBoot阶段更简单,只需要把Converter注册到容器中就可以生效(等会儿会看源码,为啥这样就行了)
Filter
在SpringBoot应用中,使用Filter(extends OncePerRequestFilter)只需要注册到容器中就会生效
@Component
public class CustomFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
FilterChain filterChain) throws ServletException, IOException {
System.out.println("hello 情歌王");
filterChain.doFilter(httpServletRequest,httpServletResponse);
}
}
如果想要指定Filter的作用范围,也是可以的;但是配置方式有所区别,需要你向容器中注册一个组件FilterRegistrationBean
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new CustomFilter());
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegistrationBean;
}
SpringBoot对MyBatis的支持
mybatis-spring-boot-starter
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
配置
- 数据源DataSource需要的参数
- Mapper的扫描包 👉 @MapperScan
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/cs_db?useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
@SpringBootApplication
@MapperScan("com.cs.mapper")
public class Demo1FirstSbApplication {
public static void main(String[] args) {
SpringApplication.run(Demo1FirstSbApplication.class, args);
}
}
需要引入一个什么框架的时候,再去引入对应的starter依赖
如果想要修改数据源(DataSource)的类型,使用spring.datasource.type就可以修改
其他配置
在配置文件中使用mybatis作为前缀的配置项
★约定大于配置
容器中的组件获得配置文件中的值
做的事情,就是打通配置文件和容器中的组件之间的联系
我们手动向容器中注册一个组件 → DruidDataSource
@Configuration
public class DataSourceConfiguration1 {
@Bean
public DataSource dataSource1() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/cs_db?useUnicode=true&characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
}
上面的代码,我们向容器中注册了DataSource组件,但是组件注册过程中,我们提供的值,是在配置类里写死的 → 魔法值
我们下面要做的事情,就是在配置文件中提供对应的配置项,组件注册过程中的值来源于配置文件
@Value
通过@Value注解来引用配置文件中key,获得配置文件中的值,赋给@Value对应的成员变量
@Configuration
public class DataSourceConfiguration2 {
// 直接赋值,魔法值
//String driverClass = "com.mysql.jdbc.Driver";
//String jdbcUrl = "jdbc:mysql://localhost:3306/cs_db?useUnicode=true&characterEncoding=utf-8";
//String username = "root";
//String password = "123456";
//@Value("com.mysql.jdbc.Driver")
//String driverClass;
//@Value("jdbc:mysql://localhost:3306/cs_db?useUnicode=true&characterEncoding=utf-8")
//String jdbcUrl;
//@Value("root")
//String username;
//@Value("123456")
//String password;
@Value("${cs.datasource.driverClass}")
String driverClass;
@Value("${cs.datasource.url}")
String jdbcUrl;
@Value("${cs.datasource.username}")
String username;
@Value("${cs.datasource.password}")
String password;
@Bean
public DataSource dataSource2() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(jdbcUrl);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
这种方式还不够方便,也不够优美
@ConfigurationProperties
使用的是set方法来赋值
@ConfigurationProperties注解中有一个prefix属性,prefix属性值(前缀) + 成员变量名=配置文件中的key,就会通过set方法给对应的成员变量做赋值
@Configuration
@Data // 主要是为了提供set方法
@ConfigurationProperties(prefix = "cs.datasource")
public class DataSourceConfiguration3 {
//cs.datasource.driverClass
String driverClass;
//cs.datasource.url
String url;
//cs.datasource.username
String username;
//cs.datasource.password
String password;
@Bean
public DataSource dataSource3() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
还不是最终的方式
@EnableConfigurationProperties
做的事情就是将上面的案例的成员变量单独在提取到单独的类中,这个类专门做参数的接收,参数类。
参数类要注册为容器中的组件,可以在参数类上直接增加@Component,也可以通过@EnableConfigurationProperties引入参数类的方式把参数类注册为容器中的组件
@Configuration
@EnableConfigurationProperties(csDatasourceProperties.class)
// 该注解可以把其value属性对应的类注册为容器中的组件
public class DataSourceConfiguration4 {
// 把成员变量提取到参数类中之后,我们想要获得之前的值,就需要通过参数类的实例来获得
/*
@Autowired
CsDatasourceProperties properties;
*/
CsDatasourceProperties properties;
public DataSourceConfiguration4(csDatasourceProperties properties) {
this.properties = properties;
}
@Bean
public DataSource dataSource4() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(properties.getDriverClass());
dataSource.setUrl(properties.getUrl());
dataSource.setUsername(properties.getUsername());
dataSource.setPassword(properties.getPassword());
return dataSource;
}
}
@Data
@ConfigurationProperties(prefix = "cs.datasource4")
//@Component
public class CsDatasourceProperties {
//cs.datasource.driverClass
String driverClass;
//cs.datasource.url
String url;
//cs.datasource.username
String username;
//cs.datasource.password
String password;
}
约定大于配置
为啥我们只需要做很少的配置?
SpringBoot给我们提供了巨量的自动配置类
starter依赖 → autoconfigure依赖 → /META-INF/spring.factories → EnableAutoConfiguration → List → 自动配置类
@Configuration
public class DataSourceConfiguration1 {
@Bean
public DataSource dataSource1() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/cs_db?useUnicode=true&characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
}
# 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
等等
这些自动配置类是全部都生效吗?这些配置类中的配置全部都生效吗?
不是,生效是有条件的,满足一定的条件才会生效。
@ConditionalOnXXX:满足对应的条件时会生效,指的是和它写在一起的其他注解生效
@ConditionalOnMissingXXX:满足缺少XXX的条件时会生效
找一个具有代表性的自动配置类DataSourceTransactionManagerAutoConfiguration
// 配置类
@Configuration
// 当包含对应的Class的时候才会生效 → 引入对应的依赖的时候
@ConditionalOnClass({JdbcTemplate.class, PlatformTransactionManager.class})
@AutoConfigureOrder(2147483647)
//datasource4的方式,通过引入参数类,来引入对应的值
@EnableConfigurationProperties({DataSourceProperties.class})
//该参数类的前缀是spring.datasource我们前面配置mybatis的时候使用过
public class DataSourceTransactionManagerAutoConfiguration {
public DataSourceTransactionManagerAutoConfiguration() {
}
@Configuration
//容器中的某个类型的组件只有一个的时候生效
@ConditionalOnSingleCandidate(DataSource.class)
static class DataSourceTransactionManagerConfiguration {
private final DataSource dataSource;
private final TransactionManagerCustomizers transactionManagerCustomizers;
// 有参构造方法从容器中按照类型取出组件
DataSourceTransactionManagerConfiguration(DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
this.dataSource = dataSource;
this.transactionManagerCustomizers = (TransactionManagerCustomizers)transactionManagerCustomizers.getIfAvailable();
}
// 非常典型的组件的约定大于配置
// 注册组件,对应的方法的返回值注册为容器中的组件
@Bean
// 容器中没有PlatformTransactionManager组件的时候生效
@ConditionalOnMissingBean({PlatformTransactionManager.class})
public DataSourceTransactionManager transactionManager(DataSourceProperties properties) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(this.dataSource);
if (this.transactionManagerCustomizers != null) {
this.transactionManagerCustomizers.customize(transactionManager);
}
return transactionManager;
}
}
}
ConditionalOnMissingBean
再来看一下自动配置类MyBatis的自动配置类
mybatis-spring-boot-autoconfigure
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisAutoConfiguration implements InitializingBean {
private final MybatisProperties properties;
// 这里有一个关于properties的有参构造方法
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
if (this.properties.getTypeAliasesSuperType() != null) {
factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
}
return factory.getObject();
}
}
再来看一个,Mvc的自动配置类
- 为啥Converter只需要注册到容器中就会生效
- 静态资源映射
public void addFormatters(FormatterRegistry registry) {
Iterator var2 = this.getBeansOfType(Converter.class).iterator();
while(var2.hasNext()) {
Converter<?, ?> converter = (Converter)var2.next();
registry.addConverter(converter);
}
var2 = this.getBeansOfType(GenericConverter.class).iterator();
while(var2.hasNext()) {
GenericConverter converter = (GenericConverter)var2.next();
registry.addConverter(converter);
}
var2 = this.getBeansOfType(Formatter.class).iterator();
while(var2.hasNext()) {
Formatter<?> formatter = (Formatter)var2.next();
registry.addFormatter(formatter);
}
}
private <T> Collection<T> getBeansOfType(Class<T> type) {
return this.beanFactory.getBeansOfType(type).values();
}
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//spring.mvc.static-path-pattern
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
//this.resourceProperties.getStaticLocations → spring.resources.static-locations
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
staticPathPattern → static-path-pattern 配置文件中驼峰命名的大写字母,可以改成短横线+小写字母
配置文件中的提示
在SpringBoot的配置文件中写一些内容的时候有提示;而我们自己写的却没有提示。
有提示的原因是引入我们有关于提示的文件 → json
/META-INF/(additional-)spring-configuration-metadata.json
如果你的配置项也想要提示 → 在classpath路径下提供/META-INF/spring-configuration-metadata.json
- 手动新增
- 使用插件 configuration processor
如果没有生效,则在resources目录下新增一个文件夹/META-INF/spring-configuration-metadata.json
{
"name": "cs.datasource4.password",
"type": "java.lang.String",
"sourceType": "com.cs.config4.csDatasourceProperties",
"defaultValue": 123456
}
新增defaultValue,现在就多了默认值的提示
问题是,在使用这个值的时候,是否有获得默认值?并不会,这里只是做提示的
如果说我们想要给它赋默认值 →
@Data
@ConfigurationProperties(prefix = "cs.datasource4")
//@Component
public class csDatasourceProperties {
//cs.datasource.driverClass
String driverClass;
//cs.datasource.url
String url;
//cs.datasource.username
String username;
//cs.datasource.password
String password = "123456";
}