
2008年11月7日
当面对一个完整的工作流系统时,你可能会被它众多的功能所困惑:流程流转模式、时间服务、组织适配、表单权限等等。但是如果我们转换一种思路,首先从用户使用的角度来进行分析,工作流系统的组成就会变得异常清晰。实际在现实开发中,整个系统也是由用户的业务需求一步步迭代而来。
一、
从用户的角度分析工作流系统的组成
这里的用户分为两类:一类是应用系统开发人员(以后简称开发人员),一类是应用系统的最终用户(以后简称最终用户)。对于最终用户而言,工作流系统往往是不能直接使用的,它需要由IT部门的开发人员嵌入到应用系统中。开发人员才是工作流系统的直接使用者,这造成了问题:工作流系统更多关注于开发人员的需求,例如如何快速开发、如何更好的嵌入业务逻辑等等,而最终用户的需求被或多或少的忽略了。

这里从最终用户的角度进行分析。
1、
面向开发人员的流程设计器
最终用户通过流程设计器对业务流程进行描述,实际是一个流程建模的过程。理论上,业务分析师完成这个业务流程建模的过程,并且业务分析师往往被假定为非技术人员。对于业务分析而言,流程建模通常是抽象的,一定程度上是模糊的,建模的目的在于通过图形的形式向其他人解释一个业务的过程,图形只是一种方式,采用它只是它更易于理解和易于沟通,实际类似于DSL。实际上企业的规章制度、文字描述的执行流程都是对业务流程具体的描述方式。
对于工作流而言,这个建模所产生的流程是需要被引擎执行的。这就要求流程中每一个节点的定义都是要有明确含义的,它需要被计算机明确而准确的解释。同时,出于集成业务系统的需要,流程模型定义往往带有很多额外的属性。
所以现实中的流程设计器往往属性配置繁多。导致最终用户在打开设计器后根本无从修改和建模,他需要关注很多与业务无关的配置,无意中的修改往往产生流程无法运行的后果。
2、
工作项列表
即任务列表。工作流系统通过工作项列表进行人工任务的分配。最终用户通过该列表签收、处理每天的工作,工作以工作项的形式展现。对于工作项,用户有着多种业务操作:签收、完成提交、收回、回退等等。对于分配给他人的工作项,也存在着多种业务操作:催办、提醒、时间限定等等。
3、
流程追踪
用户在处理工作项时,对该工作在流程中所处的位置进行查看,了解当前流程的状态和执行情况。一般情况下,流程追踪以图形化的方式展现。用户通过不同的图标和标示来区分流程中各个节点的状态和参与者信息。
4、
流程实例管理
包括流程实例、节点实例、工作项实例的管理。改变状态,包括了挂起、重新启动、终止、跳转等等。主要目的在于对流程人为执行错误进行人工干预以及对流程信息的监控。
二、
系统架构
从用户的角度分析完工作流系统的组成,这里从开发人员的角度分析工作流系统的架构。系统架构里的每一部分是如何与用户使用的部分进行对应,以及每一部分在实现时需要注意的事项。
1、
整体构成
如图,各模块分层组织,位于上层的模块依赖于底层的模块。正如你所看到的,流程定义模型位于整个工作流系统的最低层,因为它是整个工作流系统的基础。

