yue_ch 2009-07-15 08:55
浏览 354
已采纳

一个关于Spring AOP的问题

先说一下情况:小弟现正用Spring AOP实现日志记录功能,上面交待Web层,Service层,Dao层都要记录,所以打算在Web层只记一下用户请求的情况,也就是说用户请求哪个Action时,记录一下操作步骤,Service层记录方法调用时的参数及返回值以及异常情况,Dao层上面交待要记录最终SQL(这个小弟现在还不知道怎么实现)。
在此只说一下Web层的日志记录,其它的略过了。我是这样的,先定义一个名为ActionName的annotation,有一个value属性,这个value属性的值就表示该Action方法的功能说明。然后我定义一个Pointcut匹配该annotation。到这里一切都没问题,能正常拦截并代理Action方法,但是前提是必须使用CGLIB!
我记得好像Spring能自动地判断目标方法并决定是使用动态代理还是CGLIB代理实现的。但是我在配置文件中如果不强制使用CGLIB代理则程序运行报错呢?
下面是我的代码:

LogHandler类
package com.delver.bms.log.util;

import java.lang.reflect.Method;
import java.sql.Timestamp;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

import com.delver.bms.exception.BusinessException;
import com.delver.bms.log.annotation.ActionName;
import com.delver.bms.log.annotation.TaskScheduling;
import com.delver.bms.log.dao.IAppLogDao;
import com.delver.bms.log.to.AppLog;
import com.delver.bms.util.AutoID32;
import com.delver.bms.util.TenantUtil;
import com.ibm.crl.mmt.datamodel.MTUtilFactory;
import com.ibm.crl.mmt.exception.MTException;

/**

  • 日志记录切面类
  • @author yue.ch
  • */ @Aspect public class LogHandler {

private IAppLogDao appLogDao;

public void setAppLogDao(IAppLogDao appLogDao) {
this.appLogDao = appLogDao;
}

/**

  • 定义切入点,匹配使用@ActionName注解的方法
  • @param actionName @ActionName注解value值(功能解释) */ @Pointcut("@annotation(actionName)") public void annotationMethod(ActionName actionName) { }

/**

  • 定义切入点,匹配使用@TaskScheduling注解的方法
  • @param taskScheduling @TashScheduling注解value值(功能解释) */ @Pointcut("@annotation(taskScheduling)") public void annotationTaskMethod(TaskScheduling taskScheduling) { }

/**

  • 定义切入点,匹配Service层方法 / @Pointcut("execution( com.delver.bms.*.service.*.*(..))") public void serviceMethod() { }

/**

  • 定义切入点,排除UserDetailsServiceImpl类 */ @Pointcut("!within(com.delver.bms.identity.service.UserDetailsServiceImpl)") public void identityServiceMethod(){}

/**

  • 定义切入点,排除日志记录功能模块的Service层方法 / @Pointcut("!execution( com.delver.bms.log.service.*.*(..))") public void logServiceMethod(){}

/**

  • 定义切入点,排除日志记录功能模块的Dao层方法 / @Pointcut("!execution( com.delver.bms.log.dao.*.*(..))") public void logDaoMethod(){}

/**

  • 定义切入点,匹配Dao层方法 / @Pointcut("execution( com.delver.bms.*.dao.*.*(..))") public void daoMethod(){}

/**

  • 系统任务调度方法前置通知(记录任务调度方法功能说明及执行)
  • @param joinPoint
  • @param taskScheduling */ @Around("annotationTaskMethod(taskScheduling)") public void aroundTaskScheduling(ProceedingJoinPoint joinPoint, TaskScheduling taskScheduling) throws Throwable {

System.out.println("ddd");
}

/**

  • Action方法前置通知(记录Action方法功能说明)
  • @param joinPoint
  • @param actionName */ @Before("annotationMethod(actionName)") public void beforeActionLog(JoinPoint joinPoint, ActionName actionName) {

System.out.println("ddd");

}

/**

  • Service方法环绕通知
  • @param joinPoint
  • @return */ @Around("serviceMethod() && identityServiceMethod() && logServiceMethod()") public Object aroundServiceLog(ProceedingJoinPoint joinPoint) throws Throwable {

System.out.println("ddd");
}

/**

  • Dao方法环绕通知(记录SQL)
  • @param jointPoint
  • @return */ @Around("daoMethod() && logDaoMethod()") public Object aroundDaoLog(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("ddd"); }

配置文件:
<?xml version="1.0" encoding="utf-8"?>
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">





scope="prototype">




异常信息:
java.lang.NoSuchMethodException: $Proxy51.visit()
at java.lang.Class.getMethod(Unknown Source)
at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.getActionMethod(AnnotationValidationInterceptor.java:55)
at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:41)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:86)
at com.opensymphony.xwork2.DefaultActionInvocation$2.doProfiling(DefaultActionInvocation.java:224)
at com.opensymphony.xwork2.DefaultActionInvocation$2.doProfiling(DefaultActionInvocation.java:223)
at com.opensymphony.xwork2.util.profiling.UtilTimerStack.profile(UtilTimerStack.java:455)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:221)
at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:123)

下面略。。。
[b]问题补充:[/b]
我希望的是Service层,Dao层用动态代理,web层用CGLIB代理,是不是不能实现?我试过配多个aop:config,但是只要其中有一个配置了proxy-target-class="true",就全都用CGLIB实现了,网上搜了下,貌似确实是这样的。还有,CGLIB代理与动态代理在运行期性能上有区别吗?

  • 写回答

2条回答 默认 最新

  • wanghaolovezlq 2009-07-15 09:42
    关注

    配置aop:config元素的proxy-target-class="true"当然是对全局切面的配置,
    自然是全部都使用cglib,除非你定义多个不同的切面,也就是定义多个aop:config元素,那每一个就对应一种不同的配置了

    JDK 的动态代理只能对实现了接口的目标类进行代理,而不实现接口的类就不能使用 JDK 的动态代理

    *CGLIB 是针对类来实现代理,当没有实现接口的类需要代理时就需要通过 CGLIB 来实现代理了,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但是因为采用的是继承,所以不能对 finall 类进行继承。

    关于性能方面,这个就得实地测试才知道,一般来说JDK 的动态代理是用反射来实现,
    但CGLIB要产生一个子类,性能可能要差些

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试
  • ¥20 问题请教!vue项目关于Nginx配置nonce安全策略的问题