posts - 193,  comments - 520,  trackbacks - 0
 
     摘要: 使用Selenium测试showModalDialog模态对话框一直是一件困难的事情,本文提出一种hack解决的方法。  阅读全文
posted @ 2009-07-27 21:17 ronghao 阅读(3584) | 评论 (0)编辑 收藏
       现在流行抱大腿,不过对眼光的要求也高。要不就如高也,即使四眼,一样无用。对Java企业开发而言,Spring的腿则是一定要抱的。而所谓抱Spring的腿,无外乎三点:

一是通过Spring暴露出服务,将服务配置到Spring的IOC容器里;
二是在自己的运行环境里访问到Spring的IOC容器,能够轻松使用Spring容器里所配置的服务;
三是对于具有事务管理特性的项目来说,将事务管理与Spring的事务管理进行合并。

        下面分别讨论:

一、    通过Spring暴露服务
还记得在jBPM4的运行期环境里提到的JbpmConfiguration吗?它是整个jBPM4的入口,并且是整个应用独此一份的。通过它可以获取processEngine,并藉此获得工作流引擎所提供的各种服务:

ProcessEngine processEngine 
= new Configuration()
      .buildProcessEngine();


RepositoryService repositoryService 
= processEngine.getRepositoryService();
ExecutionService executionService 
= processEngine.getExecutionService();
TaskService taskService 
= processEngine.getTaskService();
HistoryService historyService 
= processEngine.getHistoryService();
ManagementService managementService 
= processEngine.getManagementService();

通过Spring暴露这些服务,配置如下:
<bean id="jbpmConfiguration" class="org.jbpm.pvm.internal.cfg.SpringConfiguration">
        
<constructor-arg value="be/inze/spring/demo/jbpm.cfg.xml" />
    
</bean>
   
    
<bean id="processEngine" factory-bean="jbpmConfiguration" factory-method="buildProcessEngine" />
    
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
    
<bean id="executionService" factory-bean="processEngine" factory-method="getExecutionService" />


细心的你会发现,配置时使用了JbpmConfiguration 的子类SpringConfiguration。SpringConfiguration相比JbpmConfiguration有哪些增强呢,下面再讲。总之,现在,就可以使用Spring来获取或注入这些Jbpm4所提供的服务了。

二、在environment里加入SpringContext
jBPM4的environment(运行期环境)提供Engine IOC(process-engine-context)和Transaction IOC(transaction-context)。要想在运行期方便地访问到Spring里所配置的服务,最直接的方法就是在environment里加入Spring IOC(applicationContext)的引用。
SpringConfiguration即是对JbpmConfiguration增强了对Spring IOC的一个引用。
 
SpringConfiguration是如何做到的呢?简单,实现Spring的ApplicationContextAware接口,自动持有applicationContext,然后openEnvironment时将其加入environment。

environment.setContext(new SpringContext(applicationContext));


SpringContext是对applicationContext的简单封装。

那么什么从Engine IOC移民到Spring IOC了呢?是的,最重要的就是Hibernate Session Factory。

在jbpm.cfg.xml的process-engine-context里干掉:

    <hibernate-configuration>
      
<cfg resource="jbpm.hibernate.cfg.xml" />    
    
</hibernate-configuration>

    
<hibernate-session-factory />

 
相关配置挪动至Spring配置文件。

三、    事务
哪里有数据库操作,哪里就有事务。对于嵌入式工作流而言,最重要的集成就是事务的集成。这里先分析jBPM4的事务实现,然后再介绍集成入Spring的事务实现。

1、    Command模式
jBPM4的逻辑实现采用了Command模式。
 
采用Command模式后,jBPM4对CommandService构造拦截器(Interceptor)链,配置在jbpm.cfg.xml的process-engine-context里:
<command-service>
      
<retry-interceptor />
      
<environment-interceptor />
      
<standard-transaction-interceptor />
    
</command-service>


2、    原有的事务实现
jBPM4原有的事务通过StandardTransactionInterceptor实现,在CommandService执行Command之前打开事务(实际委派Hibernate的事务管理),完成后提交/回滚。
 
jBPM4的事务是基于Command的。

3、    集成入Spring的事务实现
Spring的事务是基于服务调用的。

使jBPM4使用Spring提供的事务:
<command-service>
      
<retry-interceptor />
      
<environment-interceptor />
      
<spring-transaction-interceptor current="true" />
</command-service>


