`

基于@AspectJ的Aop来实现缓存控制报NoSuchMethodException

阅读更多

项目中基于@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){

           代码略..
        }

 

 

 获取还有更好的办法,暂时先用上吧

分享到:
评论

相关推荐

    征服Spring AOP—— @AspectJ

    在IT行业中,Spring框架是Java企业级应用开发的首选,而Spring AOP(面向切面编程)则是其核心特性之一,用于实现横切关注点的模块化,如日志、事务管理等。@AspectJ是Spring AOP的一种注解驱动方式,它极大地简化了...

    Spring @AspectJ 实现AOP 入门例子

    本篇文章将深入探讨如何利用Spring的@AspectJ注解来实现AOP,这是一个入门级别的例子,旨在帮助开发者理解并掌握这一关键特性。 首先,我们要明白什么是AOP。面向切面编程是一种编程范式,它允许程序员定义“切面”...

    @AspectJ配置Spring AOP,demo

    在Spring AOP中,@AspectJ注解是实现切面编程的关键。@AspectJ是一种类型级别的元数据,它允许我们定义切面类,其中包含了切点(Pointcut)、通知(Advice)和组装(Join Point)等概念。 **一、@AspectJ注解** @...

    Spring的AOP实例(XML+@AspectJ双版本解析+源码+类库)

    在Java世界中,Spring框架以其强大的功能和灵活性深受开发者喜爱,尤其在面向切面编程(AOP)方面,Spring提供了两种主要的实现方式:XML配置和@AspectJ注解。本篇文章将深入探讨这两个版本的AOP实现,并结合源码...

    Spring AOP 概念理解及@AspectJ支持

    Spring AOP的实现基于动态代理,对于接口实现类,它使用Java的`java.lang.reflect.Proxy`类来创建代理对象;对于没有接口的类,Spring使用CGLIB库生成子类。在运行时,Spring AOP会根据切面定义生成代理对象,然后...

    Spring AOP @AspectJ 入门实例

    基于代理的织入通常用于Spring的IoC容器中的bean,而基于字节码的织入则是在运行时通过ASM库动态修改类的字节码来实现,这正是@AspectJ所采用的方式。 @AspectJ是Spring AOP的一个扩展,它提供了一种更接近传统编程...

    spring AOP 实例(@AspectJ)

    一个基于@AspectJ的spring2.0 AOP应用实例,很小很简单,没有任何额外信息,最适合AOP入门学习。使用log4j打印信息。把项目直接import进myeclipse就可以使用啦......

    Spring 使用AspectJ 实现 AOP

    在Spring中,我们可以使用AspectJ来实现AOP,AspectJ是一个强大的AOP框架,它可以与Spring无缝集成,提供更细粒度的控制。 首先,让我们了解一下AOP中的通知类型: 1. **前置通知**(Before Advice):在目标方法...

    基于框架的Web开发-基于AspectJ的AOP.doc

    总结来说,基于@AspectJ的AOP使得在Web开发中可以方便地实现横切关注点,将业务逻辑与辅助功能(如日志、事务处理)分离,提高了代码的模块化程度和可维护性。通过注解和XML配置,我们可以轻松地定义和应用切面,...

    spring对AOP的支持(使用AspectJ进行AOP演示)

    Spring 提供了两种主要的 AOP 实现方式:基于代理的和基于 AspectJ 的。基于代理的方式是 Spring 默认的实现,它通过 JdkDynamicProxy 或 CGLIB 创建代理对象来实现切面。而基于 AspectJ 的方式则更为强大,它允许...

    Spring 使用AspectJ 实现 AOP(基于xml文件、基于注解)

    本教程将探讨如何在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-切面。Spring4 In Action-4.2-@AspectJ-切面

    基于AspectJ的AOP开发案例源码.rar

    demo1是aspectj的Aop开发,用于用户是否登录的验证,使用注解来实现,在切面类中配置好切入点。优点:方便快捷 demo2是aspectj的Aop开发,用于用户是否登录的验证,在xml中配置好切面。 优点:便于维护,不用修改源...

    AOP@Work AOP 工具比较

    虽然Spring AOP的功能相对较弱,不支持AspectJ的全部特性,但它与Spring框架的其他部分无缝集成,对于已经在使用Spring的项目来说,使用Spring AOP进行AOP编程非常便捷。 在选择AOP工具时,开发者需要考虑以下因素...

    spring AspectJ aop学习

    当我们谈论"spring AspectJ aop学习"时,我们将深入探讨Spring AOP如何结合AspectJ来实现更灵活的模块化和解耦。 首先,让我们理解AOP的概念。面向切面编程(Aspect Oriented Programming)是一种编程范式,旨在将...

    spring5基于aspectj实现aop操作所需jar包

    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....

Global site tag (gtag.js) - Google Analytics