利用spring的 * 自定义缓存的实现实例代码
作者:txxs 发布时间:2022-07-22 00:44:47
标签:spring,缓存, ,
本文研究的主要是利用spring的 * 自定义缓存的实现,具体实现代码如下所示。
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。本文利用Memcached 的实例和spring的 * 实现缓存自定义的实现。利用 * 读取自定义的缓存标签,key值的生成策略。
自定义的Cacheable
package com.jeex.sci;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
String namespace();
String key() default "";
int[] keyArgs() default {
}
;
String[] keyProperties() default {
}
;
String keyGenerator() default "";
int expires() default 1800;
}
自定义的CacheEvict
package com.jeex.sci;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheEvict {
String namespace();
String key() default "";
int[] keyArgs() default {
}
;
String[] keyProperties() default {
}
;
String keyGenerator() default "";
}
spring如果需要前后通知的话,一般会实现MethodInterceptor public Object invoke(MethodInvocation invocation) throws Throwable
public Object invoke(MethodInvocation invoction) throws Throwable {
Method method = invoction.getMethod();
Cacheable c = method.getAnnotation(Cacheable.class);
if (c != null) {
return handleCacheable(invoction, method, c);
}
CacheEvict ce = method.getAnnotation(CacheEvict.class);
if (ce != null) {
return handleCacheEvict(invoction, ce);
}
return invoction.proceed();
}
处理cacheable标签
private Object handleCacheable(MethodInvocation invoction, Method method,
Cacheable c) throws Throwable {
String key = getKey(invoction, KeyInfo.fromCacheable(c));
if (key.equals("")) {
if (log.isDebugEnabled()){
log.warn("Empty cache key, the method is " + method);
}
return invoction.proceed();
}
long nsTag = (long) memcachedGet(c.namespace());
if (nsTag == null) {
nsTag = long.valueOf(System.currentTimeMillis());
memcachedSet(c.namespace(), 24*3600, long.valueOf(nsTag));
}
key = makeMemcachedKey(c.namespace(), nsTag, key);
Object o = null;
o = memcachedGet(key);
if (o != null) {
if (log.isDebugEnabled()) {
log.debug("CACHE HIT: Cache Key = " + key);
}
} else {
if (log.isDebugEnabled()) {
log.debug("CACHE MISS: Cache Key = " + key);
}
o = invoction.proceed();
memcachedSet(key, c.expires(), o);
}
return o;
}
处理cacheEvit标签
private Object handleCacheEvict(MethodInvocation invoction,
CacheEvict ce) throws Throwable {
String key = getKey(invoction, KeyInfo.fromCacheEvict(ce));
if (key.equals("")) {
if (log.isDebugEnabled()) {
log.debug("Evicting " + ce.namespace());
}
memcachedDelete(ce.namespace());
} else {
Long nsTag = (Long) memcachedGet(ce.namespace());
if (nsTag != null) {
key = makeMemcachedKey(ce.namespace(), nsTag, key);
if (log.isDebugEnabled()) {
log.debug("Evicting " + key);
}
memcachedDelete(key);
}
}
return invoction.proceed();
}
根据参数生成key
//使用拦截到方法的参数生成参数
private String getKeyWithArgs(Object[] args, int[] argIndex) {
StringBuilder key = new StringBuilder();
boolean first = true;
for (int index: argIndex) {
if (index < 0 || index >= args.length) {
throw new IllegalArgumentException("Index out of bound");
}
if (!first) {
key.append(':');
} else {
first = false;
}
key = key.append(args[index]);
}
return key.toString();
}
根据属性生成key
private String getKeyWithProperties(Object o, String props[])
throws Exception {
StringBuilder key = new StringBuilder();
boolean first = true;
for (String prop: props) {
//把bean的属性转为获取方法的名字
String methodName = "get"
+ prop.substring(0, 1).toUpperCase()
+ prop.substring(1);
Method m = o.getClass().getMethod(methodName);
Object r = m.invoke(o, (Object[]) null);
if (!first) {
key.append(':');
} else {
first = false;
}
key = key.append(r);
}
return key.toString();
}
利用自定义的生成器生成key
//使用生成器生成key
private String getKeyWithGenerator(MethodInvocation invoction, String keyGenerator)
throws Exception {
Class<?> ckg = Class.forName(keyGenerator);
CacheKeyGenerator ikg = (CacheKeyGenerator)ckg.newInstance();
return ikg.generate(invoction.getArguments());
}
保存key信息的帮助类
private static class KeyInfo {
String key;
int[] keyArgs;
String keyProperties[];
String keyGenerator;
static KeyInfo fromCacheable(Cacheable c) {
KeyInfo ki = new KeyInfo();
ki.key = c.key();
ki.keyArgs = c.keyArgs();
ki.keyGenerator = c.keyGenerator();
ki.keyProperties = c.keyProperties();
return ki;
}
static KeyInfo fromCacheEvict(CacheEvict ce) {
KeyInfo ki = new KeyInfo();
ki.key = ce.key();
ki.keyArgs = ce.keyArgs();
ki.keyGenerator = ce.keyGenerator();
ki.keyProperties = ce.keyProperties();
return ki;
}
String key() {
return key;
}
int[] keyArgs() {
return keyArgs;
}
String[] keyProperties() {
return keyProperties;
}
String keyGenerator() {
return keyGenerator;
}
}
参数的设置
//使用参数设置key
@Cacheable(namespace="BlackList", keyArgs={0, 1})
public int anotherMethond(int a, int b) {
return 100;
}
测试类:
package com.jeex.sci.test;
import net.spy.memcached.MemcachedClient;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class TestMain {
public static void main(String args[]) throws InterruptedException{
ApplicationContext ctx = new FileSystemXmlApplicationContext("/src/test/resources/beans.xml");
MemcachedClient mc = (MemcachedClient) ctx.getBean("memcachedClient");
BlackListDaoImpl dao = (BlackListDaoImpl)ctx.getBean("blackListDaoImpl");
while (true) {
System.out.println("################################GETTING START######################");
mc.flush();
BlackListQuery query = new BlackListQuery(1, "222.231.23.13");
dao.searchBlackListCount(query);
dao.searchBlackListCount2(query);
BlackListQuery query2 = new BlackListQuery(1, "123.231.23.14");
dao.anotherMethond(333, 444);
dao.searchBlackListCount2(query2);
dao.searchBlackListCount3(query2);
dao.evict(query);
dao.searchBlackListCount2(query);
dao.evictAll();
dao.searchBlackListCount3(query2);
Thread.sleep(300);
}
}
}
来源:http://blog.csdn.net/maoyeqiu/article/details/50325779


