天天看點

Activiti UEL表達式是如何與Spring 的容器整合起來的

Activiti UEL 表達式

UEL表達式到底是什麼呢?

UEL是java EE6規範的一部分,UEL(Unified Expression Language)即統一表達式語言,activiti支援兩個UEL表達式:UEL-value和UEL-method

Activiti使用UEL進行表達式解析(有關詳細資訊,請參閱EE6規範)

Activiti 如何使用UEL表達式擷取Spring 容器中的bean?

答案在activiti-spring.jar中

SpringExpressionManager.java //spring表達式管理類

public class SpringExpressionManager extends ExpressionManager {
  //應用上下文
  protected ApplicationContext applicationContext;

  public SpringExpressionManager(ApplicationContext applicationContext, Map<Object, Object> beans) {
    super(beans);//這個beans是流程引擎中的beans
    this.applicationContext = applicationContext;
  }

  @Override
  protected ELResolver createElResolver(VariableScope variableScope) {
    //複合el表達式
    CompositeELResolver compositeElResolver = new CompositeELResolver();
    compositeElResolver.add(new VariableScopeElResolver(variableScope));

    //判斷beans是否為空
    if (beans != null) {
      // 在表達式中隻暴露流程引擎中的beans
      compositeElResolver.add(new ReadOnlyMapELResolver(beans));
    } else {
      // 在表達式中暴露整個application-context
      compositeElResolver.add(new ApplicationContextElResolver(applicationContext));
    }

    //添加數組解析器
    compositeElResolver.add(new ArrayELResolver());
    //添加集合解析器
    compositeElResolver.add(new ListELResolver());
    //添加map解析器
    compositeElResolver.add(new MapELResolver());
    //添加json格式的資料解析器 like {key:value,...} or [1,2,3,4,...]
    compositeElResolver.add(new JsonNodeELResolver());
    //添加bean解析器
    compositeElResolver.add(new BeanELResolver());
    return compositeElResolver;
  }
           

在ProcessEngineConfigurationImpl.java中調用

public class ProcessEngineFactoryBean implements FactoryBean<ProcessEngine>, DisposableBean, ApplicationContextAware {
  ...
  protected void configureExpressionManager() {
    if (processEngineConfiguration.getExpressionManager() == null && applicationContext != null) {
      processEngineConfiguration.setExpressionManager(new SpringExpressionManager(applicationContext, processEngineConfiguration.getBeans()));
    }
  }
  ...
}
           

使用表達式

Activiti的Expression 接口

public interface Expression extends Serializable {

  // variableScope 為變量作用域
  Object getValue(VariableScope variableScope);

  void setValue(Object value, VariableScope variableScope);

  String getExpressionText();

}
           

在代碼中的具體使用

//擷取表達式對象
//execution 為 VariableScope 的實作類 用于從不同的變量作用域中取變量
Expression expression = expressionManager.createExpression("${bean.id}");
      businessKey = expression.getValue(execution).toString();
           

為什麼有VariableScope

因為Activiti中有很多流程,每一個流程都有很多變量,使用變量的時候肯定不能去拿其他流程的變量,為了更好的管理在表達式中使用變量,是以這裡就有了一個變量作用域的概念

通過變量作用域獲得EL上下文

public class ExpressionManager {
...
    public ELContext getElContext(VariableScope variableScope) {
        ELContext elContext = null;
        if (variableScope instanceof VariableScopeImpl) {
          VariableScopeImpl variableScopeImpl = (VariableScopeImpl) variableScope;
          elContext = variableScopeImpl.getCachedElContext();
        }

        if (elContext == null) {
          //如果沒有就建立一個EL上下文
          elContext = createElContext(variableScope);
          if (variableScope instanceof VariableScopeImpl) {
            ((VariableScopeImpl) variableScope).setCachedElContext(elContext);
          }
        }

        return elContext;
    }
...
}
           

VariableScope 的實作類

Activiti UEL表達式是如何與Spring 的容器整合起來的

實作類就隻要有三個類

  • NoExecutionVariableScope.java
  • TaskEntityImpl.java
  • ExecutionEntityImpl.java

其中VariableScopeImpl 是個抽象類,這裡使用了模闆模式

需要子類實作的方法

protected abstract Collection<VariableInstanceEntity> loadVariableInstances();

protected abstract VariableScopeImpl getParentVariableScope();

protected abstract void initializeVariableInstanceBackPointer(VariableInstanceEntity variableInstance);

protected abstract VariableInstanceEntity getSpecificVariable(String variableName);
           

JUEL實作類

public class JuelExpression implements Expression {

  protected String expressionText;
  protected ValueExpression valueExpression;

  public JuelExpression(ValueExpression valueExpression, String expressionText) {
    this.valueExpression = valueExpression;
    this.expressionText = expressionText;
  }

  public Object getValue(VariableScope variableScope) {
    //擷取值的時候都要通過variableScope擷取上下文
    ELContext elContext = Context.getProcessEngineConfiguration().getExpressionManager().getElContext(variableScope);
    try {
      ExpressionGetInvocation invocation = new ExpressionGetInvocation(valueExpression, elContext);
      Context.getProcessEngineConfiguration().getDelegateInterceptor().handleInvocation(invocation);
      return invocation.getInvocationResult();
    } catch (PropertyNotFoundException pnfe) {
      throw new ActivitiException("Unknown property used in expression: " + expressionText, pnfe);
    } catch (MethodNotFoundException mnfe) {
      throw new ActivitiException("Unknown method used in expression: " + expressionText, mnfe);
    } catch (ELException ele) {
      throw new ActivitiException("Error while evaluating expression: " + expressionText, ele);
    } catch (Exception e) {
      throw new ActivitiException("Error while evaluating expression: " + expressionText, e);
    }
  }

  public void setValue(Object value, VariableScope variableScope) {
    ELContext elContext = Context.getProcessEngineConfiguration().getExpressionManager().getElContext(variableScope);
    try {
      ExpressionSetInvocation invocation = new ExpressionSetInvocation(valueExpression, elContext, value);
      Context.getProcessEngineConfiguration().getDelegateInterceptor().handleInvocation(invocation);
    } catch (Exception e) {
      throw new ActivitiException("Error while evaluating expression: " + expressionText, e);
    }
  }

  @Override
  public String toString() {
    if (valueExpression != null) {
      return valueExpression.getExpressionString();
    }
    return super.toString();
  }

  public String getExpressionText() {
    return expressionText;
  }
}