流程定义模型:定义对流程进行描述的所有对象。因为对流程进行描述的本质就是利用这些模型进行建模,所以这些模型对象的实现直接决定着工作流系统对流程的描述能力。
组织结构适配器:工作流系统在与业务系统进行集成时,需要进行组织适配,通过这一过程将业务系统里的组织机构导入到工作流系统里。具体实现时,工作流系统需要建立起自己的组织机构模型(包含在流程定义模型里),要适应多种业务系统,往往需要建立多套模型,根据具体情况进行切换。有多种方式完成这个适配,最简单的方式是利用SQL配置读取数据进行语义转换。
流程设计器:供用户使用的可视化图形工具。每种图形都对应着一种流程定义模型。具体的实现有Swing、SWT,但是基于AJAX的WEB设计器无疑会提供更好的可用性。
流程执行引擎:将流程定义模型解释为流程实例模型。利用这些流程实例模型完成流程的调度和执行。在工作流系统里,执行引擎是整个系统的核心。实现时不仅需要考虑各种流程调度的实现,还要考虑执行的效率、缓存、日志等等。
工作项引擎:解析参与者定义模型和工作项定义模型,生成相应的工作项。对用户对工作项的操作作出响应。
WEB应用:工作流系统的WEB展现。包括了工作项列表、流程追踪以及流程实例管理的操作和显示。
流程仿真:对建立好的流程模型进行运行仿真,模拟流程模型的执行过程。目的在于发现流程建模过程中的疏漏,发现由此导致的流程不能运行。
时间服务:提供对整个流程实例执行时间和任务执行时间的控制,根据规则触发相应的时间事件,例如任务超时、任务预警等等。根据规则自动触发启动新的流程实例。
业务集成:提供工作流系统与业务系统的契合方式。典型的实现包括通过注册事件监听器和提供接口抽象类调用业务系统代码、提供API给业务系统调用、工作项驱动业务表单和脚本引擎执行业务逻辑脚本等等。特定于工作项驱动业务表单,为方便开发,绝大多数的工作流厂商都提供了电子表单的实现。
2、
基于事件的流程执行引擎
流程执行引擎的主要职责就是负责流程的调度和执行。
首先需要将流程定义模型解释为流程实例模型,在定义模型和实例模型之间建立起对应关系。一个简单的对应关系如下图所示:

执行引擎将流程定义模型的属性读取到相应的实例模型里,由实例模型完成流程的调度和执行。当然,上图只是一个简单的描述,实际情况要复杂的多,特别是节点定义(ActivityDefinition),根据实际应用,往往存在着多种类型,典型的有开始节点(StartDefinition)、任务节点(TaskDefinition)、自动节点(AutoDefinition)、分裂节点(SplitDefinition)、汇聚节点(JoinDefinition)、结束节点(EndDefinition)等等。这些节点的实例根据类型的不同执行不同的逻辑。其中,分裂节点实例和汇聚节点实例负责流程的调度,它们决定流程的流向,通常情况下,它们会调用一个脚本引擎执行一段脚本来决定流程的流向,同时,也会提供对外暴露的接口,由业务系统实现,接口返回的结果决定流程的流向。任务节点实例和自动节点实例则负责流程的执行,为保证流程执行引擎职责的清晰以及对外围设施的松耦合,它们只是发布相关的事件,通过事件发布/订阅机制来触发具体的逻辑执行。

典型的事件有流程启动事件、流程结束事件、进入节点事件、离开节点事件、时间事件等。例如,任务节点实例的进入节点事件将会触发工作项引擎生成工作项(Workitem),并触发时间服务器开始计时。
3、
基于充血模型的工作项引擎
对最终用户而言,大部分的业务操作都集中在对工作项的操作上。常见的包括工作项的提交、收回、委派、追加和退回。这些操作从系统设计的角度不仅涉及到工作项(Workitem)对象内部状态的变化,而且影响到流程执行引擎的调度以及相关的其他工作项对象状态。
工作项引擎的职责包括两部分。第一,监听任务节点实例的进入事件,生成工作项实例。第二,处理上面提到的各种工作项操作。

