使用 aspectJ 根据调用方法的参数修改 return 类型的方法
Modifying return type of method based on parameter of a calling method with aspectJ
我需要使用 aspectj 修改 return 遗留代码方法的类型。
class MyClass{
public void processTracker(TrackInfo trackInfo) {
if (isValid(this.getStatus()) {
process(trackInfo);
}
}
boolean isValid(Status status){
...
}
}
我希望isValid
方法通过TrackInfo
对象的一些其他基于逻辑的状态returntrue/false(将参数传递给processTracker
方法)
方面 processTracker
方法会给我参数,但不会提供修改 return isValid
值的选项
@Around("execution(* MyClass.processTracker(..))
方面 isValid
不会让我访问参数 trackInfo
2 个方面这是不可能的,因为此代码在多线程中运行...
我没有使用 Spring 并且无法向遗留代码添加自定义注释。
有什么想法吗?
其实你的问题很难理解,可能是你的英文水平不是特别好吧。特别是,我不知道为什么您认为多线程在这里应该是个问题。也许您可以更详细地解释一下。
无论如何,我在这里为您提供两种AOP解决方案:
如果 if
条件确实是 processTracker(TrackInfo)
中的整个逻辑,则直接从方面调用 process(TrackInfo)
,如您的示例代码所示。从语义上讲,你只是替换了拦截方法的整个逻辑。
如果 processTracker(TrackInfo)
中实际上有更多逻辑,并且您的示例代码过于简单,就像外科医生一样,您需要用更细的刀切割并应用 AOP 术语中的内容通常被称为 虫洞模式 .
应用程序 + 助手 类:
因为你的示例代码不完整,我不得不猜测并编造一个MCVE,下次我希望你这样做,因为这实际上是你的工作,而不是我的。
package de.scrum_master.app;
public enum Status {
VALID, INVALID
}
package de.scrum_master.app;
public class TrackInfo {
private String info;
public TrackInfo(String info) {
this.info = info;
}
public String getInfo() {
return info;
}
@Override
public String toString() {
return "TrackInfo(" + info + ")";
}
}
package de.scrum_master.app;
import static de.scrum_master.app.Status.*;
public class MyClass {
private Status status = VALID;
public void processTracker(TrackInfo trackInfo) {
if (isValid(getStatus()))
process(trackInfo);
}
public void process(TrackInfo trackInfo) {
System.out.println("Processing " + trackInfo);
}
private Status getStatus() {
if (status == VALID)
status = INVALID;
else
status = VALID;
return status;
}
boolean isValid(Status status) {
return status == VALID;
}
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.processTracker(new TrackInfo("normal"));
myClass.processTracker(new TrackInfo("whatever"));
myClass.processTracker(new TrackInfo("special"));
}
}
如您所见,我只是在每次调用时将有效性从无效变为有效,然后再返回,只是为了在 运行 main 方法时得到不同的结果。
控制台日志为:
Processing TrackInfo(whatever)
到目前为止,还不错。不,让我们假设如果 TrackInfo
匹配字符串 "special",我们希望始终假设有效性检查的计算结果为真。
1.) processTracker(TrackInfo)
的切面替换逻辑
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import de.scrum_master.app.MyClass;
import de.scrum_master.app.TrackInfo;
@Aspect
public class SimpleAspect {
@Around("execution(* de.scrum_master.app.MyClass.processTracker(..)) && args(trackInfo) && target(myClass)")
public void modifyValidityCheck(ProceedingJoinPoint thisJoinPoint, TrackInfo trackInfo, MyClass myClass) throws Throwable {
if (trackInfo.getInfo().equalsIgnoreCase("special")) {
// Kick off processing based on some special logic
myClass.process(trackInfo);
}
else {
// Proceed normally
thisJoinPoint.proceed();
}
}
}
这里我们不需要知道有效性检查的结果,如果需要直接调用process(TrackInfo)
即可。日志输出变为:
Processing TrackInfo(whatever)
Processing TrackInfo(special)
2.)虫洞图解
这里实际上是将调用方法processTracker(TrackInfo)
中的TrackInfo
作为上下文信息拉取到isValid(Status status)
中,这样我们可以直接修改合法性检查结果
package de.scrum_master.aspect;
import static de.scrum_master.app.Status.*;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import de.scrum_master.app.Status;
import de.scrum_master.app.TrackInfo;
@Aspect
public class WormholePatternAspect {
@Pointcut("execution(* de.scrum_master.app.MyClass.processTracker(..)) && args(trackInfo)")
public static void processTracker(TrackInfo trackInfo) {}
@Pointcut("execution(* de.scrum_master.app.MyClass.getStatus())")
public static void getStatus() {}
@Around("getStatus() && cflow(processTracker(trackInfo))")
public Status modifyValidityCheck(ProceedingJoinPoint thisJoinPoint, TrackInfo trackInfo) throws Throwable {
if (trackInfo.getInfo().equalsIgnoreCase("special")) {
// Return true based on some special logic
return VALID;
}
else {
// Proceed normally
return (Status) thisJoinPoint.proceed();
}
}
}
console log和第一个方面一样,但是如果processTracker(TrackInfo)
里面的逻辑多了,剩下的也会执行,而不是像第一个方面那样截断(替换) .
随你选。如果适用,我建议使用更简单的解决方案。虫洞模式很优雅,但更难理解,并且由于cflow()
需要运行时调用堆栈分析,因此它也应该稍微慢一些。
我需要使用 aspectj 修改 return 遗留代码方法的类型。
class MyClass{
public void processTracker(TrackInfo trackInfo) {
if (isValid(this.getStatus()) {
process(trackInfo);
}
}
boolean isValid(Status status){
...
}
}
我希望isValid
方法通过TrackInfo
对象的一些其他基于逻辑的状态returntrue/false(将参数传递给processTracker
方法)
方面 processTracker
方法会给我参数,但不会提供修改 return isValid
@Around("execution(* MyClass.processTracker(..))
方面 isValid
不会让我访问参数 trackInfo
2 个方面这是不可能的,因为此代码在多线程中运行... 我没有使用 Spring 并且无法向遗留代码添加自定义注释。
有什么想法吗?
其实你的问题很难理解,可能是你的英文水平不是特别好吧。特别是,我不知道为什么您认为多线程在这里应该是个问题。也许您可以更详细地解释一下。
无论如何,我在这里为您提供两种AOP解决方案:
如果
if
条件确实是processTracker(TrackInfo)
中的整个逻辑,则直接从方面调用process(TrackInfo)
,如您的示例代码所示。从语义上讲,你只是替换了拦截方法的整个逻辑。如果
processTracker(TrackInfo)
中实际上有更多逻辑,并且您的示例代码过于简单,就像外科医生一样,您需要用更细的刀切割并应用 AOP 术语中的内容通常被称为 虫洞模式 .
应用程序 + 助手 类:
因为你的示例代码不完整,我不得不猜测并编造一个MCVE,下次我希望你这样做,因为这实际上是你的工作,而不是我的。
package de.scrum_master.app;
public enum Status {
VALID, INVALID
}
package de.scrum_master.app;
public class TrackInfo {
private String info;
public TrackInfo(String info) {
this.info = info;
}
public String getInfo() {
return info;
}
@Override
public String toString() {
return "TrackInfo(" + info + ")";
}
}
package de.scrum_master.app;
import static de.scrum_master.app.Status.*;
public class MyClass {
private Status status = VALID;
public void processTracker(TrackInfo trackInfo) {
if (isValid(getStatus()))
process(trackInfo);
}
public void process(TrackInfo trackInfo) {
System.out.println("Processing " + trackInfo);
}
private Status getStatus() {
if (status == VALID)
status = INVALID;
else
status = VALID;
return status;
}
boolean isValid(Status status) {
return status == VALID;
}
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.processTracker(new TrackInfo("normal"));
myClass.processTracker(new TrackInfo("whatever"));
myClass.processTracker(new TrackInfo("special"));
}
}
如您所见,我只是在每次调用时将有效性从无效变为有效,然后再返回,只是为了在 运行 main 方法时得到不同的结果。
控制台日志为:
Processing TrackInfo(whatever)
到目前为止,还不错。不,让我们假设如果 TrackInfo
匹配字符串 "special",我们希望始终假设有效性检查的计算结果为真。
1.) processTracker(TrackInfo)
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import de.scrum_master.app.MyClass;
import de.scrum_master.app.TrackInfo;
@Aspect
public class SimpleAspect {
@Around("execution(* de.scrum_master.app.MyClass.processTracker(..)) && args(trackInfo) && target(myClass)")
public void modifyValidityCheck(ProceedingJoinPoint thisJoinPoint, TrackInfo trackInfo, MyClass myClass) throws Throwable {
if (trackInfo.getInfo().equalsIgnoreCase("special")) {
// Kick off processing based on some special logic
myClass.process(trackInfo);
}
else {
// Proceed normally
thisJoinPoint.proceed();
}
}
}
这里我们不需要知道有效性检查的结果,如果需要直接调用process(TrackInfo)
即可。日志输出变为:
Processing TrackInfo(whatever)
Processing TrackInfo(special)
2.)虫洞图解
这里实际上是将调用方法processTracker(TrackInfo)
中的TrackInfo
作为上下文信息拉取到isValid(Status status)
中,这样我们可以直接修改合法性检查结果
package de.scrum_master.aspect;
import static de.scrum_master.app.Status.*;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import de.scrum_master.app.Status;
import de.scrum_master.app.TrackInfo;
@Aspect
public class WormholePatternAspect {
@Pointcut("execution(* de.scrum_master.app.MyClass.processTracker(..)) && args(trackInfo)")
public static void processTracker(TrackInfo trackInfo) {}
@Pointcut("execution(* de.scrum_master.app.MyClass.getStatus())")
public static void getStatus() {}
@Around("getStatus() && cflow(processTracker(trackInfo))")
public Status modifyValidityCheck(ProceedingJoinPoint thisJoinPoint, TrackInfo trackInfo) throws Throwable {
if (trackInfo.getInfo().equalsIgnoreCase("special")) {
// Return true based on some special logic
return VALID;
}
else {
// Proceed normally
return (Status) thisJoinPoint.proceed();
}
}
}
console log和第一个方面一样,但是如果processTracker(TrackInfo)
里面的逻辑多了,剩下的也会执行,而不是像第一个方面那样截断(替换) .
随你选。如果适用,我建议使用更简单的解决方案。虫洞模式很优雅,但更难理解,并且由于cflow()
需要运行时调用堆栈分析,因此它也应该稍微慢一些。