ehcache redis 双缓存(aop + 自定义注解)

该博客介绍了如何使用AOP和自定义注解实现Ehcache与Redis的双缓存机制。在查询数据时,首先查询Ehcache,未命中再查询Redis,最后若仍未找到则查询数据库。插入、更新和删除操作会同步更新Ehcache和Redis缓存。示例中包含了自定义的查询、添加和删除注解,以及对应的AOP切面处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


ehcache redis 双缓存(aop + 自定义注解)

 

查询数据:先查询ehcache缓存,如果没有数据,再查询redis缓存;如果查询不到,查询后端数据库

插入数据:后端数据库插入数据后,同时插入ehcache、redis缓存

更新数据:后端数据库更新数据后,同时更新ehcache、redis缓存

删除数据:后端数据库删除数据时,同时删除ehcache、redis缓存

 

 

****************************

示例

 

**********************

pojo 层

 

Person

@Data
public class Person implements Serializable {

    private Integer id;

    private String name;
    private Integer age;
}

 

**********************

myannotation 层

 

CustomCacheCacheable:自定义查询注解

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomCacheable {          //缓存查询注解

    String value() default "";

    /*
    key为方法参数名、参数名的属性
    Person  fun(String name,Person person){} //key可用格式:"#name"、“#person.id”
     */
    String key() default "";
}

 

CustomCachePut:自定义缓存添加注解

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomCachePut {         //缓存添加注解

    String value() default "";

    /*
    key为方法参数名、参数名的属性、返回值、返回值的属性
    Person  fun(String name,Person person){} //key可用格式:"#name"、“#person.id”、“#result”、"#result.id"
     */
    String key() default "";
}

 

CustomCacheEvict:自定义缓存删除注解

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomCacheEvict {       //缓存删除注解

    String value() default "";

    /*
    key为方法参数名、参数名的属性
    Person  fun(String name,Person person){} //key可用格式:"#name"、“#person.id”、“#result”、“#result.id”
     */
    String key() default "";
}

 

**********************

aop 层

 

CustomAspect

@Aspect
@Component
public class CustomAspect {

    private final Logger logger= LoggerFactory.getLogger(this.getClass().getName());

    @Resource(name = "ehcacheCacheManager")
    private CacheManager cacheManager;

    @Resource(name = "redisCacheManager")
    private RedisCacheManager redisCacheManager;

    @Pointcut("@annotation(com.example.demo.myannotation.CustomCacheable)")
    public void fun(){

    }

    @Pointcut("@annotation(com.example.demo.myannotation.CustomCachePut)" +
            "||@annotation(com.example.demo.myannotation.CustomCacheEvict)")
    public void fun2(){

    }

    @Around("fun()")
    public Person CustomCacheable(ProceedingJoinPoint joinPoint){
        Person result=null;

        Method method=((MethodSignature)joinPoint.getSignature()).getMethod();
        CustomCacheable cacheable=method.getDeclaredAnnotation(CustomCacheable.class);
        String value=cacheable.value();
        String key=getKeyValue(joinPoint,method,cacheable.key());

        Cache<String, Person> cache=cacheManager.getCache(value,String.class,Person.class);

        result=cache.get(key);
        if (result!=null){
            return result;
        }else {
            org.springframework.cache.Cache redisCache=redisCacheManager.getCache(value);

            assert redisCache != null;
            result=redisCache.get(key,Person.class);
            if (result!=null){
                return result;
            }else {
                try {
                    result=(Person) joinPoint.proceed();

                    cache.put(key,result);
                    redisCache.put(key,result);
                }catch (Throwable e){
                    e.printStackTrace();
                }
            }
        }

        return result;
    }

