【问题标题】:aspectj - AND and OR in the same pointcutaspectj - AND 和 OR 在同一个切入点
【发布时间】:2018-04-17 11:19:54
【问题描述】:

当在com.acme.dao.impl.*DaoImpl 类中调用getAll(...)getRec(...) 方法但排除com.acme.dao.impl.*ViewDaoImpl 类时,我想做一些事情。

我可以满足第一个要求

execution(* com.acme.dao.impl.*DaoImpl.getAll(..)) || execution(* com.acme.dao.impl.*DaoImpl.getNRecs(..))

但不确定如何排除 *ViewDaoImpl 类。
我想我应该做类似的事情

!execution(* com.acme.dao.impl.*ViewDaoImpl.*(..))

但是如何添加到包含表达式中?

谢谢,
五、

【问题讨论】:

    标签: aop aspectj spring-aop aspect


    【解决方案1】:

    您有多种选择。与您已有的最接近的是:

    (execution(* com.acme.dao.impl.*DaoImpl.getAll(..)) || execution(* com.acme.dao.impl.*DaoImpl.getNRecs(..))) &&
    !execution(* com.acme.dao.impl.*ViewDaoImpl.*(..))
    

    不过你也可以用这个,我觉得可读性更好一点:

    within(com.acme.dao.impl.*DaoImpl) && !within(*..*ViewDaoImpl) &&
    (execution(* getAll(..)) || execution(* getNRecs(..)))
    

    假设所有 DAO 类都将实现与上述相同的接口,这也可以工作(Dao+ 捕获所有实现类及其子类):

    within(com.acme.dao.impl.Dao+) && !within(*..*ViewDaoImpl) &&
    (execution(* getAll(..)) || execution(* getNRecs(..)))
    

    这是一个纯 AspectJ 示例,但它应该与 Spring AOP 的方面代码相同:

    示例应用程序类:

    package com.acme.dao.impl;
    
    import java.util.List;
    
    public interface Dao {
      List getAll();
      List getNRecs();
      void doSomething();
    }
    
    package com.acme.dao.impl;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class FirstDaoImpl implements Dao {
      @Override
      public List getAll() {
        return new ArrayList();
      }
    
      @Override
      public List getNRecs() {
        return new ArrayList();
      }
    
      @Override
      public void doSomething() {}
    }
    
    package com.acme.dao.impl;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class SecondDaoImpl implements Dao {
      @Override
      public List getAll() {
        return new ArrayList();
      }
    
      @Override
      public List getNRecs() {
        return new ArrayList();
      }
    
      @Override
      public void doSomething() {}
    }
    
    package com.acme.dao.impl;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MyViewDaoImpl implements Dao {
      @Override
      public List getAll() {
        return new ArrayList();
      }
    
      @Override
      public List getNRecs() {
        return new ArrayList();
      }
    
      @Override
      public void doSomething() {}
    }
    

    驱动程序应用:

    package de.scrum_master.app;
    
    import java.util.Arrays;
    
    import com.acme.dao.impl.Dao;
    import com.acme.dao.impl.FirstDaoImpl;
    import com.acme.dao.impl.MyViewDaoImpl;
    import com.acme.dao.impl.SecondDaoImpl;
    
    public class Application {
      public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        for (Class<?> clazz : Arrays.asList(FirstDaoImpl.class, SecondDaoImpl.class, MyViewDaoImpl.class)) {
          Dao dao = (Dao) clazz.newInstance();
          dao.getAll();
          dao.getNRecs();
          dao.doSomething();
        }
      }
    }
    

    方面:

    我在切入点字符串中添加了很多换行符和缩进,当然你不需要这样做。在 StackOverflow 上的这个 Q/A 场景中只是为了清楚起见。

    package de.scrum_master.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    @Aspect
    public class DaoAspect {
      @Before(
        "(" + 
          "execution(* com.acme.dao.impl.*DaoImpl.getAll(..)) || " + 
          "execution(* com.acme.dao.impl.*DaoImpl.getNRecs(..))" + 
        ") && " + 
        "!execution(* com.acme.dao.impl.*ViewDaoImpl.*(..))"
      )
      public void firstVariant(JoinPoint thisJoinPoint) {
        System.out.println("[1] " + thisJoinPoint);
      }
    
      @Before(
        "within(com.acme.dao.impl.*DaoImpl) && " +
        "!within(*..*ViewDaoImpl) && " +
        "(" +
          "execution(* getAll(..)) || " +
          "execution(* getNRecs(..))" +
        ")" 
      )
      public void secondVariant(JoinPoint thisJoinPoint) {
        System.out.println("[2] " + thisJoinPoint);
      }
    
      @Before(
        "within(com.acme.dao.impl.Dao+) && " +
        "!within(*..*ViewDaoImpl) && " +
        "(" +
          "execution(* getAll(..)) || " +
          "execution(* getNRecs(..))" +
        ")" 
      )
      public void thirdVariant(JoinPoint thisJoinPoint) {
        System.out.println("[3] " + thisJoinPoint);
      }
    }
    

    控制台日志:

    [1] execution(List com.acme.dao.impl.FirstDaoImpl.getAll())
    [2] execution(List com.acme.dao.impl.FirstDaoImpl.getAll())
    [3] execution(List com.acme.dao.impl.FirstDaoImpl.getAll())
    [1] execution(List com.acme.dao.impl.FirstDaoImpl.getNRecs())
    [2] execution(List com.acme.dao.impl.FirstDaoImpl.getNRecs())
    [3] execution(List com.acme.dao.impl.FirstDaoImpl.getNRecs())
    [1] execution(List com.acme.dao.impl.SecondDaoImpl.getAll())
    [2] execution(List com.acme.dao.impl.SecondDaoImpl.getAll())
    [3] execution(List com.acme.dao.impl.SecondDaoImpl.getAll())
    [1] execution(List com.acme.dao.impl.SecondDaoImpl.getNRecs())
    [2] execution(List com.acme.dao.impl.SecondDaoImpl.getNRecs())
    [3] execution(List com.acme.dao.impl.SecondDaoImpl.getNRecs())
    

    如您所见,所有三种变体的作用完全相同。根据自己的喜好选择。

    【讨论】:

    • 太棒了! within(com.acme.dao.impl.*DaoImpl) &amp;&amp; !within(*..*ViewDaoImpl) &amp;&amp; (execution(* getAll(..)) || execution(* getNRecs(..))) 成功了!我不得不将 && 更改为 'and' 但否则它可以完美运行。谢谢!
    • 如果你不得不把它改成'and',可能你不是在代码中而是在XML中定义你的切入点。您应该提到,没有办法知道您提出问题的方式,孤立地显示切入点。在询问技术(或任何类型)问题时,上下文很重要。 :-)
    • @Viktor 除了接受它之外,像这样一个很好的详细答案可能也值得一票;-)
    猜你喜欢
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 2011-01-17
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多