实现时,工作项生成器根据任务参与者的执行模式典型的分为四种情况:
竞争参与,当有多个参与者参与该任务时,产生竞争,谁先开始这项工作,就由谁负责完成该工作。此时,工作项生成器生成多个工作项实例,在某个工作项完成时会终止其余工作项。
顺序参与,多个参与者按照指定的顺序完成该工作。A完成之后由B完成,B完成之后再交给C完成。此时,工作项生成器生成多个工作项实例,根据顺序依次激活各个工作项。
共同参与,多个参与者同时对工作进行处理。此时,工作项生成器生成多个工作项实例并全部激活。
智能决策,存在多个参与者的情况下,工作项生成器能够根据一定的指标(由数据分析,例如人员的处理效率,工作负载等等)和规则来决定该节点的参与者并为其生成相应工作项。这里涉及到算法。
对于工作流系统而言,各种流程实例对象都是充血模型。特定于各种工作项操作的处理,此时的工作项对象亦设计为充血模型,将业务逻辑封装到领域模型里,简化领域模型之间的交互,省去频繁的get/set。由领域模型再委派到具体的处理类里。
Client->(Business Facade)->Domain Model->service->Data Access(DAO)
4、
工作项驱动业务表单的业务集成方式
最终用户对任务的处理,必然由工作项对应着某一业务表单。用户在工作项列表里选择自己需要办理的工作项,由工作项导航到业务表单。
特定于WEB系统,业务表单的导航由url完成。在流程定义模型设计时,将url设置入节点属性,生成工作项时将此url保存在工作项对象属性里。点击工作项详细信息时即打开该url,完成到业务表单的导航。业务表单页面通常需要引入处理工作项逻辑的父页面或者导入定制的js库,这些父页面或js库由工作流产品提供。这样,对于业务表单编写,工作流逻辑是透明的。
posted @
2008-11-07 11:20 ronghao 阅读(1166) |
评论 (0) |
编辑 收藏

