当前位置: 首页 > 知识库问答 >
问题:

各种切入点表达式作用域意外触发多个通知调用

杜经艺
2023-03-14

使用方面记录项目,以便所有用@log批注标记的方法、类和构造函数都将信息写入日志文件。

2018-09-25 12:17:29,155 |↷|   EmailNotificationServiceBean#createPayload([SECURE])
2018-09-25 12:17:29,155 |↷|     EmailNotificationServiceBean#createPayload([{service.notification.smtp.authentication.password=password, mail.smtp.port=25, service.notification.smtp.authentication.username=dev@localhost, mail.mime.allowutf8=true, mail.smtp.auth=false, mail.smtp.starttls.enable=false, mail.smtp.timeout=10000, mail.smtp.host=localhost}])
2018-09-25 12:17:29,193 |↷|       EmailPayloadImpl#<init>([{service.notification.smtp.authentication.password=password, mail.smtp.port=25, service.notification.smtp.authentication.username=dev@localhost, mail.mime.allowutf8=true, mail.smtp.auth=false, mail.smtp.starttls.enable=false, mail.smtp.timeout=10000, mail.smtp.host=localhost}])
2018-09-25 12:17:29,193 |↷|         EmailPayloadImpl#validate([SECURE])
2018-09-25 12:17:29,194 |↷|           EmailPayloadImpl#validate([{service.notification.smtp.authentication.password=password, mail.smtp.port=25, service.notification.smtp.authentication.username=dev@localhost, mail.mime.allowutf8=true, mail.smtp.auth=false, mail.smtp.starttls.enable=false, mail.smtp.timeout=10000, mail.smtp.host=localhost}, SMTP connection and credentials])
2018-09-25 12:17:29,195 |↷|         EmailPayloadImpl#setMailServerSettings([SECURE])
2018-09-25 12:17:29,196 |↷|           EmailPayloadImpl#setMailServerSettings([{service.notification.smtp.authentication.password=password, mail.smtp.port=25, service.notification.smtp.authentication.username=dev@localhost, mail.mime.allowutf8=true, mail.smtp.auth=false, mail.smtp.starttls.enable=false, mail.smtp.timeout=10000, mail.smtp.host=localhost}])

预期的记录结果:

2018-09-25 12:17:29,155 |↷|   EmailNotificationServiceBean#createPayload([SECURE])
2018-09-25 12:17:29,193 |↷|     EmailPayloadImpl#<init>([SECURE])
2018-09-25 12:17:29,193 |↷|       EmailPayloadImpl#validate([SECURE])
2018-09-25 12:17:29,195 |↷|       EmailPayloadImpl#setMailServerSettings([SECURE])

日志记录方面:

@Aspect
public class LogAspect {
    @Pointcut("execution(public @Log( secure = true ) *.new(..))")
    public void loggedSecureConstructor() { }

    @Pointcut("execution(@Log( secure = true ) * *.*(..))")
    public void loggedSecureMethod() { }

    @Pointcut("execution(public @Log( secure = false ) *.new(..))")
    public void loggedConstructor() { }

    @Pointcut("execution(@Log( secure = false ) * *.*(..))")
    public void loggedMethod() { }

    @Pointcut("execution(* (@Log *) .*(..))")
    public void loggedClass() { }

    @Around("loggedSecureMethod() || loggedSecureConstructor()")
    public Object logSecure(final ProceedingJoinPoint joinPoint) throws Throwable {
        return log(joinPoint, true);
    }

    @Around("loggedMethod() || loggedConstructor() || loggedClass()")
    public Object log(final ProceedingJoinPoint joinPoint) throws Throwable {
        return log(joinPoint, false);
    }

