SpringBoot进阶:缓存(redis)、MQ(rabbitmq)

目录

Table of Contents

一、SpringBoot与缓存

1.JSR-107(Java缓存规范):CachingProvider、CacheManager、Cache、Entry、Expiry

2.Spring缓存抽象

二、缓存(redis)

三、MQ(rabbitmq)

1.mq核心概念

2.RabbitMQ简介

一、SpringBoot与缓存

大纲:JSR-107(底层了解)、Spring缓存抽象(掌握)、整合Redis(熟练)

1.JSR-107(Java缓存规范):CachingProvider、CacheManager、Cache、EntryExpiry

CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可以在运行期访问多个CachingProvider。

CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。

Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。

Entry是一个存储在Cache中的key-value对。

Expiry 每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。

2.Spring缓存抽象

Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们开发;

Cache接口为缓存的组件规范定义,包含缓存的各种操作集合

Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache , ConcurrentMapCache等

每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取

使用Spring缓存抽象时我们需要关注以下两点;
1、确定方法需要被缓存以及他们的缓存策略
2、从缓存中读取之前缓存存储的数据

2)几个常用的缓存注解(划重点)

@Cacheable

主要针对方法配置,能够根据方法的请求参数对其结果进行缓存

@CacheEvict

清空缓存

@CachePut

保证方法被调用,又希望结果被缓存。

@EnableCaching

开启基于注解的缓存

其他keyGenerator(缓存数据时key生成策略),serialize(缓存数据时value序列化策略)

@Cacheable/@CachePut/@CacheEvict 主要的参数(公有属性)

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

