春季AOP:切入点@annotation(MyAnnotation)&& call(..)未能按预期触发

时间:2019-04-04 13:02:31

标签: java spring-boot aspectj spring-aop

我正在尝试执行我的建议中的设置代码,但是无法在具有@SecuredAPI批注的函数内部编织代码并调用 setQuery()功能。

以前,我尝试了以下切入点,并且效果很好

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 个答案:

答案 0 :(得分:3)

好的,在编辑您的问题时(代码格式有点混乱),我又读了一遍,您说call()实际上对您有用。因此,您不使用Spring AOP,因为那里不支持call()。您可能必须通过LTW(加载时编织)或CTW(编译时编织)来使用AspectJ。答案没有什么不同。

问题是@annotation(SecuredAPI)实际上可以在带注释的方法中定义的execution()切入点内工作,但是您从那里调用的方法没有带注释,因此建议不会为{{ 1}}。只有在注释了目标方法call()的情况下才会这样做,但事实并非如此。因此,setQuery(..)不是适合您的切入点。

您要表达的是:“从@annotation()注释的代码中调用setQuery(..)”。这样做如下(不带Spring的AspectJ示例,请根据需要调整类和包名称):

@SecuredAPI
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,除非注释恰好与您的方面位于同一包中。 / p>