    private Object log(final ProceedingJoinPoint joinPoint, boolean secure) throws Throwable {
        final Signature signature = joinPoint.getSignature();
        final Logger log = getLogger(signature);

        final String className = getSimpleClassName(signature);
        final String memberName = signature.getName();
        final Object[] args = joinPoint.getArgs();
        final CharSequence indent = getIndentation();
        final String params = secure ? "[SECURE]" : Arrays.deepToString(args);

        log.trace("\u21B7| {}{}#{}({})", indent, className, memberName, params);

        try {
            increaseIndent();

            return joinPoint.proceed(args);
        } catch (final Throwable t) {
            final SourceLocation source = joinPoint.getSourceLocation();
            log.warn("\u2717| {}[EXCEPTION {}] {}", indent, source, t.getMessage());
            throw t;
        } finally {
            decreaseIndent();
            log.trace("\u21B6| {}{}#{}", indent, className, memberName);
        }
    }

日志接口定义:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR})
public @interface Log {
    boolean secure() default false;
}
@Log
public class EmailNotificationServiceBean
implements EmailNotificationService {

    @Log(secure = true)
    @Override
    public EmailPayload createPayload(Map<String, Object> settings) throws NotificationServiceException {
        Map<String, Object> map = settings;
        JoinPoint joinPoint = Factory.makeJP((JoinPoint.StaticPart)ajc$tjp_2, (Object)this, (Object)this, map);
        Object[] arrobject = new Object[]{this, map, joinPoint};
        return (EmailPayload)LogAspect.aspectOf().logSecure(new EmailNotificationServiceBean$AjcClosure7(arrobject).linkClosureAndJoinPoint(69648));
    }
@Log
public class EmailPayloadImpl extends AbstractPayload implements EmailPayload {

    @Log(secure = true)
    public EmailPayloadImpl(final Map<String, Object> settings)
                    throws NotificationServiceException {
        validate(settings, "SMTP connection and credentials");
        setMailServerSettings(settings);
    }

    @Log(secure = true)
    private void validate(final Map<String, Object> map, final String message)
                    throws NotificationServiceException {
        if (map == null || map.isEmpty()) {
            throwException(message);
        }
    }

    @Log(secure = true)
    private void setMailServerSettings(final Map<String, Object> settings) {
        this.mailServerSettings = settings;
    }
    null

我怀疑这些问题是相关的。

共有1个答案

宁良平
2023-03-14

要解决重复问题,需要调整LoggedClass()切入点定义:

@Pointcut("execution(* (@Log *) .*(..)) && !@annotation(Log)")
public void loggedClass() { }

也请在附加信息部分找到概念验证的链接。

与连接点相关的问题(由@pointcut注释定义),它们的模式相互交叉--这就是日志中重复的原因。

    null

>

  • 使用@log(secure=true)=LoggedSecureMethod()
  • 注释的方法
  • 使用@log=loggedMethod()
  • 注释的方法 没有 @log批注的
  • 方法,但在用@log批注的类中,即:

    @Pointcut("execution(* (@Log *) .*(..)) && !@annotation(Log)")
    public void loggedClass() { }
    
    1. 如果还需要在类级别上处理@log(secure=true)-当然需要添加类似于LoggedClass()的附加连接点。
    2. 在GitHub中添加了概念验证

  •  类似资料:
    • 我在我的Scala项目中使用带有sbt-aspectj的AeyJ库。我正在尝试使用表达式编写: 但我有以下例外: 以下AspectJ教程介绍: 因此,通过注释样式,可以仅在@pointcut表达式中使用if()切入点。if()不能包含任何正文。然后,带注释的@切入点方法必须是公共静态布尔的形式,并且可以像往常一样使用形式绑定 可以在Scala方法上使用切入点中的if()表达式吗?

    • 我从@kriegaex那里得到了一个答案,我无法理解。 我试图理解的切入点表达式如下 据我所知,此表达式将建议使用MyAnnotation注释的任何类或方法 从引用留档中,表达式的格式如下: 基于此格式,以下表达式 可以解释为 建议使用注释的类中的任何方法调用。如果我错了,请纠正我。 对于这个表达式 我无法理解修饰符模式如何可以是MyAnnotation?这是怎么回事?

    • 我使用的是Spring security 3.2.0和Spring框架的相同版本。Spring security在我的项目中工作得很好。为了保护DAO类(和其他类)中的方法,我希望使用以下切入点方法(在文件中)。 我希望指定的pointcut表达式能够保护包内所有类中的所有方法,并且只能由具有指定权限的用户访问。

    • 我对Spring和AOP是新手。我正在尝试这个简单的事情,我已经创建了一个自定义注释,当放在任何方法之前时,它应该执行一些代码。这是我创建的注释 问题是我的spring aop从来没有被触发过。我在中包含了一个bean 有人能指出我缺少什么吗?

    • 问题是@before和@afterreturn有效,但对于pointcut却不是这样。

    • 到目前为止,我已经尝试了以下表达式,但没有成功: 有人能给我指出正确的解决办法吗?有可能吗?