SpringbootカスタムRedisCacheアノテーション

springbootによって提供されるキャッシュ注釈

クエリデータベースサービスを作成するときは、redisに必要なデータのキャッシュがあるかどうかをクエリする必要があります。キャッシュがある場合は、データベースにクエリを実行する必要がないため、クエリ速度が向上し、データベースへの負荷が軽減されます。
springbootを使用してredisを統合する場合、誰もが@Cacheableアノテーションに精通していると思います。
たとえば、サービスがデータベースにクエリを実行する前に、キャッシュでクエリを実行する必要があります。データベースにクエリを実行しない場合は、クエリを実行しません。redisTemplateを構成するだけで済みます。次のように、@ EnableCachingアノテーションをクラスに追加し、SpringCacheアノテーション関数を構成します。

package com.sunyuqi.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@EnableCaching
class RedisTemplateConfig {
    
    

    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
    
    
        return new LettuceConnectionFactory(new RedisStandaloneConfiguration("127.0.0.1", 6379));
    }
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    
    
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        return redisTemplate;
    }

    // 配置Spring Cache注解功能
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
    
    
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
        return cacheManager;
    }
}

次に、サービスメソッドに注釈を追加します

	@Cacheable(cacheManager = "cacheManager", value = "testcache", key = "#userId")
    public User findUserById(String userId) throws Exception {
    
    
        //此处编写查询数据库代码
        User user = ....
        return user;
    }

メソッドが実行される前に、redisキャッシュが照会されます。結果が見つかった場合、メソッドは実行されません。結果がない場合、メソッドが実行されます。


キャッシュクエリロジックをカスタマイズする必要がある場合は、注釈を定義する必要があります。

カスタムキャッシュアノテーション

関連する依存関係をインポートする

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.9</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.9</version>
</dependency>

まず、注釈を定義する必要があります

package com.sunyuqi.mycache.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * cache注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cache {
    
    
    String key();
}

注釈はメソッドで定義され、パラメータキーを渡す必要があります。
AOPを定義する

package com.sunyuqi.mycache.aop;

import com.sunyuqi.mycache.annotations.Cache;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
@Aspect
public class CacheAspect {
    
    

    @Autowired
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.sunyuqi.mycache.annotations.Cache)")
    public void cachePointcut() {
    
    
    }
    // 定义相应的事件
    @Around("cachePointcut()")
    public Object doCache(ProceedingJoinPoint joinPoint) {
    
    
        Object value = null;
        try {
    
    
            // 获取当前方法上注解的内容
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取被注解的方法
            Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(), signature.getMethod().getParameterTypes());
            Cache cacheAnnotation = method.getAnnotation(Cache.class);
            // 获取到传入注解中的key的值 即"#userID"(我们需要EL解析)
            String keyEl = cacheAnnotation.key();
            // 创建解析器
            ExpressionParser parser = new SpelExpressionParser();
            Expression expression = parser.parseExpression(keyEl);
            EvaluationContext context = new StandardEvaluationContext(); 
            // 添加参数
            Object[] args = joinPoint.getArgs();
            DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer();
            String[] parameterNames = discover.getParameterNames(method);
            for (int i = 0; i < parameterNames.length; i++) {
    
    
                context.setVariable(parameterNames[i], args[i].toString());
            }
            // 解析EL表达式
            String key = expression.getValue(context).toString();

            // 查询缓存,并判定缓存中是否存在
            value = redisTemplate.opsForValue().get(key);
            if (value != null) {
    
    
                System.out.println("从缓存中查询到结果:" + value);
                return value;
            }
            // 缓存中没有结果,执行被注解的方法
            value = joinPoint.proceed();
            // 将结果存入缓存
            redisTemplate.opsForValue().set(key, value);
        } catch (Throwable throwable) {
    
    
            throwable.printStackTrace();
        }
        return value;
    }
}

メソッドにカスタム注釈を使用する

	@Cache(key = "#userId")
    public User findUserById(String userId) throws Exception {
    
    
        //此处编写查询数据库代码
        User user = ....
        return user;
    }

使いやすいですか?
もちろん、redistemplateを構成することを忘れないでください

package com.sunyuqi.mycache.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@EnableAspectJAutoProxy
class MyRedisConfig {
    
    
    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
    
    
        return new LettuceConnectionFactory(new RedisStandaloneConfiguration("127.0.0.1", 6379));
    }

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    
    
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        return redisTemplate;
    }
}

ここに、すべての人に思い出させるポイントが
あります。redisに格納するオブジェクトは、実際にはシリアル化された文字列です。
デシリアライズの過程で、つまり、redisからキャッシュを照会してオブジェクトに変換するときに、オブジェクトの現在のパッケージパスが、格納されているオブジェクトのパッケージパスと異なる場合、デシリアライズは失敗します。

おすすめ

転載: blog.csdn.net/weixin_42494845/article/details/108911440