1.Springboot的初识
1.1.Springboot简介
Spring Boot是搭建基于Spring的工程的脚手架 。
它并不是对Spring进行功能增强,只是对spring框架的优化,提供的是一种方便快速使用spring 的方式,能够方便快捷的搭建spring工程。
1.2.为什么要使用SpringBoot
spring的缺点
- 配置繁琐
- 依赖繁琐
SpringBoot的功能
- 自动配置,约定大于配置(提供有默认配置,也支持使用xml文件方式自定义配置,也支持 properties/yml文件自定义配置,也可以使用配置类自定义配置)
- 起步依赖:依赖传递
- 辅助功能:tomcat内置
- 简化了第三方框架的整合使用(提供了默认配置,直接使用就可以了)
1.3.springboot有哪些好处?
- 简化Spring应用开发的一个框架;
- 整个Spring技术栈的一个大整合
- J2EE开发的一站式解决方案
2.IDEA进行Springboot环境配置maven和jdk
3.创建Springboot项目
3.1.使用springboot创建一个项目(推荐)
如果start.spring.io连不上,可以改为http://start.aliyun.com,但是构建出来的项目会和原生的 项目不太一样,需要修改成原生项目的样子。
启动项目
3.2.IDEA使用maven创建springboot项目
启动项目
3.3.使用springboot搭建一个web环境
3.3.1.引入web启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3.3.2.启动类所在包下创建controller包,编写Controller类
@RestController
public class HelloController {
@RequestMapping("/say")
public String sayHello(){
return "Hello Springboot!!!!";
}
}
3.3.3.通过启动类启动springboot项目 并进行访问
修改Tomcat端口配置,在application.properties文件中
# 修改springboot默认的项目的访问端口
# 凡是能自动提示的,都是springboot默认的配置,可以通过在配置文件中自定义更改默认
配置
server.port=9001
# 修改springboot默认的项目的访问路径
server.servlet.context-path=/hello
4.Springboot注解详解
4.1.启动类注解详解
4.1.1.@SpringBootApplication注解
- 这是一个整合的注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
...
}
4.1.2.@Target注解:表示使用这个注解的注解在哪个地方起作用
Java的注解
- TYPE 在Class上 interface上 enum上起作用
- FIELD 在属性上起作用
- METHOD 在方法上起作用
- PARAMETER 在方法中的参数上起作用
4.1.3.@Retention注解:表示使用这个注解的注解的一个有效范围
Java的注解
- source 编译之前
- class 运行之前
- runtime 运行期间也可以
4.1.4.@Documented注解
Java的注解
- 在我们生成文档注释的时候,类上的注解也能被看到
4.1.5.@Inherited注解
Java的注解
- 如果添加此注解,当前定义的注解就可以被继承了
4.1.6.@SpringBootConfiguration注解(关注)
- springboot的配置注解,在其中使用了@Configuration,表明此类是个配置类。
4.1.7.@Configuration
- 在SpringBootConfiguration注解中被使用
- 添加上此注解的类就成为了配置类
- 配置类就是之前在spring配置文件中写配置一样
4.1.8.@EnableAutoConfiguration注解(关注)
springboot的注解
- 让自动配置类起作用,在其中使用了@AutoConfigurationPackage和@Import注解
4.1.9.@AutoConfigurationPackage注解 (关注)
- 在EnableAutoConfiguration注解中被使用
- 让相关的自动配置类的注解起作用
- 在其中使用了@Import注解引入了Registrar.class,查找所有使用basePackages属性和 basePackageClasses属性的注解所在的类
4.1.10.@Import注解 (关注)
- 在EnableAutoConfiguration注解中被使用
- 引入AutoConfigurationImportSelector.class,查找所有的可用的自动配置类
4.1.11.@ComponentScan 注解 (关注)
- 起到扫描注解的作用
4.2.自动配置类的相关注解
4.2.1.@ConditionalOnClass注解
- 必须要有对应的类才能起作用,主要用于判断是否能自动初始化bean对象。
示例:通过@ConditionalOnClass注解判断项目中是否有Person类,有自动创建User类对象, 没有不创建。
创建User.java
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
创建配置类MyConfiguration.java,并创建获取User对象的方法,同时添加
@ConditionalOnClass注解,设置需要在项目中找到全类名为 com.test.springbootweb.bean.Person的类才能创建User对象。
@Configuration
public class MyConfig {
//判断条件,判断项目中是否有com.test.springbootday01anno.Person这个类,有
就创建User对象,没有不创建
@ConditionalOnClass(name =
{"com.test.springbootday01anno.bean.Person"})
@Bean
public User user(){
System.out.println("user()方法执行了");
return new User();
}
}
TestController.java中编写访问Handler
@RestController
public class TestControler {
........
@Autowired
private User user;
@RequestMapping("/test2")
public User test2(){
user.setName("张三");
user.setAge(10);
return user;
}
}
运行测试
4.2.2.@ConditionalOnMissingBean注解
- 判断spring容器中是否有对应的bean对象,有就不初始化,没有自动初始化改bean对象
在引导类中设置创建获取User对象的方法,因为MyConfiguration.java中已经设置了创建User对 象的方法,所以这里@ConditionalOnMissingBean,表示如果已经创建了User对象,则此方法 不在执行。
@SpringBootApplication
public class SpringbootDay01AnnoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDay01AnnoApplication.class, args);
}
//判断条件,判断spring容器中是否有同名的bean对象,有不创建,没有创建
@ConditionalOnMissingBean
@Bean
public User user(){
System.out.println("引导类的user()方法执行了");
return new User();
}
}
4.2.3.@ConditionalOnMissingClass注解
- 判断项目中是否有实体类,有实体类,不初始化对应的bean对象,没有实体类,初始化对 应的bean对象,和@ConditionalOnClass含义相反。
示例
将MyConfiguration.java中的@ConditionalOnClass注解换成@ConditionalOnMissingClass, 然后设置成Person会发现报错,但是随便换成没有的全类名则可以执行成功。
@Configuration
public class MyConfig {
//判断条件,判断项目中是否有com.test.springbootday01anno.bean.Person这个类,有不创建User对象,没有创建
@ConditionalOnMissingClass({"com.test.springbootday01anno.bean.Person"})
@Bean
public User user(){
System.out.println("配置类的user()方法执行了");
return new User();
}
}
4.2.4.@EnableConfigurationProperties注解
- 通过此注解可以找到对应的XXXProperties配置类,加载对应默认的配置,或者修改默认的 配置。
5.Springboot的配置文件的学习
5.1.springboot的配置文件有两种写法
- properties结尾的文件
- .yml结尾的文件(.yaml)
如果两个文件都存在于项目中,则优先级为:properties>yml
如果properties和yml文件中配置了相同内容,以properties文件为准。
如果properties和yml文件中配置的内容不同,两个文件中的内容都会生效。
另:Springboot也支持xml文件,但是不建议使用,建议使用properties或者yml文件
5.2.application.yml配置文件的要求
- 属性名称和值之间要用冒号进行分割,
- 如果要写值,前面要带有一个空格,例如:属性名称: 值
- 属性下面还有子属性回车,子属性必须tab键进行缩进(两个空格)
#属性名称和值之间要用冒号进行分割
#写值时,前面要带有一个空格
#属性下面还有子属性回车,子属性必须tab键进行缩进(两个空格)
server:
servlet:
context-path: /configfile
5.3.通过application.yml配置文件给Java类的属性赋值
5.3.1.编写Teacher类 注意添加注解
//在yml配置文件中配置TeachProperties中的属性的值
//并且在项目启动时加载yml中对应属性的值到TeacherProperties中保存
//加载yml配置文件的属性,赋值给实体类属性保存,要求yml中的属性名和实体类中的属性名对应
@ConfigurationProperties(prefix = "teacher") //prefix:yml文件中的属性前缀
public class TeacherProperties {
private Integer id;
private String name;
private List<String> hobbys;
private Map<String, String> maps;
private Student stu;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getHobbys() {
return hobbys;
}
public void setHobbys(List<String> hobbys) {
this.hobbys = hobbys;
}
public Map<String, String> getMaps() {
return maps;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public Student getStu() {
return stu;
}
public void setStu(Student stu) {
this.stu = stu;
}
}
public class Student {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
5.3.2.编写yml文件
#在yml文件中自定义属性和值,并通过自定义的Java类获取属性的值保存
teacher:
id: 1
name: 张三
hobbys:
- 篮球
- 足球
- 乒乓球
maps:
- k1: 哈哈
- k2: 嘿嘿
k3: 呵呵
stu:
id: 1
name: 李四
5.3.3.编写配置类
@Configuration
//@EnableConfigurationProperties({TeacherProperties.class}) //会自动构建TeacherProperties对象并存放到spring容器中
public class MyConfiguration {
@Bean
public TeacherProperties teacherProperties(){
return new TeacherProperties();
}
}
5.3.4.进行测试
@RestController
public class PropertiesController {
@Autowired
private TeacherProperties teacherProperties;
@RequestMapping("/get")
public TeacherProperties getProperties(){
return teacherProperties;
}
}
5.4.进行多yml文件的配置
application.yml
spring:
profiles:
active: test
application-dev.yml
# tomcat端口
server:
port: 9002
teacher:
id: 6
name: 张三
hobbys:
- 篮球
- 足球
- 乒乓球
maps:
- k1: 呵呵
- k4: 哈哈
stu:
id: 55
application-test.yml
# tomcat端口
server:
port: 9003
teacher:
id: 6
name: 王五
hobbys:
- 篮球
- 足球
- 乒乓球
maps:
- k1: 呵呵
- k4: 哈哈
stu:
id: 55
6.日志
6.1.什么是日志
springboot为了方便快速的构建功能完整的spring项目,所以springboot自动集成了安全框架 spring-boot-starter-security、消息队列ActiveMQ、日志框架spring-boot-starter-logging 等功能性框架,让我们可以方便快捷的在spring工程中整合其他功能。
在项目开发中,都不可避免的使用到日志。没有日志虽然不会影响项目的正确运行,但是没 有日志的项目可以说是不完整的。日志在调试,错误或者异常定位,数据分析中的作用是不 言而喻的。
6.2.市面上的日志框架
- JUL、JCL、Jboss-logging、logback、log4j、log4j2、slf4j....
6.3.SpringBoot默认选用 SLF4j和logback
依赖关系,在spring-boot-starter-web起步依赖中的spring-boot-starter已经包含了springboot-starter-logging起步依赖,所以不用直接引入spring-boot-starter-logging起步依赖。
6.4.SLF4j使用 springboot默认级别是info-API方式
方式一:
@RestController
public class TestController {
private static final Logger logger = LoggerFactory.getLogger(TestController.class);
@RequestMapping("/test1")
public String test1() {
logger.error("我是error");
logger.warn("我是warning");
logger.info("我是info");
logger.debug("我是degu");
logger.trace("我是trace");
return "Hello Springboot Logging";
}
}
默认日志级别是info,所以debug和trace级别是默认不打印。
当然我们可以在application.yml或者application.properties文件中修改springboot关于日志的 默认配置
# 修改日志级别
logging:
level:
com:
test: trace
file:
# 指定生成的日志文件名称
name: D:/logs/spring.log
# 在控制台输出的日志的格式
pattern:
console: "%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n"
#指定文件中日志输出的格式
file: "%d{yyyy-MM-dd} === [%thread] === %-5level === %logger{50} ====%msg%n"
方式二:需要引入lombok依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
@Slf4j
@RestController
public class LoggingController {
@RequestMapping("/test2")
public String test1() {
log.error("我是error");
log.warn("我是warning");
log.info("我是info");
log.debug("我是degu");
log.trace("我是trace");
return "Hello Springboot Logging";
}
}
会发现,我们可以直接使用日志操作,这是因为springboot已经集成了日志的相关配置,我们直 接使用默认配置即可。
查看spring-boot的依赖包内容
一般在实际工作中,开发是使用debug或者trace级别打印日志,是为了看到更多的日志信息,方 便调试程序。部署上线时,日志级别会改为info,这样就只看警告和错误信息,debug和trace级别 日志就看不到,更容易突出问题。
6.5.指定日志的xml文件
当然如果不想在application.yml文件中进行配置,也可以使用日志的原生配置文件进行配置操作。
- 给类路径下放上每个日志框架自己的配置文件即可;SpringBoot就不使用他默认配置的了
- 在项目的resources目录中创建logback.xml,这时日志将不在以application.yml中的配置 为准,而是以logback.xml配置为准。
<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位
是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状
态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<!-- 定义日志的根目录 -->
<property name="LOG_HOME" value="D:/spring/log"/>
<!-- 定义日志文件名称 -->
<property name="appName" value="atlanou-springboot"></property>
<!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<!--
日志输出格式:
%d表示日期时间,
%thread表示线程名,
%-5level:级别从左显示5个字符宽度
%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息,
%n是换行符
-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level
%logger{50} - %msg%n
</pattern>
</layout>
</appender>
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其
他文件 -->
<appender name="appLogAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 指定日志文件的名称 -->
<file>${LOG_HOME}/${appName}.log</file>
<!--
当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,
既负责滚动也负责出发滚动。
-->
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--
滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
%i:当文件大小超过maxFileSize时,按照i进行文件滚动
-->
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-
%i.log
</fileNamePattern>
<!--
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,
那些为了归档而创建的目录也会被删除。
-->
<MaxHistory>365</MaxHistory>
<!--
当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件
滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须
配置timeBasedFileNamingAndTriggeringPolicy
-->
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 日志输出格式: -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ]
[ %logger{50} : %line ] - %msg%n
</pattern>
</layout>
</appender>
<!--
logger主要用于存放日志对象,也可以定义日志类型、级别
name:表示匹配的logger类型前缀,也就是包的前半部分
level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR
additivity:作用在于children-logger是否使用 rootLogger配置的appender
进行输出,
false:表示只用当前logger的appender-ref,true:
表示当前logger的appender-ref和rootLogger的appender-ref都有效
-->
<!-- hibernate logger -->
<logger name="com.test" level="debug"/>
<!-- Spring framework logger -->
<logger name="org.springframework" level="debug" additivity="false">
</logger>
<!--
root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个
logger对应,
要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个
logger的appender和level。
-->
<root level="info">
<appender-ref ref="stdout"/>
<appender-ref ref="appLogAppender"/>
</root>
</configuration>
7.引入数据库连接
7.1.使用默认数据源
- 在pom.xml中引入相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
- 编写连接数据库的属性
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/aa?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
# springboot内置的数据库连接池
hikari:
# 最小空闲连接数量
minimum-idle: 6
- 编写java代码进行测试
@RestController public class UserController { @Autowired private DataSource dataSource; @Autowired private JdbcTemplate jdbcTemplate; @RequestMapping("/select") public List<Map<String, Object>> getUser() { System.out.println(dataSource + "---------------------"); List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from user_inf"); System.out.println(list); return list; } }
7.2.自定义数据源
- springboot默认的数据源是HikariCP
- springboot默认支持哪些数据源
spring-boot-autoconfigure.jar包 org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@Configuration(
proxyBeanMethods = false
)
@Conditional({DataSourceAutoConfiguration.PooledDataSourceCondition.class})
@ConditionalOnMissingBean({DataSource.class, XADataSource.class})
//支持的数据源Hikari.class, Tomcat.class, Dbcp2.class
//Generic.class 自定义数据源的配置
@Import({Hikari.class, Tomcat.class, Dbcp2.class, Generic.class, DataSourceJmxConfiguration.class})
protected static class PooledDataSourceConfiguration {
protected PooledDataSourceConfiguration() {
}
}
- 配置druid的pom.xml配置相关依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.16</version>
</dependency>
- com.alibaba druid-spring-boot-starter 1.1.16
spring: datasource: driver-class-name: com.mysql.jdbc.Driver username: root password: url: jdbc:mysql://127.0.0.1:3306/aa?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC # 指定数据源 type: com.alibaba.druid.pool.DruidDataSource
8.SpringBoot起步依赖原理分析
问题
1. 为什么Springboot项目中引入的起步依赖不需要设置版本?
2. 为什么Springboot项目中只引入了一个起步依赖,就能使用所关联的所有依赖Jar包的功能?
spring-boot-starter-parent
- 最终使用dependencyManagement定义管理各种依赖包的版本
- 确定了可以引入springboot相关的依赖,将项目变成springboot项目
spring-boot-starter-web
- 本身依赖了所有spring、springmvc相关的依赖包,通过依赖传递将依赖包依赖到项目中。
9.Springboot的自动配置原理
9.1.自动配置原理
- SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration @EnableAutoConfiguration 作用,利用EnableAutoConfigurationImportSelector给容器 中导入一些组件;
将类路径下META-INF/spring.factories里面配置的所有EnableAutoConfiguration的值加入到了容器中。
- 每一个这样的 xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们 来做自动配置。
- 以RedisAutoConfiguration为例解释自动配置原理,
//标识为配置,proxyBeanMethods=false, Lite轻量级模式,@Bean 修饰的方法不会被代理。
@Configuration(
proxyBeanMethods = false
)
//判断是否有RedisOperations类,有则创建bean对象,没有则不创建
@ConditionalOnClass({RedisOperations.class})
//加载RedisProperties,RedisProperties有redis的默认配置,也可以加载yml文件中的自定义的redis配置
@EnableConfigurationProperties({RedisProperties.class})
//引入其他配置
@Import({LettuceConnectionConfiguration.class,
JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
public RedisAutoConfiguration() {
}
//判断spring容器中是否有名称为redisTemplate的RedisTemplate对象,没有创建,
有不创建
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
)
public RedisTemplate<Object, Object>
redisTemplate(RedisConnectionFactory redisConnectionFactory) throws
UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory
redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
- 一但这个配置类生效;这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的 properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
- 所有在配置文件中能配置的属性都是在xxxxProperties类中封装着;配置文件能配置什么就 可以参照某个功能对应的这个属性类