例如:
@Cacheable(value=”mycache”) 或者 
@Cacheable(value={”cache1”,”cache2”}

key

 

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

例如:
@Cacheable(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存/清除缓存,在调用方法之前之后都能判断

例如:
@Cacheable(value=”testcache”,condition=”#userName.length()>2”)

allEntries

(@CacheEvict )

是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存

例如:
@CachEvict(value=”testcache”,allEntries=true)

beforeInvocation

(@CacheEvict)

是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存

例如:

@CachEvict(value=”testcache”beforeInvocation=true)

unless

(@CachePut)

(@Cacheable)

用于否决缓存的,不像condition,该表达式只在方法执行之后判断,此时可以拿到返回值result进行判断。条件为true不会缓存,fasle才缓存

例如:
@Cacheable(value=”testcache”,unless=”#result == null”)

缓存中使用SPEL表达式

 

@Cacheable缓存目标对象

开启:    
    1、开启基于注解的缓存 @EnableCaching(在启动类上开启)
    2、标注缓存注解即可@Cacheable、@CacheEvict、@CachePut

使用:
    @Cacheable(value = "sysDataPage")
    public PageInfo<SysData> findPage(Integer start, Integer size) {

解析:将方法的运行结果进行缓存;以后再要相同的数据,直接从缓存中获取,不用调用方法;

原理:
    1.自动配置类;CacheAutoConfiguration
    2.缓存的配置类:默认SimpleCacheConfiguration
    3.给容器中注册了一个CacheManager:ConcurrentMapCacheManager
    4.以获取和创建ConcurrentMapCache类型的缓存组件;他的作用将数据保存在ConcurrentMap中;

运行流程:
    @Cacheable:
     1、方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;
       (CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建。
     2、去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;
        key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成key;
           SimpleKeyGenerator生成key的默认策略;
                   如果没有参数;key=new SimpleKey();
                   如果有一个参数:key=参数的值
                   如果有多个参数:key=new SimpleKey(params);
     3、没有查到缓存就调用目标方法;
     4、将目标方法返回的结果,放进缓存中
 
     @Cacheable标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,
     如果没有就运行方法并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据;

属性:
     cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
     
     key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值  1-方法的返回值
          编写SpEL; #i d;参数id的值   #a0  #p0  #root.args[0]
          getEmp[2]
     
     keyGenerator:key的生成器;可以自己指定key的生成器的组件id
          key/keyGenerator:二选一使用;
     
     cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器
     
     condition:指定符合条件的情况下才缓存;
         ,condition = "#id>0"
         condition = "#a0>1":第一个参数的值》1的时候才进行缓存
     
     unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
         unless = "#result == null"
         unless = "#a0==2":如果第一个参数的值是2,结果不缓存;
     sync:是否使用异步模式

@CacheEvict清空指定缓存

@CacheEvict(value="sysDataPage",beforeInvocation = true)

@CacheEvict(value = "sysDataPage", allEntries = true)

属性:
    key:指定要清除的数据
    allEntries = true:指定清除这个缓存中所有的数据
    beforeInvocation = false:缓存的清除是否在方法之前执行
       默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除

    beforeInvocation = true:
       代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除

@CachePut更新缓存

 @CachePut(value = "sysDataPage", key = "#result.id")

作用:
    既调用方法,又更新缓存数据;同步更新缓存
    修改了数据库的某个数据,同时更新缓存;

运行时机:
    1、先调用目标方法
    2、将目标方法的结果缓存起来

#result.id是更新后返回的对象id,用于更新缓存中的数据(必须要@Cacheable缓存时的key是id)

@CacheConfig标注在类上面抽取缓存的公共配置

@CacheConfig(cacheNames="emp", cacheManager = "employeeCacheManager") 

@Caching 定义复杂的缓存规则

    @Caching(
         cacheable = {
             @Cacheable(/*value="emp",*/key = "#lastName")
         },
         put = {
             @CachePut(/*value="emp",*/key = "#result.id"),
             @CachePut(/*value="emp",*/key = "#result.email")
         }
    )

配置一个自定义的KeyGenerator(key生成器)

@Configuration
public class MyCacheConfig {

    @Bean("myKeyGenerator")
    public KeyGenerator keyGenerator(){
        return new KeyGenerator(){
            @Override
            public Object generate(Object target, Method method, Object... params) {
                return method.getName()+"["+ Arrays.asList(params).toString()+"]";
            }
        };
    }
}

使用:
    @Cacheable(value = {"emp"},keyGenerator = "myKeyGenerator",condition = "#a0>1",unless = "#a0==2")

 

二、缓存(redis)

yml配置
spring:
  redis:
    host: localhost
    # 连接超时时间(记得添加单位,Duration)
    timeout: 10000ms
    # Redis默认情况下有16个分片,这里配置具体使用的分片
    # database: 0
    lettuce:
      pool:
        # 连接池最大连接数(使用负值表示没有限制) 默认 8
        max-active: 8
        # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
        max-wait: -1ms
        # 连接池中的最大空闲连接 默认 8
        max-idle: 8
        # 连接池中的最小空闲连接 默认 0
        min-idle: 0
  cache:
    # 一般来说是不用配置的,Spring Cache 会根据依赖的包自行装配
    type: redis


操作
1.引入spring-boot-starter-data-redis
2.application.yml配置redis连接地址
3.使用ReditTemplate操作redis
    1>redisTemplate.opsForValue();//操作字符串
        stringRedisTemplate.opsForValue();//字符串专用模板
    2>redisTemplate.opsForHash();//操作hash
    3>redisTemplate.opsForList();//操作list
    4>redisTemplate.opsForSet();//操作set
    5>redisTemplate.opsForZSet();//操作有序set
4.配置缓存、CacheManagerCustomizers
5.测试使用缓存、切换缓存、 CompositeCacheManager

redis配置序列化规则

@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
@EnableCaching
public class RedisConfig {

    /**
     * 默认情况下的模板只能支持RedisTemplate<String, String>,也就是只能存入字符串,因此支持序列化
     */
    @Bean
    public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Serializable> template = new RedisTemplate<>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

 

三、MQ(rabbitmq)

1.mq核心概念

1.作用:异步处理、应用解耦、流量削峰

2.消息服务中两个重要概念消息代理(message broker目的地(destination当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目的地。

3.消息队列主要有两种形式的目的地:
    1>队列:点对点消息通信(point-to-point)
    2>主题:发布(publish)/订阅(subscribe)消息通信

4.点对点式:
    消息发送者发送消息,消息代理将其放入一个队列中,消息接收者从队列中获取消息内容,消息读取后被移出队列
    消息只有唯一的发送者和接受者,但并不是说只能有一个接收者

5.发布订阅式:
    发送者(发布者)发送消息到主题,多个接收者(订阅者)监听(订阅)这个主题,那么就会在消息到达时同时收到消息


6.JMS(Java Message Service)JAVA消息服务:java开发
    基于JVM消息代理的规范。ActiveMQ、HornetMQ是JMS实现

7.AMQP(Advanced Message Queuing Protocol):非java开发
    高级消息队列协议,也是一个消息代理的规范,兼容JMS
    RabbitMQ是AMQP的实现

8.spring提供的支持
    spring-jms提供了对JMS的支持
    spring-rabbit提供了对AMQP的支持
    需要ConnectionFactory的实现来连接消息代理
    提供JmsTemplate、RabbitTemplate来发送消息
    @JmsListener(JMS)、@RabbitListener(AMQP)注解在方法上监听消息代理发布的消息
    @EnableJms、@EnableRabbit开启支持


9.spring的自动配置
    JmsAutoConfiguration
    RabbitAutoConfiguration

 

2.RabbitMQ简介

RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue Protocol)的开源实现。

Message
消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等。

Publisher
消息的生产者,也是一个向交换器发布消息的客户端应用程序。

Exchange
交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。
Exchange有4种类型:direct(默认),fanout, topic, 和headers,不同类型的Exchange转发消息的策略有所区别

Queue
消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走

Binding
绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。
Exchange 和Queue的绑定可以是多对多的关系。

Connection
网络连接,比如一个TCP连接。

Channel
信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内的虚拟连接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。

Consumer
消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。

Virtual Host
虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。

Broker
表示消息队列服务器实体

2>RabbitMQ的运行机制:

AMQP 中消息的路由过程和 Java 开发者熟悉的 JMS 存在一些差别,AMQP 中增加了 Exchange Binding 的角色。生产者把消息发布到 Exchange 上,消息最终到达队列并被消费者接收,而 Binding 决定交换器的消息应该发送到那个队列。

3>Exchange交换器类型:directfanouttopicheaders

direct:点对点

fanout:发布/订阅(fanout 类型转发消息是最快的

topic:消息的路由键匹配(#匹配0个或多个单词*匹配一个单词。)

 

3使用Docker安装rabbitmq

1.下载镜像
docker pull rabbitmq:3.7.7-management

2.运行容器
docker run -d -p 5671:5617 -p 5672:5672 -p 4369:4369 -p 15671:15671 -p 15672:15672 -p 25672:25672 --name rabbit-3.7.7 rabbitmq:3.7.7-management

3.进入容器
docker exec -it rabbit-3.7.7 /bin/bash

4.给容器安装 下载工具 wget
apt-get update
apt-get install wge

5.下载插件包,因为我们的 RabbitMQ 版本为 3.7.7 所以我们安装 3.7.x 版本的延迟队列插件
root@f72ac937f2be:/plugins# wget https://dl.bintray.com/rabbitmq/community-plugins/3.7.x/rabbitmq_delayed_message_exchange/rabbitmq_delayed_message_exchange-20171201-3.7.x.zip

6.给容器安装 解压工具 unzip
apt-get install -y unzip

7.解压插件包
root@f72ac937f2be:/plugins# unzip rabbitmq_delayed_message_exchange-20171201-3.7.x.zip
Archive:  rabbitmq_delayed_message_exchange-20171201-3.7.x.zip
  inflating: rabbitmq_delayed_message_exchange-20171201-3.7.x.ez

8.启动延迟队列插件
root@f72ac937f2be:/plugins# rabbitmq-plugins enable rabbitmq_delayed_message_exchange

9.推出容器
exit

10.停止容器
docker stop rabbit-3.7.7

11.启动容器
docker startrabbit-3.7.7

12.图形管理界面
http://192.168.25.131:15672  账号:guest 密码:guest

 

 

 

 

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值