拦截器换用SpringTransactionInterceptor,SpringTransactionInterceptor从environment 提供的Spring IOC获取PlatformTransactionManager,使用事务模板回调Command,事务传播模式强制加入当前事务。

同时,对hibernate session的配置(jbpm.cfg.xml的transaction-context)强制从当前线程中获取:
<hibernate-session current="true"/>

并干掉原有的事务实现:
<transaction />

参考文档:
http://www.slideshare.net/guest8d4bce/spring-integration-with-jbpm4


posted @ 2009-06-22 16:38 ronghao 阅读(7360) | 评论 (7)编辑 收藏
        万物生长靠太阳,儿童的生长离不开土壤、空气和水,当然,也离不开绿坝娘的调教。应用程序也是如此,离不开数据库连接、事务、日志、消息等,这些,共同构成了应用程序的运行期环境。
        理想中的环境是什么样子的哩。好吧,一句话,召之即来,挥之即去,当需要某个服务时,ok,打个响指,该服务就准备好被调用了,调用完毕后也不用费心费力地擦屁股,不必老是提心吊胆有好事者追问:你擦了吗,确定擦了?真的确定擦了?直接丢弃给环境降解处理,自然又环保,还有个好名声叫专注领域逻辑。

一、    运行期环境就是一个餐馆
1、    提供必要的服务
作为一个餐馆,必须有厨师做饭我吃,必须有桌子和椅子。作为运行期环境同样如此,我要发消息,你得提供我发消息的Service,我要获取节点任务,你得扔给我TaskService。

2、    提供获取这些服务的统一方式
好吧,我不会亲自到厨房告诉厨师我想吃什么(因为我担心这样一来我会吃不下去),我也不会亲自到收银台给钱。这些服务有一个统一的获取方式:服务员。我想吃什么和结账,告诉服务员即可。关键是这一方式要统一,要足够简单。Spring最懒,把服务给你全部注入了,当然你也可以握住BeanFactory的纤纤细手,一个一个的get。

3、    提供特定于我线程不安全的服务
我点了一盘鱼香肉丝,隔壁也点了一盘鱼香肉丝,结果服务员让我们吃同一盘鱼香肉丝。我立刻跳起来:靠,你们的服务不是线程安全的吗?!Hibernate的Session正是属于这么一种情况,需要环境进行隔离,我的唯一职责就是吃饭!我的领域逻辑是如何优美的进餐!为此还要不断重构我吃饭的姿势哩。
好不容易吃完饭,付完款,正准备离场。服务员风度翩翩地走到我的身旁,我以为还有打折券供应,结果是:服务员小姐轻启朱唇:先生,麻烦您把吃剩的盘子清洗完毕。
崩溃!
像数据库连接的打开,关闭、事务的打开、提交等都属于运行期环境应该做的事情。

4、    其他的七七八八
杂事不少,例如统一的事件机制、权限拦截等等。

二、    jBPM4的运行期环境
好吧,先来看看如何建立jBPM4的运行期环境:
EnvironmentFactory environmentFactory = new DefaultEnvironmentFactory();
 
  
 
  Environment environment 
= environmentFactory.openEnvironment();
  
try {
 
     everything available in 
this block 
 
  } 
finally {
    environment.close();
  }


两个关键的类:EnvironmentFactory和Environment。

EnvironmentFactory是全局的,在整个应用程序中保持一个实例即可。

Environment则是每次方法调用则要new一个。

看看Environment的主要方法:
public abstract Object get(String name);
public abstract <T> T get(Class<T> type);


是的,environment为我们的代码提供所需要的服务类实例。

那么,如何获得environment?
继续看:
public static Environment getCurrent();

static,我喜欢也。方便、快捷,不管是在地上、车上还是房顶上,随处都可调用。

那么,为什么Environment每次调用要new呢?
好吧,当你需要获取数据库Session的时候,是不是每次都要new呢。Environment提供的服务里包括了非线程安全的数据库操作服务。

三、    jBPM4运行期环境的实现

1、JbpmConfiguration
JbpmConfiguration是jBPM4里最重要的类,它是整个应用程序的入口。它实现了EnvironmentFactory接口。

      JbpmConfiguration加载jBPM总的配置文件,还是大概扫一下这个配置文件:
      <jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">

  
<process-engine-context>
 
    
<repository-service />
    
<repository-cache />
    
<execution-service />
    
<history-service />
    
<management-service />
    
