Java 如何在外呼中使用AOP
我对如何在AOP中使用假客户端感兴趣。例如: API:Java 如何在外呼中使用AOP,java,aop,aspectj,spring-aop,feign,Java,Aop,Aspectj,Spring Aop,Feign,我对如何在AOP中使用假客户端感兴趣。例如: API: public interface LoanClient { @RequestLine("GET /loans/{loanId}") @MeteredRemoteCall("loans") Loan getLoan(@Param("loanId") Long loanId); } @Aspect @Component // Spring Component annotation public class Metric
public interface LoanClient {
@RequestLine("GET /loans/{loanId}")
@MeteredRemoteCall("loans")
Loan getLoan(@Param("loanId") Long loanId);
}
@Aspect
@Component // Spring Component annotation
public class MetricAspect {
@Around(value = "@annotation(annotation)", argNames = "joinPoint, annotation")
public Object meterRemoteCall(ProceedingJoinPoint joinPoint,
MeteredRemoteCall annotation) throws Throwable {
// do something
}
}
配置:
public interface LoanClient {
@RequestLine("GET /loans/{loanId}")
@MeteredRemoteCall("loans")
Loan getLoan(@Param("loanId") Long loanId);
}
@Aspect
@Component // Spring Component annotation
public class MetricAspect {
@Around(value = "@annotation(annotation)", argNames = "joinPoint, annotation")
public Object meterRemoteCall(ProceedingJoinPoint joinPoint,
MeteredRemoteCall annotation) throws Throwable {
// do something
}
}
但我不知道如何“拦截”api方法调用。我哪里出错了
更新:
public interface LoanClient {
@RequestLine("GET /loans/{loanId}")
@MeteredRemoteCall("loans")
Loan getLoan(@Param("loanId") Long loanId);
}
@Aspect
@Component // Spring Component annotation
public class MetricAspect {
@Around(value = "@annotation(annotation)", argNames = "joinPoint, annotation")
public Object meterRemoteCall(ProceedingJoinPoint joinPoint,
MeteredRemoteCall annotation) throws Throwable {
// do something
}
}
我的Spring类注释:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MeteredRemoteCall {
String serviceName();
}
您的情况有些复杂,因为您有几个问题:
- 您可以使用SpringAOP,这是一个基于动态代理(接口为JDK代理,类为CGLIB代理)的“AOPLite”框架。它只适用于SpringBean/组件,但从我所看到的
不是SpringLoanClient
@Component
- 即使它是Spring组件,Feign也会通过反射创建自己的JDK动态代理。它们不受春天的控制。可能有一种方法可以手动将它们连接到Spring中,既可以通过编程方式,也可以通过XML配置。但在那个里我帮不了你们,因为我不用弹簧
- SpringAOP只支持AspectJ切入点的子集。具体来说,它不支持
,只支持call()
。也就是说,它只在执行方法的地方编织,而不是调用方法的地方execution()
- 但是执行发生在实现接口的方法中,接口方法上的注释(如
)永远不会被它们的实现类继承。事实上,在Java中永远不会继承方法注释,只继承类(而不是接口!)到相应子类的类级注释。也就是说,即使您的注释类具有继承的@meteredmotecall
@元注释,它对
也没有帮助,只对@Target({ElementType.METHOD})
有帮助更新:因为我以前已经回答过好几次这个问题,所以我刚刚记录了这个问题,并在中介绍了一个解决方法@Target({ElementType.TYPE})
call()
切入点,而不是SpringAOP隐式使用的execution()
。如果在AspectJ中的方法上使用@annotation()
切入点,它将匹配调用和执行,我将在一个独立的示例中向您展示(没有Spring,但效果与在Spring中使用LTW的AspectJ相同):
标记注释:
public interface LoanClient {
@RequestLine("GET /loans/{loanId}")
@MeteredRemoteCall("loans")
Loan getLoan(@Param("loanId") Long loanId);
}
@Aspect
@Component // Spring Component annotation
public class MetricAspect {
@Around(value = "@annotation(annotation)", argNames = "joinPoint, annotation")
public Object meterRemoteCall(ProceedingJoinPoint joinPoint,
MeteredRemoteCall annotation) throws Throwable {
// do something
}
}
package de.scrum\u master.app;
导入java.lang.annotation.ElementType;
导入java.lang.annotation.Retention;
导入java.lang.annotation.RetentionPolicy;
导入java.lang.annotation.Target;
@保留(RetentionPolicy.RUNTIME)
@目标(ElementType.METHOD)
public@interface meteredmotecall{}
外国客户:
public interface LoanClient {
@RequestLine("GET /loans/{loanId}")
@MeteredRemoteCall("loans")
Loan getLoan(@Param("loanId") Long loanId);
}
@Aspect
@Component // Spring Component annotation
public class MetricAspect {
@Around(value = "@annotation(annotation)", argNames = "joinPoint, annotation")
public Object meterRemoteCall(ProceedingJoinPoint joinPoint,
MeteredRemoteCall annotation) throws Throwable {
// do something
}
}
此示例客户端获取完整的StackOverflow问题页面(HTML源代码)作为字符串
package de.scrum\u master.app;
进口外国参数;
进口外国请求行;
公共接口StackOverflowClient{
@请求行(“GET/questions/{questionId}”)
@计量远程呼叫
字符串getQuestionPage(@Param(“questionId”)长questionId);
}
驱动程序应用程序:
public interface LoanClient {
@RequestLine("GET /loans/{loanId}")
@MeteredRemoteCall("loans")
Loan getLoan(@Param("loanId") Long loanId);
}
@Aspect
@Component // Spring Component annotation
public class MetricAspect {
@Around(value = "@annotation(annotation)", argNames = "joinPoint, annotation")
public Object meterRemoteCall(ProceedingJoinPoint joinPoint,
MeteredRemoteCall annotation) throws Throwable {
// do something
}
}
此应用程序以三种不同的方式使用外部客户端接口进行演示:
package de.scrum\u master.app;
导入java.util.regex.Matcher;
导入java.util.regex.Pattern;
进口外国;
导入feign.codec.StringDecoder;
公共类应用程序{
公共静态void main(字符串[]args){
StackOverflowClient soClient;
长问题ID=41856687L;
soClient=新的StackOverflowClient(){
@凌驾
公共字符串getQuestionPage(长loanId){
返回“StackOverflowClient无伪”;
}
};
System.out.println(“+soClient.getQuestionPage(questionId));
soClient=新的StackOverflowClient(){
@凌驾
@计量远程呼叫
公共字符串getQuestionPage(长loanId){
返回“StackOverflowClient无伪+额外注释”;
}
};
System.out.println(“+soClient.getQuestionPage(questionId));
//通过外挂创建StackOverflowClient
字符串baseUrl=”http://stackoverflow.com";
soClient=假装
.builder()
.decoder(新的StringDecoder())
.target(StackOverflowClient.class,baseUrl);
匹配器标题匹配器=模式
.compile(([^您的情况有些复杂,因为您有几个问题:
- 您使用SpringAOP,这是一个基于动态代理(JDK代理用于接口,CGLIB代理用于类)的“AOP-lite”框架。它只适用于SpringBean/组件,但从我看来,您的
LoanClient
不是Spring@组件
- 即使它是一个Spring组件,Feign也会通过反射创建自己的JDK动态代理。它们不在Spring的控制范围内。可能有一种方法可以通过编程或XML配置手动将它们连接到Spring中。但我无法帮助您,因为我不使用Spring
- Spring AOP只支持AspectJ切入点的一个子集。具体来说,它不支持
call()
,只支持execution()
。也就是说,它只在方法执行的地方进行编织,而不是在方法被调用的地方
- 但执行发生在实现接口的方法中,接口方法(如
@meteredmotecall
)上的注释永远不会被它们的实现类继承。事实上,方法注释永远不会在Java中继承,只会从类(而不是接口)继承类级注释到相应的子类,即即使y