2008年10月28日
系统要集群,使用SNA方案。
一、 缓存的处理
缓存要使用统一的缓存服务器,集中式缓存。
原先的实现采用ehcache。
在spring里的配置,以资源缓存为例:
<!-- EhCache Manager -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation">
<value>classpath:ehcache.xml</value>
</property>
</bean>
<bean id="resourceCacheBackend"
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="cacheManager"/>
<property name="cacheName" value="resourceCache"/>
</bean>
<bean id="resourceCache"
class="com.framework.extcomponent.security.authentication.services.acegi.cache.EhCacheBasedResourceCache"
autowire="byName">
<property name="cache" ref="resourceCacheBackend"/>
</bean>
cacheManager负责对ehcache进行管理,初始化、启动、停止。
resourceCacheBackend负责实际执行缓存操作,put 、get、remove。
resourceCache实现具有业务语义的业务应用层面的缓存操作,内部调用resourceCacheBackend操作。
现在采用memcached。
关于客户端,采用文初封装的客户端,地址在http://code.google.com/p/memcache-client-forjava/。
使用spring的FactoryBean进行二次封装。同理:
memcachedManager负责对memcached进行管理,初始化、启动、停止。
代码:
/**
* User: ronghao
* Date: 2008-10-14
* Time: 10:36:30
* 管理Memcached 的CacheManager
*/
public class MemcachedCacheManagerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
private ICacheManager<IMemcachedCache> cacheManager;
public Object getObject() throws Exception {
return cacheManager;
}
public Class getObjectType() {
return this.cacheManager.getClass();
}
public boolean isSingleton() {
return true;
}
public void afterPropertiesSet() throws Exception {
logger.info("Initializing Memcached CacheManager");
cacheManager = CacheUtil.getCacheManager(IMemcachedCache.class,
MemcachedCacheManager.class.getName());
cacheManager.start();
}
public void destroy() throws Exception {
logger.info("Shutting down Memcached CacheManager");
cacheManager.stop();
}
}
配置:
<bean id="memcachedManager"
class="com.framework.extcomponent.cache.MemcachedCacheManagerFactoryBean"/>
resourceCacheBackend负责实际执行缓存操作,put 、get、remove。
代码:
/**
* User: ronghao
* Date: 2008-10-14
* Time: 10:37:16
* 返回 MemcachedCache
*/
public class MemcachedCacheFactoryBean implements FactoryBean, BeanNameAware, InitializingBean {
protected final Log logger = LogFactory.getLog(getClass());
private ICacheManager<IMemcachedCache> cacheManager;
private String cacheName;
private String beanName;
private IMemcachedCache cache;
public void setCacheManager(ICacheManager<IMemcachedCache> cacheManager) {
this.cacheManager = cacheManager;
}
public void setCacheName(String cacheName) {
this.cacheName = cacheName;
}
public Object getObject() throws Exception {
return cache;
}
public Class getObjectType() {
return this.cache.getClass();
}
public boolean isSingleton() {
return true;
}
public void setBeanName(String name) {
this.beanName=name;
}
public void afterPropertiesSet() throws Exception {
// If no cache name given, use bean name as cache name.
if (this.cacheName == null) {
this.cacheName = this.beanName;
}
cache = cacheManager.getCache(cacheName);
}
}
配置:
<bean id="resourceCacheBackend"
class="com.framework.extcomponent.cache.MemcachedCacheFactoryBean">
<property name="cacheManager" ref="memcachedManager"/>
<property name="cacheName" value="memcache"/>
</bean>
resourceCache同上,替换新的实现类MemcachedBasedResourceCache即可。
二、 Session失效的处理
采用memcached作为httpsession的存储,并不直接保存httpsession对象,自定义SessionMap,SessionMap直接继承HashMap,保存SessionMap。
会话胶粘:未失败转发的情况下没必要在memcached保存的SessionMap和httpsession之间复制来复制去,眉来眼去。
利用memcached计数器保存在线人数。
系统权限采用了acegi,在acegi的拦截器链里配置snaFilter
<bean id="filterChainProxy"
class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=snaFilter,httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>
注意需要配置在第一个。
snaFilter的职责:
1、 没有HttpSession时,创建HttpSession;
2、 创建Cookie保存HttpSession id;
3、 如果Cookie保存的HttpSession id与当前HttpSession id一致,说明是正常请求;
4、 如果Cookie保存的HttpSession id与当前HttpSession id不一致,说明是失败转发;失败转发的处理:
4.1、根据Cookie保存的HttpSession id从memcached获取SessionMap;
4.2、SessionMap属性复制到当前HttpSession;
4.3、memcached删除SessionMap。
5、 判断当前请求url是否是登出url,是则删除SessionMap,在线人数减1.
代码:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest hrequest = (HttpServletRequest) servletRequest;
final HttpServletResponse hresponse = (HttpServletResponse) servletResponse;
String uri = hrequest.getRequestURI();
logger.debug("开始SNA拦截-----------------" + uri);
HttpSession httpSession = hrequest.getSession();
String sessionId = httpSession.getId();
//如果是登出,则直接干掉sessionMap
if (uri.equals(logoutUrl)) {
logger.debug("remove sessionmap:" + sessionId);
//在线人数减1
getCache().addOrDecr("userCount",1);
getCache().remove(sessionId);
} else {
String cookiesessionid = getSessionIdFromCookie(hrequest, hresponse);
if (!sessionId.equals(cookiesessionid)) {
createCookie(sessionId, hresponse);
SessionMap sessionMap = getSessionMap(cookiesessionid);
if (sessionMap != null) {
logger.debug("fail over--------sessionid:" + sessionId + "cookiesessionid:" + cookiesessionid);
initialHttpSession(sessionMap, httpSession);
cache.remove(cookiesessionid);
}
}
}
filterChain.doFilter(hrequest, hresponse);
}
利用HttpSessionAttributeListener监听httpsession的属性变化,同步到memecached中的sessionmap。
public void attributeAdded(HttpSessionBindingEvent event) {
HttpSession httpSession = event.getSession();
String attrName = event.getName();
Object attrValue = event.getValue();
String sessionId = httpSession.getId();
logger.debug("attributeAdded sessionId:" + sessionId + "name:" + attrName + ",value:" + attrValue);
SessionMap sessionMap = getSessionMap(sessionId);
if (sessionMap == null){
//在线人数加1
getCache().addOrIncr("userCount",1);
sessionMap = new SessionMap();
}
logger.debug("name:" + attrName + ",value:" + attrValue);
sessionMap.put(attrName, attrValue);
getCache().put(sessionId, sessionMap);
}
public void attributeRemoved(HttpSessionBindingEvent event) {
HttpSession httpSession = event.getSession();
String attrName = event.getName();
String sessionId = httpSession.getId();
logger.debug("attributeRemoved sessionId:" + sessionId + "name:" + attrName);
SessionMap sessionMap = getSessionMap(sessionId);
if (sessionMap != null) {
logger.debug("remove:" + attrName);
sessionMap.remove(attrName);
getCache().put(sessionId, sessionMap);
}
}
public void attributeReplaced(HttpSessionBindingEvent event) {
attributeAdded(event);
}
利用HttpSessionListener,sessionDestroyed事件时根据sessionid删除memcached里的sessionMap(如果存在)。不再担心httpsession的过期问题。
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession httpSession = event.getSession();
String sessionId = httpSession.getId();
logger.debug("session Removed sessionId:" + sessionId);
SessionMap sessionMap = getSessionMap(sessionId);
if (sessionMap != null) {
logger.debug("remove sessionmap:" + sessionId);
//在线人数减1
getCache().addOrDecr("userCount",1);
getCache().remove(sessionId);
}
}
三、 文件保存的处理
和缓存类似,采用集中式的文件服务。对于linux,采用nfs。参考文档http://linux.vbird.org/linux_server/0330nfs.php#What_NFS_perm。关键在于对权限的分配。
应用程序本身不用修改。
posted @
2008-10-28 20:41 ronghao 阅读(1098) |
评论 (3) |
编辑 收藏