<identity-service />
    
<task-service />

    
<hibernate-configuration>
      
<cfg resource="jbpm.hibernate.cfg.xml" />    
    
</hibernate-configuration>

    
<hibernate-session-factory />
 
  
</process-engine-context>

  
<transaction-context>
    
<repository-session />
    
<pvm-db-session />
    
<job-db-session />
    
<task-db-session />
    
<message-session />
    
<timer-session />
    
<history-session />
  
</transaction-context>

</jbpm-configuration>


配置文件被分为了两部分,分别是:process-engine-context和transaction-context。
对应于两个IOC容器(WireContext)的配置文件。

作为EnvironmentFactory,JbpmConfiguration持有成品process-engine-context对应的IOC容器(全局的)实例,持有半成品transaction-context的WireDefinition。当调用openEnvironment方法时,JbpmConfiguration会new Environment,然后将process-engine-context IOC填充入environment,同时初始化transaction-context IOC,并将其也填充入environment。这样通过environment就可以获得所有所需要的服务,包括全局的和非线程安全的服务实例。也就是environment透过IOC容器提供了查找各种服务的能力。


 

2、与线程绑定的environment
environment初始化之后,避免参数传递得一塌糊涂的方式就是将environment与线程绑定。看Environment的代码:
  static ThreadLocal<Environment> currentEnvironment = new ThreadLocal<Environment>();

  
static ThreadLocal<Stack<Environment>> currentEnvironmentStack = new ThreadLocal<Stack<Environment>>();


是的,在openEnvironment时,有这么一行代码:
Environment.pushEnvironment(environment);


这样environment就与线程绑定了,可以通过Environment.getCurrent()任意调用了。

哪里有压迫,哪里就有放抗。
在environment.close()方法里:

Environment.popEnvironment();


OK,结束。


posted @ 2009-06-17 18:15 ronghao 阅读(2802) | 评论 (5)编辑 收藏
一、目前的情况
目前我们要进行持续集成的对象是一个有着100人左右的开发团队,他们开发着一套很庞大的系统。整个开发团队划分为多个开发小组进行协同开发,每个开发小组负责2-3个模块的开发,实际这里的模块已经相当于一个中小型系统。各模块所有的类都通过eclipse整体编译在一起,直接放置在WEB-INF/classes下。本地是无法启动整个系统的,需要耗费大量的资源。

二、碰到的问题
在了解具体情况之前,我们最初的想法是为整个产品做一个持续集成,但是很快就发现这一想法存在很多的问题:
1、整个产品每次构建的时间会很长,这个时间包括代码的编译、启动Weblogic,完成自动化测试,同时对服务器的硬件要求非常高
2、因为构建时间长,所以如果本地构建通过后再提交会严重影响开发效率,况且本地的硬件条件很可能启动不了
3、如果本地不构建提交,则由于开发人数众多,构建会非常不稳定,会经常处于失败状态。而构建失败会导致后续提交的阻塞。
4、作为一个100人的开发团队,代码提交会引发频繁的服务器构建,服务器无法负担。

同时作为客户,他们有这样一种想法:敏捷开发是好的,但是不适合于大的项目和大的团队。

最重要的问题集中在两个方面
1、启动整个产品过于重量级(不包括自动化测试的情况下已经如此)
2、如何不影响开发人员的频繁提交

三、我们的想法
我们现在的想法是做多阶段的持续集成(multi-stage CI)

可以参考这里http://www.ddj.com/development-tools/212201506

具体而言:
1、各个开发小组内做小组内的持续集成
2、开发小组间集成做整个产品的持续集成


大概:
1、每个开发小组一个分支,整个产品一条主线
2、在小组分支上搭建持续集成环境,小组内的开发向该分支上提交,各个小组可以并发开发,互不影响
3、小组完成一个完整的功能后,从主线更新合并代码,本地构建通过,提交,触发整个产品的持续集成

为使小组内持续集成构建加快,小组内尽量划分清楚对其他模块的依赖,不必要的模块(这里的模块包括基础模块,例如工作流模块)不必加载。
同时推荐轻量级的web服务器例如Tomcat来完成小组内的测试环境。需要启动weblogic的情况或功能依赖过多的情况下,建议在产品持续集成时进行测试。
同时保留原有的启动单独测试服务器进行手工测试的习惯。
posted @ 2009-05-26 23:13 ronghao 阅读(1518) | 评论 (0)编辑 收藏
       和Jbpm3一样,Jbpm4实现了自己的IOC容器。以现在的眼光看来,应用程序里一个IOC容器几乎是居家必备的,否则,又要平白多出一坨一坨的工厂类和单态类来。

