zoukankan      html  css  js  c++  java
  • JBPM之Environment分析

    JBPMEnvironment分析 

           只要们稍微深入的学习一下JBPM,我们就会发现代码的每个角落都有environment的影子,可见environment的地位之重要,今天我们学习一下environment的作用和使用方法,以及其中的一些运行机制!

           Environment的作用

           线程安全对象,为每个线程维护一系列的资源

            我们一般像这样使用Environment获取资源对象       

    Session session = EnvironmentImpl.getFromCurrent(Session.class);
          
             EnvironmentImpl中对应的代码实现

           

    //线程安全的真正原因
     static ThreadLocal<EnvironmentImpl> currentEnvironment = new ThreadLocal<EnvironmentImpl>();


    //从当前的环境中获取对应的对象
    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 EnvironmentImpl getCurrent() {
        
    return currentEnvironment.get();
      }

           之所以说environment是现成安全,是因为使用了ThreadLocal,其相关的知识请参考我以前的文章。

           作为资源对象的承载容器,承载了不同生命周期和作用范围的变量等资源   

             BasicEnvironment中定义了承载各种Context的集合和Context方法

           

    protected Map<String, Context> contexts = new LinkedHashMap<String, Context>();
    public Context getContext(String contextName) {
        
    return contexts.get(contextName);
      }

      
    public void setContext(Context context) {
        contexts.put(context.getName(), context);
      }

      
    public Context removeContext(Context context) {
        
    return removeContext(context.getName());
      }
      
      
    public Context removeContext(String contextName) {
        
    return contexts.remove(contextName);
      }

      
    public Context getEnvironmentFactoryContext() {
        
    return getContext(Context.CONTEXTNAME_PROCESS_ENGINE);
      }

      
    public Context getEnvironmentContext() {
        
    return getContext(Context.CONTEXTNAME_TRANSACTION);
      }

             各种Context如下图

                  

           可以通过特定的顺序在环境中查找需要的资源    

           BasicEnvironment中定义了各种按顺序查找对象的方法

          

    // search methods ///////////////////////////////////////////////////////////

      
    public Object get(String name) {
        
    return get(name, null);
      }

      
    public Object get(String name, String[] searchOrder) {
        
    return get(name, searchOrder, true);
      }

      
    public Object get(String name, boolean nullIfNotFound) {
        
    return get(name, null, nullIfNotFound);
      }

      
    public Object get(String name, String[] searchOrder, boolean nullIfNotFound) {
        
    if (searchOrder == null) {
          searchOrder 
    = getDefaultSearchOrder();
        }
        
    for (String contextName : searchOrder) {
          Context context 
    = contexts.get(contextName);
          
    if (context.has(name)) {
            
    return context.get(name);
          }
        }
        
    if (nullIfNotFound) {
          
    return null;
        } 
    else {
          
    throw new JbpmException("Null value found for " + name + " but null is not allowed");
        }
      }

      
    public <T> T get(Class<T> type) {
        
    return get(type, (String[]) null);
      }

      
    //在所有的context中查找与给定类型相同的实例,返回第一个找到的
      public <T> T get(Class<T> type, String[] searchOrder) {
        
    if (searchOrder==null) {
          searchOrder 
    = getDefaultSearchOrder();
        }
        
    for (String contextName : searchOrder) {
          Context context 
    = contexts.get(contextName);
          T object 
    = context.get(type);
          
    if (object != nullreturn object;
        }
        
    return null;
      }
      
      
    /**
       * searches an object based on type in the default search order.
       * if this environment contains the given context, the search skips
       * contexts registered after it.
       
    */
      
    public <T> T get(Class<T> type, Context requester) {
        String[] searchOrder 
    = getDefaultSearchOrder();
        
    int searchPosition = 0;
        
    for (int i = 0; i < searchOrder.length; i++) {
          
    if (contexts.get(searchOrder[i]) == requester) {
            searchPosition 
    = i + 1;
            
    break;
          }
        }
        
    for (int i = searchPosition; i < searchOrder.length; i++) {
          Context context 
    = contexts.get(searchOrder[i]);
          T object 
    = context.get(type);
          
    if (object != nullreturn object;
        }
        
    return null;
      }

          可以使jbpm兼容企业版和标准版

                  注释说是可以实现的,但是自己并没有找到实现机制,希望明了的网友不吝赐教告知!

         相关的Environment的uml类图

        

        

           相关的EnvironmentFactory UML类图

          

       环境生成机制

       

    执行流程如上图所示,下面详细讲解

    JBPM中环境的生成是由EnvironmentInterceptor拦截器调用EnvironmentFactory生成的。

    1.在配置文件中做相应的配置

    在配置文件中设置流程引擎初始化是初始化相关的拦截器

    Jbpm.wire.bindings.xml

    <binding class="org.jbpm.pvm.internal.wire.binding.EnvironmentInterceptorBinding"
     
    />

            jbpm.tx.*.cfg.xml文件中定义拦截器策略,这里以展示一下hibernate的配置

              

     <command-service name="txRequiredCommandService">
          
    <skip-interceptor />
          
    <retry-interceptor />
          
    <environment-interceptor />
          
    <standard-transaction-interceptor />
        
    </command-service>

        
    <command-service name="newTxRequiredCommandService">
          
    <retry-interceptor />
          
    <environment-interceptor policy="requiresNew" />
          
    <standard-transaction-interceptor />
        
    </command-service>

    2.解析配置文件并生成相关的descriptor

    binding类用于解析xml定义,并最终生成descriptor(了解binding、descriptor请参考我相关的文章)

     

    public class CommandServiceBinding extends WireDescriptorBinding {

      
    public CommandServiceBinding() {
        
    super("command-service");
      }
      
      
    protected CommandServiceBinding(String tagName) {
        
    super(tagName);
      }

      
    //解析command-service定义的拦截器策略
      public Object parse(Element element, Parse parse, Parser parser) {
        CommandServiceDescriptor commandServiceDescriptor 
    = new CommandServiceDescriptor();

        CommandService commandService 
    = getCommandService(element, parse, parser);
        commandServiceDescriptor.setCommandService(commandService);
        
        
    //解析拦截器策略
        List<Element> interceptorElements = XmlUtil.elements(element);
        
    for (Element interceptorElement : interceptorElements) {
          Descriptor interceptorDescriptor 
    = (Descriptor) parser.parseElement(interceptorElement, parse, WireParser.CATEGORY_INTERCEPTOR);
          commandServiceDescriptor.addInterceptorDescriptor(interceptorDescriptor);
        }

        
    return commandServiceDescriptor;
      }

      
    protected CommandService getCommandService(Element element, Parse parse, Parser parser) {
        Boolean async 
    = XmlUtil.attributeBoolean(element, "async", parse);
        
    if (Boolean.TRUE.equals(async)) {
          AsyncCommandService asyncCommandService 
    = new AsyncCommandService();

          Boolean propagateUserId 
    = XmlUtil.attributeBoolean(element, "propagate-auth", parse);
          
    if (propagateUserId!=null) {
            asyncCommandService.setPropagateUserId(propagateUserId);
          }
          
    return asyncCommandService;
        }
        
        
    return new DefaultCommandService();
      }

    }

     

    public class CommandServiceDescriptor extends AbstractDescriptor {

      
    private static final long serialVersionUID = 1L;
      
      CommandService commandService;
      List
    <Descriptor> interceptorDescriptors;
    //根据配置的拦截器策略初始化拦截器
      public Object construct(WireContext wireContext) {
        CommandService interceptedCommandService 
    = commandService;
        
    if (interceptorDescriptors!=null) {
            
    //commandService配置的拦截器
          for (int i=interceptorDescriptors.size()-1 ; i>=0; i--) {
            Descriptor descriptor 
    = interceptorDescriptors.get(i);
            Interceptor interceptor 
    = (Interceptor) descriptor.construct(wireContext);
            interceptor.setNext(interceptedCommandService);
            interceptedCommandService 
    = interceptor;
          }
        }
        
    return interceptedCommandService;
      }
      
      
    public Class< ? > getType(WireDefinition wireDefinition) {
        
    return (name==null ? CommandService.class : null);
      }
      
      
    public void addInterceptorDescriptor(Descriptor descriptor) {
        
    if (interceptorDescriptors==null) {
          interceptorDescriptors 
    = new ArrayList<Descriptor>();
        }
        interceptorDescriptors.add(descriptor);
      }
      
      
    public void setCommandService(CommandService commandService) {
        
    this.commandService = commandService;
      }
    }

     

    public class EnvironmentInterceptorBinding extends WireInterceptorBinding {
        
      
    public EnvironmentInterceptorBinding() {
        
    super("environment-interceptor");
      }
    //解析commandService中定义的environment-interceptor拦截器
      public Object parse(Element element, Parse parse, Parser parser) {
        EnvironmentInterceptorDescriptor environmentInterceptorDescriptor 
    = new EnvironmentInterceptorDescriptor();

        ConfigurationImpl configuration 
    = parse.contextStackFind(ConfigurationImpl.class);
        environmentInterceptorDescriptor.setConfiguration(configuration);
        
    //每次执行拦截器都生成新的环境
        if ( element.hasAttribute("policy")
             
    && ("requiresNew".equals(element.getAttribute("policy")))
           ) {
          environmentInterceptorDescriptor.setPolicy(Policy.REQUIRES_NEW);
        }
        
        
    return environmentInterceptorDescriptor;
      }

    }

     

    public class EnvironmentInterceptorDescriptor extends AbstractDescriptor {

      
    private static final long serialVersionUID = 1L;
      
      
    protected ConfigurationImpl configuration;
      
    protected Policy policy;
      
    //根据配置生成EnvironmentInterceptor拦截器
      public Object construct(WireContext wireContext) {
          
    //获取初始化的流程引擎实例作为环境工厂
        EnvironmentFactory environmentFactory = (EnvironmentFactory) configuration.getProducedProcessEngine();
        EnvironmentInterceptor environmentInterceptor 
    = new EnvironmentInterceptor();
        environmentInterceptor.setEnvironmentFactory(environmentFactory);
        
    if (policy!=null) {
          environmentInterceptor.setPolicy(policy);
        }
        
    return environmentInterceptor;
      }

      
    public void setPolicy(Policy policy) {
        
    this.policy = policy;
      }
      
    public void setConfiguration(ConfigurationImpl configuration) {
        
    this.configuration = configuration;
      }
    }

     

    3.流程引擎初始化检查数据库,调用拦截器策略并初始化环境

     类ConfigurationImpl  中流程引擎初始化的代码

    public ProcessEngine buildProcessEngine() {
        
    if (!isConfigured) {
          setResource(DEFAULT_CONFIG_RESOURCENAME);
        }
        
    if (jndiName!=null) {
          
    try {
            InitialContext initialContext 
    = new InitialContext();
            ProcessEngineImpl existing 
    = (ProcessEngineImpl) initialContext.lookup(jndiName);
            
    if (existing!=null) {
              log.debug(
    "found existing process engine under "+jndiName);
              
    return existing;
            }
          } 
    catch (NamingException e) {
            log.debug(
    "jndi name "+jndiName+" is not bound");
          }
        }
        
        
    if (isSpringEnabled) {
          
    return SpringProcessEngine.create(this);
        }
        
    return instantiateProcessEngine();
      }
      
      
    /**
       * This method is called at the end of the buildProcessEngine() operation.
       * Subclasses should override this method for custom ProcessEngine instantiation.
       
    */
      
    protected ProcessEngine instantiateProcessEngine() {
        
    return new ProcessEngineImpl(this);
      }

    ProcessEngineImpl

     
    public ProcessEngineImpl(ConfigurationImpl configuration) {
        initializeProcessEngine(configuration);
        checkDb(configuration);
      }

      
    protected void initializeProcessEngine(ConfigurationImpl configuration) {
        configuration.setProducedProcessEngine(
    this);
        
    this.processEngineWireContext = configuration.getProcessEngineWireContext();
        
    this.transactionWireDefinition = configuration.getTransactionWireDefinition();
        
        
    if (log.isTraceEnabled()) {
          log.trace(
    "created ProcessEngine "+System.identityHashCode(this));
          
    if ( (processEngineWireContext!=null)
               
    && (processEngineWireContext.getWireDefinition()!=null)
               
    && (processEngineWireContext.getWireDefinition().getDescriptorTypes()!=null)
             ) {
            log.trace(
    "  process-engine-context "+System.identityHashCode(processEngineWireContext));
            
    for (Class<?> descriptorType: processEngineWireContext.getWireDefinition().getDescriptorTypes()) {
              log.trace(
    "    "+descriptorType.getName());
            }
          }
          
    if ( (transactionWireDefinition!=null)
               
    && (transactionWireDefinition.getDescriptorTypes()!=null)
             ) {
            log.trace(
    "  transaction-context:");
            
    for (Class<?> descriptorType: transactionWireDefinition.getDescriptorTypes()) {
              log.trace(
    "    "+descriptorType.getName());
            }
          }
        }

        processEngineWireContext.create();
        
    //根据配置的拦截器策略(相应的descriptor)生成相应的commandservice
        userCommandService = (CommandService) processEngineWireContext.get(CommandService.NAME_TX_REQUIRED_COMMAND_SERVICE);

        String jndiName 
    = configuration.getJndiName();
        
    if (jndiName!=null) {
          
    try {
            log.debug(
    "publishing jBPM ProcessEngine in jndi at "+jndiName);
            InitialContext initialContext 
    = new InitialContext();
            initialContext.bind(jndiName, 
    this);
          } 
    catch (NamingException e) {
            
    throw new JbpmException("JNDI binding problem", e);
          }
        }

      }

      
    protected void checkDb(ConfigurationImpl configuration) {
        
    if (configuration.isCheckDb()) {
          
    //按照配置的拦截器策略顺序执行,当运行到EnvironmentInterceptor时,根据配置选择是否生成新的环境
          userCommandService.execute(new CheckDbCmd());
        }
      }

     

     

  • 相关阅读:
    WeX5那些坑
    项目总结-微信公众平台Html5
    项目总结-APP中的HTML5
    夜幕团队成员的工资究竟几 K ?
    Docker竟然还能这么玩?商业级4G代理搭建实战!
    今天,大佬云集的夜幕团队正式成立了!
    InnoDB物理行中null值的存储的推断与验证
    探究InnoDB数据页内部行的存储方式
    DAO模式
    JDBC
  • 原文地址:https://www.cnblogs.com/wufengtinghai/p/2096047.html
Copyright © 2011-2022 走看看