oracle bpm难点,Oracle Bpm 11g 审批性能优化

背景

​ 项目上协调办公、工作流使用的是Oracle Bpm的产品,最近被甲方爸爸投诉审批耗时长,希望能达到平均耗时1秒,甲方爸爸都要求了,没办法,于是就开始了一段痛苦的优化过程。本着普渡众生的想法,记录下本次优化的过程,希望能为减少类似的痛苦。

问题描述

环境描述

Oracle Bpm 11.1.1.6 (后续简称BPM)

Oracle ESB 12.1.3(后续简称OSB)、Oracle SOA Suit 11g(后续简称SOA)

代码调用路径

​ 业务代码-->OSB-->SOA-->JAVA审批代码-->调用bpm提供的审批API

​ 本文主要描述如何对JAVA审批代码做优化

相关代码

​ 熟悉Oracle Bpm提供的审批API的同学对下面的代码应该不陌生,若是没接触过可以参考:

Oracle 官方教程

​ 项目上的审批代码:

package cn.com.utility.bpm.utils;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import oracle.bpel.services.workflow.StaleObjectException;

import oracle.bpel.services.workflow.WorkflowException;

import oracle.bpel.services.workflow.client.IWorkflowServiceClient;

import oracle.bpel.services.workflow.client.IWorkflowServiceClientConstants;

import oracle.bpel.services.workflow.client.WorkflowServiceClientFactory;

import oracle.bpel.services.workflow.query.ITaskQueryService;

import oracle.bpel.services.workflow.task.ITaskService;

import oracle.bpel.services.workflow.task.model.CommentType;

import oracle.bpel.services.workflow.task.model.ObjectFactory;

import oracle.bpel.services.workflow.task.model.Task;

import oracle.bpel.services.workflow.verification.IWorkflowContext;

public class TaskService {

private IWorkflowServiceClient wfSvcClient = null;

private ITaskQueryService taskQueryService = null;

private ITaskService taskService = null;

private IWorkflowContext wfContext = null;

private static final String BPM_MANAGER_UN = "weblogic";

private static final String BPM_MANAGER_PW = "weblogic1";

private static final String SOA_URL = "t3://bpmtest1.wlj.com.cn:8001";

private static final String BPM_CLIENT_TYPE = "EJB";

private static final String BPM_LDAP_DOMAIN = "jazn.com";

private String username;

public TaskService() {

super();

}

public IWorkflowServiceClient getWorkflowServiceClient() {

if (wfSvcClient == null) {

Map properties =

new HashMap();

properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.CLIENT_TYPE,

BPM_CLIENT_TYPE);

properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_PROVIDER_URL,

SOA_URL);

properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_PRINCIPAL,

BPM_MANAGER_UN);

properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_CREDENTIALS,

BPM_MANAGER_PW);

wfSvcClient =

WorkflowServiceClientFactory.getWorkflowServiceClient(WorkflowServiceClientFactory.REMOTE_CLIENT,

properties,

null);

}

return wfSvcClient;

}

public ITaskQueryService getTaskQueryService() {

if (taskQueryService == null) {

taskQueryService =

this.getWorkflowServiceClient().getTaskQueryService();

}

return taskQueryService;

}

public ITaskService getTaskService() {

if (taskService == null) {

taskService = this.getWorkflowServiceClient().getTaskService();

}

return taskService;

}

public IWorkflowContext getWorkflowContext() {

long start = System.currentTimeMillis();

if (wfContext == null) {

try {

wfContext =

getTaskQueryService().authenticate(BPM_MANAGER_UN, BPM_MANAGER_PW.toCharArray(),

BPM_LDAP_DOMAIN);

wfContext =

this.getTaskQueryService().authenticateOnBehalfOf(wfContext,

username);

} catch (WorkflowException e) {

return null;

}

}

return wfContext;

}

/**

* 审批操作

* @param taskId

* @param outcome

* @param comments

* @param params

* @return

* @throws StaleObjectException

* @throws WorkflowException

*/

public Task updateTaskOutcome(String taskId, String outcome,

String comments,

Map params) throws StaleObjectException,