一、    Jbpm4 IOC容器介绍
IOC容器的目的是管理组件和实现组件之间的解耦。和Spring里的BeanFactory对应,Jbpm4里的接口是Context,具体实现则是WireContext。Context实际在Jbpm4里有更多的含义,它与Environment一起,共同构成了代码运行的运行期环境。在这个环境里可以获取系统的组件,更为重要的是提供了数据库连接(session)和事务(这个稍后会讲)。

先来看看Context接口的核心方法:
      Object get(String key);
  
<T> T get(Class<T> type);


很明显,提供两种从容器里获取组件的方法,一种是通过name,一种是通过type。

对于IOC容器来说,一般情况下都会提供一种加载的方式,比如从xml文件进行加载、从资源文件进行加载。Jbpm4透过WireParser具备从xml加载的能力。

此外,WireContext通过一个Map缓存初始化后的组件。

二、    Jbpm4 IOC容器实现
容器的实现有五个关键类和接口,分别是:WireParser、Binding、Descriptor、WireDefinition和WireContext。
 

WireParser读取xml文件,同时WireParser会加载一系列的Binding(默认从jbpm.wire.bindins.xml文件读取加载)。

Binding负责根据xml里元素的tag将xml元素转换为对应的Descriptor。

Descriptor负责初始化对象。它们被添加到WireDefinition。

WireDefinition被WireParser返回给WireContext。WireContext创建对象时会访问WireDefinition里的Descriptor,同时将初始化对象的任务委托给Descriptor自身。

需要注意的是:Jbpm4在初始化对象时有着四种策略,分别是:延迟创建和初始化、延迟创建和立刻初始化、立刻创建和延迟初始化、立刻创建和立刻初始化。

立刻创建:在WireContext创建完毕后对象就已经创建。
延迟创建:调用WireContext的get方法获取该对象时才创建该对象。
初始化:一般完成对象属性的注入等操作。

三、    Jbpm4 IOC容器在Jbpm4里的应用
IOC容器在Jbpm4里最重要的作用就是加载Jbpm的总的配置文件(默认是jbpm.cfg.xml),这也是整个Jbpm应用的起点。大概扫一下这个配置文件:

<?xml version="1.0" encoding="UTF-8"?>

<jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">

  
<process-engine-context>
 
    
<repository-service />
    
<repository-cache />
    
<execution-service />
    
<history-service />
    
<management-service />
    
<identity-service />
    
<task-service />

    
<hibernate-configuration>
      
<cfg resource="jbpm.hibernate.cfg.xml" />    
    
</hibernate-configuration>

    
<hibernate-session-factory />
 
  
</process-engine-context>

  
<transaction-context>
    
<repository-session />
    
<pvm-db-session />
    
<job-db-session />
    
<task-db-session />
    
<message-session />
    
<timer-session />
    
<history-session />
  
</transaction-context>

</jbpm-configuration>


可以看到配置文件被分为了两部分,分别是:process-engine-context和transaction-context。在实际应用中,它们分别对应着两个不同的WireContext:ProcessEngineContext和TransactionConext。ProcessEngineContext覆盖了jbpm4里最重要的服务类,这些类是全局唯一的,当然,ProcessEngineContext也是独此一份。本是同根生,命运各不同。TransactionConext则是在每次openEnvironment时重新创建,因为其包含了数据库连接和事务。

贯穿于整个Jbpm4中,这两个Context被压到Environment里(Environment和线程绑定),在任何需要的地方都能提供一条龙的服务。于是,在很多领域类里,利用这些服务实现充血模型就是很顺理成章的一件事了。

总结: ProcessEngineContext给引擎领域模型提供全局的组件查找;TransactionConext提供数据库相关服务。


posted @ 2009-05-07 18:43 ronghao 阅读(3686) | 评论 (2)编辑 收藏
仅列出标题
共39页: First 上一页 10 11 12 13 14 15 16 17 18 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

关注工作流和企业业务流程改进。现就职于ThoughtWorks。新浪微博:http://weibo.com/ronghao100

常用链接

留言簿(38)

随笔分类

随笔档案

文章分类

文章档案

常去的网站

搜索

  •  

最新评论

阅读排行榜

评论排行榜