`

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
分享到:
评论

相关推荐

    2022面试题6java背诵版本.doc

    - AOP代理模式:实现切面编程,如AspectJ和JDK动态代理。 - 发布订阅模式:事件驱动,如ApplicationEventPublisher。 7. **Redis的特点**: - 内存存储:高读写速度。 - 键值对存储:支持多种数据结构(字符串...

    JAVA架构师课程+面试资料 2.zip

    7. **缓存技术**:了解并能运用Redis、Memcached等缓存系统,理解缓存穿透、缓存雪崩、缓存击穿等问题及其解决方案。 8. **消息队列**:理解消息队列的作用,如RabbitMQ、Kafka、ActiveMQ等,熟悉其工作原理和使用...

    个人用了8年的Java工程师简历

    - **Redis**: 熟练掌握Redis的数据结构及其应用场景,解决缓存雪崩、击穿等问题。 ### 微服务架构与分布式系统 - **Spring Cloud**: 掌握Spring Cloud生态系统中的各种组件,如服务网关(Gateway)、服务注册与...

    spring-ai-bedrock-converse-1.0.0-M7.jar中文文档.zip

    # 【spring-ai-bedrock-converse-1.0.0-M7.jar中文文档.zip】 中包含: 中文文档:【spring-ai-bedrock-converse-1.0.0-M7-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【spring-ai-bedrock-converse-1.0.0-M7.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【spring-ai-bedrock-converse-1.0.0-M7.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【spring-ai-bedrock-converse-1.0.0-M7.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【spring-ai-bedrock-converse-1.0.0-M7-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: spring-ai-bedrock-converse-1.0.0-M7.jar中文文档.zip,java,spring-ai-bedrock-converse-1.0.0-M7.jar,org.springframework.ai,spring-ai-bedrock-converse,1.0.0-M7,org.springframework.ai.bedrock.converse,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,springframework,spring,ai,bedrock,converse,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【spring-ai-bedrock-converse-1

    房地产 -可视化管理课件.ppt

    房地产 -可视化管理课件.ppt

    tokenizers-0.18.0.jar中文-英文对照文档.zip

    # 【tokenizers-***.jar***文档.zip】 中包含: ***文档:【tokenizers-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【tokenizers-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【tokenizers-***.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【tokenizers-***.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【tokenizers-***-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: tokenizers-***.jar***文档.zip,java,tokenizers-***.jar,ai.djl.huggingface,tokenizers,***,ai.djl.engine.rust,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,djl,huggingface,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【tokenizers-***.jar***文档.zip】,再解压其中的 【tokenizers-***-javadoc-API文档-中文(简体)版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件; # Maven依赖: ``` <dependency> <groupId>ai.djl.huggingface</groupId> <artifactId>tokenizers</artifactId> <version>***</version> </dependency> ``` # Gradle依赖: ``` Gradle: implementation group: 'ai.djl.huggingface', name: 'tokenizers', version: '***' Gradle (Short): implementation 'ai.djl.huggingface:tokenizers:***' Gradle (Kotlin): implementation("ai.djl.huggingface:tokenizers:***") ``` # 含有的 Java package(包): ``` ai.djl.engine.rust ai.djl.engine.rust.zoo ai.djl.huggingface.tokenizers ai.djl.huggingface.tokenizers.jni ai.djl.huggingface.translator ai.djl.huggingface.zoo ``` # 含有的 Java class(类): ``` ai.djl.engine.rust.RsEngine ai.djl.engine.rust.RsEngineProvider ai.djl.engine.rust.RsModel ai.djl.engine.rust.RsNDArray ai.djl.engine.rust.RsNDArrayEx ai.djl.engine.rust.RsNDArrayIndexer ai.djl.engine.rust.RsNDManager ai.djl.engine.rust.RsSymbolBlock ai.djl.engine.rust.RustLibrary ai.djl.engine.rust.zoo.RsModelZoo ai.djl.engine.rust.zoo.RsZooProvider ai.djl.huggingface.tokenizers.Encoding ai.djl.huggingface.tokenizers.HuggingFaceTokenizer ai.djl.huggingface.tokenizers.HuggingFaceTokenizer.Builder ai.djl.hu

    基于MATLAB的BP神经网络预测模型构建与应用

    内容概要:本文详细介绍了如何使用MATLAB构建和应用BP神经网络预测模型。首先,通过读取Excel数据并进行预处理,如归一化处理,确保数据的一致性和有效性。接着,配置网络结构,选择合适的训练算法(如SCG),设置训练参数(如最大迭代次数、目标误差等)。然后,进行模型训练,并通过可视化窗口实时监控训练过程。训练完成后,利用测试集评估模型性能,计算均方误差(MSE)和相关系数(R²),并通过图表展示预测效果。最后,将训练好的模型保存以便后续调用,并提供了一个简单的预测函数,确保新数据能够正确地进行归一化和预测。 适合人群:具有一定MATLAB基础,从事数据分析、机器学习领域的研究人员和技术人员。 使用场景及目标:适用于需要对多维数据进行预测的任务,如电力负荷预测、金融数据分析等。主要目标是帮助用户快速搭建一个可用的BP神经网络预测系统,提高预测准确性。 其他说明:文中提供了完整的代码框架和详细的注释,便于理解和修改。同时,强调了数据预处理的重要性以及一些常见的注意事项,如数据量的要求、归一化的必要性等。

    tokenizers-0.22.1.jar中文-英文对照文档.zip

    # 【tokenizers-***.jar***文档.zip】 中包含: ***文档:【tokenizers-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【tokenizers-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【tokenizers-***.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【tokenizers-***.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【tokenizers-***-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: tokenizers-***.jar***文档.zip,java,tokenizers-***.jar,ai.djl.huggingface,tokenizers,***,ai.djl.engine.rust,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,djl,huggingface,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【tokenizers-***.jar***文档.zip】,再解压其中的 【tokenizers-***-javadoc-API文档-中文(简体)版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件; # Maven依赖: ``` <dependency> <groupId>ai.djl.huggingface</groupId> <artifactId>tokenizers</artifactId> <version>***</version> </dependency> ``` # Gradle依赖: ``` Gradle: implementation group: 'ai.djl.huggingface', name: 'tokenizers', version: '***' Gradle (Short): implementation 'ai.djl.huggingface:tokenizers:***' Gradle (Kotlin): implementation("ai.djl.huggingface:tokenizers:***") ``` # 含有的 Java package(包): ``` ai.djl.engine.rust ai.djl.engine.rust.zoo ai.djl.huggingface.tokenizers ai.djl.huggingface.tokenizers.jni ai.djl.huggingface.translator ai.djl.huggingface.zoo ``` # 含有的 Java class(类): ``` ai.djl.engine.rust.RsEngine ai.djl.engine.rust.RsEngineProvider ai.djl.engine.rust.RsModel ai.djl.engine.rust.RsNDArray ai.djl.engine.rust.RsNDArrayEx ai.djl.engine.rust.RsNDArrayIndexer ai.djl.engine.rust.RsNDManager ai.djl.engine.rust.RsSymbolBlock ai.djl.engine.rust.RustLibrary ai.djl.engine.rust.zoo.RsModelZoo ai.djl.engine.rust.zoo.RsZooProvider ai.djl.huggingface.tokenizers.Encoding ai.djl.huggingface.tokenizers.HuggingFaceTokenizer ai.djl.huggingface.tokenizers.HuggingFaceTokenizer.Builder ai.djl.hu

    基于蒙特卡洛算法的电动汽车对IEEE 33节点电网影响的研究及应用场景分析

    内容概要:本文探讨了电动汽车(EV)对IEEE 33节点电网的影响,特别是汽车负荷预测与节点潮流网损、压损计算。通过蒙特卡洛算法模拟电动汽车负荷的时空特性,研究了四种不同场景下电动汽车接入电网的影响。具体包括:负荷接入前后的网损与电压计算、不同节点接入时的变化、不同时段充电的影响以及不同负荷大小对电网的影响。通过这些分析,揭示了电动汽车充电行为对电网的具体影响机制,为未来的电网规划和优化提供了重要参考。 适合人群:从事电力系统研究的专业人士、电网规划工程师、电动汽车行业从业者、能源政策制定者。 使用场景及目标:①评估电动汽车大规模接入对现有电网基础设施的压力;②优化电动汽车充电设施的布局和运营策略;③为相关政策和技术标准的制定提供科学依据。 其他说明:文中提供的Python代码片段用于辅助理解和验证理论分析,实际应用中需要更复杂的模型和详细的电网参数。

    房地产 -【万科经典-第五园】第五园产品推介会.ppt

    房地产 -【万科经典-第五园】第五园产品推介会.ppt

    稳压器件.SchLib

    稳压器件.SchLib

    1.jpg

    1

    模拟符号.SCHLIB

    模拟符号.SCHLIB

    基于Simulink的三相电压型逆变器SPWM与电压单闭环控制仿真

    内容概要:本文详细介绍了如何在Simulink中构建并仿真三相电压型逆变器的SPWM调制和电压单闭环控制系统。首先,搭建了由六个IGBT组成的三相全桥逆变电路,并设置了LC滤波器和1000V直流电源。接着,利用PWM Generator模块生成SPWM波形,设置载波频率为2kHz,调制波为50Hz工频正弦波。为了实现精确的电压控制,采用了abc/dq变换将三相电压信号转换到旋转坐标系,并通过锁相环(PLL)进行同步角度跟踪。电压闭环控制使用了带有抗饱和处理的PI调节器,确保输出电压稳定。此外,文中还讨论了标幺值处理方法及其优势,以及如何通过FFT分析验证输出波形的质量。 适用人群:电力电子工程师、自动化控制专业学生、从事逆变器研究的技术人员。 使用场景及目标:适用于希望深入了解三相电压型逆变器控制原理和技术实现的研究人员和工程师。主要目标是掌握SPWM调制技术和电压单闭环控制的设计与调试方法,提高系统的稳定性和效率。 其他说明:文中提供了详细的建模步骤和参数设置指南,帮助读者快速上手并在实践中不断优化模型性能。同时,强调了一些常见的调试技巧和注意事项,如载波频率的选择、积分器防饱和处理等。

    【蓝桥杯EDA】客观题解析:第十三届立创EDA出品省赛模拟题一.pdf

    【蓝桥杯EDA】客观题解析

    房地产 -物业 苏州设备房管理标准.ppt

    房地产 -物业 苏州设备房管理标准.ppt

    3.png

    3

    房地产 -2024H1房地产市场总结与展望(新房篇).docx

    房地产 -2024H1房地产市场总结与展望(新房篇).docx

    LabVIEW与PLC基于TCP协议的自动化数据交互解决方案

    内容概要:本文详细介绍了利用LabVIEW与PLC进行自动化数据交互的技术方案,涵盖参数管理、TCP通信、串口扫描、数据转移等方面。首先,通过配置文件(INI)实现参数的自动加载与保存,确保参数修改不影响程序运行。其次,在TCP通信方面采用异步模式和心跳包设计,增强通信稳定性,并加入CRC16校验避免数据丢失。对于串口扫描,则通过VISA配置实现状态触发,确保进出站检测的准确性。最后,针对不同类型的数据转移提出具体方法,如TDMS文件存储策略,确保高效可靠的数据处理。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是熟悉LabVIEW和PLC编程的从业者。 使用场景及目标:适用于需要将LabVIEW作为上位机与PLC进行数据交互的工业生产线环境,旨在提高系统的自动化程度、稳定性和易维护性。 其他说明:文中提供了多个实用代码片段和注意事项,帮助读者更好地理解和应用相关技术。

    d65689da7ed20e21882a634f8f5ce6c9_faad2735d293907fb32f7c5837f7302a.png

    d65689da7ed20e21882a634f8f5ce6c9_faad2735d293907fb32f7c5837f7302a

Global site tag (gtag.js) - Google Analytics