2008年9月4日
在集群部署的情况下,应用程序需要做出调整,主要集中在四个方面:对httpsession的处理、对缓存的处理、共享的文件系统、synchronized关键字的失效。
对httpsession的处理
对httpsession的处理最为重要,因为对WEB程序而言,httpsession无疑是最重要的全局资源,它需要被多个web服务器所共享。
无共享的集群架构(SNA),在这样的集群中,每个节点具备完全相同的功能,并且不需要知道其他节点存在与否。每个节点JVM进程不保持全局状态,才能够保证n个JVM节点的幂等性,那些所有涉及到全局状态的,必须放在JVM进程之外,例如用户ID可以使用cookie,session可以放入数据库(这并不是一个好的选择),文件可以放在共享存储系统中。
也就是说httpsession的信息需要被保存在JVM进程之外,例如分布式缓存、数据库。
这里是方案:
1、使用会话cookie保存web服务器产生的sessionid
为什么是sessionid而不是userid,原因在于谁也不知道除去登录外其他人会在httpsession里干些什么
2、自定义SessionMap<String,Serializable>同步保存httpsession内的信息
自定义SessionMap同步httpsession,在操作httpsession时不用改变调用接口,不用东张西望
3、使用分布式缓存memcached保存自定义SessionMap<String,Serializable>
4、会话胶粘
未失败转发的情况下没必要在memcached和httpsession之间复制来复制去,眉来眼去
5、使用SnaFilter处理失败转发
6、使用HttpSessionListener实现SessionMap<String,Serializable>的过期
利用容器session 机制的好处,httpsession过期的时候干掉memecached里的SessionMap
下面根据web请求的过程分情况讨论该方案:
A、登录

根据请求的url判断是否是登录请求
在线人数保存在memcached里
B、 正常请求

C、 失败转发

D、登出

根据请求的url判断是否是登出请求
E、HttpSession过期
不hack memcached,使用HttpSessionListener,sessionDestroyed事件时根据sessionid删除memcached里的sessionMap(如果存在)
关于在线人数的统计:在线人数存储在memcached里,将在线人数与sessionMap绑定,往memcached里增加sessionMap时在线人数+1,删除时-1.
posted @
2008-09-04 14:31 ronghao 阅读(831) |
评论 (0) |
编辑 收藏

