Spring Aop 实现一个简单的memcached小插件

memcached我就不多做介绍了,也就是一个分布式缓存系统!是一个典型的NOSQL。

下面我将用spring aop来实现一个简单的插件,来实现annotation方式,简单方便的取得缓存

一、首先我们得定义一个annotation.

<strong>package org.xiezhaodong.spring.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GetCacheVaule {

	public String key();//key

}</strong>

因为memcached有很多不同得客户端,那么我会定义一个自己的接口。让用户自行实现。下面就是接口,定义了一些简单的方法

package org.xiezhaodong.spring.cache.cacheutil;
/**
 * 2015-1-14
 * @author xiezhaodong
 *缓存接口,用户自行实现
 */
public interface CacheSupport {
	long CACHE_TIME=2*60*60;//默认缓存时间为2小时

	/**
	 * 加入缓存
	 * @param key 键
	 * @param value 值
	 * @return 是否成功
	 */
	 boolean addCache(String key,Object value);

	 /**
	  * 加入缓存,并设置缓存时间
	  * @param key 键
	  * @param value 值
	  * @param time 缓存时间
	  * @return 是否成功
	  */
	 boolean addCache(String key,Object value,long cacheTime);

	 /**
	  * 删除缓存
	  * @param key 键
	  * @return 是否成功
	  */
	 boolean deleteCache(String key);

	 /**
	  * 得到缓存
	  * @param key 键
	  * @return 返回值
	  */
	 Object getCache(String key);

	 /**
	  * 替换缓存中对应的值
	  * @param key 键
	  * @param value 值
	  * @return 是否替换成功
	  */
	 boolean replaceCache(String key,Object value);

}

接下来就是切面了。注释里面都很详细

package org.xiezhaodong.spring.cache.aop;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.xiezhaodong.spring.annotation.GetCacheVaule;
import org.xiezhaodong.spring.cache.cacheutil.CacheSupport;

/**
 * Aop切面类,实际的作用类
 *
 * @author xiezhaodong
 *
 */
public class GetCacheAop {

	private static final Log log = LogFactory.getLog(GetCacheAop.class);

	private CacheSupport cacheSupport;

	public void setCacheSupport(CacheSupport cacheSupport) {
		this.cacheSupport = cacheSupport;
	}

	public Object ProxyInvoke(ProceedingJoinPoint pjp) {
		log.info("invoke proxyinvoke method");
		Object result = null;
		// 得到运行的方法
		Method method = getMethod(pjp);
		Annotation[] annotations = method.getDeclaredAnnotations();

		if (annotations.length == 0) {//如果不存在注解,直接执行不缓存
			try {
				result = pjp.proceed();
				return result;
			} catch (Throwable e) {
				log.warn("your method " + method.getName()+ " have some errors");
			}
		}
		// --------------------------
		String cacheKey = getCacheKey(pjp, method);

		result = get_or_input_cache(pjp, result, cacheKey);

		return result;

	}
	/**
	 * 得到缓存或者从数据库中查到并且放入缓存
	 * @param pjp
	 * @param result
	 * @param cacheKey
	 * @return
	 */
	private Object get_or_input_cache(ProceedingJoinPoint pjp, Object result,
			String cacheKey) {
		if (cacheKey != null) {
			result = cacheSupport.getCache(cacheKey);// 得到缓存,修改result的值
			if(result==null){//如果该缓存里面没有,得到result并缓存到缓存服务其中
				try {
					result=pjp.proceed();
					cacheSupport.addCache(cacheKey,result);
					return result;
				} catch (Throwable e) {
					log.warn("invoke default");
				}
			}
			return result;//缓存存在,直接返回result
		}else{//如果没有该注解直接执行方法
			try {
				result=pjp.proceed();

			} catch (Throwable e) {
				log.warn("invoke default");
			}
		}
		return result;
	}

	/**
	 * 取得cache 键值
	 *
	 * @param pjp
	 * @param method
	 * @return 返回string
	 */
	private String getCacheKey(ProceedingJoinPoint pjp, Method method) {
		if (method.isAnnotationPresent(GetCacheVaule.class)) {
			// 如果有该注解
			String key = method.getAnnotation(GetCacheVaule.class).key();// 得到要缓存的键值

			Object[] values = pjp.getArgs();// 得到顺序的参数值
			ParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
			String[] names = discoverer.getParameterNames(method);
			Map<String, Integer> map = new ConcurrentHashMap<String, Integer>();
			for (int i = 0; i < names.length; i++) {
				map.put(names[i], i);// 将名字和对应的序号放入hashmap
			}
			// 得到真正的key 、value值
			try {
				Integer int_value = map.get(key);// hash中没有对应的值,表示getcachekey和名字不符合
				if (int_value == null) {
					log.warn("your cachekey is not equals" + key
							+ "please check this then change them");
				} else {
					String cache_key_real = (String) values[int_value];// 要缓存键值的真正cahe值
					return cache_key_real;
				}
			} catch (Exception e) {
				log.warn("your filed " + key + " must be String.class");
			}

		}
		return null;
	}

	/**
	 * 得到运行时方法对象
	 *
	 * @param pjp
	 * @return
	 */
	private Method getMethod(ProceedingJoinPoint pjp) {
		MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
		Method method = methodSignature.getMethod();
		return method;
	}

}

