SpringBoot系列——使用技巧之方法添加缓存功能

SpringBoot系列——使用技巧之方法添加缓存功能

一、文章概述

各位小伙伴,在JAVA编程中,肯定常常会遇到某个方法因处理时间较为缓慢,如果每次调用都重新进行响应处理,较为浪费性能和时间。本文教大家使用老生常谈的Springboot + Spring data redis缓存技术实现简单的方法调用,有兴趣的同志,可详细探究哈!!!

文章书写不易,点个关注不迷路哦,O(∩_∩)O哈哈~

二、准备工作

  • 开发环境
    java 1.8
    springboot2.0版本
    maven

三、具体实现

1. 导入依赖

导入相关依赖,cache、spring data redis

<!-- spring-boot-starter-cache -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
    <version>2.7.4</version>
</dependency>

<!-- spring-data-redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.7.4</version>
</dependency>

2. 添加redis配置

在application中添加redis配置和使用缓存

spring:
  # 指明使用什么作为缓存存储
  cache:
    type: redis
  # 配置redis,具体需要什么配置,这个根据项目需求自行添加配置
  redis: 
    host: 192.168.2.156
    port: 32190
    database: 2
    jedis:
      pool:
        max-active: 200
        max-wait: -1
        min-idle: 10
    timeout: 2000

3. 添加缓存配置类

该配置类,主要配置内容为:自定义缓存配置,自定义缓存key生成器,任选一种即可

关于什么是缓存配置、key生成器,这个大家自行了解一下,这里就不多赘述啦_

  • 使用默认的缓存配置
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Method;


/**
 * 缓存配置类
 */
@Configuration
public class CacheManagerConfig {

    /**
     * 自定义缓存配置
     * <cacheManager.setAllowNullValues(false)> 设置不对null值使用缓存 </>
     * <其他需求配置自行选择>
     * @return
     */
    @Bean
    public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
        return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
            public void customize(ConcurrentMapCacheManager cacheManager) {
                cacheManager.setAllowNullValues(false);
            }
        };
    }

    /**
     * 自定义key配置
     * @return
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            public Object generate(Object target, Method method, Object... params) {
                /**
                 * 配置key的生成策略为:方法名称+“-”+参数列表,返回内容自己定,想要啥就咋配置
                 */
                return method.getName() + "-" + params.toString();
            }
        };
    }
}
  • 带有缓存过期的缓存配置
package com.king.fun.test.cofig;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import java.lang.reflect.Method;
import java.time.Duration;


/**
 * 缓存配置类
 */
@Configuration
public class CacheManagerConfig {

    @Autowired
    private ResourceLoader resourceLoader;

    /**
     * 有缓存过期时间的缓存配置
     * @param connectionFactory
     * @return
     */
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig(resourceLoader.getClassLoader()).entryTtl(Duration.ofHours(2))) // 获取默认缓存配置,设置缓存过期时间
                .transactionAware() // 在spring事务提交时才进行数据缓存
                .build();
    }
 
    /**
     * 自定义key配置
     * @return
     */
    @Bean(value = "myKeyGenerator")
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            public Object generate(Object target, Method method, Object... params) {
                /**
                 * 配置key的生成策略为:方法名称+“-”+参数列表,返回内容自己定,想要啥就咋配置
                 */
                return method.getName() + "-" + params.toString();
            }
        };
    }
}

4. 配置redis连接池

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
public class JedisConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Value("${spring.redis.jedis.pool.max-active}")
    private int maxActive;

    @Value("${spring.redis.jedis.pool.max-wait}")
    private int maxWait;

    @Value("${spring.redis.jedis.pool.max-idle}")
    private int maxIdle;

    @Value("${spring.redis.jedis.pool.min-idle}")
    private int minIdle;

    @Value("${spring.redis.timeout}")
    private int timeout;

    @Bean
    public JedisPool jedisPoolFactory() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWait);
        jedisPoolConfig.setMaxTotal(maxActive);
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, null);
        Logger logger = LoggerFactory.getLogger(JedisPool.class);
        logger.info("redis连接成功:{} {}", host, port);
        return jedisPool;
    }
}

5. 方法添加注解实现缓存

  • 关于缓存注解

    @EnableCaching

    ​ 开关性注解,在项目启动类或某个配置类上使用此注解后,则表示允许使用注解的方式进行缓存操作

    @Cacheable

    ​ 可用于类或方法上;在目标方法执行前,会根据key先去缓存中查询看是否有数据,有就直接
    ​ 返回缓存中的key对应的value值。不再执行目标方法;无则执行目标方法,并将方法的返回值
    ​ 作为value,并以键值对的形式存入缓存

    @CachePut

    ​ 可用于类或方法上;在执行完目标方法后,并将方法的返回值作为value,并以键值对的形式存入缓存中

    @CacheEvice:

    ​ 可用于类或方法上;在执行完目标方法后,清除缓存中对应key的数据

    @Caching

    ​ 此注解用作复杂缓存配置情形,可组合@Cacheable、@CacheEvict、@CachePut三种注解任意几种使用

    @CacheConfig

    ​ 用于配置一些公共的属性

  • 本文主要使用的注解

    • 启动类添加开启缓存支持

      @EnableCaching
      
    • 方法添加缓存注解

      @Cacheable
      
      对使用的方法添加缓存功能,主要属性如下
      value / cacheNames:缓存名字
      key:存储在缓存中的数据key,可以用来判定或获取数据等
      keyGenerator:使用的key生成器,可使用自定义的/Spel表达式/或默认的
      unless:是否缓存方法的返回值,true为不缓存
      condition:满足什么条件才会进行缓存
      
      注意:key与keyGenerator不能同时使用!
      
  • 实现代码

    在需要使用缓存的方法上添加@Cacheable注解,即可解锁方法缓存功能,如下:

    /**
         * 返回名字
         * @return
         */
        @Cacheable(cacheNames = "getName", keyGenerator = "myKeyGenerator")
        public String getName(int key) {
            System.out.println("缓存在不存在该key:"+key);
            return persionName.get(key);
        }
    

6. 测试代码

不知道怎么用的小伙伴,给大家提供一个简单的测试代码。但是工作中,大家完成以上配置后,肯定不会这么简单调用,在自己工程中灵活使用即可,但是要想用的出神入化,还需要深入了解缓存技术以及redis缓存雪崩等各类问题。

import org.springframework.cache.annotation.Cacheable;

import java.util.HashMap;
import java.util.Map;

public class CacheUtils {

    static final Map<Integer, String> persionName = new HashMap<Integer, String>(){};

    static {
        persionName.put(1, "JAVA");
        persionName.put(2, "PYTHON");
        persionName.put(3, "GO");
    }

    /**
     * 返回名字
     * @return
     */
    @Cacheable(cacheNames = "getName", keyGenerator = "myKeyGenerator")
    public String getName(int key) {
        System.out.println("缓存在不存在该key:"+key);
        return persionName.get(key);
    }

	/**
	 * 此处为调用main函数,注意不能将这个调用放在方法同类中,因为缓存注解本质是基于Spring AOP切面,必须走代理才能生效,如果是同类方法调用或子类调用父类缓存方法都属于内部调用,缓存不会生效
	 **/
    public static void main(String[] args) {
        // 这里调用两次如果没有缓存,那么测试方法中的语句将会打印2遍,反之则1遍
        String name = new CacheUtils().getName(1);
        String name1 = new CacheUtils().getName(1);
    }
}

通过Spring data redis实现的缓存仅为个人想法,如果有其他好的想法,欢迎评论区交流。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值