2008年9月1日
项目情况:是一个大型公司的内部办公系统,该系统有两个和一般企业应用不太一样的特点:一是用户量非常多,人员数达到2W左右,另一个是采用分级管理的形式,各个分公司数据分开管理。
我们的定位:我们是作为业务平台的提供商参与这个项目的,我们提供底层的开发平台,系统集成商在此基础上进行二次开发。
在项目从开发到部署的过程中遇到了很多的问题,也反映出很多问题。
一、怎么回事,跑得比猫还慢
项目开发完毕后部署在Ibm aix
小型机上,32G内存,16个cpu。应用服务器采用的是weblogic9.2,数据库是oracle10.0.2。上线后发现系统运行的非常缓慢,甚
至比开发环境下的tomcat还要慢。于是开始排查原因,最开始是对SQL进行监控,优先考虑是数据库访问性能产生瓶颈。通过监控,发现很多业务需要执行
大量的SQL语句,查看客户编写的相关代码,发现在查询数据时循环执行了大量SQL。主要原因在于他们在代码中循环调用了我们相关API,一个最典型的例
子是通过用户ID查找用户NAME,他们在业务表格里没有保存用户name,而是在查询的时候通过用户ID查找用户name填充到页面,几乎每一个查询都
是n+1。
另外由于平台使用了hibernate,使得oo编程得非常爽快,导致开发人员完全忽略了相应的数据库操作所带来的压力。很多业务逻辑直接通过PO叠加完成,把一些可以通过很少SQL完成的逻辑全部分散放置到PO里,导致了大量PO的交互和SQL语句。
开始优化SQL,优化的同时增加大量业务缓存。但优化完毕后运行缓慢的现象依旧存在,性能有了一定的提升但是不是非常明显。继续优化,其中考虑过
多频繁访问的数据使用内存数据库的方式。但是优化过后在tomcat上效果明显,部署到生产环境就问题依旧。于是考虑weblogic的配置问题,作为开
发平台提供商,我们只是提供系统开发相关方面的支持,对于应用服务器和数据库服务器只是做基本的配置系统可运行即可。但是在这个问题上系统集成商咬定是我
们平台的问题不放,并且存在一个很严重的问题:他们使用的是盗版的weblogic,这样根本就没有相应的技术支持。
问题的解决:最后是找了一个BEA曾经的开发人员,问题实际非常的简单,现场部署的weblogic默认是运行在32位机器上,与64位机器存
在一定的不兼容。通过替换相应的jar包,问题得到了解决,主要是IO方面。替换完毕后,速度提升了进30%
。该开发人员说,如果没有lisence,根本就不会得到这些替换的jar包。
二、内存耗尽了
访问速度的问题解决了,系统的使用量很快上来,马上遇到新的问题:内存耗尽了。严重到几乎每天都要out of memory一次。这种问题在客户现场频繁出现。
本地测试,tomcat,sun jdk
通过Jprofiler监测内存使用情况。在并发访问门户的情况下,内存确实存在暴涨的情况,100并发,内存使用立刻上升了150m左右,继续并发
100,再增长150m。但是很快在抵达高峰时会有一次gc发生,内存使用稳定在200m,内存里大量char[]数组对象。疲劳测试,内存使用曲线并没
有出现逐渐上升泄露的情况。换weblogic和jrocket测试,gc发生的更加频繁,内存使用稳定。
但是现场依旧频繁当机,内存根本释放不了,一直逐渐增长,典型的内存泄露。对系统缓存、单态对象包括spring管理的对象、IO流进行了统一
排查,依旧没有找到内存泄露的原因。使用IBM
工具分析heapdump文件,结果还是大量的char[]数组对象占据内存,查找应用,找不到相关业务对象引用。
问题解决:问题解决是一篇偶尔搜到的oracle论坛的帖子,这里
http://forums.oracle.com/forums/message.jspa?messageID=1040570
。原因在于oracle10的数据库驱动对statement最后执行的结果集有着引用,并且不会释放,目的在于通过内存而换取更好的性能。数据库连接采
用的是weblogic的连接池,关于connection有个相关的statement
cache设定,设定一个connection能够被缓存的statement个数,最大是1024,而现场就被设定为了1024!connection
pool的connection个数被设置为了500
。真是个恐怖的设置。在将1024改为10后,内存使用量轰然倒地,稳定在1g左右。这个设置是在前面系统访问速度存在问题时由系统集成商的开发人员设置
上去的,他们将所有和优化相关的参数全部开到了最大。这个问题要是用户购买的是正版的weblogic和oracle的话,相信也会很快得到解决。
三、线程阻塞
内存泄露的问题解决后,线程阻塞的问题浮出水面。系统集成商报告是线程死锁,通过分析工具其实是线程阻塞,主要问题在于系统用到了
synchronized关键字,对工作流相关API全部使用了synchronized,原因在这里:
http:
//ronghao.javaeye.com/blog/205731
。分析发现一个工作项提交的操作在连接数据库时被挂起了20分钟!造成了大量线程的排队阻塞。被挂起的原因有很多种。我们采用的方法是将接口拆分和设置事
务timeout时间。但是这显然不是一个好方法。最后是去掉所有的synchronized关键字,将同步的问题交由数据库解决,问题解决。
四、反思
1、系统集成商为什么不购买正版?
2、开发平台提供商究竟在项目开发中处于一种什么样的位置?开发平台是否对所有软件开发问题都要负责?
3、开发平台是越封装越快乐吗?还是越封装越丑陋?
更具体的细节在这里:
posted @
2008-09-01 13:49 ronghao 阅读(1922) |
评论 (8) |
编辑 收藏