WorkflowException {

Task task = this.getTaskById(taskId);

if (params != null) {

Iterator iter = params.entrySet().iterator();

while (iter.hasNext()) {

Map.Entry entry = (Map.Entry)iter.next();

if (entry.getKey() != null && entry.getValue() != null) {

String key = entry.getKey().toString();

String value = entry.getValue().toString();

this.updatePayloadElement(task, key, value);

}

}

}

ObjectFactory factory = new ObjectFactory();

CommentType commentType = factory.createCommentType();

commentType.setComment(comments);

commentType.setCommentScope("TASK");

commentType.setTaskId(taskId);

commentType.setAction(outcome);

task.addUserComment(commentType);

this.getTaskService().updateTask(this.getWorkflowContext(), task);

task = this.getTaskById(taskId);

this.getTaskService().updateTaskOutcome(this.getWorkflowContext(),

task, outcome);

return task;

}

public void updatePayloadElement(Task task, String name, String value) {

task.getPayloadAsElement().getElementsByTagName(name).item(0).setTextContent(value);

}

public Task getTaskById(String taskId) {

Task task = null;

try {

task = this.getTaskQueryService().getTaskDetailsById(this.getWorkflowContext(),

taskId);

} catch (WorkflowException e) {

e.printStackTrace();

}

return task;

}

}

问题排查

​ 这个过程很痛苦的:......

(PS:不知道有没大佬能提供一套方法能减少这个过程的痛苦?欢迎大佬指点!)

思路

​ 记录下排查的思路:

源码检查

打印每一段可能耗时长的代码耗时

部署、监控

导出日志、统计分析

结果

项目上的审批接口主要实现了两件事:

审批

记录审批历史

从日志上分析,记录审批历史(这一步其实可以不要,但是由于项目上的种种原因,无法使用BPM官方的审批历史表(WFHISTORY),审批历史需要单独写入一张历史表中)暂时可以不考虑。

所以下面的篇幅就主要开始描述如优化审批操作。

优化处理

日志分析

结合源码可以看出,获取context的总耗时达到4s左右

审批时似乎重复调用了一次BPM 审批的API

【getWorkflowContext】获取context总耗时 cost(ms):918

【getWorkflowContext】获取context总耗时 cost(ms):700

【getWorkflowContext】获取context总耗时 cost(ms):1957

【getWorkflowContext】获取context总耗时 cost(ms):300

【BpmService】taskId :0a28e3e0-8c75-4eac-ae0d-78a29783be83 审批操作 cost(ms):1917

【BpmService】taskId :0a28e3e0-8c75-4eac-ae0d-78a29783be83 记录审批历史 cost(ms):8

【BpmService】taskId :0a28e3e0-8c75-4eac-ae0d-78a29783be83 总耗时 cost(ms):5892【MHM.MHM_RECEIPT_HEADERS_T】

优化

缓存context

处理重复调用API的代码

增加参数(系统/流程标识)让没有设置Outcomes Require Comment的流程跳过。

测试后发现,BPM流程建模的时候如果设置了Outcomes Require Comment ,那么就不能直接调用updateTaskOutcome() 方法,需要先调用下述代码:

this.getTaskService().updateTask(this.getWorkflowContext(), task);

Bpm 建模时在humanTask上设置Outcomes Require Comment:

bVbBfci

代码举例:

//标识流程模型上有没有设置OUTCOME必须注释

Boolean comment = true;

if (funName != null && funName.startsWith("CRM.")) {

//CRM系统不进行备注

comment = false;

}

//省略部分代码

if (comment) {

this.getTaskService().updateTask(this.getWorkflowContext(), task);

task = this.getTaskById(taskId);

}

相关代码

package cn.com.utility.bpm.utils;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.HashMap;

import java.util.Hashtable;

import java.util.Iterator;

import java.util.Map;

import oracle.bpel.services.workflow.StaleObjectException;

import oracle.bpel.services.workflow.WorkflowException;

import oracle.bpel.services.workflow.client.IWorkflowServiceClient;

import oracle.bpel.services.workflow.client.IWorkflowServiceClientConstants;

import oracle.bpel.services.workflow.client.WorkflowServiceClientFactory;

import oracle.bpel.services.workflow.query.ITaskQueryService;

import oracle.bpel.services.workflow.task.ITaskService;

import oracle.bpel.services.workflow.task.model.CommentType;

import oracle.bpel.services.workflow.task.model.ObjectFactory;

import oracle.bpel.services.workflow.task.model.Task;

