一、回顾
二、知识目标
SpringBoot概述【了解】
SpringBoot快速入门【掌握】
SpringBoot启动原理【重点】
SpringBoot配置文件【掌握】
SpringBoot属性注入【掌握】
三、为什么使用SpringBoot?
-SSM开发有哪些痛点?
1、在早期我们都是使用的是SSM来完成Web的开发的,应该都知道,当时采用的是XML配置文件,特别的多,整合起来非常复杂
2、特别容易出错,出现问题不好排查
3、不方便快速集成第三方的类库
4、需要放入外部的web容器中启动
-SpringBoot有哪些优点?
1、快速构建项目,目录结构一键生成
2、大量场景启动器,方便快速依赖第三方环境,并且没有依赖冲突问题
3、去除了繁琐的XML,采用注解配置
4、无需外部的启动web容器,内嵌tomcat,jetty等web容器,一键启动
四、什么是SpringBoot?
Spring Boot 是由 Pivotal 团队提供的基于 Spring 的全新框架,其设计目的是为了简化 Spring 应用的搭建和开发过程。该框架遵循『约定大于配置』原则,采用特定的方式进行配置,从而使开发者无需定义大量的 XML 配置。通过这种方式,Spring Boot 致力于在蓬勃发展的快速应用开发领域成为领导者。
SpringBoot是Spring项目中的一个子工程,与我们所熟知的Spring-framework 同属于spring的产品,人们把Spring Boot称为搭建程序的『**脚手架**』。其最主要作用就是帮我们快速的构建庞大的spring项目,并且尽可能的减少一切xml配置,做到开箱即用,迅速上手,让我们关注于业务而非配置。我们可以使用SpringBoot创建java应用,并使用java –jar 启动它,就能得到一个生产级别的web工程。
五、如何使用SpringBoot?
1、搭建SpringBoot工程
第1步:创建maven控制台项目
创建一个 Maven 控制台项目,但是『不用』勾选 Create from archetype
。截止目前为止,该项目与 SpringBoot 还没有任何关系。
第2步:引入依赖
Spring Boot 提供了一个名为 spring-boot-starter-parent 的工程,里面已经对各种常用依赖(并非全部)的版本进行了管理,我们的项目需要以这个项目为父工程,这样我们就不用操心依赖的版本问题了,需要什么依赖,直接引入坐标即可!
-
添加父工程坐标
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.7.RELEASE</version> </parent>
-
添加 web 启动器
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
需要注意的是,我们并没有在这里指定版本信息。因为 Spring Boot 的 父工程 已经对版本进行了管理了,见后面讲解
这些都是 Spring Boot 根据spring-boot-starter-web
这个依赖自动引入的,而且所有的版本都已经管理好,不会出现冲突。 -
完整 pom
<?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> <groupId>cn.woniu</groupId> <artifactId>springboot-demo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.7.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>
有时候,你不想,甚至是不能使用 spring-boot-starter-parent 作为你的父项目。例如,在父子模块项目中,你本身就有自己的父亲。这种情况下,你需要使用别的方式来使用 spring boot。见最后
2、创建类
SpringBoot 项目通过 main
函数即可启动,我们需要创建一个启动类,该类必须建在最大的包中
/**
* SpringBoot启动类
*/
@SpringBootApplication
public class ApplicationApp {
public static void main(String[] args) {
SpringApplication.run(ApplicationApp.class,args);
}
}
接下来的编码工作,就是正常的 Spring MVC 项目的开发过程。
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "hello springboot";
}
}
运行启动类的 main 方法,会在控制台中看见日志信息,其中有一条信息如下:
说明:
- 监听的默认端口是 8080
- Spring MVC 的映射路径是:
/
/hello
路径已经映射到了HelloController
中的hello()
方法- 打开页面访问:http://localhost:8080/hello
六、SpringBoot的启动原理
1、启动器分析1
为了让SpringBoot帮我们完成各种自动配置,我们必须引入SpringBoot提供的自动配置依赖,我们称为启动器
。spring-boot-starter-parent工程将依赖关系声明为一个或者多个启动器,我们可以根据项目需求引入相应的启动器,因为我们是web项目,这里我们引入web启动器:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
需要注意的是,我们并没有在这里指定版本信息。因为SpringBoot的父工程已经对版本进行了管理了。按住Ctrl点击pom.xml中的spring-boot-starter-web,跳转到了spring-boot-starter-web的pom.xml,xml配置如下(只摘抄了部分重点配置)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.3.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.11.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.11.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
可以发现该启动器引入了部分spring的相关jar
2、启动器分析2
按住Ctrl点击pom.xml中的spring-boot-starter-parent,跳转到了spring-boot-starter-parent的pom.xml【重点配置】
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.7.RELEASE</version>
</parent>
可以发现spring-boot-starter-parent的父工程又是spring-boot-dependencies,继续ctrl点击spring-boot-dependencies,发现这个spring-boot-dependencies工程里面定义了很多jar的版本锁定以及引入了很多的jar。所以我们的SpringBoot工程继承spring-boot-starter-parent后就已经具备版本锁定等配置了。所以起步依赖的作用就是进行依赖的传递。
3、启动流程分析3
注解@SpringBootApplication
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
发现@SpringBootApplication其实是一个组合注解,这里重点的注解有3个:
-
@SpringBootConfiguration 可以简单的理解为就是一个@Configuration注解,通过@Configuration 与 @Bean结合,将Bean注册到Spring ioc 容器
-
标注这个类是一个配置类
-
它只是@Configuration注解的派生注解
-
它与@Configuration注解的功能一致
-
只不过@SpringBootConfiguration是springboot的注解,而@Configuration是spring的注解
-
-
@ComponentScan:开启注解扫描:默认扫描@SpringBootApplication所在类的同级目录以及它的子目录
大概的意思: 配置组件扫描的指令。提供了类似与<context:component-scan>标签的作用 通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包
而我们的@ComponentScan注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。一般启动类会放在一个比较浅的包目录中
-
@EnableAutoConfiguration:开启spring应用程序的自动配置,SpringBoot基于你所添加的依赖和你自己定义的bean,试图去猜测并配置你想要的配置。比如我们引入了
spring-boot-starter-web
,而这个启动器中帮我们添加了tomcat
、SpringMVC
的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
该注解引入了AutoConfigurationImportSelector.class这个类,在该类中有如下方法,启动时会调用该方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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; }
可以看到该方法内部调用了loadFactoryNames(),该方法是获取配置类下的全限定名,它会去spring-boot-autoconfigure:2.3.7里面找META-INF/spring.factories,这个文件里就是大量配置类的全限定名。
这些配置类路径在springboot启动时,通过反射创建配置类对象并且由spring的IOC容器来管理,当然我们也可以通过exclude属性关闭某些配置类,在springboot启动时,这些配置类不加载
@SpringBootApplication(exclude = {RedisAutoConfiguration.class, ActiveMQAutoConfiguration.class})
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class,args);
}
}
4、默认配置类分析
-以我们熟悉的WebMvcAutoConfiguration配置类为例
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
public static final String DEFAULT_PREFIX = "";
public static final String DEFAULT_SUFFIX = "";
private static final String[] SERVLET_LOCATIONS = new String[]{"/"};
......
}
我们看到这个类上的4个注解:
-
@Configuration:声明这个类是一个配置类
-
@ConditionalOnWebApplication(type = Type.SERVLET)
ConditionalOn,翻译就是在某个条件下,此处就是满足项目的类是Type.SERVLET类型,也就是一个普通web工程,显然我们就是
-
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
这里的条件是OnClass,也就是满足以下类存在:Servlet、DispatcherServlet、WebMvcConfigurer,其中Servlet只要引入了tomcat依赖自然会有,后两个需要引入SpringMVC才会有。这里就是判断你是否引入了相关依赖,引入依赖后该条件成立,当前类的配置才会生效!
-
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
这个条件与上面不同,OnMissingBean,是说环境中没有指定的Bean这个才生效。其实这就是自定义配置的入口,也就是说,如果我们自己配置了一个WebMVCConfigurationSupport的类,那么这个默认配置就会失效!
-WebMvcAutoConfiguration类定义相关的方法,这里只说明部分方法
- 定义视图解析器(解析jsp的视图解析器)
- 定义处理器适配器
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager, conversionService, validator);
adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}
-
-
this.mvcProperties属性
这写些法都用到了this.mvcProperties属性,通过查看该属性是WebMvcProperties类型
@ConfigurationProperties( prefix = "spring.mvc" ) public class WebMvcProperties { ........... public static class View { private String prefix; private String suffix; public View() { } .......... } }
可以在springboot全局配置文件application里面去定义属性值,如spring.mvc.prefix = 前缀路径 spring.mvc.suffix= 后缀名
-
this.resourceProperties属性,定义了静态资源的位置
@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;
更多全局属性,参考当前SpringBoot全局属性笔记
-
七、SpringBoot配置文件
1、properties 和 yml
Spring Boot 整个应用程序只有一个配置文件,那就是 .properties
或 .yml
文件。如果你的 Spring Boot 项目中没有包含这个配置文件,Spring Boot 对每个配置项都有默认值(当然,我们也可以添加配置文件,用以覆盖其默认值)。
这里以 .properties
文件为例,首先在 resources
下新建一个名为 application.properties
(必须是这个名字)的文件。
内容为:
server.port=8081 //设置tomcat访问端口为8081
server.servlet.context-path=/aaa //设置项目启动路径为aaa
并且启动 main 方法,这时程序请求地址则变成了:http://localhost:8081/aaa/hello
Spring Boot 支持 .properties 和 .yml 两种格式的文件,文件名分别对应 application.properties
和 application.yml
。
下面贴出 yaml 文件格式供大家参考:
server:
port: 8080
servlet:
context-path: /aaa
可以看出 yml 则 换行 + tab 隔开。这里需要注意的是冒号后面 必须有空格,否则会报错
idea中可以安装Convert YAML andProperties File插件,将properties文件变为yml文件
2、springboot日志配置
Spring Boot 直接使用 slf4j ,默认间接使用 logback 日志,因此,它支持直接在 .properties
和 .yml
文件中对日志的相关信息进行配置。另外,Spring Boot 还支持控制台日志上色功能。
logging.level.root=INFO
logging.level.cn.woniu.dao=DEBUG
logging.pattern.console=${CONSOLE_LOG_PATTERN:%clr(${LOG_LEVEL_PATTERN:%5p}) %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}}
logging.file=D:/mylog/log.log
采用application.yml
logging:
level:
cn:
woniu:
dao: DEBUG
root: INFO
pattern:
console: ${CONSOLE_LOG_PATTERN:%clr(${LOG_LEVEL_PATTERN:%5p}) %clr([%15.15t]){faint}
%clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}}
可以在idea中安装插件 Convert YAML and Properties File,该插件可以将properties文件直接转为yml文件
八、springBoot属性注入
1、Spring 配置类注解回顾
从 Spring 3.0 开始,Spring 官方就推荐大家使用 java 代码配置来代替以前的 xml 文件配置。而到了 SpringBoot,Java 代码配置更是成了标配。Java 代码配置主要靠 Java 类和一些注解,比较常用的注解有:
常用注解 | 说明 |
---|---|
@Configuration | 声明一个类作为配置类,代替 .xml 文件 |
@Bean | 声明在方法上,将方法的返回值加入Bean容器,代替 <bean> 标签 |
@Value | 属性注入 |
@PropertySource | 指定外部属性文件 |
2、使用spring的属性注入配置druid数据源
-
添加相关的依赖
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency>
-
添加外部属性文件:db.properties
jdbc.driverClassName=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/woniu_db?serverTimezone=UTC jdbc.username=root jdbc.password=root
-
编写配置类: DataSourceConfig
/** * 读取数据库连接信息配置类 */ @Configuration @PropertySource(value={"classpath:db.properties"}) public class DataSourceConfig { @Value("${jdbc.url}") String url; @Value("${jdbc.driverClassName}") String driverClassName; @Value("${jdbc.username}") String username; @Value("${jdbc.password}") String password; @Bean public DruidDataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(url); dataSource.setDriverClassName(driverClassName); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } }
-
controller获取druid数据源
@RestController public class HelloController { //注入数据源对象 @Autowired private DataSourceConfig dataSource; @RequestMapping("/hello") public String hello(){ System.out.println(dataSource.dataSource().getUrl()); return "hello springboot"; } }
3、SpringBoot的属性注入
在上面的案例中,我们实验了java配置方式。不过属性注入使用的是@Value注解。这种方式虽然可行,但是不够强大,因为它只能注入基本类型值。在SpringBoot中,提供了一种新的属性注入方式,支持各种java基本数据类型及复杂类型的注入。
a、@ConfigurationProperties普通注入
该注解为属性注值,该注解声明当前类为属性读取类
-
编写application.properties配置文件
jdbc.driverClassName=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/mall_db?serverTimezone=UTC jdbc.username=root jdbc.password=123
-
创建属性类:JdbcProperties
@Component @ConfigurationProperties(prefix = "jdbc")//根据前缀去springboot配置文件找对应的属性值 @Data public class JdbcProperties { //属性必须有get和set方法 private String url; private String driverClassName; private String username; private String password; }
-
在类上通过@ConfigurationProperties注解声明当前类为属性读取类
-
@Component创建该类的对象
-
prefix=“jdbc” 读取属性⽂件中,前缀为jdbc的值。
-
在类上定义各个属性,名称必须与属性⽂件中 jdbc. 后⾯部分⼀致,并且必须具有getter和setter⽅法
-
需要注意的是,这⾥我们并没有指定属性⽂件的地址,SpringBoot默认会读取⽂件名为application.properties的资源⽂件,所以我们把jdbc.properties名称改为application.properties,或者定义application.properties,把jdbc.properties属性⽂件内容拷⻉到application.properties中
-
-
编写配置类
@Configuration public class JdbcSourceConfig { @Autowired private JdbcProperties jdbcProperties; @Bean public DruidDataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(jdbcProperties.getUrl()); dataSource.setDriverClassName(jdbcProperties.getDriverClassName()); dataSource.setUsername(jdbcProperties.getUsername()); dataSource.setPassword(jdbcProperties.getPassword()); System.out.println(jdbcProperties.getUrl()); return dataSource; } }
b、@ConfigurationProperties更优雅的注入
我们直接把@ConfigurationProperties(prefix = "jdbc")
声明在需要使用的@Bean
的方法上,然后SpringBoot就会自动调用这个Bean(此处是DataSource)的set方法,然后完成注入。使用的前提是:该类必须有对应属性的set方法!
-
编写application.properties配置文件
jdbc.driverClassName=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/mall_db?serverTimezone=UTC jdbc.username=root jdbc.password=123
-
编写配置类
/** * 读取数据库连接信息配置类 */ @Configuration public class DataSourceConfig { /* prefix:声明要注入的属性前缀,SpringBoot调用该方法创建对象时 根据前缀去application配置文件中找对应的属性,然后把属性的值注入给对象的同名属性 */ @Bean @ConfigurationProperties(prefix = "jdbc") public DruidDataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); return dataSource; } }
-
编写controller
@RestController public class HelloController { @Autowired private DataSourceConfig dataSource; @RequestMapping("/hello") public String hello(){ System.out.println(dataSource.dataSource().getUrl()); return "hello springboot"; } }