工作流框架Activiti源码学习(一)

由于工作原因,需要用到工作流框架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,那么所有的服务都会有这个默认初始化的拦截器

你可能感兴趣的:(activiti)