2008年8月26日
从事工作流以及相关开发已经三年。提到工作流,很多人都会想到BPM,想到业务流程。对于业务流程,我的理解经过了一个过程,从最开始对工作流抱有的不切实际的期望,到对BPM的一些看法,再到目前的趋于实际。有一些感触,也有一些理解。对于业务流程管理而言,我想说的是:BPM向左,工作流向右,都不靠谱,或者说它们实际所能描述的流程和这里的业务流程根本就风牛马不相及,不是一个概念,唯一的相同点是只不过都叫流程而已。
一、什么是业务流程
业务流程是一个技术术语,它具有准确的定义:有组织的活动,相互联系,为客户创造价值。
这句话很好理解。甚至可以说任何企业的活动都是以业务为主线,以流程为线索串联起来的。企业的规章制度、操作手册等都与业务流程有着契合点。
二、业务流程对于企业的意义
业务流程对于企业的意义不仅仅在于对企业关键业务的一种描述,更在于对企业的业务运营有着指导意义,这种意义体现在对资源的优化、对企业组织机构的优化以及对管理制度的一系列改变。这种优化的目的实际也是企业所追求的目标:降低企业的运营成本,提高对市场需求的响应速度,争取企业利润的最大化。
三、业务流程也是一个体系
业务流程通常的表现形式是流程图(不是唯一形式),毕竟图形是最易于理解的一种形式,但似乎我们太关注于流程图本身而忽略了其他。除了流程图之外,业务流程还应该包括目标和指导方针,这才是一个完整的业务流程。在梳理业务使用业务流程描述时首先要想到的是该流程所要达到的目标,能为客户创造什么价值,脱离开业务目标或者说纯粹为描述业务而描述业务是没有意义的。同时在制定业务流程时也要考虑到该业务流程的指导方针,同一个业务可能有很多种业务流程的描述形式,具体哪一种是最合适的,这里就必须有一个指导方针来进行约束。
四、业务流程的特征
1、层次性、逐层抽象
业务流程是有层次性的,这种层次体现在由上至下、由整体到部分、由宏观到微观、由抽象到具体的逻辑关系。

这样一个层次关系符合人们的思维习惯,有利于企业业务模型的建立。一般来说,我们可以先建立主要业务流程的总体运行过程(其中包括了整个企业的大的战略),然后对其中的每项活动进行细化,落实到各个部门的业务过程,建立相对独立的子业务流程以及为其服务的辅助业务流程。
业务流程之间的层次关系一定程度上也反映了企业部门之间的层次关系。不同层级的部门有着对业务流程不同的分级管理权限。决策层、管理者、使用者可以清晰的查看到下属和下属部门的业务流程。