import oracle.bpel.services.workflow.verification.IWorkflowContext;

public class TaskService2 {

private IWorkflowServiceClient wfSvcClient = null;

private ITaskQueryService taskQueryService = null;

private ITaskService taskService = null;

private IWorkflowContext wfContext = null;

private static final String BPM_MANAGER_UN = "weblogic";

private static final String BPM_MANAGER_PW = "weblogic1";

private static final String SOA_URL = "t3://bpmtest1.wlj.com.cn:8001";

private static final String BPM_CLIENT_TYPE = "EJB";

private static final String BPM_LDAP_DOMAIN = "jazn.com";

private static IWorkflowContext managerWfContext = null;

private static Map tokenCache =

new Hashtable();

private String username;

public TaskService2() {

super();

}

public IWorkflowServiceClient getWorkflowServiceClient() {

if (wfSvcClient == null) {

Map properties =

new HashMap();

properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.CLIENT_TYPE,

BPM_CLIENT_TYPE);

properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_PROVIDER_URL,

SOA_URL);

properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_PRINCIPAL,

BPM_MANAGER_UN);

properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_CREDENTIALS,

BPM_MANAGER_PW);

wfSvcClient =

WorkflowServiceClientFactory.getWorkflowServiceClient(WorkflowServiceClientFactory.REMOTE_CLIENT,

properties,

null);

}

return wfSvcClient;

}

public ITaskQueryService getTaskQueryService() {

if (taskQueryService == null) {

taskQueryService =

this.getWorkflowServiceClient().getTaskQueryService();

}

return taskQueryService;

}

public ITaskService getTaskService() {

if (taskService == null) {

taskService = this.getWorkflowServiceClient().getTaskService();

}

return taskService;

}

private IWorkflowContext getIWorkflowContext() {

String logTag = "【getWorkflowContext】";

long totalStartTime = System.currentTimeMillis();

long totalEndTime = 0;

long startTime = 0;

long endTime = 0;

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

TokenCache token = tokenCache.get(username);

if (token == null || token.isTimeout()) {

System.out.println(logTag + "【" + df.format(new Date()) + "】" +

"create new context cache:" + username);

try {

if (managerWfContext == null) {

startTime = System.currentTimeMillis();

managerWfContext =

getTaskQueryService().authenticate(BPM_MANAGER_UN,

BPM_MANAGER_PW.toCharArray(),

BPM_LDAP_DOMAIN);

endTime = System.currentTimeMillis();

System.out.println(logTag + "【" + df.format(new Date()) +

"】" + " 获取managerWfContext cost(ms):" +

(endTime - startTime));

}

startTime = System.currentTimeMillis();

wfContext =

this.getTaskQueryService().authenticateOnBehalfOf(managerWfContext,

username);

endTime = System.currentTimeMillis();

System.out.println(logTag + "【" + df.format(new Date()) + "】" +

" 获取wfContext cost(ms):" +

(endTime - startTime));

startTime = System.currentTimeMillis();

if (token == null) {

token = new TokenCache();

token.setWorkflowContext(wfContext);

tokenCache.put(username, token);

} else {

token.updateToken(wfContext);

}

endTime = System.currentTimeMillis();

System.out.println(logTag + "【" + df.format(new Date()) + "】" +

" 处理缓存 cost(ms):" + (endTime - startTime));

System.out.println(logTag + "【" + df.format(new Date()) + "】" +

"WorkflowContext Initialization Completed!");

} catch (WorkflowException e) {

System.out.println(logTag + "【" + df.format(new Date()) + "】" +

"获取IWorkflowContext报错");

System.out.println(e.getMessage());

return null;

}

} else {

System.out.println(logTag + "【" + df.format(new Date()) + "】" +

"get context from cache:" + username);

wfContext = token.getWorkflowContext();

}

totalEndTime = System.currentTimeMillis();

System.out.println(logTag + "【" + df.format(new Date()) + "】" +

" 获取context总耗时 cost(ms):" +

(totalEndTime - totalStartTime));

return wfContext;

}

public IWorkflowContext getWorkflowContext() {

String logTag = "【getWorkflowContext】";

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

IWorkflowContext context = getIWorkflowContext();

//报错或者超时后增加一次重试

if (context == null) {

System.out.println(logTag + "【" + df.format(new Date()) + "】" +

"重新获取IWorkflowContext");

managerWfContext = null;

context = getIWorkflowContext();

}

return context;

}

