项目中基于@Aspect实现AOP,通过环绕增强(@Around)控制Dao的缓存(set/delete)。DAO接口及实现及AOP部分代码如下:
///////////////////////////////////////////////////
package cn.xxx.dao;
public interface FunModuleDao {
/**
* 更新用户视图布局
*
* @param userId 用户ID
* @param fmlList 布局对象列表
*/
public void updateFunModuleUsers(Long userId,List fmlList);
}
//////////////////////////////////////////////
package cn.xxx.dao.impl;
@Repository
public class FunModuleDaoImpl implements FunModuleDao {
@Override
@CacheEvict(prefix = "userCache", suffix="0")
public void updateFunModuleUsers(Long userId,List fmlList){
代码略..
}
////////////////////////////////////////////////
package cn.xxx.cache.aop;
@Component
@Aspect
public class CacheAop {
private static final Log log = LogFactory.getLog(CacheAop.class);
@Autowired
private SiteService siteService;
@Autowired
private MemKeyService memKeyService;
@Autowired
private MemCachedClient memCachedClient ;
@Around(value="@annotation(cn.xxx.cache.annotation.Cacheable)")
public Object cache(ProceedingJoinPoint call){
Object result = null;
Boolean cacheEnable = CustomizedPropertyPlaceholderConfigurer.getCacheEnabled();
//判断是否开启缓存
if(!cacheEnable){
try {
result= call.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
return result;
}
Method method=getMethod(call);
Cacheable cacheable=method.getAnnotation(cn.ac.ucas.sep.cache.annotation.Cacheable.class);
String fieldKey =parseKey(cacheable.suffix(),method,call.getArgs());
String prefix = cacheable.prefix();
String cacheKey = prefix+"_"+fieldKey;
result =memCachedClient.get(cacheKey);
if(null == result){
try {
result = call.proceed();
long expiration = cacheable.expiration();//1000*60*60*48==48小时过期
Date expirationTime=new Date(System.currentTimeMillis()+expiration);
memCachedClient.set(cacheKey, result,expirationTime));
} catch (Throwable e) {
e.printStackTrace();
}
}
return result;
}
/**
* 定义清除缓存逻辑
*/
@Around(value="@annotation(cn.xxx.cache.annotation.CacheEvict)")
public Object evict(ProceedingJoinPoint call){
代码略...
}
/**
* 获取被拦截方法对象
*
* MethodSignature.getMethod() 获取的是顶层接口或者父类的方法对象
* 而缓存的注解在实现类的方法上
* 所以应该使用反射获取当前对象的方法对象
*/
public Method getMethod(ProceedingJoinPoint call){
//获取参数的类型
Object [] args=call.getArgs();
Class [] argTypes=new Class[call.getArgs().length];
for(int i=0;i<args.length;i++){
argTypes[i]=args[i].getClass();
}
Method method=null;
try {
method=call.getTarget().getClass().getMethod(call.getSignature().getName(),argTypes);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return method;
}
/**
* 获取缓存的key
* key 定义在注解上,支持SPEL表达式
*/
private String parseKey(String key,Method method,Object [] args){
代码略...
}
}
运行调试过程中出现一个很诡异的问题,错误信息如下:
java.lang.NoSuchMethodException: cn.xxx.dao.impl.FunModuleDaoImpl.updateFunModuleUsers(java.lang.Long, java.util.ArrayList) at java.lang.Class.getMethod(Class.java:1607) at cn.ac.ucas.sep.cache.aop.CacheAop.getMethod(CacheAop.java:148) //CacheAop.java:148即method=call.getTarget().getClass().getMethod(call.getSignature().getName(),argTypes);
跟踪执行过程最终找到原因:
通过ProceedingJoinPoint.getArgs()[1].getClass()获取的第二个参数类型(java.util.ArrayList)与call.getTarget().getClass().getMethod(...)中的类型(java.util.List)不匹配造成的。
解决办法:
修改Dao接口和实现的参数类型由List变为ArrayList
/////////////////////////////////////////////////// package cn.xxx.dao; public interface FunModuleDao { /** * 更新用户视图布局 * * @param userId 用户ID * @param fmlList 布局对象列表 */ public void updateFunModuleUsers(Long userId,ArrayList fmlList); } ////////////////////////////////////////////// package cn.xxx.dao.impl; @Repository public class FunModuleDaoImpl implements FunModuleDao { @Override @CacheEvict(prefix = "userCache", suffix="0") public void updateFunModuleUsers(Long userId,ArrayList fmlList){ 代码略.. }
获取还有更好的办法,暂时先用上吧
相关推荐
在IT行业中,Spring框架是Java企业级应用开发的首选,而Spring AOP(面向切面编程)则是其核心特性之一,用于实现横切关注点的模块化,如日志、事务管理等。@AspectJ是Spring AOP的一种注解驱动方式,它极大地简化了...
本篇文章将深入探讨如何利用Spring的@AspectJ注解来实现AOP,这是一个入门级别的例子,旨在帮助开发者理解并掌握这一关键特性。 首先,我们要明白什么是AOP。面向切面编程是一种编程范式,它允许程序员定义“切面”...
在Spring AOP中,@AspectJ注解是实现切面编程的关键。@AspectJ是一种类型级别的元数据,它允许我们定义切面类,其中包含了切点(Pointcut)、通知(Advice)和组装(Join Point)等概念。 **一、@AspectJ注解** @...
在Java世界中,Spring框架以其强大的功能和灵活性深受开发者喜爱,尤其在面向切面编程(AOP)方面,Spring提供了两种主要的实现方式:XML配置和@AspectJ注解。本篇文章将深入探讨这两个版本的AOP实现,并结合源码...
Spring AOP的实现基于动态代理,对于接口实现类,它使用Java的`java.lang.reflect.Proxy`类来创建代理对象;对于没有接口的类,Spring使用CGLIB库生成子类。在运行时,Spring AOP会根据切面定义生成代理对象,然后...
基于代理的织入通常用于Spring的IoC容器中的bean,而基于字节码的织入则是在运行时通过ASM库动态修改类的字节码来实现,这正是@AspectJ所采用的方式。 @AspectJ是Spring AOP的一个扩展,它提供了一种更接近传统编程...
一个基于@AspectJ的spring2.0 AOP应用实例,很小很简单,没有任何额外信息,最适合AOP入门学习。使用log4j打印信息。把项目直接import进myeclipse就可以使用啦......
在Spring中,我们可以使用AspectJ来实现AOP,AspectJ是一个强大的AOP框架,它可以与Spring无缝集成,提供更细粒度的控制。 首先,让我们了解一下AOP中的通知类型: 1. **前置通知**(Before Advice):在目标方法...
总结来说,基于@AspectJ的AOP使得在Web开发中可以方便地实现横切关注点,将业务逻辑与辅助功能(如日志、事务处理)分离,提高了代码的模块化程度和可维护性。通过注解和XML配置,我们可以轻松地定义和应用切面,...
Spring 提供了两种主要的 AOP 实现方式:基于代理的和基于 AspectJ 的。基于代理的方式是 Spring 默认的实现,它通过 JdkDynamicProxy 或 CGLIB 创建代理对象来实现切面。而基于 AspectJ 的方式则更为强大,它允许...
本教程将探讨如何在Spring中结合AspectJ实现AOP,包括基于XML配置和基于注解的方式。 **一、AOP基本概念** AOP的核心概念有切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)和引入...
Spring4 In Action-4.2-@AspectJ-切面,Spring4 In Action-4.2-@AspectJ-切面。Spring4 In Action-4.2-@AspectJ-切面
demo1是aspectj的Aop开发,用于用户是否登录的验证,使用注解来实现,在切面类中配置好切入点。优点:方便快捷 demo2是aspectj的Aop开发,用于用户是否登录的验证,在xml中配置好切面。 优点:便于维护,不用修改源...
虽然Spring AOP的功能相对较弱,不支持AspectJ的全部特性,但它与Spring框架的其他部分无缝集成,对于已经在使用Spring的项目来说,使用Spring AOP进行AOP编程非常便捷。 在选择AOP工具时,开发者需要考虑以下因素...
当我们谈论"spring AspectJ aop学习"时,我们将深入探讨Spring AOP如何结合AspectJ来实现更灵活的模块化和解耦。 首先,让我们理解AOP的概念。面向切面编程(Aspect Oriented Programming)是一种编程范式,旨在将...
spring5基于aspectj实现aop操作所需jar包 com.springsource.net.sf.cglib-2.2.0.jar com.springsource.org.aopalliance-1.0.ar com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar spring-aspects-5.2.6....