Spring AOP: pointcut @annotation (MyAnnotation) && call (..) не запускается должным образом - PullRequest
2 голосов
/ 04 апреля 2019

Я пытаюсь выполнить заданный код в своем совете, но не могу втиснуть код в функцию, которая имеет аннотацию @SecuredAPI и вызывает setQuery() функция.

Ранее я пробовал следующий pointcut, и он работал очень хорошо

call(* org.elasticsearch.action.search.SearchRequestBuilder.setQuery(org.elasticsearch.index.query.QueryBuilder)) && args(queryBuilder)

Но нужно также включить аннотированное условие в это. Пожалуйста, помогите мне с этим.

Мой совет и совет выглядят так

@Around(value = "@annotation(SecuredAPI)  && call(* org.elasticsearch.action.search.SearchRequestBuilder.setQuery(org.elasticsearch.index.query.QueryBuilder)) && args(queryBuilder)" )
public Object decorateQuery(ProceedingJoinPoint proceedingJoinPoint, QueryBuilder queryBuilder) throws Throwable {
  // ...
}

И моя функция выглядит так

@SecuredAPI
public List<Integer> getAllIds() {
  // ...
  SearchResponse response = conn
    .getESClient().prepareSearch(ElasticSearchConstants.ATTRIBUTE_INDEX)
    .setSearchType(SearchType.DEFAULT)
    //.setQuery(QueryBuilders.queryStringQuery(searchQuery))
    .setQuery(qb)
    .setFrom(0).setSize(10000).setExplain(true).get();
}

Пожалуйста, помогите мне найти способ, чтобы он работал при следующих условиях

1 Ответ

3 голосов
/ 11 апреля 2019

Хорошо, во время редактирования вашего вопроса (форматирование кода было немного хаотичным), я прочитал его снова, и вы сказали, что call() на самом деле работает для вас.Таким образом, вы не используете Spring AOP, потому что call() там не поддерживается.Вы должны использовать AspectJ, возможно, через LTW (ткачество во время загрузки) или, возможно, через CTW (ткачество во время компиляции).Это не имеет значения для ответа.

Проблема в том, что @annotation(SecuredAPI) будет фактически работать внутри execution() pointcut, определенного в вашем аннотированном методе, но метод, который вы вызываете оттуда, не аннотирован, поэтомусовет не срабатывает для call().Это было бы, если бы целевой метод setQuery(..) был аннотирован, но это не так.Следовательно, @annotation() не является правильным указателем для вашей цели.

То, что вы хотите выразить, это: «вызов setQuery(..) изнутри кода, аннотированного @SecuredAPI».Это делается следующим образом (пример AspectJ без Spring, пожалуйста, измените имена классов и пакетов в соответствии с вашими потребностями):

package de.scrum_master.app;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD })
public @interface SecuredAPI {}
package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    Application application = new Application();
    application.doSomething();
    application.doSomethingElse();
  }

  @SecuredAPI
  public void doSomething() {
    System.out.println("Doing something before setting query");
    setQuery("my first query");
    System.out.println("Doing something after setting query");
  }

  public void doSomethingElse() {
    System.out.println("Doing something else before setting query");
    setQuery("my second query");
    System.out.println("Doing something else after setting query");
  }

  public void setQuery(String query) {
    System.out.println("Setting query to: " + query);
  }
}
package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class SecuredAPIAspect {
  @Around("@withincode(de.scrum_master.app.SecuredAPI) && call(* setQuery(..))")
  public Object myAdvice(ProceedingJoinPoint thisJoinPoint) throws Throwable {
    System.out.println(thisJoinPoint);
    return thisJoinPoint.proceed();
  }
}

Видите?@withincode() ваш друг в этом случае.Журнал консоли выглядит следующим образом:

Doing something before setting query
call(void de.scrum_master.app.Application.setQuery(String))
Setting query to: my first query
Doing something after setting query
Doing something else before setting query
Setting query to: my second query
Doing something else after setting query

Кроме того, для аннотации также необходимо использовать полное имя класса, например de.scrum_master.app.SecuredAPI, а не просто SecuredAPI, если только аннотация не оказываетсяв той же упаковке, что и ваш аспект.

...