JBPM流程部署之部署环境初始化
JBPM流程部署之部署环境初始化
流程的部署是流程引擎需要完成的几个重要的任务之一,流程定义是现实中复杂业务需求在流程流转实现的体现;流程部署需要完成xml格式流程定义的校验、流程定义的持久化、流程定义到流程定义实体的转化、流程版本升级和流程实例的迁移等众多的功能;
今天我们来简单的学习一下流程部署的环境初始化;流程部署环境初始化需要完成部署服务、流程部署缓存、流程部署持久化相关对象、流程引擎支持的节点类型等相关binding对象及相关的部署解析器的实例化;
流程引擎支持的节点类型初始化
流程引擎支持众多的节点类型,比如任务节点、状态节点、子流程等等;此过程初始化JBPM默认支持的系统节点类型;JBPM将xml格式的流程定义解析成运行
时流程引擎流转所使用的流程定义(ProcessDefinitionImpl)、Activity等对象;而流程引擎对xml的解析也是依赖自己实现的IOC来实现的,所以归根结底流程引
擎支持的节点类型的初始化,就是将流程引擎支持的节点类型相应的binding进行实例化!此过程中相关的对象和UML类图如下
流程引擎支持的节点类型初始化相关对象
流程引擎支持的节点类型初始化相关对象UML图
下面我们通过图中的对象的实现代码,看一下他们的作用
jbpm.jpdl.bindings.xml 定义JBPM支持的节点类型和节点事件监听器,我们可以根据业务的需要注释到不使用的节点类型对应的元素,那么运行时就不会解
析流程定义xml中相应的元素,从而不会生成对应节点的对象;同时我们也可以在这里配置加载我们自定义或者扩展现有的节点类型。
//流程引擎支持的各种节点的binding
<activity binding="org.jbpm.jpdl.internal.activity.StartBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.StateBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.DecisionBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.EndBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.EndCancelBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.EndErrorBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.ForEachBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.ForkBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.JoinBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.HqlBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.SqlBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.JavaBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.ScriptBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.TaskBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.SubProcessBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.MailBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.GroupBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.CustomBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.AssignBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.PassthroughBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.RulesBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.RulesDecisionBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.JmsBinding" />
//流程引擎节点的事件监听器
<eventlistener binding="org.jbpm.jpdl.internal.activity.EventListenerBinding" />
<eventlistener binding="org.jbpm.jpdl.internal.activity.JavaBinding" />
<eventlistener binding="org.jbpm.jpdl.internal.activity.HqlBinding" />
<eventlistener binding="org.jbpm.jpdl.internal.activity.SqlBinding" />
<eventlistener binding="org.jbpm.jpdl.internal.activity.ScriptBinding" />
<eventlistener binding="org.jbpm.jpdl.internal.activity.MailBinding" />
<eventlistener binding="org.jbpm.jpdl.internal.activity.AssignBinding" />
<eventlistener binding="org.jbpm.jpdl.internal.activity.JmsBinding" />
</bindings>
JpdlDeployer 主要负责根据既有的规则生成流程定义的Id,key和版本,同时在首次解析时,通过静态字段JpdlParser来完成相关节点的binding类的实例化
private static Log log = Log.getLog(JpdlDeployer.class.getName());
private static Parser parser = new Parser();
//静态字段自动初始化
static JpdlParser jpdlParser = new JpdlParser();
static final String jpdlExtension = ".jpdl.xml";
JpdlDeployer的父类ProcessDeployer中的部分代码,完成对流程定义Id、version、key等的设置并持久化等
for (String resourceName: deployment.getResourceNames()) {
if (resourceName.endsWith(extension)) {
//加载xml格式的流程定义资源
byte[] bytes = deployment.getBytes(resourceName);
InputStream inputStream = new ByteArrayInputStream(bytes);
Parse parse = parser.createParse();
parse.contextMapPut(Parse.CONTEXT_KEY_DEPLOYMENT, deployment);
parse.setProblems(deployment.getProblems());
parse.setInputStream(inputStream);
//解析xml格式的流程定义生成ProcessDefinitionImpl
parse.execute();
List<ProcessDefinitionImpl> processDefinitions = (List<ProcessDefinitionImpl>) parse.getDocumentObject();
if (processDefinitions!=null) {
for (ProcessDefinitionImpl processDefinition : processDefinitions) {
if ((processDefinition != null) && (processDefinition.getName() != null)) {
processDefinition.setSuspended(deployment.isSuspended());
String imageResourceName = resourceName.substring(0, resourceName.lastIndexOf(extension)) + ".png";
if (deployment.getResourceNames().contains(imageResourceName)) {
processDefinition.setImageResourceName(imageResourceName);
}
processDefinition.setDeploymentDbid(deployment.getDbid());
String processDefinitionName = processDefinition.getName();
//获取已经发布完得流程执行(比如启动流程时获取流程定义对象)
if (deployment.hasObjectProperties(processDefinitionName)) {
String key = deployment.getProcessDefinitionKey(processDefinitionName);
String id = deployment.getProcessDefinitionId(processDefinitionName);
Long version = deployment.getProcessDefinitionVersion(processDefinitionName);
processDefinition.setId(id);
processDefinition.setKey(key);
processDefinition.setVersion(version.intValue());
} else {
//流程部署校验并设置流程定义的id、key、version
checkKey(processDefinition, deployment);
checkVersion(processDefinition, deployment);
checkId(processDefinition, deployment);
//持久化对流程定义id、key、version的设置
deployment.setProcessDefinitionId(processDefinitionName, processDefinition.getId());
deployment.setProcessDefinitionKey(processDefinitionName, processDefinition.getKey());
deployment.setProcessDefinitionVersion(processDefinitionName, new Long(processDefinition.getVersion()));
//execute migration
//流程实例迁移
Map<ProcessDefinition, MigrationDescriptor> migrations = (Map<ProcessDefinition, MigrationDescriptor>)parse.contextMapGet(Parse.CONTEXT_KEY_MIGRATIONS);
if (migrations != null) {
MigrationDescriptor migrationDescriptor = migrations.get(processDefinition);
if (migrationDescriptor != null) {
InstanceMigrator.migrateAll(processDefinition, migrationDescriptor);
}
}
}
deployment.addObject(processDefinitionName, processDefinition);
}
}
}
}
}
}
ProcessDefinitionImpl,流程定义的运行时对象,作为流程实例运行的流转依据,其定义了流程的启动节点,同时父类CompositeElementImpl定义了流程中
的所有的节点
private static final long serialVersionUID = 1L;
private static final Log log = Log.getLog(ProcessDefinitionImpl.class.getName());
public static final int UNASSIGNED_VERSION = -1;
/** user provided short reference for the process definition that
* has the same scope as the name. Multiple versions of the same
* process can have the same key. The key is used to build the
* globally unique execution ids. */
protected String key;
/** the unique id (e.g. combination of name and versionnumber) for this
* process definition. */
protected String id;
/** the version number of the process definitions with the same name.*/
protected int version = UNASSIGNED_VERSION;
/** optional package name similar to the Java package name. */
protected String packageName;
/** time this process was deployed */
protected Date deploymentTime;
/** ref to the deployment */
protected long deploymentDbid;
/** propagated from deployment to process definition during deploy */
protected boolean isSuspended = false;
/** the activity which is executed when the process starts */
protected ActivityImpl initial;
ProcessDefinitionImpl的父类CompositeElementImpl中定义了其所有的直接子节点
private static final long serialVersionUID = 1L;
//流程定义的所有直接子节点,节点本身是可以嵌套的
protected List<ActivityImpl> activities;
JpdlParser定义了部署中需要使用的一些关键信息,并完成xml格式流程定义的解析,并在初次解析xml前完成节点类型binding类的解析初始化
private static final Log log = Log.getLog(JpdlParser.class.getName());
//xml格式流程定义使用的命名空间
public static final String NAMESPACE_JPDL_40 = "http://jbpm.org/4.0/jpdl";
public static final String NAMESPACE_JPDL_42 = "http://jbpm.org/4.2/jpdl";
public static final String NAMESPACE_JPDL_43 = "http://jbpm.org/4.3/jpdl";
public static final String NAMESPACE_JPDL_44 = "http://jbpm.org/4.4/jpdl";
//当前JBPM的版本、流程定义的命名空间、jbpl的版本
public static final String CURRENT_VERSION_JBPM = "4.4";
public static final String CURRENT_VERSION_NAMESPACE =
"http://jbpm.org/" + CURRENT_VERSION_JBPM + "/jpdl";
public static final String CURRENT_VERSION_PROCESS_LANGUAGE_ID =
"jpdl-" + CURRENT_VERSION_JBPM;
//流程定义xml校验使用的xsd
private static final String[] SCHEMA_RESOURCES =
{ "jpdl-4.0.xsd", "jpdl-4.2.xsd", "jpdl-4.3.xsd", "jpdl-4.4.xsd" };
//节点类型binding的配置文件
private static final String[] DEFAULT_BINDING_RESOURCES =
{ "jbpm.jpdl.bindings.xml", "jbpm.user.bindings.xml" };
//解析配置文件中的binding类
private static JpdlBindingsParser jpdlBindingsParser = new JpdlBindingsParser();
//节点的binding类的分类
public static final String CATEGORY_ACTIVITY = "activity";
public static final String CATEGORY_EVENT_LISTENER = "eventlistener";
//初始化时,加载并解析节点的binding类
public JpdlParser() {
parseBindings();
setSchemaResources(SCHEMA_RESOURCES);
}
//加载并解析节点的binding类
protected void parseBindings() {
this.bindings = new Bindings();
for (String activityResource : DEFAULT_BINDING_RESOURCES) {
Enumeration<URL> resourceUrls = getResources(activityResource);
if (resourceUrls.hasMoreElements()) {
while (resourceUrls.hasMoreElements()) {
URL resourceUrl = resourceUrls.nextElement();
log.trace("loading jpdl bindings from resource: " + resourceUrl);
jpdlBindingsParser.createParse()
.setUrl(resourceUrl)
.contextMapPut(Parse.CONTEXT_KEY_BINDINGS, bindings)
.execute()
.checkErrors("jpdl bindings from " + resourceUrl.toString());
}
}
else {
log.trace("skipping unavailable jpdl activities resource: " + activityResource);
}
}
}
protected Enumeration<URL> getResources(String resourceName) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Enumeration<URL> resourceUrls;
try {
resourceUrls = classLoader.getResources(resourceName);
if (!resourceUrls.hasMoreElements()) {
resourceUrls = JpdlParser.class.getClassLoader().getResources(resourceName);
}
}
catch (Exception e) {
throw new JbpmException("couldn't get resource urls for " + resourceName, e);
}
return resourceUrls;
}
//解析xml格式的流程定义,并生成processDefinitionImpl
public Object parseDocumentElement(Element documentElement, Parse parse) {
JpdlProcessDefinition processDefinition = instantiateNewJpdlProcessDefinition();
parse.contextStackPush(processDefinition);
Bindings负责承载解析生成的节点的binding对象,并负责根据流程定义中的节点元素的tagName找到对相应的bingding对象(用于解析该节点元素)
/** maps categories to a list of bindings */
protected Map<String, List<Binding>> bindings = null;
public Set<String> getTagNames(String category) {
Set<String> tagNames = new HashSet<String>();
List<Binding> categoryBindings = (bindings!=null ? bindings.get(category) : null );
if (categoryBindings!=null) {
for (Binding binding: categoryBindings) {
tagNames.add(binding.toString());
}
}
return tagNames;
}
}
JpdlBindingsParser 负责解析jbpm.jpdl.bindings.xml,并生成其中配置的binding实例
private static final Log log = Log.getLog(JpdlBindingsParser.class.getName());
//解析jbpm.jpdl.bindings.xml中的xml
public Object parseDocumentElement(Element documentElement, Parse parse) {
Bindings bindings = (Bindings) parse.contextMapGet(Parse.CONTEXT_KEY_BINDINGS);
parse.setDocumentObject(bindings);
for (Element bindingElement : XmlUtil.elements(documentElement)) {
Binding binding = instantiateBinding(bindingElement, parse);
bindings.addBinding(binding);
}
return bindings;
}
//实例化jbpm.jpdl.bindings.xml中的元素中定义的binding类
protected Binding instantiateBinding(Element bindingElement, Parse parse) {
String bindingClassName = XmlUtil.attribute(bindingElement, "binding", parse);
log.trace("adding jpdl binding "+bindingClassName);
if (bindingClassName!=null) {
try {
Class<?> bindingClass = ReflectUtil.classForName(bindingClassName);
TagBinding binding = (TagBinding) bindingClass.newInstance();
String tagLocalName = bindingElement.getLocalName();
if ("activity".equals(tagLocalName)) {
binding.setCategory(JpdlParser.CATEGORY_ACTIVITY);
} else if ("eventlistener".equals(tagLocalName)) {
binding.setCategory(JpdlParser.CATEGORY_EVENT_LISTENER);
} else {
parse.addProblem("unrecognized binding tag: "+tagLocalName);
}
return binding;
} catch (Exception e) {
parse.addProblem("couldn't instantiate activity binding "+bindingClassName, e);
}
}
return null;
}
}
初始化发布服务相关和初始化流程部署解析器相关
流程的发布服务对外提供发布服务,我们可以通过调用该服务来完成流程的发布;流程部署解析器则主要负责xml格式流程定义的解析!
流程部署解析器相关对象
流程部署服务相关对象
流程部署解析器和流程部署服务相关对象的UML图,由于两部分的管理比较紧密,所以UML图可能比较复杂
下面我们同样结合UML中的类的代码来探究JBPM的实现
jbpm.cfg.xml定义了并导入JBPM中的各种配置文件,方便对配置文件的集中管理
<import resource="jbpm.default.cfg.xml" />
<import resource="jbpm.businesscalendar.cfg.xml" />
<import resource="jbpm.tx.hibernate.cfg.xml" />
//流程定义JPDL的配置文件
<import resource="jbpm.jpdl.cfg.xml" />
<import resource="jbpm.bpmn.cfg.xml" />
<import resource="jbpm.identity.cfg.xml" />
<!-- Job executor is excluded for running the example test cases. -->
<!-- To enable timers and messages in production use, this should be included. -->
<!--
<import resource="jbpm.jobexecutor.cfg.xml" />
-->
</jbpm-configuration>
jbpm.wire.bindings.xml定义了流程引擎需要使用的一些相关对象的binding,是JBPM 自身实现的IOC框架的重要组成部分
<!-- hibernate bindings -->
<binding class="org.jbpm.pvm.internal.wire.binding.RepositorySessionBinding" />
<!-- services -->
<binding class="org.jbpm.pvm.internal.wire.binding.RepositoryServiceBinding" />
<binding class="org.jbpm.pvm.internal.wire.binding.RepositoryCacheBinding" />
<!-- deployers -->
<binding class="org.jbpm.pvm.internal.wire.binding.DeployerManagerBinding" />
<!-- jpdl bindings -->
<binding class="org.jbpm.jpdl.internal.xml.JpdlDeployerBinding" />
</wire-bindings>
jbpm.default.cfg.xml 配置流程引擎的相关对象,配置需要立即实例化的对象会在解析配置文件的同时生成对象实例,否则仅根据相应的binding生成对象的descriptor实例,到实际使用时再延迟实例化
<jbpm-configuration>
<import resource="jbpm.default.scriptmanager.xml" />
<import resource="jbpm.mail.templates.xml" />
<process-engine-context>
//部署服务
<repository-service />
<repository-cache />
<execution-service />
<history-service />
<management-service />
<identity-service />
<task-service />
<object class="org.jbpm.pvm.internal.id.DatabaseDbidGenerator">
<field name="commandService"><ref object="newTxRequiredCommandService" /></field>
</object>
<object class="org.jbpm.pvm.internal.id.DatabaseIdComposer" init="eager" />
<object class="org.jbpm.pvm.internal.el.JbpmElFactoryImpl" />
<types resource="jbpm.variable.types.xml" />
<address-resolver />
</process-engine-context>
<transaction-context>
<repository-session />
<db-session />
<message-session />
<timer-session />
<history-sessions>
<object class="org.jbpm.pvm.internal.history.HistorySessionImpl" />
</history-sessions>
<mail-session>
<mail-server>
<session-properties resource="jbpm.mail.properties" />
</mail-server>
</mail-session>
</transaction-context>
</jbpm-configuration>
ConfigrationImpl作为流程引擎初始化的入口,几乎完成流程引擎所有所有的配置文件的解析,同时负责根据配置生成流程引擎对象
//流程引擎的默认配置文件
public static final String DEFAULT_CONFIG_RESOURCENAME = "jbpm.cfg.xml";
private static Log log = Log.getLog(ConfigurationImpl.class.getName());
transient protected boolean isConfigured = false;
transient String jndiName;
transient boolean checkDb = true;
transient boolean isSpringEnabled = false;
// type is Object because we don't want a dependency on spring in this class
transient Object applicationContext = null;
//承载流程相关的descriptor
transient WireContext processEngineWireContext = new WireContext(new WireDefinition(), Context.CONTEXTNAME_PROCESS_ENGINE, true);
//承载事务相关的descriptor
transient WireDefinition transactionWireDefinition = new WireDefinition();
transient ProcessEngine producedProcessEngine;
public ConfigurationImpl() {
// to prevent a loop in the constructors, we need to delegate to a non-default constructor in Configuration
super(null);
}
//构建流程引擎对象
public ProcessEngine buildProcessEngine() {
ConfigrationParser主要负责解析JBPM的配置文件并根据不同的标签调用不同的Parser
private static final long serialVersionUID = 1L;
//解析配置文件中标签process-engine-context及其子元素
Parser processEngineContextParser = new WireParser();
//解析配置文件中标签transaction-context及其子元素
Parser transactionContextParser = new WireParser();
protected static ConfigurationParser INSTANCE = new ConfigurationParser();
public static ConfigurationParser getInstance() {
return INSTANCE;
}
//解析配置文件
public Object parseDocument(Document document, Parse parse) {
WireParser主要负责流程定义文件的具体解析,同时负责在首次运行之前解析jbpm.wire.bindings.xml
//默认的bindings配置文件
public static final String[] DEFAULT_WIRE_BINDING_RESOURCES = new String[]{
"jbpm.wire.bindings.xml",
"jbpm.user.wire.bindings.xml"
};
private static final long serialVersionUID = 1L;
private static final Log log = Log.getLog(WireParser.class.getName());
//生成的descriptor的分类
public static final String CATEGORY_DESCRIPTOR = "descriptor";
public static final String CATEGORY_OPERATION = "operation";
public static final String CATEGORY_INTERCEPTOR = "interceptor";
private static WireParser instance;
//承载jbpm.wire.bindings.xml中的binding实例
private static Bindings defaultBindings; // initialized at the bottom of this file
//解析配置文件
public Object parseDocumentElement(Element documentElement, Parse parse) {
List<Element> elements = XmlUtil.elements(documentElement);
WireDefinition wireDefinition = parse.contextStackFind(WireDefinition.class);
if (wireDefinition==null) {
wireDefinition = new WireDefinition();
}
parse.contextStackPush(wireDefinition);
try {
for (Element descriptorElement: elements) {
Descriptor descriptor = (Descriptor) parseElement(descriptorElement, parse, CATEGORY_DESCRIPTOR);
// add the descriptor
if ( (wireDefinition!=null)
&& (descriptor!=null)
) {
wireDefinition.addDescriptor(descriptor);
}
}
} finally {
parse.contextStackPop();
}
return wireDefinition;
}
//解析jbpm.wire.bindings.xml
static {
// default descriptor parsers ///////////////////////////////////////////////
defaultBindings = new Bindings();
BindingParser bindingParser = new BindingParser();
for (String wireResource: DEFAULT_WIRE_BINDING_RESOURCES) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Enumeration<URL> resourceUrls;
try {
resourceUrls = classLoader.getResources(wireResource);
if (!resourceUrls.hasMoreElements()) {
resourceUrls = WireParser.class.getClassLoader().getResources(wireResource);
}
} catch (Exception e) {
throw new JbpmException("couldn't get resource urls for "+wireResource, e);
}
if (resourceUrls.hasMoreElements()) {
while (resourceUrls.hasMoreElements()) {
URL resourceUrl = resourceUrls.nextElement();
log.trace("loading wire bindings from resource: "+resourceUrl);
bindingParser.createParse()
.setUrl(resourceUrl)
.contextStackPush(defaultBindings)
.execute()
.checkErrors(resourceUrl.toString());
}
} else {
log.trace("skipping unavailable wire bindings resource "+wireResource);
}
}
}
BindingParser主要负责jbpm.wire.bindings.xml
private static final Log log = Log.getLog(BindingParser.class.getName());
public Object parseDocumentElement(Element documentElement, Parse parse) {
List<Element> elements = XmlUtil.elements(documentElement, "binding");
for (Element bindingElement : elements) {
String bindingClassName = XmlUtil.attribute(bindingElement, "class");
log.trace("adding wire binding for "+bindingClassName);
Binding binding = null;
if (bindingClassName!=null) {
try {
Class<?> bindingClass = ReflectUtil.classForName(bindingClassName);
binding = (Binding) bindingClass.newInstance();
} catch (Exception e) {
log.trace("couldn't instantiate binding "+bindingClassName);
}
} else {
parse.addProblem("class is a required attribute in a binding "+XmlUtil.toString(bindingElement), documentElement);
}
if (binding!=null) {
Bindings bindings = parse.contextStackFind(Bindings.class);
bindings.addBinding(binding);
}
}
return null;
}
}
ProcessEnginImpl持有流程解析配置文件形成的相关对象,对外提供相关服务,可以获取相关的对象,为事务提供环境对象实例
private static final long serialVersionUID = 1L;
private static final Log log = Log.getLog(ProcessEngineImpl.class.getName());
public static final String JBPM_LIBRARY_VERSION = "4.4-SNAPSHOT";
//持有流程引擎解析配置文件形成的对象
transient protected WireContext processEngineWireContext;
transient protected WireDefinition transactionWireDefinition;
transient protected ThreadLocal<List<UserProvidedEnvironmentObject>> userProvidedEnvironmentObjectsThreadLocal = new ThreadLocal<List<UserProvidedEnvironmentObject>>();
transient protected ThreadLocal<String> authenticatedUserIdThreadLocal = new ThreadLocal<String>();
transient protected CommandService userCommandService = null;
public ProcessEngineImpl() {
}
//对外提供各种服务
public ExecutionService getExecutionService() {
return get(ExecutionService.class);
}
public HistoryService getHistoryService() {
return get(HistoryService.class);
}
public ManagementService getManagementService() {
return get(ManagementService.class);
}
public TaskService getTaskService() {
return get(TaskService.class);
}
public IdentityService getIdentityService() {
return get(IdentityService.class);
}
public RepositoryService getRepositoryService() {
return get(RepositoryService.class);
}
//提供与事务相关的环境对象
public EnvironmentImpl openEnvironment() {
PvmEnvironment environment = new PvmEnvironment(this);
if (log.isTraceEnabled()) log.trace("opening " + environment);
installAuthenticatedUserId(environment);
installProcessEngineContext(environment);
installTransactionContext(environment);
return environment;
}
//获取流程需要使用的相关对象
public Object get(String key) {
return processEngineWireContext.get(key);
}
public <T> T get(Class<T> type) {
return processEngineWireContext.get(type);
}
public String getName() {
return processEngineWireContext.getName();
}
public boolean has(String key) {
return processEngineWireContext.has(key);
}
public Set<String> keys() {
return processEngineWireContext.keys();
}
public Object set(String key, Object value) {
return processEngineWireContext.set(key, value);
}
public <T> T execute(Command<T> command) {
return userCommandService.execute(command);
}
}
EnvironmentImpl主要为具体的一次事务提供上下文环境,并提供获取相关对象的方法
private static final long serialVersionUID = 1L;
public abstract Object get(String name);
public abstract Object get(String name, String[] searchOrder);
public abstract Object get(String name,String[] searchOrder, boolean nullAllowed) throws JbpmException;
public abstract Object get(String name, boolean nullAllowed) throws JbpmException;
public abstract <T> T get(Class<T> type);
public abstract <T> T get(Class<T> type, String[] searchOrder);
static ThreadLocal<EnvironmentImpl> currentEnvironment = new ThreadLocal<EnvironmentImpl>();
static ThreadLocal<Stack<EnvironmentImpl>> currentEnvironmentStack = new ThreadLocal<Stack<EnvironmentImpl>>();
public static EnvironmentImpl getCurrent() {
return currentEnvironment.get();
}
public static <T> T getFromCurrent(Class<T> type) {
return getFromCurrent(type, true);
}
public static <T> T getFromCurrent(Class<T> type, boolean required) {
EnvironmentImpl environment = getCurrent();
if (environment==null) {
if (required) {
throw new JbpmException("no environment to get "+type.getName());
}
return null;
}
T object = environment.get(type);
if (object==null) {
if (required) {
throw new JbpmException("no "+type.getName()+" in current environment");
}
return null;
}
return object;
}
public static Object getFromCurrent(String name, boolean required) {
EnvironmentImpl environment = getCurrent();
if (environment==null) {
if (required) {
throw new JbpmException("no environment to get '"+name+"'");
}
return null;
}
Object object = environment.get(name);
if (object==null) {
if (required) {
throw new JbpmException("no '"+name+"' in current environment");
}
return null;
}
return object;
}
static Stack<EnvironmentImpl> getStack() {
// lazy initialize the current environment stack
Stack<EnvironmentImpl> stack = currentEnvironmentStack.get();
if (stack==null) {
stack = new Stack<EnvironmentImpl>();
currentEnvironmentStack.set(stack);
}
return stack;
}
}
jbpm.jpdl.cfg.xml配置流程部署管理者和部署解析器
<process-engine-context>
//部署管理者
<deployer-manager>
//部署解析器
<jpdl-deployer />
<object class="org.jbpm.pvm.internal.repository.RulesDeployer" />
</deployer-manager>
</process-engine-context>
</jbpm-configuration>
DeployManager 负责调用部署解析器解析xml流程定义,并管理生成的流程定义进行缓存
private static Log LOG = Log.getLog(DeployerManager.class.getName());
List<Deployer> deployers;
public void deploy(DeploymentImpl deployment) {
deployment.setProblems(new ArrayList<Problem>());
//调用部署解析器
for (Deployer deployer: deployers) {
deployer.deploy(deployment);
}
if (deployment.hasErrors()) {
JbpmException jbpmException = deployment.getJbpmException();
LOG.info("errors during deployment of "+deployment+": "+jbpmException.getMessage());
throw jbpmException;
}
//缓存流程定义
RepositoryCache repositoryCache = EnvironmentImpl.getFromCurrent(RepositoryCache.class);
if (repositoryCache != null) {
// If there are no objects after deploying, then there is something wrong
if (deployment.getObjects() == null || deployment.getObjects().isEmpty()) {
if (LOG.isWarnEnabled()) {
LOG.warn("WARNING: no objects were deployed! Check if you have configured a correct deployer "
+"in your jbpm.cfg.xml file for the type of deployment you want to do.");
}
} else {
repositoryCache.set(deployment.getId(), deployment.getObjects());
}
}
}
//更新流程定义
public void updateResource(DeploymentImpl deployment, String resourceName, byte[] bytes) {
for (Deployer deployer: deployers) {
deployer.updateResource(deployment, resourceName, bytes);
}
RepositoryCache repositoryCache = EnvironmentImpl.getFromCurrent(RepositoryCache.class);
repositoryCache.remove(deployment.getId());
}
}
RepositoryService主要对外提供部署服务接口
public NewDeployment createDeployment() {
return new DeploymentImpl(commandService);
}
public void suspendDeployment(String deploymentId) {
commandService.execute(new SuspendDeploymentCmd(deploymentId));
}
public void resumeDeployment(String deploymentId) {
commandService.execute(new ResumeDeploymentCmd(deploymentId));
}
public void deleteDeployment(String deploymentId) {
commandService.execute(new DeleteDeploymentCmd(deploymentId));
}
RepositorySessionImpl主要负责流程部署的持久化,持有一些部署相关的对象
private static Log log = Log.getLog(RepositorySessionImpl.class.getName());
protected Session session;
protected RepositoryCache repositoryCache;
protected DeployerManager deployerManager;
public String deploy(NewDeployment deployment) {
DeploymentImpl deploymentImpl = (DeploymentImpl) deployment;
long dbid = DbidGenerator.getDbidGenerator().getNextId();
deploymentImpl.setDbid(dbid);
deploymentImpl.initResourceLobDbids();
session.save(deploymentImpl); // will also save the attached resources
deployerManager.deploy(deploymentImpl);
return deploymentImpl.getId();
}
RepositoryCacheImpl 封装集合对流程定义进行缓存
Map<String, Map<String, Object>> deployments = new HashMap<String, Map<String,Object>>();
Map<Object, DeploymentClassLoader> deploymentClassLoaders = new HashMap<Object, DeploymentClassLoader>();
public Object get(String deploymentId, String objectName) {
Map<String, Object> deploymentObjects = deployments.get(deploymentId);
if (deploymentObjects==null) {
return null;
}
return deploymentObjects.get(objectName);
}
public void set(String deploymentId, String key, Object cachedObject) {
Map<String, Object> objects = new HashMap<String, Object>();
objects.put(key, cachedObject);
set(deploymentId, objects);
}
流程引擎的部署环境的初始化涉及流程引擎的各个方面,相对比较复杂,就简单介绍到这里,接下来我们将结合部署环境的初始化进行扩展自定义!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现