1.常用注解
-
修饰类
-
@ SpringBootApplication //标记这是个主程序类,并自动扫描该主类所在包及其子包中的类
-
@ ConfigurationProperties(prefix = "zhangsan") //表示全局配置文件 文件中 zhangsan 这个父节点下的子节点属性对应该bean类
-
@PropertySource(value={ " classpath:jdbc.properties " , "classpath:spring.properties" }) //加载指定的配置文件
-
@ImportResource //在SpringBoot中不支持Spring的xml配置文件,该注解可以引入Spring的XML配置文件
-
@ Configuration //表示这是一个配置类
-
@Bean //将方法的返回值添加到容器中,方法名是默认的组件id
-
@Component //组件,用于给Spring接管
-
@Controller //表示这是一个控制器,能被Spring接管
-
@ResponseBody //表示这个类的所有方法的返回值,都写给浏览器(如果是对象则返回json数据)
-
@ RestController 等价于@ Controller + @ResponseBody
-
@ validated //启动数据校验,可以给属性添加注解如,@Email该属性必须为email
-
@ Conditional //满足条件,配置类才会生效
-
-
-
修饰属性
-
@ Autowired //自动装配
-
@ value //给容器中的bean的属性注入值,不和@ ConfigurationProperties搭配,支持字面量,SPEL,配置文件
-
字面量@value(3)
-
SPEL@value("#{11*3}")
-
配置文件@value("${person.name}")
-
-
@Email和@ validated搭配,校验数据JSR303
-
-
-
修饰函数
-
@ RequestMapping( "/hello") //该函数用于接收/hello请求
-
@ResponseBody / / 将方法返回的对象写入到response对象的body区,通常用来返回JSON数据或者是XML
-
修饰参数
-
2.SpringBoot的精髓在于自动配置(xxxAutoConfiguration,自动配置类;xxxProperties,属性类)
-
springboot会加载大量的自动配置类,可以搜索*AutoConfiguration查看实现类
-
查看我们需要的功能有没有SpringBoot默认写好的自动配置类
-
再看这个自动配置类中配置了哪些组件
-
这些组件的属性会从propeties类中加载属性
-
3.环境准备
-
java版本--1.8.0_241
-
为Eclipse安装 Spring Tools 4
-
-
Maven版本--3.3.9
4.Spring Boot HelloWorld
![](https://img-blog.csdnimg.cn/20200712223436325.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIzOTM3MzQx,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200712223436328.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIzOTM3MzQx,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200712223436337.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIzOTM3MzQx,size_16,color_FFFFFF,t_70)
@SpringBootApplication
//标记这是个主程序类
public
class Application {
public
static
void main(String[]
args) {
SpringApplication.
run(Application.
class,
args);
}
}
@Controller
public
class HelloWorld {
@RequestMapping(
"/hello")
@ResponseBody
public String hello() {
return
"Hello World";
}
}
![](https://img-blog.csdnimg.cn/20200712223436289.png)
-
创建SpringBoot工程
-
resources目录结构
-
static:保存所有的静态资源。如js,css,image
-
template:保存所有的模板页面。springBoot默认不支持jsp页面,但是可以使用模板引擎如freemaker,thymeleaf
-
application.properties:应用配置。用于修改SpringBoot的默认配置,如服务器端口号
-
-
标记主程序
-
编写业务代码
-
测试
-
打包成jar包
-
run as---maven install
-
-
-
部署
-
5.配置文件语法
-
Springboot 使用一个全局的配置文件application.properties或者application.yml(application.yaml)
-
示例
-
server:port: 8080address: localhost
-
语法
-
基本语法
-
大小写敏感
-
以空格的缩进代表层级关系
-
k:(空格)v表示-对键值对
-
-
值的写法
-
字面量的写法(数字,布尔值,字符串)
-
直接写就可以了,字符串默认可以不带单引号或者双引号
-
单引号括起来的字符串会自动转里面的转义字符
-
双引号括起来的字符串不转特殊的转义字符
-
-
对象,Map(键,值)(键值对)
-
对象friend:name: zhangsanage: 18friend: { name: zhangsan, age: 18}
-
写法1
-
写法2
-
-
-
-
-
数组(List,Set)
-
用-表示一个元素pets:- cat- dog- duckpets: [ cat, dog, duck]
-
写法1
-
写法2
-
-
-
-
6.利用配置文件自动配置bean
<
dependency
>
<
groupId
>org.springframework.boot
</
groupId
>
<
artifactId
>spring-boot-configuration-processor
</
artifactId
>
<
optional
>true
</
optional
>
</
dependency
>
@Component
//组件,用于给Spring接管
@ConfigurationProperties(prefix =
"zhangsan")
//表示
yml
文件中
zhangsan
这个父节点下的子节点属性对应该类
public
class Person {
private String
name;
private
int
age;
private
boolean
alive;
//这些属性不能用is开头,不然生成的getter,setter方法不太对
private Date
birth;
private Map<String,Object>
maps;
private List<Object>
list;
zhangsan:
name:
zhangsan
age:
18
alive:
true
birth:
2019/2/2
maps: {
k1:
v1,
k2:
v2}
list: [
v1,
v2,
v3]
@SpringBootTest
class ApplicationTests {
@Autowired
Person
person;
@Test
void contextLoads() {
System.
out.println(
person);
}
}
![](https://img-blog.csdnimg.cn/20200712223436308.png)
![](https://img-blog.csdnimg.cn/20200712223436312.png)
-
pom文件引入配置处理器,这样写yml文件时有提示
-
编写bean的类,同时自动生成getter,setter方法
-
编写yml文件(这里不知道为什么eclipse不提示,还显示报错,但是可以正常运行)
-
运行查看是否注入
-
@ConfigurationProperties与@valuez注入值的区别
-
@ ConfigurationProperties与@PropertySource的区别
-
@Component //组件,用于给Spring接管//@ConfigurationProperties(prefix = " zhangsan ")//表示 yml 文件中 zhangsan 这个父节点下的子节点属性对应该类@PropertySource(value= { "classpath:person.properties"})public class Person {private String name;private int age;
-
@ ConfigurationProperties从全局配置文件中加载属性
-
@PropertySource可以指定配置文件
-
-
-
@ImportResource //在SpringBoot中不支持Spring的xml配置文件,该注解可以引入Spring的XML配置文件@ImportResource(locations = { "classpath:spring.xml"})@SpringBootApplication //标记这是个主程序类public class Application {public static void main(String[] args) {SpringApplication. run(Application. class, args);}
-
7.SpringBoot向容器中添加组件的方式是通过配置类
-
创建配置类
-
@Configuration //指明当前类是一个配置类,取代了之前的SpringXML文件public class MyConfiguration {@Bean //将方法的返回值添加到容器中,方法名是默认的组件idpublic Person person() {return new Person();}}
-
获取组件
-
@Autowiredprivate ApplicationContext ac;@Testvoid testPerson() {System. out.println( ac.getBean( "person"));}
8.Profile可以快速切换环境
![](https://img-blog.csdnimg.cn/20200712223436317.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzIzOTM3MzQx,size_16,color_FFFFFF,t_70)
-
对于application.properties可以采用多文档方式application-{profile}.propertiesspring.profiles.active= devserver.port= 8080
-
创建application-dev.properties
-
在application.properties中激活指定配置文件
-
-
对于application.yml可以采用文档块方式
9.日志模块
-
日志抽象类与实现类
-
-
意味着我们如果使用日志框架,需要选一个抽象类jar包(SLF4j)。一个实现类jar包(logback)
-
-
如何使用
-
Springboot的web自动含有日志jar包,如果没有导入jar包
-
slf4j-api.jar
-
lobback-classic.jar
-
logback-core.jar
-
-
代码
-
import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class HelloWorld {public static void main(String[] args) {Logger logger = LoggerFactory.getLogger(HelloWorld. class);logger.info( "Hello World");}}
-
-
SpringBoot日志模块的依赖关系
-
-
Springboot输出日志
-
日志的类一定要使用slf4j包内的类
-
import org.junit.jupiter.api.Test;
-
import org.slf4j.Logger;
-
import org.slf4j.LoggerFactory;
-
import org.springframework.boot.test.context.SpringBootTest;
-
@SpringBootTest
-
class BootApplicationTests {
-
Logger logger = LoggerFactory. getLogger( this.getClass());
-
@Test
-
void contextLoads() {
-
//日志级别,由低到高 trace<debug<info<warn<error
-
//可以调整日志的级别,这样日志只会在>=该级别才输出
-
logger.trace( "这是trace日志");
-
logger.debug( "这是debug日志");
-
//Spring默认是info级别的
-
logger.info( "这是info日志");
-
logger.warn( "这是warn日志");
-
logger.error( "这是error日志");
-
}
-
}
-
-
日志模块的配置
-
日志输出级别
-
logging:
-
level:
-
com.example.demo: trace //com.example.demo这个包下的所有类的输出级别为trace
-
-
日志输出路径:不要和file.name一起用,不然不生效
-
logging:
-
file:
-
path: log //会在当前项目路径下生成log文件夹,/log/spring.log
-
-
日志输出文件
-
logging:
-
file:
-
name: spring/log.log //会在当前项目下创建/spring/log.log,并将日志输出到log.log
-
-
日志输出格式
-
logging:
-
pattern:
-
file: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %m%n'
-
%d{yyyy-MM-dd HH:mm:ss.SSS}:表示年月日时分秒毫秒
-
[%thread]:线程名
-
%-5level:左对齐,输出日志级别,最多占5个字符
-
%logger{50}:最多50个字符,输出类名(也就是this.getClass() LoggerFactory. getLogger( this.getClass()); )
-
%m%n:消息内容和换行
-
-
-
10.Springboot进行web开发
11.Springboot整合MyBatis进行数据库交互
-
Mybatis访问数据库
-
注解方式
-
创建项目
-
勾选mysql Driver; JDBC API;Mybatis
-
-
配置数据源
-
spring:
-
datasource:
-
url: jdbc:mysql://192.168.1.103:3306/jdbc?serverTimezone=Asia/Shanghai
-
username: root
-
password: yahang.521
-
driver-class-name: com.mysql.cj.jdbc.Driver
-
-
# Hikari 连接池配置
-
hikari:
-
minimum-idle: 5 # 最小空闲连接数量
-
idle-timeout: 180000 # 空闲连接存活最大时间,默认600000(10分钟)
-
maximum-pool-size: 10 # 连接池最大连接数,默认是10
-
auto-commit: true # 此属性控制从池返回的连接的默认自动提交行为,默认值:true
-
pool-name: HikariPool # 连接池名称
-
max-lifetime: 1800000 # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
-
connection-timeout: 30000 # 数据库连接超时时间,默认30秒,即30000
-
connection-test-query: SELECT 1
-
-
创建操作不同表对应的Mapper接口
-
@Mapper
-
public interface StudentMapper {
-
-
@Select( "select * from student where id=#{id}")
-
Student queryStudentById(Integer id);
-
-
@Delete( "delete from student where id = #{id}")
-
int deleteStudentById(Integer id);
-
-
}
-
-
编写业务代码
-
@Controller
-
public class StController {
-
-
@Autowired
-
private StudentMapper studentMapper;
-
-
@ResponseBody
-
@RequestMapping( "/getStudentById")
-
public Student getStudentById(Integer id) {
-
Student student = studentMapper.queryStudentById( id);
-
return student;
-
}
-
}
-
-
其他
-
批量扫描包下的mapper类
-
@MapperScan(value = "com.njupt.mapper")
-
@SpringBootApplication
-
public class MybatisApplication {
-
public static void main(String[] args) {
-
SpringApplication. run(MybatisApplication. class, args);
-
}
-
}
-
-
-
配置文件方式
-
创建项目
-
勾选mysql Driver; JDBC API;Mybatis
-
-
配置数据源
-
spring:
-
datasource:
-
url: jdbc:mysql://192.168.1.103:3306/jdbc?serverTimezone=Asia/Shanghai
-
username: root
-
password: yahang.521
-
driver-class-name: com.mysql.cj.jdbc.Driver
-
-
# Hikari 连接池配置
-
hikari:
-
minimum-idle: 5 # 最小空闲连接数量
-
idle-timeout: 180000 # 空闲连接存活最大时间,默认600000(10分钟)
-
maximum-pool-size: 10 # 连接池最大连接数,默认是10
-
auto-commit: true # 此属性控制从池返回的连接的默认自动提交行为,默认值:true
-
pool-name: HikariPool # 连接池名称
-
max-lifetime: 1800000 # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
-
connection-timeout: 30000 # 数据库连接超时时间,默认30秒,即30000
-
connection-test-query: SELECT 1
-
-
在resources目录下创建两个目录
-
mybatis官方文档: https://mybatis.org/mybatis-3/zh/index.html
-
resources/mybatis/config:mybatis全局配置文件目录
-
新建mybatis-config.xml文件: 该文件无需配置环境,也无需引用mapper文件,直接配置就可以
-
<? xml version= "1.0" encoding= "UTF-8" ?>
-
<! DOCTYPE configuration
-
< configuration >
-
< settings >
-
< setting name= "mapUnderscoreToCamelCase" value= "true" />
-
</ settings >
-
</ configuration >
-
-
-
resources/mybatis/mapper:mybatis sql映射文件目录
-
新建StudentMapper.xml
-
<? xml version= "1.0" encoding= "UTF-8" ?>
-
<! DOCTYPE mapper
-
< mapper namespace= "com.njupt.mapper.StudentMapper" > <!-- 接口全类名 -->
-
< select id= "getStudentById" resultType= "com.njupt.entities.Student" >
-
select * from student where id=#{id}
-
</ select >
-
</ mapper >
-
-
-
-
让SpringBoot查找到这两个xml文件,需要在application.yml中配置以下两项
-
mybatis:
-
config-location: classpath:mybatis/config/mybatis-config.xml
-
mapper-locations:
-
- classpath:mybatis/mapper/*.xml
-
-
创建操作不同表对应的Mapper接口
-
public interface StudentMapper {
-
public Student getStudentById(Integer id);
-
}
-
-
批量扫描包下的mapper类
-
@ SpringBootApplication
-
@MapperScan(value = "com.njupt.mapper")
-
public class MybatisApplication {
-
public static void main(String[] args) {
-
SpringApplication. run(MybatisApplication. class, args);
-
}
-
}
-
-
编写业务代码
-
@Controller
-
public class StudentController {
-
-
@Autowired
-
private StudentMapper studentMapper;
-
private Logger logger = LoggerFactory. getLogger( this.getClass());
-
-
@RequestMapping( "/getStudentById/{id}")
-
@ResponseBody
-
public Student getStudentById( @PathVariable( "id") Integer id) {
-
logger.info( "enter getStudentById");
-
return studentMapper.getStudentById( id);
-
}
-
}
-
-
测试
-
-
-
12.springboot整合多数据源
-
引入数据源依赖
-
写自定义数据源配置
-
spring: datasource: mybatis-datasource: jdbc-url: jdbc:mysql://192.168.1.103:3306/mybatis?serverTimezone=Asia/Shanghai driver-class-name: com.mysql.cj.jdbc.Driver username: root password: yahang.521 # Hikari connection pool type: com.zaxxer.hikari.HikariDataSource auto-commit: true minimum-idle: 50 maximum-pool-size: 100 pool-name: packageDatasourcePool jdbc-datasource: jdbc-url:jdbc:mysql://192.168.1.103:3306/jdbc?serverTimezone=Asia/Shanghai driver-class-name: com.mysql.cj.jdbc.Driver username:root password: yahang.521 # Hikari connection pool type: com.zaxxer.hikari.HikariDataSource auto-commit: true minimum-idle: 50 maximum-pool-size: 100 pool-name: datailDatasourcePool
-
新建各个数据源的配置类
-
MybatisDBConfiguration.java
-
@Configuration @MapperScan(basePackages = "com.njupt.mappers.mybatisMapper",sqlSessionFactoryRef = "mybatisSqlSessionFactory") public classMybatisDBConfiguration{ @Primary @Bean("mybatisDataSource") @ConfigurationProperties(prefix = "spring.datasource.mybatis-datasource") public DataSource packageDataSource(){ return DataSourceBuilder.create().build(); } @Primary @Bean("mybatisSqlSessionFactory") public SqlSessionFactory mybatisSqlSessionFactory(@Qualifier("mybatisDataSource") DataSource dataSource) throws Exception{ SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/mappers/mybatisMapper/mybatisMapper.xml")); org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); configuration.setMapUnderscoreToCamelCase(true);//开启驼峰 bean.setConfiguration(configuration); return bean.getObject(); } @Primary @Bean("mybatisTransactionManager") public DataSourceTransactionManager mybatisTransactionManager(@Qualifier("mybatisDataSource") DataSource dataSource){ return new DataSourceTransactionManager(dataSource); } @Primary @Bean("mybatisSqlSessionTemplate") public SqlSessionTemplate mybatisSqlSessionTemplate(@Qualifier("mybatisSqlSessionFactory") SqlSessionFactory sqlSessionFactory){ return new SqlSessionTemplate(sqlSessionFactory); } }
-
JDBCDBConfiguration.java
-
@Configuration @MapperScan(basePackages = "com.njupt.mappers.jdbcMapper",sqlSessionFactoryRef = "jdbcSqlSessionFactory") public class JDBCDBConfiguration{ @Bean("jdbcDataSource") @ConfigurationProperties(prefix = "spring.datasource.jdbc-datasource") public DataSource detailDataSource(){ return DataSourceBuilder.create().build(); } @Bean("jdbcSqlSessionFactory") public SqlSessionFactory jdbcSqlSessionFactory(@Qualifier("jdbcDataSource") DataSource dataSource) throws Exception{ SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); configuration.setMapUnderscoreToCamelCase(true); bean.setConfiguration(configuration); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/mappers/jdbcMapper/JDBC1Mapper.xml"),new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/mappers/jdbcMapper/JDBC2Mapper.xml")); return bean.getObject(); } @Bean("jdbcTransactionManager") public DataSourceTransactionManager jdbcTransactionManager(@Qualifier("jdbcDataSource") DataSource dataSource){ return new DataSourceTransactionManager(dataSource); } @Bean("jdbcSqlSessionTemplate") public SqlSessionTemplate jdbcSqlSessionTemplate(@Qualifier("jdbcSqlSessionFactory") SqlSessionFactory sqlSessionFactory){ return new SqlSessionTemplate(sqlSessionFactory); } }
-
正常使用Mapper执行对应方法即可
-
12.SpringBoot整合redis
-
RedisTemplate和StringRedisTemplate
-
RedisTemplate放的key和value是对象,因此放入的对象需要实现序列化接口
-
StringRedisTemplate放的key和value是String
-
-
使用@AutowiredStringRedisTemplate stringRedisTemplate ;@Testvoid contextLoads() {stringRedisTemplate .opsForValue().set( "key" , "value" );}
-
引入依赖
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-data-redis</artifactId>
-
<version>2.2.5.RELEASE</version>
-
</dependency>
-
配置配置文件
-
spring.redis.host=192.168.1.100
-
spring.redis.port=6379
-
spring.redis.database=0
-
-
操作数据库
-
-
相关操作
-
操作key
-
stringRedisTemplate.delete("key"):删除key
-
stringRedisTemplate .hasKey("key"):是否存在key
-
stringRedisTemplate .type("key"):key的类型
-
stringRedisTemplate .keys("*"):返回所有key
-
stringRedisTemplate .getExpire( "key" ):获取key的超时时间。-1:永不超时,-2:key不存在,>=0:过期时间
-
-
opsForValue:操作字符串
-
set("key","value");设置key,value
-
set( "key" , "value" , 60 , TimeUnit. SECONDS );设置超时时间
-
-
opsForHash:操作散列表
-
opsForList:操作List
-
opsForSet:操作Set
-
opsForZset:操作ZSet
-
-
bound Api
-
由于opsForXX的每次操作都要输入一个key,当我们后续操作都对同一个key进行的操作,可以使用boundApi,绑定key
-
示例代码
-
BoundValueOperations<String,String> boundValueOperations = stringRedisTemplate.boundValueOps( "key");
-
boundValueOperations.get()
-
-
boundValueOps():绑定一个字符串
-
boundHashOps():绑定散列表
-
boundListOps():绑定List
-
boundSetOps():绑定Set
-
boundZSetOps():绑定ZSet
-
-
经常使用RedisTemplate,可以更改RedisTemplate的序列化器,默认是jdk序列化,我们改为Json序列化
-
@Bean
-
public RedisTemplate<Object, Object> redisTemplateWithJson(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
-
RedisTemplate<Object, Object> template = new RedisTemplate<>();
-
template.setConnectionFactory(redisConnectionFactory);
-
RedisSerializer<Person> redisSerializer = new Jackson2JsonRedisSerializer<Person>(Person. class );
-
template.setDefaultSerializer(redisSerializer);
-
return template;
-
-
}
-
13.Springboot缓存
-
Spring缓存抽象
-
重要概念以及缓存注解
-
Cache:缓存接口,定义缓存操作,实现又:RedisCache,EhCacheCache,ConcurrentMapCache等
-
CacheManager:缓存管理器,管理各种缓存组件
-
@Cacheable:修饰方法,能够根据方法的请求参数和返回结果进行缓存
-
@CacheEvict:修饰方法,清空缓存,例如从数据库删除某个用户,那就需要把相应的缓存也删除掉
-
@CachePut:修饰方法,调用函数,更新缓存
-
@Cacheable一旦缓存命中,就不再调用修饰的函数了
-
@CachePut一定会调用函数,并把值放到缓存,常用于更新操作,先调用函数,在更新缓存
-
-
@EnableCaching:开启基于注解的缓存模式
-
keyGenerator:缓存数据时key的生成策略
-
serialize:缓存数据时value序列化策略
-
-
搭建环境
-
引入包
-
< dependency>
-
< groupId > org.springframework.boot </ groupId >
-
< artifactId > spring-boot-starter-cache </ artifactId >
-
</ dependency >
-
-
使用缓存@Cacheablepublic String getUser( int id){System. out .println( " 缓存未命中 " );return "zhangsan" ;}
-
开启基于注解的缓存
-
-
使用缓存
-
-
-
@Cacheable@Caching(cacheable={ @Cacheable (), @Cacheable ()},put={},evict = {})
-
属性
-
cacheNames/value :数组,缓存名字,因为缓存管理器下有许多缓存,所以这个指定从哪个缓存中查找数据,或者将数据存入哪个缓存中,可以将一份数据存到多个缓存
-
@Cacheable(cacheNames="emp")
-
-
key:存缓存或者查找缓存value时用的键,支持spel表达式。默认key为参数的值
-
-
@Cacheable的key不能用#result
-
-
keyGenerator:key的生成器,可以指定key生成器的组件id,key和 keyGenerator两个属性二选一@Configurationpublic class CacheAutoConfiguration{@Bean ( "myKeyGenerator" )public KeyGenerator keyGenerator(){return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {return "hahaha" ;}}}}
-
自定义 keyGenerator
-
使用自定义的 keyGenerator
-
@Cacheable (cacheNames = "emp" , keyGenerator = "myKeyGenerator" )
-
-
-
cacheManager:指定从哪个缓存管理器中拿到缓存,
-
cacheResolver:指定寻找 cacheManager的策略, cacheResolver与 cacheManager二选一
-
condition:可以使用spel表达式,满足条件才缓存
-
unless:满足unless条件,则不缓存,可以获取到结果进行判断
-
@Cacheable(unless="#result == null")
-
-
sync:是否使用异步模式,默认false.意思是。在put数据时,是异步还是同步
-
-
原理
-
自动配置类: CacheAutoConfiguration
-
Import选择器: CacheConfigurationImportSelector
-
org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
-
org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
-
org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
-
org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
-
org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
-
org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
-
org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
-
org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
-
org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration
-
org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
-
-
哪个配置生效呢?
-
每个CacheConfiguration上面都用注解标识了生效条件
-
SimpleCacheConfiguration这个有可能生效
-
-
SimpleCacheConfiguration给容器中注入了一个CacheManager( ConcurrentMapCacheManager)的bean
-
ConcurrentMapCacheManager维护了一个Map<String, ConcurrentMapCache>,String为缓存的名字
-
-
ConcurrentMapCacheManager可以获取和创建 ConcurrentMapCache组件,并将数据放到 ConcurrentMapCache中
-
ConcurrentMapCache就是一个类,属性有name和 ConcurrentMap
-
-
整个流程
-
-
-
@CachePut
-
先调用函数在更新缓存
-
注意点
-
@Cacheable添加缓存
-
@Cacheable(cacheNames = "emp", keyGenerator = "myKeyGenerator")
-
public String getUser( int id){
-
-
@ CachePut添加缓存
-
@CachePut (cacheNames = "emp" )
-
public Employee update(Employee emp){
-
-
这两个缓存的key的生成可能不一杨,可能会导致他们更新的缓存原本应该是同一个,但是却由于生成key不一样,导致缓存更新错误
-
-
-
@CacheEvict
-
key:指定要清除的key
-
allEntries=true:清除缓存中的所有数据,默认false
-
beforeInvocation=true:实在方法执行之前清除缓存,还是在方法执行之后清除缓存,默认为false,
-
如果在方法执行之后清除缓存,一旦方法出现异常,那么缓存不会被清除
-
-
-
@Caching可以使用组合注解
-
@CacheConfig修饰类,可以将 Cacheable, CachePut, CacheEvict的公共属性提取出来
-
-
-
整合redis使用缓存
-
引入依赖
-
<!-- springboot整合redis的starter- ->
-
< dependency>
-
< groupId > org.springframework.boot </ groupId >
-
< artifactId > spring-boot-starter-data-redis </ artifactId >
-
</ dependency >
-
<!-- redis如果要使用连接池技术,需要依赖这个包- ->
-
< dependency >
-
< artifactId > commons-pool2 </ artifactId >
-
</ dependency >
-
<!-- 由于我们需要更改对象序列化为json存到redis中,需要这个包 -->
-
< dependency >
-
< groupId > com.fasterxml.jackson.core </ groupId >
-
< artifactId > jackson-core </ artifactId >
-
< version > 2.9.8 </ version >
-
</ dependency >
-
<!-- 从redis读取数据,反序列化为对象时,绑定数据需要这个包 -->
-
< dependency >
-
< groupId > com.fasterxml.jackson.core </ groupId >
-
< artifactId > jackson-databind </ artifactId >
-
< version > 2.9.8 </ version >
-
</ dependency >
-
-
配置redis连接池
-
spring:
-
redis :
-
host : 127.0.0.1
-
port : 6379
-
database : 0
-
lettuce :
-
pool :
-
# 连接池最大连接数 默认 8 ,负数表示没有限制
-
max-active : 20
-
# 连接池中的最大空闲连接 默认 8
-
max-idle : 10
-
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
-
max-wait : 1000
-
-
-
timeout : 10000
-
-
-
-
修改cacheManager的默认配置
-
public CacheManager cacheManager(LettuceConnectionFactory redisConnectionFactory) {// 初始化一个 RedisCacheWriterRedisCacheWriter redisCacheWriter = RedisCacheWriter. nonLockingRedisCacheWriter (redisConnectionFactory);// 设置 CacheManager 的值序列化方式为 json 序列化Jackson2JsonRedisSerializer<Person> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Person. class );RedisSerializationContext.SerializationPair<Person> pair = RedisSerializationContext.SerializationPair. fromSerializer (jackson2JsonRedisSerializer);RedisCacheConfiguration defaultCacheConfig= RedisCacheConfiguration. defaultCacheConfig ().serializeValuesWith(pair).entryTtl(Duration. ofSeconds ( 30 )) // 设置默认超过期时间是 30 秒.disableCachingNullValues();// 初始化 RedisCacheManagerreturn new RedisCacheManager(redisCacheWriter, defaultCacheConfig);}
-
使用注解即可
-
开启缓存@EnableCaching
-
在相应方法上添加注解
-
@Cacheable(cacheNames = "statuschecker")
-
public Person request( int id){
-
System. out .println( "Cache 未命中 " );
-
return new Person( "www" , 24 );
-
-
}
-
-
-
13.SpringData统一数据库交互
13.Springboot整合线程池
-
添加线程池bean
-
@Beanpublic TaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();// 设置核心线程数executor.setCorePoolSize( 5 );// 设置最大线程数executor.setMaxPoolSize( 10 );// 设置队列容量executor.setQueueCapacity( 20 );// 设置线程活跃时间(秒)executor.setKeepAliveSeconds( 60 );// 设置默认线程名称executor.setThreadNamePrefix( "hello-" );// 设置拒绝策略executor.setRejectedExecutionHandler( new ThreadPoolExecutor.CallerRunsPolicy());// 等待所有任务结束后再关闭线程池executor.setWaitForTasksToCompleteOnShutdown( true );return executor;}
-
开启异步调用
-
@Configuration
-
@EnableAsync
-
public class BeanConfig {
-
-
在需要异步调用的方法添加注解
-
@Async( "taskExecutor")//里面的字符串表示使用哪个线程池
-
public List<Student> queryStudentByPage(){
-
-
使用异步调用
-
@SpringBootApplication@MapperScan ( "com.njupt.mybatis.mappers" )public class MybatisApplication implements CommandLineRunner {@Autowiredprivate MyService myService ;@Autowiredprivate ThreadPoolTaskExecutor taskExecutor ;public static void main(String[] args) {SpringApplication. run (MybatisApplication. class , args);}@Overridepublic void run(String... args) throws Exception {System. out .println( " 主线程 : " +Thread. currentThread ().getName());System. out .println( "hahah" );myService .queryStudentByPage();System. out .println( " 主线程结束 " );taskExecutor .shutdown()//虽然我们关闭了线程池,但是线程池还是会把任务执行完毕在关掉}}
-
注意事项
-
@SpringbootTest修饰的类,主线程停止,子线程也会停止,因为 Juint跑完主线程的逻辑后就把整个JVM都关掉了
-
14.Springboot整合RabbitMQ
-
引入依赖
-
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
-
自定义消息转换器
-
public class MyMessageConvert implements MessageConverter { @Override public Message toMessage(Object o, MessageProperties messageProperties) throws MessageConversionException { messageProperties.setContentType("application/json"); messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT); Message message=null; try { message = new Message(o.toString().getBytes("UTF-8"),messageProperties); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return message; } @Override public Object fromMessage(Message message) throws MessageConversionException { return null; } }
-
配置Properties
-
spring:myrabbitmq :host : 192.168.0.104port : 5672username : guestpassword : guestvirtual-host : /channel-cache-size : 10channel-time-out : 1000@ConfigurationProperties (prefix = "spring.myrabbitmq" )public class RabbitMQProperties {private String host ;private int port ;private String username ;private String password ;private String virtualHost ;private int channelCacheSize ;private Long channelTimeOut ;
-
配置bean
-
@Configuration @EnableConfigurationProperties({RabbitMQProperties.class}) public class RabbitMQAutoConfig { @Autowired RabbitMQProperties rabbitMQProperties; @Bean("connectionFactory") public ConnectionFactory connectionFactory() { CachingConnectionFactory connectionFactory = new CachingConnectionFactory(rabbitMQProperties.getHost(), rabbitMQProperties.getPort()); connectionFactory.setUsername(rabbitMQProperties.getUsername()); connectionFactory.setPassword(rabbitMQProperties.getPassword()); connectionFactory.setVirtualHost(rabbitMQProperties.getVirtualHost()); connectionFactory.setCacheMode(CachingConnectionFactory.CacheMode.CHANNEL); connectionFactory.setChannelCacheSize(rabbitMQProperties.getChannelCacheSize()); connectionFactory.setChannelCheckoutTimeout(rabbitMQProperties.getChannelTimeOut()); return connectionFactory; } @Bean public RabbitAdmin rabbitAdmin(@Qualifier("connectionFactory") ConnectionFactory connectionFactory){ RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory); TopicExchange topicExchange = new TopicExchange("topic",true,false,null); rabbitAdmin.declareExchange(topicExchange); Queue queue = new Queue("queue",true,false,false,null); rabbitAdmin.declareQueue(queue); Binding binding = new Binding("queue", Binding.DestinationType.QUEUE,"topic","aha",null); rabbitAdmin.declareBinding(binding); return rabbitAdmin; } @Bean public RabbitTemplate rabbitTemplate(@Qualifier("connectionFactory") ConnectionFactory connectionFactory) { RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); rabbitTemplate.setMessageConverter(new MyMessageConvert()); return rabbitTemplate; } }
-
使用
-
@Override public void run(String... args) throws Exception { rabbitTemplate.convertAndSend("topic","aha",new String("Hello World")); connectionFactory.destroy();//如果不销毁ConnectionFactory,那么Connection不会断开,Springboot项目会一直委会这该Connection,导致项目运行无法结束。 }
14.自定义启动器
-
新建maven工程yahang-spring-boot-starter (starter是一个空JAR包,仅仅作为maven下载jar包的启动器)
-
新建maven工程yahang-spring-boot-starter-autoconfigure (实际工作的模块)
-
yahang-spring-boot-starter作为一个启动器,设置依赖于yahang-spring-boot-starter-autoconfigure
-
<dependency> <groupId>com.njupt</groupId> <artifactId>yahang-spring-boot-starter-autoconfigure</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
-
yahang-spring-boot-starter-autoconfigure模块下,设置依赖于spring-boot-starter
-
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.3.0.RELEASE</version> </dependency>
-
yahang-spring-boot-starter-autoconfigure模块下,新建包com.njupt,然后新建一个实体类,该实体类为要配置为bean的类
-
public class MyDataSource {
-
public String url;
-
public String username;
-
public String password;
-
public MyDataSource(String url, String username, String password) {
-
super();
-
this. url = url;
-
this. username = username;
-
this. password = password;
-
}
-
}
-
-
yahang-spring-boot-starter-autoconfigure模块下的com.njupt包下,然后新建一个MyDataSourceProperties类,该实体类为读取yml文件的类,并设置getter,setter方法。
-
@ConfigurationProperties(prefix = "yahang.mydatasource")
-
public class MyDataSourceProperties {
-
private String url;
-
private String username;
-
private String password;
-
-
yahang-spring-boot-starter-autoconfigure模块下的com.njupt包下,然后新建一个MyDataSourceAutoConfigure类,该类使用MyDataSourceProperties对象的属性,new MyDataSource对象,并注入为Bean
-
@Configuration
-
@ConditionalOnWebApplication
-
@EnableConfigurationProperties(MyDataSourceProperties. class)
-
public class MyDataSourceAutoConfigure {
-
-
@Autowired
-
private MyDataSourceProperties myDataSourceProperties;
-
-
@ Bean
-
public MyDataSource getDataSource() {
-
String url= myDataSourceProperties.getUrl();
-
String username= myDataSourceProperties.getUsername();
-
String password= myDataSourceProperties.getPassword();
-
return new MyDataSource( url, username, password);
-
}
-
}
-
-
为了让Springboot加载MyDataSourceAutoConfigure,需要在resources目录下新建META-INF/spring.factories
-
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-
com.njupt.MyDataSourceAutoConfigure
-
-
使用maven install 安装autoconfigure和starter模块。
-
测试< dependency >< groupId >com.njupt </ groupId >< artifactId >yahang-spring-boot-starter </ artifactId >< version >0.0.1-SNAPSHOT </ version ></ dependency >
-
新建Springboot的web应用,pom文件引入自定义的starter
-
编写application.yml
-
yahang:
-
mydatasource:
-
url: localhaost
-
username: yahang
-
password: 123456
-
-
编写测试代码
-
@Controller
-
public class MyController {
-
-
@Autowired
-
private MyDataSource dataSource;
-
@ResponseBody
-
@RequestMapping( "/test")
-
public String getDatasource() {
-
return dataSource. url+ " : "+ dataSource. username+ " : "+ dataSource. password;
-
}
-
}
-
-
测试
-
-
15.SpringBoot对事务的支持
-
使用事务的步骤
-
第一步在启动类上开启事务
-
-
提示:@EnableTransactionManagement注解其实在大多数情况下,不是必须的,因为SpringBoot在TransactionAutoConfiguration类里为我们自动配置启用了@EnableTransactionManagement注解。不过自动启用该注解有两个前提条件,分别是:@ConditionalOnBean(PlatformTransactionManager.class)和@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class),而一般情况下,这两个条件都是满足的,所以一般的,我们在启动类上写不写@EnableTransactionManagement都行。
-
-
在相关方法上使用注解
-
-
-
Transactional注解常用属性
-
-
isolation:隔离级别,默认值采用DEFAULT
-
propagation:传播行为,默认值采用REQUIRED
-
timeout:事务超时时间,默认为-1.即永不超时,如果超时,就回滚事务
-
readOnly:只读事务,默认false
-
rollbackFor: 用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。{xxx1.class, xxx2.class,……}
-
noRollbackFor: 出 no-rollback-for 指定的异常类型,不回滚事务。{xxx1.class, xxx2.class,……}
-
-
事务的传播行为
-
TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
-
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
-
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
-
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
-
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
-
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
-
TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
-
-
注意事项
-
service实现类(一般不建议在接口上)上添加@Transactional,可以将整个类纳入spring事务管理,在每个业务方法执行时都会开启一个事务,这些事务采用相同的管理方式。
-
Transactional 注解只能应用到 public 可见度的方法上。 如果应用在protected、private或者 package可见度的方法上,也不会报错,不过事务设置不会起作用。
-
默认情况下,Transactional 注解的事物所管理的方法中,如果方法抛出运行时异常或error,那么会进行事务回滚;如果方法抛出的是非运行时异常,那么不会回滚。
-
SQL异常属于检查异常(有的框架将SQL异常重写为了运行时异常),但是有时我们写SQL时,检查异常并不会提示;而默认情况下,事物对检查异常不会作出回滚处理。
-
在很多时候,我们除了catch一般的异常或自定义异常外,我们还习惯于catch住Exception异常;然后再抛出Exception异常。但是Exception异常属于非运行时异常(即:检查异常),因为默认是运行时异常时事物才进行回滚,那么这种情况下,是不会回滚的。我们可以在@Transacional注解中,通过rollbackFor = {Exception.class} 来解决这个问题。即:设置当Exception异常或Exception的所有任意子类异常时事物会进行回滚。
-
-
-
-
被catch处理了的异常,不会被事物作为判断依据;如果异常被catch 了,但是又在catch中抛出了新的异常,那么事物会以这个新的异常作 为是否进行回滚的判断依据。
-