/**

* 审批操作

* @param taskId

* @param outcome

* @param comments

* @param params

* @param funName 系统标识

* @return

* @throws StaleObjectException

* @throws WorkflowException

*/

public Task updateTaskOutcome(String taskId, String outcome,

String comments, Map params,

String funName) throws StaleObjectException,

WorkflowException {

Task task = this.getTaskById(taskId);

if (params != null) {

Iterator iter = params.entrySet().iterator();

while (iter.hasNext()) {

Map.Entry entry = (Map.Entry)iter.next();

if (entry.getKey() != null && entry.getValue() != null) {

String key = entry.getKey().toString();

String value = entry.getValue().toString();

this.updatePayloadElement(task, key, value);

}

}

}

//标识流程模型上有没有设置OUTCOME必须注释

Boolean comment = true;

if (funName != null && funName.startsWith("CRM.")) {

//CRM不进行备注

comment = false;

}

ObjectFactory factory = new ObjectFactory();

CommentType commentType = factory.createCommentType();

commentType.setComment(comments);

commentType.setCommentScope("TASK");

commentType.setTaskId(taskId);

commentType.setAction(outcome);

task.addUserComment(commentType);

if (comment) {

this.getTaskService().updateTask(this.getWorkflowContext(), task);

task = this.getTaskById(taskId);

}

this.getTaskService().updateTaskOutcome(this.getWorkflowContext(),

task, outcome);

return task;

}

// //旧代码

// public IWorkflowContext getWorkflowContext() {

// long start = System.currentTimeMillis();

// if (wfContext == null) {

// try {

// wfContext =

// getTaskQueryService().authenticate(BPM_MANAGER_UN, BPM_MANAGER_PW.toCharArray(),

// BPM_LDAP_DOMAIN);

// wfContext =

// this.getTaskQueryService().authenticateOnBehalfOf(wfContext,

// username);

// } catch (WorkflowException e) {

// return null;

// }

// }

// System.out.println("getWorkflowContext cost:" +

// (System.currentTimeMillis() - start) + "ms");

// return wfContext;

// }

// 旧代码

// /**

// * 审批操作

// * @param taskId

// * @param outcome

// * @param comments

// * @param params

// * @return

// * @throws StaleObjectException

// * @throws WorkflowException

// */

// public Task updateTaskOutcome(String taskId, String outcome,

// String comments,

// Map params) throws StaleObjectException,

// WorkflowException {

// Task task = this.getTaskById(taskId);

// if (params != null) {

// Iterator iter = params.entrySet().iterator();

// while (iter.hasNext()) {

// Map.Entry entry = (Map.Entry)iter.next();

// if (entry.getKey() != null && entry.getValue() != null) {

// String key = entry.getKey().toString();

// String value = entry.getValue().toString();

// this.updatePayloadElement(task, key, value);

// }

// }

// }

//

// ObjectFactory factory = new ObjectFactory();

// CommentType commentType = factory.createCommentType();

// commentType.setComment(comments);

// commentType.setCommentScope("TASK");

// commentType.setTaskId(taskId);

// commentType.setAction(outcome);

// task.addUserComment(commentType);

// this.getTaskService().updateTask(this.getWorkflowContext(), task);

// task = this.getTaskById(taskId);

//

// this.getTaskService().updateTaskOutcome(this.getWorkflowContext(),

// task, outcome);

//

// return task;

// }

public void updatePayloadElement(Task task, String name, String value) {

task.getPayloadAsElement().getElementsByTagName(name).item(0).setTextContent(value);

}

public Task getTaskById(String taskId) {

Task task = null;

try {

task = this.getTaskQueryService().getTaskDetailsById(this.getWorkflowContext(),

taskId);

} catch (WorkflowException e) {

e.printStackTrace();

}

return task;

}

}

结果

设置了Outcomes Require Comment的流程由于添加了缓存机制,平均减少了2秒的耗时

没有设置Outcomes Require Comment的流程平均耗时1秒

最后

​ 做了缓存和系统标识后,总算是满足了甲方爸爸。

其他优化

修改审批方案:可以考虑使用MQ等消息队列做异步处理

审批历史的优化:如果需要单独记录审批历史,建议使用MQ等消息队列做异步处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值