为使得所建立的业务流程能够更顺畅的运行,业务流程的改进与企业组织结构的优化是一个相互制约、相互促进的过程。
2、以人为本
组织中最重要的部分是人员的工作方式以及构成他们每日操作的工作流程。
人是业务流程的驱动者,组织中的每一个人都会在业务流程中充当一个角色。通过良好的业务流程,每一个人都会有自己清晰的职责,要求具有良好的沟通协作意识和团队意识,明确自己在一个个业务流程中所担当的角色。
同时对于参与其中的业务流程,每个人员都要有自己的反馈。
首先,每个人员都能查看到这些业务流程,他们需要充分理解这些业务流程、流程的业务意义和目的,这些业务流程通过切合他们理解能力的方式(切合业务的图形、说明文字、相应的制度、规范、标准等等)得以展现。
其次,对于流程运行中存在的问题或瓶颈,每个人员都要积极反馈(提出修改的建议,或者在权限范围内直接修改)以促进流程的持续改进,业务流程的管理和变动不仅仅是业务分析人员或管理人员的职责,每一个员工都要参与其中,否则只有失败。管理人员和决策层更重要的职责是制定出业务流程的规则和约束,在这个规则和约束范围内,员工可以根据变化的商业环境对业务流程做出迅速修改,这样不必等到领导了解情况后再做出决策从而失去机会。
3、对流程运行效益的分析
从企业投资者的角度来讲,好的业务流程设计必然是能够为企业带来最高利润的设计。因此,对业务流程的效益分析是评价业务流程的一个重要方面。财务数据是最关键的数据,但这种分析不一定完全是由数据支撑的,有些是不能量化的,比如人员效率等等。
五、业务流程管理
良好的业务流程管理是保证企业灵活运营的关键(业务流程管理又何尝不是一种业务流程?)。
1、业务分析
实际这也是业务流程管理最重要的部分。它需要对企业业务有着强大的分析能力,因为业务分析对企业的运营有着重大的指导意义,只有具备了这样的业务分析能力,才能把握住企业运转的真实流程,而且这种分析能力往往带有对整个行业的深刻理解和前瞻性。没有异议,业务分析在于人,与IT无关。
2、业务流程的持续改进
不仅仅是流程管理人员(管理决策层)根据运行效益的分析和商业环境的分析对流程进行重整。还包括每个员工对其参与的流程的持续反馈和持续改进。柔性的业务流程。
3、IT系统与业务流程的关系
IT系统与业务流程并没有直接的关系。正如06z在SOA帖子里表达的:soa95%以上的工作是在做业务流程的分析解构和重整,技术层面的支持只占5%不到。在落实到技术层面,你觉得一个soa产品究竟应该包括些什么内容呢?这些内容又能有多少是能够辅助大家对业务流程进行分析和测试,对业务元素进行重整和再分配?如果你们真的有这个能力,你们觉得是在这里继续开发软件过苦日子,还是去开拓商业咨询呢?我的观点是:SOA很美好,但是一落地就变成了小丑。所谓的业务流程管理软件同理。
可以这样理解:业务流程管理是一个很大的命题,IT系统通过信息化对它的子集进行支撑,这里的IT系统包括的范围很广泛,包括了所有的企业应用软件(所有的企业应用软件都可以看作是对企业某部分的业务流程进行的描述)。业务流程管理的核心在于业务流程的分析解构和重整,这点是所有软件都不可企及的,关键在于人。至于BPM还是工作流,它们本来就有它们自己的适用范围,硬要把它提升到业务流程管理的高度来宣传,那就真的和小丑一样,滑稽而可笑。
关注下篇:BPM是干什么的
posted @
2008-08-26 17:33 ronghao 阅读(1411) |
评论 (1) |
编辑 收藏