然后就是xml的配置,注意cglib代理一定要开启

	<bean id="aimpl" class="org.xie.service.Service_A_impl"></bean>
	<bean id="bimpl" class="org.xie.service.Service_B_impl"></bean>

	<bean id="memDefault" class="org.xie.framework.memcached.spring.MemcachedDefault">
		<property name="cached" ref="memClient"></property>
	</bean>

	<bean id="cacheAop" class="org.xie.framework.memcached.spring.GetCacheAop">
	<property name="cacheSupport" ref="memDefault"></property>
	</bean>
	<aop:aspectj-autoproxy proxy-target-class="true"/> <!-- cglib代理开启 -->
	<aop:config>

		<aop:aspect id="myAspect" ref="cacheAop">
			<aop:pointcut id="businessService" expression="execution(* org.xie.service.*.*(..))" />
			<aop:around pointcut-ref="businessService" method="ProxyInvoke" />
		</aop:aspect>

	</aop:config>

那么现在service层的所有方法都有被代理了。那么我们只需要这样做,key就表示要缓存的键值

@Override
	@GetCacheVaule(key="id")//表示要缓存id
	public Object testaop(String id) {

		return "sssss";
	}

其实感觉也没有什么好讲的,要讲的都是在代码里面,各位都指点指点吧。但是目前只实现了醉简单的getcache,以后我会慢慢的完善各种api,敬请期待吧!!

转载请注明http://blog.csdn.net/a837199685

时间: 2024-10-17 11:18:40

Spring Aop 实现一个简单的memcached小插件的相关文章

一个简单的数学小魔术

在一张纸上并排画 11 个小方格.叫你的好朋友背对着你(确保你看不到他在纸上写什么),在前两个方格中随便填两个 1 到 10 之间的数.从第三个方格开始,在每个方格里填入前两个方格里的数之和.让你的朋友一直算出第 10 个方格里的数.假如你的朋友一开始填入方格的数是 7 和 3 ,那么前 10 个方格里的数应该是 7 3 10 13 23 36 59 95 154 249 现在,叫你的朋友报出第 10 个方格里的数,你只需要在计算器上按几个键,便能说出第 11 个方格里的数应该是多少.你的朋友会

【SSH进阶之路】一步步重构容器实现Spring框架——从一个简单的容器开始(八)

目录 [SSH进阶之路]一步步重构容器实现Spring框架--从一个简单的容器开始(八) [SSH进阶之路]一步步重构容器实现Spring框架--解决容器对组件的"侵入式"管理的两种方案--主动查找和控制反转(九)(未更新) [SSH进阶之路]一步步重构容器实现Spring框架--配置文件+反射实现IoC容器(十)(未更新) [SSH进阶之路]一步步重构容器实现Spring框架--彻底封装,实现简单灵活的Spring框架(十一)(未更新) 最近一直在和容器打交道,甚至前面的博文,我们也

一个简单的页面弹窗插件 jquery.pageMsgFrame.js

页面弹窗是网站中常用的交互效果,它可以强提示网站的某些信息给用户,或者作用于某些信息的修改等等功能. 这几天在做一个项目的时候,就顺捎把这个插件写一下,栽棵树,自己乘凉吧. 原创博文,转载请注明出处:http://www.cnblogs.com/dereksunok/p/3724764.html html代码: 1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5

一个简单的MariaDB认证插件demo

代码地址如下:http://www.demodashi.com/demo/13076.html 一.前言 众所周知(其实可能很多人不知道)MariaDB支持插件认证.在MariaDB中新建用户,常见的语句是: CREATE USER 'username'@'host' IDENTIFIED BY 'password'; 这样创建的用户,登录时的认证方式是密码.其实创建用户的语句还可以是: CREATE USER 'username'@'host' IDENTIFIED VIA 'pluginna

spring AOP + 自定义注解实现权限控制小例子

今天看了一下黑马程序员的视频,上面讲到一个使用spring AOP + 自定义注解的方式来实现权限控制的一个小例子,个人觉得还是可以借鉴,整理出来与大家分享. 需求:service层有一些方法,这些方法需要不同的权限才能访问. 实现方案:自定义一个PrivilegeInfo的注解,使用这个注解为service层中的方法进行权限配置,在aop中根据PrivilegeInfo注解的值,判断用户是否拥有访问目标方法的权限,有则访问目标方法,没有则给出提示. 关键技术:自定义注解及注解解析,spring

spring AOP概述和简单应用

引用概念: http://www.cnblogs.com/hongwz/p/5764917.html AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入封装.继承.多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合.不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能.日志代码往往横向地散布在所有对象层次中,而与它对

Spring AOP注解形式简单实现

实现步骤: 1:导入类扫描的注解解析器 命名空间:xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-2.5.xsd" xml配置文件如下配置

阿里微服务专家手写Spring Boot 实现一个简单的自动配置模块

为了更好的理解 Spring Boot 的 自动配置和工作原理,我们自己来实现一个简单的自动配置模块. 假设,现在项目需要一个功能,需要自动记录项目发布者的相关信息,我们如何通过 Spring Boot 的自动配置,更好的实现功能呢? 实战的开端 – Maven搭建 先创建一个Maven项目,我来手动配置下 POM 文件. 参数的配置 - 属性参数类 首先,我们定义一个自定义前缀,叫做 custom 吧.之前说到,这里的配置参数,可以通过 application.properties 中直接设置

spring aop 的一个demo(未完,待完善)

假设我们有这样的一个场景 : 对于一个类的众多方法,有些方法需要从缓存读取数据,有些则需要直接从数据库读取数据.怎样实现呢? 实现方案有多种.下面我说下常见的几种实现方案 : 1.直接采用spring xml.或者  annotation AOP完成.但个人认为这种方案似乎有点不是很完美. 原因 :  ①.如果只有针对这个类做切面拦截,这种方案是没有问题的,只需对需要走DB(or 缓存,两者择一)的方法配置切面. ②.那如果是多个类呢?统一做一个切面,对指定方法拦截,如selectXXX.但,还