Spring AOP:切入点@annotation(MyAnnotation) && call(..) 未按预期触发
Spring AOP: pointcut @annotation(MyAnnotation) && call(..) is not triggered as expected
我正在尝试执行我的建议中的一组代码,但无法将代码编织到具有 @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();
}
请帮我想办法让它适用于以下条件
好的,在编辑你的问题时(代码格式有点乱)我又看了一遍,你说 call()
实际上对你有用。所以你没有使用 Spring AOP,因为那里不支持 call()
。您必须使用 AspectJ,可能是通过 LTW(加载时织入)或 CTW(编译时织入)。这对答案没有影响。
问题是 @annotation(SecuredAPI)
实际上可以在注释方法上定义的 execution()
切入点内工作,但是您从那里调用的方法没有注释,因此不会触发建议call()
。它只有在目标方法 setQuery(..)
被注释时才会出现,但事实并非如此。因此,@annotation()
不是适合您目的的切入点。
您想表达的是:"a call to setQuery(..)
from within code annotated by @SecuredAPI
"。这是按如下方式完成的(没有 Spring 的 AspectJ 示例,请根据您的需要调整 class 和包名称):
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
此外,您还需要为注释使用完全限定的 class 名称,例如 de.scrum_master.app.SecuredAPI
,而不仅仅是 SecuredAPI
,除非注释恰好在同一个包装成你的方面
我正在尝试执行我的建议中的一组代码,但无法将代码编织到具有 @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();
}
请帮我想办法让它适用于以下条件
好的,在编辑你的问题时(代码格式有点乱)我又看了一遍,你说 call()
实际上对你有用。所以你没有使用 Spring AOP,因为那里不支持 call()
。您必须使用 AspectJ,可能是通过 LTW(加载时织入)或 CTW(编译时织入)。这对答案没有影响。
问题是 @annotation(SecuredAPI)
实际上可以在注释方法上定义的 execution()
切入点内工作,但是您从那里调用的方法没有注释,因此不会触发建议call()
。它只有在目标方法 setQuery(..)
被注释时才会出现,但事实并非如此。因此,@annotation()
不是适合您目的的切入点。
您想表达的是:"a call to setQuery(..)
from within code annotated by @SecuredAPI
"。这是按如下方式完成的(没有 Spring 的 AspectJ 示例,请根据您的需要调整 class 和包名称):
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
此外,您还需要为注释使用完全限定的 class 名称,例如 de.scrum_master.app.SecuredAPI
,而不仅仅是 SecuredAPI
,除非注释恰好在同一个包装成你的方面