аспект j - И и ИЛИ в одном и том же pointcut

Я хотел бы что-то сделать, когда методы getAll(...) или getRec(...) вызываются в классах com.acme.dao.impl.*DaoImpl, но исключают классы com.acme.dao.impl.*ViewDaoImpl.

Я могу выполнить 1-е требование с помощью

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

но не уверен, как исключить классы *ViewDaoImpl.
Я полагаю, что должен сделать что-то вроде

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

но как добавить в выражение включения?

Спасибо,
В.


person Viktor    schedule 17.04.2018    source источник


Ответы (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();
    }
  }
}

Аспект:

Я добавил много разрывов строк и отступов в строках pointcut, конечно, вам не нужно этого делать. Это просто для ясности здесь, в этом сценарии вопросов и ответов на StackOverflow.

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())

Как видите, все три варианта работают одинаково. Выбирайте в соответствии с вашими предпочтениями.

person kriegaex    schedule 17.04.2018
comment
Великолепно! within(com.acme.dao.impl.*DaoImpl) && !within(*..*ViewDaoImpl) && (execution(* getAll(..)) || execution(* getNRecs(..))) сделал свое дело! Мне пришлось изменить && на «и», но в остальном он работает отлично. Спасибо! - person Viktor; 18.04.2018
comment
Если вам пришлось изменить его на «и», возможно, вы определяете свои точки не в коде, а в XML. Вы должны были упомянуть, что не было никакого способа узнать, как вы задали свой вопрос, показывая точечный разрез изолированно. Контекст важен при задании технических (или любых) вопросов. :-) - person kriegaex; 18.04.2018
comment
@Viktor, хороший подробный ответ, подобный этому, может стоить и плюса, помимо его принятия ;-) - person Nándor Előd Fekete; 18.04.2018