一.springboot与缓存
spring 缓存抽象
1.几个重要概念&缓存注解
概念/注解 | 解释说明 |
---|---|
Cache | 缓存接口,定义缓存操作。实现有RedisCache,EhCache,ConcurrentMapCache等 |
CacheManager | 缓存管理器,管理各种缓存组件 |
@Cacheable | 主要针对方法配置,能根据方法的请求参数对其结果进行缓存 |
@CacheEvict | 清空缓存 |
@CachePut | 保证方法被调用,又希望结果被缓存 |
@EnableCaching | 开启基于注解的缓存 |
keyGenerator | 缓存数据的时候,key的生成策略 |
serialize | 缓存数据时,value的生成策略 |
2.快速体验缓存
步骤:
1.开启基于注解的缓存 @EnableCaching
@MapperScan("com.pt.cache.mapper")
@SpringBootApplication
@EnableCaching
public class CacheApplication {
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class, args);
}
}
2.在方法上标注缓存注解 @Cacheable即可
@Service
public class UserService {
@Autowired
UserMapper userMapper;
@Cacheable
public User getUserById(Integer id){
User user= userMapper.getUserById(id);
return user;
}
}
3.说明
将方法的运行结果进行缓存,以后再要相同的数据,直接从缓存中获取,不调用方法。
CacheManager管理多个Cache.对缓存的正常curd操作在cache组件中,每一个缓存组件有自己唯一的名字。
4. @Cacheable
几个属性:
cacheNames/value : 指定缓存的名字
key:缓存数据使用的key。可以用它来指定,默认是使用方法参数的值
keyGenerator:key的生成器,可以自己指定生成器。(和key二选一)
cacheManager :指定缓存管理器
condition:指定符合条件的情况下才缓存
unless 是否缓存;当unless指定的条件为true,方法的返回值就不会被缓存
运行流程
@Cacheable:
1.方法运行之前,先去查询Cache (缓存组件),按照cacheNames指定的名字获取;(CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建
2.去Cache中查找缓存内容,使用一个key(默认就是方法的参数);
key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用SimplekeyGenerator生成。
SimplekeyGenerator生成策略:
如果方法没有参数,key=new SimpleKey() 如果有一个参数,key=参数值
如果有多个参数,key=new SimpleKey(parms …)
3.没有查到缓存就是调用方法
4.将目标方法的返回值放入缓存中
5.原理
1.自动配置类 CacheAutoConfiguration
2.缓存的配置类,会有一堆缓存配置类
3.哪个配置类默认生效?SimpleCacheConfiguration
4.给容器中注册了一个CacheManager
5.可以获取和创建一个ConcurrentMapCacheManager类型的缓存组件,他的作用是将数据保存到ConcurrentMap中
核心:
1.CacheManager [ ConcurrentMapCacheManager] 按照名字得到Cache【ConcurrentMapCache】组件
2.key是使用keyGenerator生成的。默认是SimplekeyGenerator
6.@CachePut 缓存更新
@CachePut 即调用方法,又更新数据库
修改数据库的某个数据,同时更新缓存
运行时机:
1.先调用目标方法
2.将目标方法的结果缓存起来
7.@CacheEvict 缓存清除
一般使用在删除的时候,用来清空缓存的
属性:
key 可以指定删除的缓存的id
allEntries = true 是否删除全部缓存,默认false
beforeInvocation = false 缓存的清除是否在方法之前执行。默认方法执行之后执行,如果方法出错了的话,就不会清空缓存了。
8.@Caching 定义复杂缓存规则
@Cacheable,@CachePut @CacheEvict 的混合注解。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Caching {
Cacheable[] cacheable() default {};
CachePut[] put() default {};
CacheEvict[] evict() default {};
}
使用
@Caching(
cacheable = {@Cacheable(value = "user",key = "#userName")},
put = {@CachePut(value = "user",key = "#result.id"),
@CachePut(value = "user",key = "#result.passWord")
}
)
public User getUserById(Integer id){
User user= userMapper.getUserById(id);
return user;
}
9.CacheConfig
写在类上,可以指定公共的cache属性
@CacheConfig(cacheNames = "user")
@Service
public class UserService {
公共配置过的,后面的Cache可以不用配置了
10.redis 缓存
1.安装redis,可以作为数据库,缓存,消息中间件
docker中
docker pull redis
2.引入redis的starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
3.配置redis
spring.redis.host=主机地址
@Autowired
StringRedisTemplate stringRedisTemplate; //操作k-v都是字符串
@Autowired
RedisTemplate redisTemplate; //k-v都是对象
@Autowired
RedisTemplate<Object,User> userRedisTemplate; //自定义RedisTemplate
/**
*Redis常见的五大数据类型
* String(字符串),List(列表),Set(集合),Hash(散列),ZSet(有序集合)
* StringRedisTemplate.opsForValue() 作用于String(字符串)
* stringRedisTemplate.opsForList() 作用于List
* ...
*/
public void test(){
stringRedisTemplate.opsForValue().append("msg","hello");
String msg = stringRedisTemplate.opsForValue().get("msg");
}
public void test2(){
User user = new User(1, "uname", "pwd");
//保存对象的话,默认使用jdk序列化机制,序列化后保存到redis中
// redisTemplate.opsForValue().set("user",user);
//如果不想用默认的,可以以转换为json格式保存
//方法1:自己转换为json
//方法2:自定义redisTemplate默认的序列化规则
userRedisTemplate.opsForValue().set("user01",user);
}
//方法2:自定义redisTemplate默认的序列化规则
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<Object, User> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object,User> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer<User> userJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<User>(User.class);
template.setDefaultSerializer(userJackson2JsonRedisSerializer);
return template;
}
}
二.springboot与消息队列
一些概念
1.消息服务中有两个重要概念:
消息代理(message broker)== 和 目的地(destination)
当消息发送者发送消息的时候,将由消息代理接管,消息代理保证消息传递到指定目的地。
2.消息队列主要有两种形式的目的地
1.队列(queue) :点对点消息通信(point-to-point)
2.主题(topic):发布(publish)/订阅(subscribe)消息通信
3.点对点式:
消息发送者发送消息到队列中,消息接收者从队列中获取消息,获取后消息从队列中移除。
消息有唯一的发送者,有多个接受者,有唯一的接收者。就是说,可以多个接受者来拿消息,但只有一个能拿到。
4.发布订阅式:
发送者(发布者)发送消息到主题,可以有多个接收者(订阅者)监听(订阅)这个主题,那么就会在消息到达的时候,同时接收到消息。
5.JMS(java message service) java消息服务
基于JVM的消息代理规范。如,ActiveMQ,HornetMQ就是JMS实现
6.AMQP(advianced message queuing protocol)
高级消息队列,也是一个消息代理的规范,兼容JMS
如,RabbitMQ就是AMQP实现
JMS | AMQP | 比较 |
---|---|---|
java api | 网络线级协议 | 定义 |
否,java | 是 | 跨语言 |
否 | 是 | 夸平台 |
提供两种:1 .peer-2-peer 点对点 2.pub/sub 发布/订阅 | 提供五种,第一种也是点对点,后面四种和 pub/sub没什么区别,但是在路由机制上做了更详细的规划 | Model |
TextMessage,MapMessage, BytesMessage, StreamMessasge, ObjectMessage, Message(只有消息头和属性) | byte[] | 支持消息类型 |
7.Spring的支持
1.spring-jms 提供对JMS的支持
2.spring-rabbit 提供对AMQP的支持
3.需要ConnectionFactory的实现来连接消息代理
4.提供JmsTemplate,RabbitTemplate来发送消息
5.@JmsListener 和 @RabbitListener 注解在方法上监听消息代理发布消息
6.@EnableJms,@EnableRabbit 开启支持
8.SpringBoot自动配置
JmsAutoConfiguration
RabbitAutoConfiguration
RabbitMQ
核心概念
1.Message 消息
2.Publisher 消息的生产者,
3.Exchange 交换器
4.Queue 消息队列
5.Binding 绑定
6.Connection 网络连接
7.Channel 信道
8.Consumer 消息的消费者
9.Virtual Host 虚拟主机,表示一批交换机,消息队列和相关对象。
10.Broker 表示消息队列服务器实体
rabbit与springboot整合与使用
pom.xml引入rabbitmq
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
application配置文件中配置rabbitmq基本属性
spring.rabbitmq.host=主机地址
#默认用户密码guest
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
来到UserService
@Service
public class UserService {
@Autowired
RabbitTemplate rabbitTemplate;
//单播
public void test3(){
//需要定义一个Message
//rabbitTemplate.send(exchange,routeKey,message);
//值需要传递要发送的对象,自动序列化,默认java方式序列化,可以自定义配置类修改
//rabbitTemplate.convertAndSend(exchange,routeKey,Object);
//交换器名字
String exchange="exchange.direct";
//路由键的名字
String routeKey="pt.news";
Map<String,Object> map = new HashMap<>();
map.put("msg","第一个");
map.put("data","第二个");
rabbitTemplate.convertAndSend(exchange,routeKey,map);
//接收消息
Object o = rabbitTemplate.receiveAndConvert("pt.mews");
}
//广播
public void test4(){
//不需要指定key了
rabbitTemplate.convertAndSend("exchange.fanout","","object");
}
}
实用消息监听
监听Queue或Binding,当有消息的时候,就会调用这个方法
@RabbitListener(queues = "pt.news")
public void test5(User user){
System.out.println("pt.news收到消息,就会调用这个方法"+user);
}
要使用@RabbitListener注解,还需要开启注解支持
@EnableRabbit
public class CacheApplication {
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class, args);
}
}
@AmqpAdmin : RabbitMQ系统管理功能组件
创建和删除Queue,Exchange,Binding
@Autowired
AmqpAdmin amqpAdmin;
public void test6(){
amqpAdmin.declareExchange(new DirectExchange("abc.exchange"));
System.out.println("创建exahnge完成");
//创建Binding规则
amqpAdmin.declareBinding(new Binding("abc.queue",Binding.DestinationType.QUEUE,"abc.exchange","abc.key",null));
//删除
amqpAdmin.deleteExchange("abc.exchange");
}
三.springboot与检索
ElasticSearch
ElasticSearch是分布式搜索服务,提供Restful API,底层基于lucen.
springboot整合ElasticSearch
导入pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
写Repository继承ElasticsearchRepository
public interface UserRepository extends ElasticsearchRepository<User,Integer> {
List<User> findByUserNameLike(String UserName);
}
配置文件中指定基本信息
spring.elasticsearch.rest.uris=127.0.0.1:9300
spring.elasticsearch.rest.username=elasticsearch
实体类得加上@Document
@Document(indexName = "pt")
public class User {
service中就可以使用了
@Autowired
UserRepository userRepository;
public void test7(){
User user=new User(1,"123","abc");
for (User u : userRepository.findByUserNameLike("1")){
System.out.println(u);
}
}
docker 安装ElasticSearch
安装的时候看一下Springboot对应的版本
docker pull elasticsearch:7.9.3
docker images后查看到容器id
docker images
docker 启动 运行 ElasticSearch
因为默认启动得2G,所以需要设置一下内存
并且加上-e “discovery.type=single-node”
docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -e “discovery.type=single-node” -d -p 9201:9200 -p 9301:9300 --name ES02 a7e1d4b5ee81
四.springboot与任务
1.异步任务
启动类上添加@EnableAsync,开启异步
@EnableAsync
public class CacheApplication {
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class, args);
}
}
方法上添加@Async,表示这个是一个异步方法,不会影响主线程
@Async
public void test08(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("处理数据...");
}
2.定时任务
基本使用
启动类添加@EnableScheduling上开启定时任务的注解
@EnableScheduling
public class CacheApplication {
方法上添加 @Scheduled 表示定时任务,按照cron上的规则执行
//cron: 秒,分,时,day of month,month,day of week
//如: 0 * * * * MON-FRI 周一到周五每一分钟运行一次
//*表示任意时刻
@Scheduled(cron = "0 * * * * MON-FRI")
public void test09(){
System.out.println("定时任务运行了一次");
}
cron表达式:
字段 | 允许值 | 允许的特殊符号 |
---|---|---|
秒 | 0-59 | ,-*/ |
分 | 0-59 | ,-*/ |
小时 | 0-23 | ,-*/ |
日期 | 1-31 | ,-*/?LWC |
月份 | 1-12 | ,-*/ |
星期 | 0-7或者SUN-SAT 0,7是SUN | ,-*/?LC# |
特殊符号:
符号 | 意义 |
---|---|
, | 枚举 |
- | 区间 |
* | 任意 |
/ | 步长 |
? | 日/星期冲突匹配 |
L | 最后 |
W | 工作日 |
C | 和calendar联系后计算过的值 |
# | 星期,4#2,第二个星期四 |
3.邮件任务
导入pom.xml的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
配置一些基本信息
spring.mail.username=1111111@qq.com
spring.mail.password=授权码
spring.mail.host=smtp.qq.com
#安全连接
spring.mail.properties.mail.smtp.ssl.enable=true
授权码的获取,到qq邮箱中获取
简单的邮件发送
@Autowired
JavaMailSenderImpl javaMailSender;
public void test010(){
SimpleMailMessage mailMessage=new SimpleMailMessage();
//邮件设置
mailMessage.setSubject("通知-今晚开会");
mailMessage.setText("晚上7.30开会");
mailMessage.setTo("sqdpt666@163.com");
mailMessage.setFrom("2624890652@qq.com");
javaMailSender.send(mailMessage);
}
带附件的邮件发送
//带附件的邮件发送
public void test011() throws MessagingException {
MimeMessage mimeMessage=javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setSubject("通知-今晚开会");
//后面为true表示发送的是html,默认为false
helper.setText("<h1>730kaihui</h1>",true);
helper.setTo("sqdpt666@163.com");
helper.setFrom("2624890652@qq.com");
helper.addAttachment("1.jpg",new File("D:\\1.jpg"));
javaMailSender.send(mimeMessage);
}