    @Around("fun2()")
    public Person CustomCachePutOrEvict(ProceedingJoinPoint joinPoint){
        Person result=null;

        Method method=((MethodSignature)joinPoint.getSignature()).getMethod();

        String keyValue;
        if (method.isAnnotationPresent(CustomCachePut.class)){
            CustomCachePut cachePut=method.getDeclaredAnnotation(CustomCachePut.class);
            String value=cachePut.value();
            String key=cachePut.key();

            Cache<String, Person> cache=cacheManager.getCache(value,String.class,Person.class);
            org.springframework.cache.Cache redisCache=redisCacheManager.getCache(value);

            try {
                result=(Person) joinPoint.proceed();

                keyValue=getKeyValue2(joinPoint,method,key,result);
                cache.put(keyValue,result);

                assert redisCache != null;
                redisCache.put(keyValue,result);
            }catch (Throwable e){
                e.printStackTrace();
            }
        }else {
            CustomCacheEvict cacheEvict=method.getDeclaredAnnotation(CustomCacheEvict.class);
            String value=cacheEvict.value();
            String key=cacheEvict.key();

            Cache<String,Person> cache=cacheManager.getCache(value,String.class,Person.class);
            org.springframework.cache.Cache redisCache=redisCacheManager.getCache(value);

            try {
                result=(Person) joinPoint.proceed();

                keyValue=getKeyValue2(joinPoint,method,key,result);
                cache.remove(keyValue);

                assert redisCache != null;
                redisCache.evictIfPresent(keyValue);
            }catch (Throwable e){
                e.printStackTrace();
            }
        }

        return result;
    }

