@AspectJ切入点,用于包内所有方法。

34

我有一个关于特定包的工作代码,但我想将其配置为所有控制器服务数据访问对象(dao)包,例如:

  • com.abc.xyz.content.controller
  • com.abc.xyz.content.service
  • com.abc.xyz.content.dao
  • com.abc.xyz.category.controller
  • com.abc.xyz.category.service
  • com.abc.xyz.category.dao

等等...那是我的项目的基础包,可以有人帮我解决如何让它适用于我的 Web 项目中的所有类,包括控制器,谢谢提前。

package com.abc.xyz.utilities;

import java.util.Arrays;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
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 org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect
{
    private Log log = LogFactory.getLog(this.getClass());

    @Pointcut("execution(* com.abc.xyz.content.service..*(..))")
    protected void loggingOperation()
    {
    }

    @Before("loggingOperation()")
    @Order(1)
    public void logJoinPoint(JoinPoint joinPoint)
    {
    log.info("Signature declaring type : " + joinPoint.getSignature().getDeclaringTypeName());
    log.info("Signature name : " + joinPoint.getSignature().getName());
    log.info("Arguments : " + Arrays.toString(joinPoint.getArgs()));
    log.info("Target class : " + joinPoint.getTarget().getClass().getName());
    }

    @AfterReturning(pointcut = "loggingOperation()", returning = "result")
    @Order(2)
    public void logAfter(JoinPoint joinPoint, Object result)
    {
    log.info("Exiting from Method :" + joinPoint.getSignature().getName());
    log.info("Return value :" + result);
    }

    @AfterThrowing(pointcut = "execution(* com.abc.xyz.content.service..*(..))", throwing = "e")
    @Order(3)
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e)
    {
    log.error("An exception has been thrown in " + joinPoint.getSignature().getName() + "()");
    log.error("Cause :" + e.getCause());
    }

    @Around("execution(* com.abc.xyz.content.service..*(..))")
    @Order(4)
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable
    {
    log.info("The method " + joinPoint.getSignature().getName() + "() begins with " + Arrays.toString(joinPoint.getArgs()));
    try
    {
        Object result = joinPoint.proceed();
        log.info("The method " + joinPoint.getSignature().getName() + "() ends with " + result);
        return result;
    }
    catch (IllegalArgumentException e)
    {
        log.error("Illegal argument " + Arrays.toString(joinPoint.getArgs()) + " in " + joinPoint.getSignature().getName() + "()");
        throw e;
    }
    }

}
3个回答

71

这些替代方案中有一个怎么样?

A) 限制包的通用执行切点:

execution(* *(..)) &&
(
    within(com.abc.xyz..controller..*) ||
    within(com.abc.xyz..service..*) ||
    within(com.abc.xyz..dao..*)
)

B) 仅限于包的执行切入点:

execution(* com.abc.xyz..controller..*(..)) ||
execution(* com.abc.xyz..service..*(..)) ||
execution(* com.abc.xyz..dao..*(..))

顺便说一下,我更喜欢B,因为它有点短且易读。你可能已经猜到了,.. 表示“任何包或子包”,而在 .. 后表达式末尾加上 * 则表示“任何类中的任何方法”。


所以基本上可以使用其他切入点描述符定义所有within()切入点表达式,对吧?我认为对于嵌套类,within()可以简化表达式(有时是极其简单的),但除此之外它只是一个方便的切入点描述符。 - Behrang
1
理论上是可以的,但通常并没有意义。作为开发人员,我总是会选择最清晰地表达我的意图的(组合)切入点。好的切入点可以像句子一样阅读,例如:“在 x 和 y 包内,选择所有由 @Z 注释的类中的公共非静态方法,但仅当它们返回类型 A 的值时。” - kriegaex
我之前的评论有一个晚期修改:within匹配的连接点类型比仅仅是execution更多,例如callgetsetinitializationstaticinitialization等。它还匹配构造函数执行,而使用execution切入点时,构造函数执行具有不同的语法。 - kriegaex

10

1
好的。对于控制器,您可以像这样做:https://dev59.com/eXI-5IYBdhLWcg3wHUdB - Vimal Bera
在名为'dispatcher'的DispatcherServlet中没有找到与HTTP请求URI [/xyz-web-vodafone/content.showContentWorkbench.htm] 相对应的映射。 - Mohan Seth
首先,我能否至少为服务和数据访问对象包配置它?你能告诉我如何实现吗? - Mohan Seth
很简单。你需要在@Pointcut本身中提供表达式,就像答案中所提到的那样。 - Vimal Bera

1
另一种选择是使用。
@Pointcut("bean(*Controller)")

但是你的bean的命名应该相对应。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接