`

aop实现通用缓存,并且防止缓存击穿

    博客分类:
  • java
阅读更多
实现代码在附件中
1.自定义注解文件

package sgnctest.el;

import java.lang.annotation.*;

/**
* Author by gjp, Date on 2019/9/16.
*/

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyCache {
    //key 值
    String key() default "";
    //缓存前缀
    String preName() default "lypt";
    //超时时间
    long outTime() default 60000;
}


2.实现类
package sgnctest.el.service;

import org.springframework.stereotype.Service;
import sgnctest.el.MyCache;

/**
* Author by gjp, Date on 2019/9/16.
*/
@Service
public class ServiceCacheInf{


    @MyCache(key="#key")
    public String getName(String key) {
        System.out.println("====访问数据库"+key);
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return key;
    }
}


3.建立aop 类

package sgnctest.el.service;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import sgnctest.el.MyCache;
import sgnctest.el.Spel;
import sgnctest.el.util.LockServer;

import javax.annotation.Resource;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* Author by gjp, Date on 2019/9/16.
* aop 操作
*/

@Aspect
@Component
public class CacheAop {

    @Resource
    private RedisCache redisCache;

    ThreadLocal<Long> startTime = new ThreadLocal<>();


    // 定义需要匹配的切点表达式,同时需要匹配参数
    @Around("@annotation(cache)")
    public Object around(ProceedingJoinPoint pjp, MyCache cache) throws Throwable {
        System.out.println("方法环绕start...around");
        String key = cache.key();
        String preName = cache.preName();
        long timeOut = cache.outTime();
        Object result = null;
        String keyVal ="";
        try {
          //  System.out.println("key:" + key + ";preName=" + preName + ";timeOut=" + timeOut);
            MethodSignature signature = (MethodSignature) pjp.getSignature();
            String[] parameters = signature.getParameterNames();
            //jdk1.8
            //Method method = signature.getMethod();
            //  Parameter[] parameters = method.getParameters();
            Object obj[] = pjp.getArgs();
            //通过el表达式获取值
            keyVal = Spel.el(key, parameters, obj);
            //从缓存中读取数据
           result =  redisCache.getCacheById(keyVal);
           if(null != result){
               return result;
           }

           //先加锁,然后从数据库中获取数据,从数据库中获取
            LockServer.getInstance().doLock(keyVal);

            result =  redisCache.getCacheById(keyVal);
            if(null != result){
                return result;
            }

            result = pjp.proceed(); //pjp.proceed().toString() + "aop String keyVal:"+keyVal;

            //加入缓存
            redisCache.putCacheById(keyVal,result);
        } catch (Throwable e) {
            e.printStackTrace();
        }finally {
            LockServer.getInstance().releaseLock(keyVal);
        }
       // System.out.println("方法环绕end...around");
        return result;
    }


}



4.模拟缓存类

package sgnctest.el.service;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

/**
* Author by gjp, Date on 2019/9/16.
* 从缓存中获取数据
*/
@Service
public class RedisCache {
    private String keys="";

    public Object getCacheById(String key){
        if(StringUtils.isEmpty(keys)){
            return null;
        }
        return "cache"+keys;
    }


    public void putCacheById(String key,Object object){
        System.out.println("加入缓存"+key);
        keys =key;
    }
}



5.配置类
package sgnctest.el;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
* Author by gjp, Date on 2019/9/16.
*/

@Configuration
@ComponentScan("sgnctest.el.service")
@EnableAspectJAutoProxy //开启Spring对AspectJ代理的支持
public class AopConfig {
}


6.el表达式(技术核心)

package sgnctest.el;

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;

/**
* Author by gjp, Date on 2019/9/16.
*/
public class Spel {

   private static ExpressionParser parser = new SpelExpressionParser();
    /**
     * el表达式解析
     * @param key 需要转换的el表达式
     * @param parameters 变量名称
     * @param args 变量值
     * @return
     */
    public static String el(String key,String[] parameters,Object[] args){
        //key 解析为el表达式
        Expression exp = parser.parseExpression(key);
        EvaluationContext context = new StandardEvaluationContext();
        if(null == args || args.length==0){
            return null;
        }
        int len = args.length;
        for(int i=0;i<len;i++) {
            //参数和值防止上下文中
            context.setVariable(parameters[i],args[i]);
        }
        //获取el中的参数值
        return exp.getValue(context,String.class);
    }

    public static void main(String[] args) {
        Spel spel = new Spel();
        String key ="#ztb+' '+#pay";
        String [] parameter = {"ztb","pay"};
        Object [] obj ={"ztb123","pay123"};
        System.out.println("result ::"+spel.el(key,parameter,obj));
    }
}




7.测试类:

package sgnctest.el;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import sgnctest.el.service.ServiceCacheInf;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Author by gjp, Date on 2019/9/16.
*
* 测试类
*/
public class SpringMain {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AopConfig.class);

       final ServiceCacheInf demoAnnotationService = context.getBean(ServiceCacheInf.class);

        ExecutorService executor = Executors.newFixedThreadPool(10);
        int callTime = 20;
        final CountDownLatch countDownLatch = new CountDownLatch(callTime);
        //模拟并发情况下的接口调用统计
        for(int i=0;i<callTime;i++){
            final int count =i;
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        countDownLatch.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    if(count%3 ==0) {
                        System.out.println(demoAnnotationService.getName("123456"));
                    }else if(count %3 ==1){
                        System.out.println(demoAnnotationService.getName("666"));
                    }else {
                        System.out.println(demoAnnotationService.getName("7775"));
                    }


                }
            });


            countDownLatch.countDown();
        }

        executor.shutdown();
        //等待所有线程统计完成后输出调用次数
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        context.close();


    }
}




日志:

main 2019-09-16 14:52:27.765 [main] INFO  org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
方法环绕start...around
方法环绕start...around
方法环绕start...around
方法环绕start...around
方法环绕start...around
方法环绕start...around
方法环绕start...around
方法环绕start...around
方法环绕start...around
方法环绕start...around
====访问数据库123456
====访问数据库7775
====访问数据库666
加入缓存666
加入缓存123456
加入缓存7775
cache123456
cache123456
cache123456
方法环绕start...around
cache666
666
123456
方法环绕start...around
方法环绕start...around
cache7775
方法环绕start...around
方法环绕start...around
cache7775
cache7775
cache7775
方法环绕start...around
cache7775
7775
cache7775
方法环绕start...around
方法环绕start...around
cache7775
cache7775
方法环绕start...around
cache7775
cache7775
方法环绕start...around
cache7775
cache7775
cache7775


  • el.zip (6.6 KB)
  • 下载次数: 1
分享到:
评论

相关推荐

    Asp.net Core 3.1基于AspectCore实现AOP实现事务、缓存拦截器功能

    在net core2.2时,我当时就尝试过用autofac实现aop,但这次我不想用autofac,我用了一个更轻量级的框架,AspectCore。 用起来非常非常的简单,但一开始还是走了一点弯路,主要是网上都是net core3以下的教程,3以下...

    spring AOP实现查询缓存

    本代码通过使用spring aop+ehcache的技术,实现了方法级别的查询缓存,主要原理是 方法的完整路径+方法参数值,作为key,放入cache中,下次访问时先判断cache中是否有该key.

    Spring AOP实现Redis缓存数据库查询

    Spring AOP实现Redis缓存数据库查询 Spring AOP(Aspect-Oriented Programming,面向方面编程)是一种编程技术,可以将散落在各个对象之间的逻辑提取出来,封装成一个个独立的模块,并将这些模块组合起来,形成一...

    SpringAOP结合ehCache实现简单缓存实例

    本文将深入探讨如何结合Spring AOP与EhCache实现一个简单的缓存实例,以便优化Java应用的运行效率。 首先,让我们了解Spring AOP。Spring AOP是Spring框架的一部分,它允许我们在不修改业务代码的情况下,通过定义...

    spring aop 自定义缓存实现

    本实例将介绍如何利用Spring AOP来实现自定义缓存功能。 首先,理解Spring AOP的基本概念。AOP是一种编程范式,它允许我们在不修改代码的情况下,为程序添加额外的功能,如日志记录、事务管理、安全检查等。在...

    spring aop实现原理

    NULL 博文链接:https://zhang-yingjie-qq-com.iteye.com/blog/319927

    浅谈SpringBoot集成Redis实现缓存处理(Spring AOP实现)

    SpringBoot集成Redis实现缓存处理(Spring AOP实现) 本文主要介绍了如何使用SpringBoot框架集成Redis实现缓存处理,通过Spring AOP(面向切面编程)实现缓存处理。下面是相关知识点的总结: 一、需求分析 在开源...

    Spring AOP如何整合redis(注解方式)实现缓存统一管理详解

    Spring AOP如何整合redis(注解方式)实现缓存统一管理详解 Spring AOP是Spring框架中的一种面向方面编程(AOP)的实现,它可以将横切关注点(Cross-Cutting Concerns)与业务逻辑进行分离,从而实现更加灵活和模块...

    Spring AOP实现机制

    总之,Spring AOP通过代理技术实现了面向切面编程,使得开发者能够更专注于业务逻辑,而将通用的横切关注点剥离出来,提高了代码的可读性和可维护性。通过深入理解Spring AOP的实现机制,我们可以更好地利用这一强大...

    Spring AOP+ehCache简单缓存系统解决方案

    在本篇【Spring AOP+ehCache简单缓存系统解决方案】中,我们将探讨如何利用Spring AOP(面向切面编程)和ehCache框架来构建一个高效、简单的缓存系统,以提升应用程序的性能。ehCache是一款流行的开源Java缓存库,它...

    springboot实现消息转换、切面AOP和Redis缓存

    在本项目中,我们将探讨如何在SpringBoot中实现消息转换、切面编程(AOP)以及使用Redis作为缓存。 ### 消息转换 在SpringBoot中,消息转换是处理应用程序与外部系统之间数据交换的过程。Spring提供了`...

    spring的aop实现

    下面我们将深入探讨Spring AOP的概念、实现方式以及实际应用。 首先,我们需要理解AOP的基本概念。AOP是一种编程范式,它将关注点分离,使系统中的核心业务逻辑与辅助性任务(如日志、安全检查等)解耦。在Spring中...

    基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip

    4、本资源作为“参考资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研,自行调试。 基于springboot+mvc+freemarker+aop实现校友信息管理系统源码.zip 基于springboot+mvc+freemarker+aop实现校友信息管理...

    基于注解实现SpringAop

    基于注解实现SpringAop基于注解实现SpringAop基于注解实现SpringAop

    反射实现 AOP 动态代理模式(Spring AOP 的实现原理)

    总之,AOP通过提供一种新的角度来解决OO编程中存在的问题,使得我们能够在保持业务逻辑清晰的同时,增加额外的通用功能。利用Java反射机制和Spring AOP框架,开发者可以方便地实现AOP,从而提升代码的模块化和可维护...

    redis命令缓存AOP代码

    在Java开发中,通过Spring框架可以方便地集成Redis,并利用AOP(面向切面编程)实现命令缓存,提升应用性能。本项目包含HashMap、List、Set、SortedSet以及String等多种Redis数据类型的命令操作。 首先,`pom.xml`...

    .net平台AOP的实现

    在.NET平台上实现AOP,我们可以借助于不同的库和技术,如PostSharp、Unity、Autofac等。下面我们将深入探讨.NET平台AOP的实现方法和应用。 首先,我们需要理解AOP的基本概念。AOP的核心是切面(Aspect),它封装了...

    在Python中使用AOP实现Redis缓存示例

    越来越觉得的缓存是计算机科学里最NB的发明(没有之一),本文就来介绍了一下在Python中使用AOP实现Redis缓存示例,小伙伴们一起来了解一下 import redis enable=True #enable=False def readRedis(key): if enable: ...

    JAVA 中Spring aop 实现日志记载

    在Java开发中,Spring AOP(面向切面编程)是一个强大的功能,用于实现日志记录。AOP允许我们在不修改原有代码的情况下,插入新的行为,比如日志记录,事务管理等。下面将详细介绍如何在Spring框架中使用AOP来实现...

Global site tag (gtag.js) - Google Analytics