    private String getKeyValue(ProceedingJoinPoint joinPoint,Method method,String key) {
        if (key==null||!key.startsWith("#")){
            return null;
        }

        String result=null;
        if (!key.contains(".")){
            String name=key.substring(1);

            Object[] args=joinPoint.getArgs();
            Parameter[] parameters=method.getParameters();

            for (int i=0;i<parameters.length;i++){
                if (parameters[i].getName().equals(name)){
                    result=args[i].toString();
                    break;
                }
            }
        }else {
            String[] s=key.substring(1).split("\\.");
            Object[] args = joinPoint.getArgs();
            Parameter[] parameters=method.getParameters();

            for (int i=0;i<parameters.length;i++){
                if (parameters[i].getName().equals(s[0])){
                    try {
                        Field field=parameters[i].getType().getDeclaredField(s[1]);
                        field.setAccessible(true);

                        result= field.get(args[i]).toString();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }

        return result;
    }

    private String getKeyValue2(ProceedingJoinPoint joinPoint,Method method,String key,Person returnValue) {
        if (key==null||!key.startsWith("#")){
            return null;
        }

        String result=null;
        if (!key.contains(".")){
            String name=key.substring(1);

            if (!name.equals("result")){
                Object[] args=joinPoint.getArgs();
                Parameter[] parameters=method.getParameters();

                for (int i=0;i<parameters.length;i++){
                    if (parameters[i].getName().equals(name)){
                        result=args[i].toString();
                        break;
                    }
                }
            }else {
                Class<?> returnType=method.getReturnType();
                try {
                    Field field=returnType.getDeclaredField(name);
                    field.setAccessible(true);

                    result = field.get(returnValue).toString();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }else {
            String[] s=key.substring(1).split("\\.");

            if (!s[0].equals("result")){
                Object[] args = joinPoint.getArgs();
                Parameter[] parameters=method.getParameters();

                for (int i=0;i<parameters.length;i++){
                    if (parameters[i].getName().equals(s[0])){
                        try {
                            Field field=parameters[i].getType().getDeclaredField(s[1]);
                            field.setAccessible(true);

                            result= field.get(args[i]).toString();
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }
            }else {
                Class<?> returnType=method.getReturnType();
                try {
                    Field field=returnType.getDeclaredField(s[1]);
                    field.setAccessible(true);

                    result = field.get(returnValue).toString();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }

        return result;
    }
}

 

**********************

config 层

 

CacheConfig

@EnableCaching
@Configuration
public class CacheConfig {

    @Bean("ehcacheCacheManager")
    public CacheManager initEhcacheCacheManager(){
        return CacheManagerBuilder.newCacheManagerBuilder()
                .withCache("custom", CacheConfigurationBuilder
                        .newCacheConfigurationBuilder(String.class, Person.class,
                                ResourcePoolsBuilder.newResourcePoolsBuilder()
                                        .heap(10, MemoryUnit.MB)
                        )).build(true);
    }

    @Bean("redisCacheManager")
    public RedisCacheManager initRedisCacheManager(RedisConnectionFactory connectionFactory){
        RedisCacheConfiguration cacheConfiguration=RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()))
                .entryTtl(Duration.ofMinutes(2L))
                .disableCachingNullValues();

        RedisCacheConfiguration defaultCacheConfiguration=RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()))
                .entryTtl(Duration.ofMinutes(1L))
                .disableCachingNullValues();

        Map<String,RedisCacheConfiguration> map=new HashMap<>();
        map.put("custom",cacheConfiguration);
        map.put("default",defaultCacheConfiguration);

        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(defaultCacheConfiguration)
                .withInitialCacheConfigurations(map)
                .transactionAware()
                .build();
    }

}

 

**********************

service 层

 

HelloService

public interface HelloService {

    Person getById(Integer id);
    Person getByPerson(Person person);

    Person put(Integer id,String name,Integer age);
    Person put2(Person person);

    Person deleteById(Integer id);
    Person delete2(Person person);
}

 

**********************

serviceImpl 层

 

HelloServiceImpl

@Service
public class HelloServiceImpl implements HelloService {

    private final Map<String,Person> map=new HashMap<>();

    @Override
    @CustomCacheable(value = "custom",key = "#id")
    public Person getById(Integer id) {
        System.out.println("查询数据:getById");

        if (map.containsKey(id.toString())){
            return map.get(id.toString());
        }

        return new Person();
    }

    @Override
    @CustomCacheable(value = "custom",key = "#person.id")
    public Person getByPerson(Person person) {
        System.out.println("查询数据:getByPerson");
        if (!map.containsKey(person.getId().toString())){
            return new Person();
        }

        return map.get(person.getId().toString());
    }

    @Override
    @CustomCachePut(value = "custom",key = "#id")
    public Person put(Integer id, String name, Integer age) {
        System.out.println("插入数据:id、name、age");
        Person person=new Person();
        person.setId(id);
        person.setName(name);
        person.setAge(age);

        map.put(id.toString(),person);

        return person;
    }

    @Override
    @CustomCachePut(value = "custom",key = "#person.id")
    public Person put2(Person person) {
        System.out.println("插入数据:person");
        map.put(person.getId().toString(),person);

        return person;
    }

    @Override
    @CustomCacheEvict(value = "custom",key = "#id")
    public Person deleteById(Integer id) {
        System.out.println("删除数据:deleteById");

        Person person=map.get(id.toString());
        map.remove(id.toString());

        return person;
    }

    @Override
    @CustomCacheEvict(value = "custom",key = "#result.id")
    public Person delete2(Person person) {
        System.out.println("删除数据:person");
        map.remove(person.getId().toString());

        return person;
    }
}

 

**********************

controller 层

 

HelloController

@RestController
public class HelloController {

    @Resource
    private HelloService helloService;

    @RequestMapping("/get")
    public Person get(){
        return helloService.getById(1);
    }

    @RequestMapping("/get2")
    public Person getBYPerson(){
        Person person=new Person();
        person.setId(2);
        person.setName("瓜田李下 2");
        person.setAge(21);

        return helloService.getByPerson(person);
    }

    @RequestMapping("/put")
    public Person put(){
        return helloService.put(1,"瓜田李下",20);
    }

    @RequestMapping("/put2")
    public Person put2(){
        Person person=new Person();
        person.setId(2);
        person.setName("瓜田李下 2");
        person.setAge(21);

        return helloService.put2(person);
    }

    @RequestMapping("/delete")
    public Person delete(){
        return helloService.deleteById(1);
    }

    @RequestMapping("/delete2")
    public Person delete2(){
        Person person=new Person();
        person.setId(2);
        person.setName("瓜田李下 2");
        person.setAge(21);

        return helloService.delete2(person);
    }
}

 

 

****************************

使用测试

 

缓存插入 byId:localhost:8080/get、localhost:8080/put、localhost:8080/get,控制台输出:

查询数据:getById
插入数据:id、name、age

              

第一次查询:缓存里面没有数据,执行方法体

第二次查询:缓存里面有数据,直接返回缓存里面的数据

 

缓存删除 byId:localhost:8080/delete、loclahost:8080/get,控制台输出:

删除数据:deleteById
查询数据:getById

              

由于删除了缓存,查询时执行方法体返回数据

 

 

缓存插入 byPerson:loclahost:8080/get2、localhost:8080/put2、loclahost:8080/get2,控制台输出 

查询数据:getByPerson
插入数据:person

              

第一次查询:缓存里面没有数据,执行方法体

第二次查询:缓存里面存有数据,直接从缓存里面获取数据

 

缓存删除 byPerson:localhost:8080/delete2、localhost:8080/get2,控制台输出:

删除数据:person
查询数据:getByPerson

              

由于缓存删除了,查询时执行方法体查询数据

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值