Java 如何将变量作为参数传递给方面

Java 如何将变量作为参数传递给方面,java,spring,aspectj,flowable,Java,Spring,Aspectj,Flowable,我需要OneEvent完全完成,然后将OneEvent(FlowableEvent事件)中设置的局部变量传递到aspect insertThing()方法中: 我无法修改OneEvent(FlowableEvent事件)方法以返回某些内容,而OneEvent(FlowableEvent事件)方法必须首先完全完成,因此我如何将参数传递到insertThing()?根据您的问题,不可能更改OneEvent()方法的签名,这应该由一个方面来处理。您可以尝试创建一个基于ThreadLocal的容器类,该

我需要OneEvent完全完成,然后将OneEvent(FlowableEvent事件)中设置的局部变量传递到aspect insertThing()方法中:


我无法修改OneEvent(FlowableEvent事件)方法以返回某些内容,而OneEvent(FlowableEvent事件)方法必须首先完全完成,因此我如何将参数传递到insertThing()?

根据您的问题,不可能更改OneEvent()方法的签名,这应该由一个方面来处理。您可以尝试创建一个基于ThreadLocal的容器类,该类在调用onEvent()之前在aspect中初始化,并在完成onEvent()之后进行评估。但这种方法要求您能够编辑onEvent()代码(但不需要更改其返回类型)。以下是一些细节:

@Aspect
@Component
public class DetermineCaseTypeOfWork {

@Transactional
@After(@annotation(path goes here))
public void insertThing() {
    //Do something here with the variables passed in from doSomething method
//if(procInstId.equals("abc1234") && type.equals("case1")) {
//do something
} else if(//other id and type) {
//do something else
} else {
//do something else
}
}
公共类VariableContextHolder{
/**
*带有映射存储变量的ThreadLocal
*/
private final ThreadLocal ThreadLocal=新ThreadLocal();
私有静态VariableContextHolder实例;
私有变量contextholder(){
}
公共最终静态变量ContextHolder getInstance(){
if(实例==null){
instance=newvariableContextHolder();
}
返回实例;
}
公共Mapget(){
返回threadlocal.get();
}
公共空集(Mapmap){
threadlocal.set(map);
}
公共空间清除(){
threadlocal.remove();
}
}
方面类:

public class VariableContextHolder {

/**
 * ThreadLocal with map storing variables
 */
private final ThreadLocal<Map<String, Object>> threadlocal = new ThreadLocal<>();

private static VariableContextHolder instance;

private VariableContextHolder () {

}

public final static VariableContextHolder getInstance() {
    if (instance == null) {
        instance = new VariableContextHolder ();
    }
    return instance;
}

public Map<String, Object>get() {
    return threadlocal.get();
}

public void set(Map<String, Object>map) {
    threadlocal.set(map);
}

public void clear() {
    threadlocal.remove();
}
}
@Aspect()
公共类确定工作类型{
@交易的
@周围(@annotation(“路径在此”))
public void insertThing(ProceedingJoinPoint-joinPoint)抛出可丢弃{
//将初始化的映射保存到threadlocal
VariableContextHolder.getInstance().set(新HashMap());
//将调用方法onEvent()
joinPoint.procedure();
//从threadlocal检索地图
Map variablesMap=VariableContextHolder.getInstance().get();
//按名称获取变量并处理它们
字符串procInstId=variablesMap.get(“procInstId”);
//使用后清除threadlocal
VariableContextHolder.getInstance().clear();
}
}
需要在OneEvent()方法中进行更改:

public void onEvent(FlowableEvent事件){
//从threadlocal检索地图
Map variablesMap=VariableContextHolder.getInstance().get();
字符串procInstId=“abc1234”;
字符串类型=“case1”;
//保存要映射的变量
变量映射put(“procInstId”,procInstId);
变量映射放置(“类型”,类型);
}

根据您的问题,不可能更改OneEvent()方法的签名,它应该由方面来处理。您可以尝试创建一个基于ThreadLocal的容器类,该类在调用onEvent()之前在aspect中初始化,并在完成onEvent()之后进行评估。但这种方法要求您能够编辑onEvent()代码(但不需要更改其返回类型)。以下是一些细节:

@Aspect
@Component
public class DetermineCaseTypeOfWork {

@Transactional
@After(@annotation(path goes here))
public void insertThing() {
    //Do something here with the variables passed in from doSomething method
//if(procInstId.equals("abc1234") && type.equals("case1")) {
//do something
} else if(//other id and type) {
//do something else
} else {
//do something else
}
}
公共类VariableContextHolder{
/**
*带有映射存储变量的ThreadLocal
*/
private final ThreadLocal ThreadLocal=新ThreadLocal();
私有静态VariableContextHolder实例;
私有变量contextholder(){
}
公共最终静态变量ContextHolder getInstance(){
if(实例==null){
instance=newvariableContextHolder();
}
返回实例;
}
公共Mapget(){
返回threadlocal.get();
}
公共空集(Mapmap){
threadlocal.set(map);
}
公共空间清除(){
threadlocal.remove();
}
}
方面类:

public class VariableContextHolder {

/**
 * ThreadLocal with map storing variables
 */
private final ThreadLocal<Map<String, Object>> threadlocal = new ThreadLocal<>();

private static VariableContextHolder instance;

private VariableContextHolder () {

}

public final static VariableContextHolder getInstance() {
    if (instance == null) {
        instance = new VariableContextHolder ();
    }
    return instance;
}

public Map<String, Object>get() {
    return threadlocal.get();
}

public void set(Map<String, Object>map) {
    threadlocal.set(map);
}

public void clear() {
    threadlocal.remove();
}
}
@Aspect()
公共类确定工作类型{
@交易的
@周围(@annotation(“路径在此”))
public void insertThing(ProceedingJoinPoint-joinPoint)抛出可丢弃{
//将初始化的映射保存到threadlocal
VariableContextHolder.getInstance().set(新HashMap());
//将调用方法onEvent()
joinPoint.procedure();
//从threadlocal检索地图
Map variablesMap=VariableContextHolder.getInstance().get();
//按名称获取变量并处理它们
字符串procInstId=variablesMap.get(“procInstId”);
//使用后清除threadlocal
VariableContextHolder.getInstance().clear();
}
}
需要在OneEvent()方法中进行更改:

public void onEvent(FlowableEvent事件){
//从threadlocal检索地图
Map variablesMap=VariableContextHolder.getInstance().get();
字符串procInstId=“abc1234”;
字符串类型=“case1”;
//保存要映射的变量
变量映射put(“procInstId”,procInstId);
变量映射放置(“类型”,类型);
}
前言/基本原理 我不建议使用,因为

  • 它增加了在方面(OK)和核心业务代码(我认为不是OK)中处理线程局部变量的复杂性
  • 作为映射的上下文持有者不是特别的类型安全
  • 如果没有方面(它依赖于方面初始化上下文持有者),核心业务代码将不再工作,并且与它有着千丝万缕的联系,这是一个糟糕的设计决策
主要问题在于OP(moesyzlack23)的思维方式:他说,他想“将参数传递给方面”。这违反了AOP的基本原则,即方面应该知道如何添加横切行为,但应用程序代码应该与方面无关

AspectJ解决方案 我建议

  • 只需将负责计算结果的方法添加到
    TaskCreateListener
    类中,并从
    onEvent(…)
    调用它
  • 从Spring AOP切换到AspectJ,如中所述,并使用
    cflowdown
    切入点和
    percflow
    方面实例化等功能,从而摆脱线程局部变量,使AOP的核心代码再次不可知
  • 可以选择使用常规getter方法将
    Map
    转换为类型更安全的数据对象。只有当方面应用于许多需要处理的数据集非常多样化的带注释的方法时,这才是困难的。但在我看来,这方面是相当具体的,你
    public void onEvent(FlowableEvent event) {
    
        // retrieve map from threadlocal
        Map<String, Object> variablesMap = VariableContextHolder.getInstance().get();
        String procInstId = "abc1234";
        String type = "case1";
        // save variables to map
        variablesMap.put("procInstId", procInstId);
        variablesMap.put("type", type);
    }