由于工作原因,需要用到工作流框架activiti5,所以花了点时间研究了下,今天花点时间来整理下,第一次写的不好请见谅,也请你们多多提意见
首先我写了个测试demo,如下
static ProcessEngine processEngine = null;
static {
processEngine = ProcessEngines.getDefaultProcessEngine();
}
@Test
public void test1() {
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment()
.name("测试流程")
.addClasspathResource("processes/serviceTaskDemo.bpmn")
.deploy();
RuntimeService runtimeService = processEngine.getRuntimeService();
String businessKey = UUIDUtils.generateShortUuid();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess_7", businessKey, null);
System.out.println();
}
(1)工作流引擎的初始化
第一步是获取流程引擎
processEngine = ProcessEngines.getDefaultProcessEngine();
debug进入里面会得到一个默认的流程引擎
public static ProcessEngine getDefaultProcessEngine() {
return getProcessEngine(NAME_DEFAULT);
}
然后会判断流程引擎是否初始化
public static ProcessEngine getProcessEngine(String processEngineName) {
if (!isInitialized()) {
init();
}
return processEngines.get(processEngineName);
}
如果初始化则直接通过流程引擎名字获取,processEngines是一个map映射
否则开始初始化
进入初始化方法
public synchronized static void init() {
if (!isInitialized()) {
if(processEngines == null) {
// Create new map to store process-engines if current map is null
processEngines = new HashMap<String, ProcessEngine>();
}
ClassLoader classLoader = ReflectUtil.getClassLoader();
Enumeration<URL> resources = null;
try {
resources = classLoader.getResources("activiti.cfg.xml");
} catch (IOException e) {
throw new ActivitiIllegalArgumentException("problem retrieving activiti.cfg.xml resources on the classpath: "+System.getProperty("java.class.path"), e);
}
// Remove duplicated configuration URL's using set. Some classloaders may return identical URL's twice, causing duplicate startups
Set<URL> configUrls = new HashSet<URL>();
while (resources.hasMoreElements()) {
configUrls.add( resources.nextElement() );
}
for (Iterator<URL> iterator = configUrls.iterator(); iterator.hasNext();) {
URL resource = iterator.next();
log.info("Initializing process engine using configuration '{}'", resource.toString());
initProcessEnginFromResource(resource);
}
try {
resources = classLoader.getResources("activiti-context.xml");
} catch (IOException e) {
throw new ActivitiIllegalArgumentException("problem retrieving activiti-context.xml resources on the classpath: "+System.getProperty("java.class.path"), e);
}
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
log.info("Initializing process engine using Spring configuration '{}'", resource.toString());
initProcessEngineFromSpringResource(resource);
}
setInitialized(true);
} else {
log.info("Process engines already initialized");
}
}
首先会使用流程引擎的具体实现类的类加载器来加载配置文件activiti.cfg.xml
使用set集合来去重配置文件路径
Set<URL> configUrls = new HashSet<URL>();
while (resources.hasMoreElements()) {
configUrls.add( resources.nextElement() );
}
使用配置文件路径来初始化流程信息
private static ProcessEngineInfo initProcessEnginFromResource(URL resourceUrl) {
ProcessEngineInfo processEngineInfo = processEngineInfosByResourceUrl.get(resourceUrl.toString());
// if there is an existing process engine info
if (processEngineInfo!=null) {
// remove that process engine from the member fields
processEngineInfos.remove(processEngineInfo);
if (processEngineInfo.getException()==null) {
String processEngineName = processEngineInfo.getName();
processEngines.remove(processEngineName);
processEngineInfosByName.remove(processEngineName);
}
processEngineInfosByResourceUrl.remove(processEngineInfo.getResourceUrl());
}
String resourceUrlString = resourceUrl.toString();
try {
log.info("initializing process engine for resource {}", resourceUrl);
ProcessEngine processEngine = buildProcessEngine(resourceUrl);
String processEngineName = processEngine.getName();
log.info("initialised process engine {}", processEngineName);
processEngineInfo = new ProcessEngineInfoImpl(processEngineName, resourceUrlString, null);
processEngines.put(processEngineName, processEngine);
processEngineInfosByName.put(processEngineName, processEngineInfo);
} catch (Throwable e) {
log.error("Exception while initializing process engine: {}", e.getMessage(), e);
processEngineInfo = new ProcessEngineInfoImpl(null, resourceUrlString, getExceptionString(e));
}
processEngineInfosByResourceUrl.put(resourceUrlString, processEngineInfo);
processEngineInfos.add(processEngineInfo);
return processEngineInfo;
}
首先通过配置文件路径获取流程信息,若获取不到则通过配置文件路径创建流程信息
ProcessEngine processEngine = buildProcessEngine(resourceUrl);
通过获取配置文件信息位置读取文件信息,主要是使用流操作
private static ProcessEngine buildProcessEngine(URL resource) {
InputStream inputStream = null;
try {
inputStream = resource.openStream();
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream);
return processEngineConfiguration.buildProcessEngine();
} catch (IOException e) {
throw new ActivitiIllegalArgumentException("couldn't open resource stream: "+e.getMessage(), e);
} finally {
IoUtil.closeSilently(inputStream);
}
}
然后通过获取到的流程配置文件构建流程引擎
processEngineConfiguration.buildProcessEngine();
进入里面,会发现是个抽象方法,使用debug调试发现是由***ProcessEngineConfigurationImpl***来具体实现该类的初始化,这个类是工作流初始化的核心
里面包含了所有的工作流服务
protected RepositoryService repositoryService = new RepositoryServiceImpl();
protected RuntimeService runtimeService = new RuntimeServiceImpl();
protected HistoryService historyService = new HistoryServiceImpl(this);
protected IdentityService identityService = new IdentityServiceImpl();
protected TaskService taskService = new TaskServiceImpl(this);
protected FormService formService = new FormServiceImpl();
protected ManagementService managementService = new ManagementServiceImpl();
protected DynamicBpmnService dynamicBpmnService = new DynamicBpmnServiceImpl(this);
命令配置
protected CommandConfig defaultCommandConfig;
protected CommandConfig schemaCommandConfig;
拦截器
/** the configurable list which will be {@link #initInterceptorChain(java.util.List) processed} to build the {@link #commandExecutor} */
protected List<CommandInterceptor> customPreCommandInterceptors;
protected List<CommandInterceptor> customPostCommandInterceptors;
protected List<CommandInterceptor> commandInterceptors;
/** this will be initialized during the configurationComplete() */
protected CommandExecutor commandExecutor;
ibatis等数据库相关操作
protected List<SessionFactory> customSessionFactories;
protected DbSqlSessionFactory dbSqlSessionFactory;
protected Map<Class<?>, SessionFactory> sessionFactories;
解析器
protected BpmnDeployer bpmnDeployer;
protected BpmnParser bpmnParser;
protected List<Deployer> customPreDeployers;
protected List<Deployer> customPostDeployers;
protected List<Deployer> deployers;
protected DeploymentManager deploymentManager;
那么我们以服务TaskService为例,进入complete()功能的具体实现类,会发现如下这种操作
public void complete(String taskId) {
commandExecutor.execute(new CompleteTaskCmd(taskId, null));
}
看到这种实现方式,就不得不谈activiti框架设计所使用的命令模式和责任链模式
activiti的所有的操作都是这种模式,把动作包装一个命令,把动作和执行动作的行为充分解耦,在动作周边相关的一些操作都放在拦截器链中,层次更加清晰
比如这个commandExecutor这个执行器其实在ProcessEngineConfigurationImpl就已经初始化了,并添加了默认的拦截器
找到
protected void init() {
initConfigurators();
configuratorsBeforeInit();
initProcessDiagramGenerator();
initHistoryLevel();
initExpressionManager();
initDataSource();
initVariableTypes();
initBeans();
initFormEngines();
initFormTypes();
initScriptingEngines();
initClock();
initBusinessCalendarManager();
initCommandContextFactory();
initTransactionContextFactory();
initCommandExecutors();
initServices();
initIdGenerator();
initDeployers();
initJobHandlers();
initJobExecutor();
initAsyncExecutor();
initTransactionFactory();
initSqlSessionFactory();
initSessionFactories();
initJpa();
initDelegateInterceptor();
initEventHandlers();
initFailedJobCommandFactory();
initEventDispatcher();
initProcessValidator();
initDatabaseEventLogging();
configuratorsAfterInit();
}
找到
protected void initServices() {
initService(repositoryService);
initService(runtimeService);
initService(historyService);
initService(identityService);
initService(taskService);
initService(formService);
initService(managementService);
initService(dynamicBpmnService);
}
找到
protected void initService(Object service) {
if (service instanceof ServiceImpl) {
((ServiceImpl)service).setCommandExecutor(commandExecutor);
}
}
可以看到拦截器被设置到ServiceImpl上了,
那么问题来了,ServiceImpl又是什么了?这个等会解答
先看看这个拦截器又是在哪初始化
回到上一层
protected void init() {
initConfigurators();
configuratorsBeforeInit();
initProcessDiagramGenerator();
initHistoryLevel();
initExpressionManager();
initDataSource();
initVariableTypes();
initBeans();
initFormEngines();
initFormTypes();
initScriptingEngines();
initClock();
initBusinessCalendarManager();
initCommandContextFactory();
initTransactionContextFactory();
*initCommandExecutors();*
*initServices();*
initIdGenerator();
initDeployers();
initJobHandlers();
initJobExecutor();
initAsyncExecutor();
initTransactionFactory();
initSqlSessionFactory();
initSessionFactories();
initJpa();
initDelegateInterceptor();
initEventHandlers();
initFailedJobCommandFactory();
initEventDispatcher();
initProcessValidator();
initDatabaseEventLogging();
configuratorsAfterInit();
}
可以看到拦截器在service前面被初始化
进入
protected void initCommandExecutors() {
initDefaultCommandConfig();
initSchemaCommandConfig();
initCommandInvoker();
initCommandInterceptors();
initCommandExecutor();
}
发现有initCommandInterceptors()初始化拦截器
进入
protected void initCommandInterceptors() {
if (commandInterceptors==null) {
commandInterceptors = new ArrayList<CommandInterceptor>();
if (customPreCommandInterceptors!=null) {
commandInterceptors.addAll(customPreCommandInterceptors);
}
commandInterceptors.addAll(getDefaultCommandInterceptors());
if (customPostCommandInterceptors!=null) {
commandInterceptors.addAll(customPostCommandInterceptors);
}
commandInterceptors.add(commandInvoker);
}
}
会加载三个拦截器,customPreCommandInterceptors(执行命令前),getDefaultCommandInterceptors(默认拦截器),customPostCommandInterceptors(执行命令后)
进入默认的拦截器里面
protected Collection< ? extends CommandInterceptor> getDefaultCommandInterceptors() {
List<CommandInterceptor> interceptors = new ArrayList<CommandInterceptor>();
interceptors.add(new LogInterceptor());
CommandInterceptor transactionInterceptor = createTransactionInterceptor();
if (transactionInterceptor != null) {
interceptors.add(transactionInterceptor);
}
interceptors.add(new CommandContextInterceptor(commandContextFactory, this));
return interceptors;
}
会发现默认加载了日志拦截器和事务拦截器
日至拦截器打印日志
public class LogInterceptor extends AbstractCommandInterceptor {
private static Logger log = LoggerFactory.getLogger(LogInterceptor.class);
public <T> T execute(CommandConfig config, Command<T> command) {
if (!log.isDebugEnabled()) {
// do nothing here if we cannot log
return next.execute(config, command);
}
log.debug("\n");
log.debug("--- starting {} --------------------------------------------------------", command.getClass().getSimpleName());
try {
return next.execute(config, command);
} finally {
log.debug("--- {} finished --------------------------------------------------------", command.getClass().getSimpleName());
log.debug("\n");
}
}
}
事务拦截器会使用spring集成的包括事务的传播级别和隔离级别
下面开始解析上面的问题,ServiceImpl又是什么了?
所有的服务,包括TaskService都会继承ServiceImpl,那么所有的服务都会有这个默认初始化的拦截器