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

问题描述 投票:2回答:1

我试图在我的建议中执行一组代码但是无法在具有@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();
}

请帮我找到一种可能适用于下列情况的方法

java spring-boot aspectj spring-aop
1个回答
3
投票

好的,在编辑你的问题时(代码格式有点混乱)我再次读它,你说call()实际上适合你。所以你没有使用Spring AOP,因为那里不支持call()。您必须使用AspectJ,可能通过LTW(加载时编织)或可能通过CTW(编译时编织)。这对答案没有影响。

问题是@annotation(SecuredAPI)实际上在你的注释方法中定义的execution()切入点内部工作,但是你从那里调用的方法没有注释,所以call()不会触发建议。只有当目标方法setQuery(..)被注释时才会这样,但事实并非如此。因此,@annotation()不是适合您目的的切入点。

你要表达的是:“从setQuery(..)注释的代码中调用@SecuredAPI”。这是完成如下(没有Spring的AspectJ示例,请根据您的需要调整类和包名称):

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,除非注释恰好与您的方面在同一个包中。

© www.soinside.com 2019 - 2024. All rights reserved.