猜你喜欢
- Redis 3.X版本引入了集群的新特性,为了保证所开发系统的高可用性项目组决定引用Redis的集群特性。对于Redis数据访问的支持,目前
- 一、算法描述波雷费密码是一种对称式密码,是首种双字母取代的加密法。下面描述算法步骤:1、从1号二维码M05,提取明文信息和密文,M05格式:
- 一、TkMybatisTkmybatis 是基于 Mybatis 框架开发的一个工具,通过调用它提供的方法实现对单表的数据操作,不需要写任何
- 目录1、设Tree为已定义的类名,下列语句能正确创建 Tree 对象的是 。2、区分类中重载方法的依据是( )。3、以下代码执行后输出结果为
- 1.RecycledPool的重用场景以及使用:多个RecyclerView出现,并且他们的item布局结构一致,这时候可以进行重用。在进行
- 本课程的目标是帮你更有效的使用Java。其中讨论了一些高级主题,包括对象的创建、并发、序列化、反射以及其他高级特性。本课程将为你的精通Jav
- 一.内部类的介绍 内部类: 一个类定义在 另一个类 的 内部。 &
- dynamic是C#里面的动态类型,可在未知类型的情况访问对应的属性,非常灵活和方便。使用Json.Net可以把一个Json字符串转换成一个
- 原理 Redis Cluster 一般由多个节点组成,节点数量至少为 6 个才能保证组成完整高可用的集群,其中三个为主
- 前言在日常的Android开发中,我们在做登录注册等带有提示性输入校验的时候。常常会写样子写代码:然后你会发现每一次写带有提交信息页面的时候
- 最近项目需要用到可以滑动删除并且带有上拉加载下拉刷新的Listview,查阅了一些资料,大多都是在SwipeMenuListView的基础上
- 写在前面“The origin server did not find a current representation for the t
- 第一种:(调用系统API)首先引入两个命名空间using System.Runtime.InteropServices;using Syst
- 一、什么是 RestTemplate?RestTemplate是执行HTTP请求的同步阻塞式的客户端,它在HTTP客户端库(例如JDK Ht
- 先上效果图,如果大家感觉不错,请参考实现代码。 重要的是如何实现自定义的
- 效果视频简述本Demo采用Hilt+Retrofit+Paging3完成,主要为了演示paging3分页功能的使用,下列为Demo所需要的相
- 本文实例讲述了Android编程实现二级下拉菜单及快速搜索的方法。分享给大家供大家参考,具体如下:一、我们要做什么?上面有个搜索框,下面是一
- C++的函数指针(function pointer)是通过指向函数的指针间接调用函数。相信很多人对指向一般函数的函数指针使用的比较多,而对指
- 1.企业实际项目中Git的使用在实际的企业项目开发中,我们一般Java的项目在公司都有自己的局域网代码仓库,仓库上存放着很多的项目。以我工作
- 首先创建一个工具类import android.annotation.TargetApi;import android.app.Activi