文章目录
- SpringBoot介绍
- 概述
- 为什么要学习SpringBoot
- Spring Boot 的特点
- 快速入门
- Java配置
- 回顾历史
- 尝试Java配置
- SpringBoot属性注入的两种方式
- 方式一:新建一个类专用于读属性
- 方式二:更优雅的方式
- yaml配置文件
- 自动配置
- 自动配置原理
- SpringMVC的自动配置示例
- 自动配置中的判断注解
- 覆盖自动配置
- 总结
- SpringBoot实战
SpringBoot介绍
Spring框架,Spring Framework框架
Boot,启动,引导
概述
Spring Boot可以快速、非常轻易的构建独立的、生产级别的spring应用。
Spring官方为spring平台和第三方依赖库提供了一种固定化的使用方式,使开发者能非常轻松的开始开发应用程序。大部分Spring Boot应用只需要很少的配置。
为什么要学习SpringBoot
把SpringBoot称为搭建程序的脚手架,因为它的作用就是帮助我们快速构建庞大的Spring项目,并且尽可能地减少一切xml配置,做到开箱即用,迅速上手,让我们重点关注业务而非配置。
Java被诟病的一点就是臃肿,麻烦。当我们还在构建项目的时候,python程序员已经把功能写好了。它麻烦的原因主要是两点:
- 复杂的配置
项目各种配置其实是开发时的损耗, 因为在思考 Spring 特性配置和解决业务问题之间需要进行思维切换,所以写配置挤占了写应用程序逻辑的时间。 - 混乱的依赖管理
项目的依赖管理也是件吃力不讨好的事情。决定项目里要用哪些库就已经够让人头痛的了,你还要知道这些库的哪个版本和其他库不会有冲突,这也是件棘手的问题。并且,依赖管理也是一种损耗,添加依赖不是写应用程序代码。一旦选错了依赖的版本,随之而来的不兼容问题毫无疑问会是生产力杀手。
Spring Boot 的特点
Spring Boot 主要特征是:
- 为所有Spring的开发者提供一个非常快速的、广泛接受的入门体验。
- 开箱即用(启动器starter—其实就是一个SpringBoot提供的一个jar包),通过自己设置参数(.properties/.yml/.yaml),可以替换这种方式。
- 提供了一些大型项目中常见的非功能性特性,例如直接内嵌tomcat、jetty和undertow(不需要打包成war包部署)、安全指标、运行状况监测和外部化配置等
- 尽可能的自动配置spring和第三方库
- 绝对不会生成代码,并且不需要XML配置
更多细节,可以到SpringBoot官网查看。
快速入门
(1)创建一个Maven工程,不要勾选create from archetype
(2)pom.xml
- SpringBoot提供了一个名为spring-boot-starter-parent的工程,里面已经对各种常用依赖(并非全部)的版本进行了管理,我们的项目需要以这个项目为父工程,这样就不用操心依赖的版本问题了,需要什么依赖,直接引入坐标即可!
- 要配置一个SpringMVC的web工程,需要引入一个启动器,这里是Spring提供的启动器
spring-boot-starter-web
。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
如果想要修改SpringBoot项目的jdk版本,只需要在pom.xml中添加以下属性
<properties>
<java.version>1.8</java.version>
</properties>
(3)新建BootDemoApplication类
/**
* 引导类:springboot应用的入口
*/
//@EnableAutoConfiguration //启用自动配置
//@ComponentScan //组件扫描,作用类似于<context:component-scan base-package="com.cncs">
@SpringBootApplication//它时组合注解,可以替代上面两个注解,它包括了@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan等注解
public class BootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(BootDemoApplication.class,args);
}
}
args的应用
java -jar Hello.jar hello
这个java命令会将
hello
作为字符串参数传入给args
(4)此时访问localhost:8080/
,会出现如图所示错误页面,这是因为我们没有写controller,没有页面可以访问。
(5)新建类HelloController
@RestController
public class HelloController {
@GetMapping("/hello")
@ResponseBody
public String hello(){
return "hello SpringBoot !";
}
}
PS1:使用@RestController
注解可以不用在public String hello()
上面加@ResponseBody
,这样只能返回json格式的字符串。
PS2:@RestController
相当于@Controller
和@ResponseBody
两个注解
(6)访问页面,可以看见页面显示hello SpringBoot !
查看控制台,可以看见一些信息
Java配置
SpringBoot不用配置web.xml,它默认使用servlet3.0。servlet3.0可以不用再写 web.xml,可以用纯注解。 低版本需要自己写。
原来配置一个连接池的做法:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/spring_learn"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
</bean>
可是在SpringBoot如果要配置一个bean呢?要配置一个连接池该怎么做?
回顾历史
在Spring3.0开始,Spring官方就推介使用java配置来替代传统的xml配置,这里不妨回顾一下历史:
- Spring1.0时代
此时,jdk1.5刚出来,注解开发尚未流行,因此一切Spring配置都是xml格式,想象一下,所有的bean配置都是以xml方式,细思极恐。 - Spring2.0时代
Spring引入了注解开发,但是尚未完善,因此并没有完全替代xml,这时程序员通常是将xml与注解配置结合使用,之前的学习都是这种方式。 - Spring3.0及以后
3.0以后Spring的注解已经非常完善,因此Spring官方推介大家使用完全的java配置来替代以前的xml,在国内却并没有推广盛行,直到SpringBoot来临,人们才意识到java配置的优雅。
尝试Java配置
java配置主要靠java类和一些注解,比较常见的注解有:
- @Configuration:声明一个类作为配置类,替代xml
- @Bean:声明在方法上,将方法的返回值加入Bean容器,代替
<bean>
- @Value:属性注入,将properties中的连接信息注入到属性中。
- @PropertySource:指定外部属性文件。
工程目录文件结构:
下面使用java配置来实现连接池配置:
(1)首先引入Druid依赖,这里不引启动器的原因是:引入启动器就不需要我们自己配置了,为了展示配置效果,这里直接引入坐标。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
(2)新建配置类JdbcConfig
@Configuration
@PropertySource("classpath:jdbcConfig.properties")
public class JdbcConfig {
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource createDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
(3)新建连接池配置文件jdbc.propeties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis_learn
jdbc.username=root
jdbc.password=123456
(4)在HelloController添加并注入DataSource
@Autowired
private DataSource dataSource;
(5)测试注入是否成功
在HelloController的hello()
方法中添加一个断点,然后运行BootDemoApplication类中的main函数,在浏览器中输入地址回车后,在debug控制台可以看见已经注入了DataSource。
SpringBoot属性注入的两种方式
方式一:新建一个类专用于读属性
(1)去掉@PropertySource(“classpath:jdbcConfig.properties”)
(2)删除jdbc.propeties,并新建一个文件:application.properties
。注意,文件名不能是其它的,Spring识别application文件。
(3)新建类JdbcProperties,并在该类上加上@ConfigurationProperties
- 这里使用了
@Data
注解,作用是替代getter
、setter
、hashCode()
、equals()
、toString()
等方法。它不是运行的时候起作用,而是在编译成class的时候,自动生成getter、setter....
等方法。 - 设置属性变量的前缀,必须和
application.properties
的前缀一致。
@ConfigurationProperties(prefix = "jdbc")
@Data
public class JdbcProperties {
String driverClassName;
String url;
String username;
String password;
}
PS1:这里如果有红色警告,点击🔧按钮,取消勾选Show notification panel
PS2:成员变量名必须和application.properties
中属性名完全一致
PS3:要使用@Data
注解,需要引入lambok依赖,如下。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
PS4:IDEA需要安装Lombok插件。
点击@Data
注解,可以看见它支持的
(4)在JdbcConfig类中使用@EnableConfigurationProperties
注解,参数是连接属性类JdbcProperties的字节码。
-
public DataSource createDataSource(JdbcProperties prop)
这个方法由Spring调用执行。
@Configuration
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcConfig {
@Bean
public DataSource createDataSource(JdbcProperties prop){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(prop.getDriverClassName());
dataSource.setUrl(prop.getUrl());
dataSource.setUsername(prop.getUsername());
dataSource.setPassword(prop.getPassword());
return dataSource;
}
}
- JdbcProperties prop的三种注入方式:
- 通过
public DataSource createDataSource(JdbcProperties prop)
方法直接注入 - 通过属性注入
@Autowired
private JdbcProperties prop;
- 通过构造方法注入
private JdbcProperties prop;
public JdbcConfig(JdbcProperties prop) {
this.prop=prop;
}
完成上面4步,属性注入就ok了。
PS:这种属性注入方式适用于大家都要使用的情境,哪里用哪里就使用@Autowired
注入即可。
方式二:更优雅的方式
只使用JdbcConfig一个配置类完成配置
- 当Spring扫描到@Bean注解时,会执行方法dataSource()方法,然后会发现@ConfigurationProperties注解,然后会找到
application.properties
文件,检查返回的类DataSource里面有没有driverClassName、url、username、password
同名的setter
方法,有则完成注入
@Configuration
public class JdbcConfig {
@Bean
@ConfigurationProperties(prefix = "jdbc")
public DataSource dataSource(){
return new DruidDataSource();
}
}
PS1:这种注入方式适用于一个需要注入的情况
PS2:这种情况application.properties
中的属性名和DataSource中的变量名称必须完全一致才能注入
yaml配置文件
我们在使用.properties文件的时候发现,它的结构还不够优雅,还有许多重复的前缀需要书写,且无法书写复杂的类型。而yaml文件帮助我们做到了这点。
application.properties
还可以写成application.yaml
或者application.yml
,它的用法示例:
application.yaml
jdbc:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql:///mybatis_learn
username: root
password: 123456
User:
name: jack
age: 18
sex: male
language:
- java
- python
- c++
- c#
- scala
它对应的java类的写法:
@Data
public class JdbcProperties {
String driverClassName;
String url;
String username;
String password;
User user = new User();
class User {
String name;
int age;
List<String> language;
}
}
将它注入到DataSource类中
@Configuration
public class JdbcConfig {
@Bean
@ConfigurationProperties(prefix = "jdbc")
public DataSource dataSource(){
return new DruidDataSource();
}
}
PS1:变量名与值之间需要有一个空格。
PS2:当application.properties
和application.yaml
重名文件同时存在时,以application.properties
为准
自动配置
使用SpringBoot后,视图解析器,注解驱动,文件上传解析器,过滤器,组件扫描,tomcat端口,dispatcherServlet拦截路径等等都不用再配置,为什么可以不用配置呢?我们通过下面的分析来一步步说明。
@SpringBootApplication
public class BootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(BootDemoApplication.class,args);
}
}
打开@SpringBootApplication注解
- @SpringBootConfiguration注解作用,标识当前应用类声明为一个SpringBoot配置类,它只是一个有别名的配置类,可以在应用类中使用@Bean标签等等。
打开@SpringBootConfiguration注解
- @Configuration,表示为一个普通配置
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
打开@EnableAutoConfiguration注解
- @EnableAutoConfiguration作用,启动Spring的自动配置,尝试猜测怎么去配置bean。一般基于classpath中的文件,引入的依赖。引入mybatis依赖,它会检测classpath的依赖,它就会自动配置mybatis;引入tomcat,会配置tomcat…
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
.........
}
打开@ComponentScan注解
- @ComponentScan作用,扫描包,类似
<context:component-scan base-package="com.cnccs">
。在没有扫描的包的情况下,它会从声明注解的类所在的包开始扫描,如下图会扫描com.cncs
包。
PS1:原先扫描的时候,因为springmvc扫描web层,spring扫描service层,它们各自会产生一个spring容器,这就会导致它们俩如果想要交互就有限制条件,这就是父子容器的问题(一些bug),现在是统一扫描,就不会有这个问题了。
自动配置原理
提前写好一个类,在这个类中将所有的配置都配好,并通过条件判断是否进行自动配置。
从run()
方法开始
SpringApplication.run(BootDemoApplication.class,args);
自动配置流程图:
SpringMVC的自动配置示例
自动配置中的判断注解
以SpringMVC的自动配置举例
覆盖自动配置
方式一:覆盖bean,具体做法就是手动写一个配置类。
方式二:覆盖bean中的属性。
在application.yaml
配置属性,完成部分属性覆盖:
例一:配置tomcat端口
总结
在pom.xml中输入spring.boot.starter.xxxxxx
就可以引入某个启动器。
SpringBoot为我们提供了默认配置,而默认配置生效的条件一般有两个:
- 你引入了相关依赖
- 你自己没有配置
启动器
所以,我们如果不想配置,只需要引入依赖即可,而依赖版本我们也不用操心,因为只要引入了SpringBoot提供的stater(启动器),就会自动管理依赖及版本了。因此,玩SpringBoot的第一件事情,就是找启动器,SpringBoot提供了大量的默认启动器
全局配置
另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义application.properties
文件来进行覆盖。这样虽然使用的还是默认配置,但是配置中的值改成了我们自定义的。
因此,玩SpringBoot的第二件事情,就是通过application.properties
来覆盖默认属性值,形成自定义配置。我们需要知道SpringBoot的默认属性key,非常多,参考《SpringBoot全局属性.md》
PS1:SpringBoot没有为mybatis写启动器。
PS2:SpringBoot默认不支持jsp。