`

在JBPM的Handle类中调用由Spring管理的类原理方法详解

    博客分类:
  • JBPM
阅读更多
我们在使用JBPM定义流程的时候经常要在流程定义文件中加入一个继承xxxHandler的类来实现我们的业务逻辑判断或者其他的需求,在这个类中我们默认情况下只能通过JBPM提供的API拿到Hibernate的Session,如果我们想要执行一条hql查询语句的话要使用session进行查询这样不太好。最好是我们将要执行的代码封装到一个Service类中,然后进行调用 如果想要调用这个Service类中的方法,首先要通过Spring得到这个类的对象。如何才能得到呢?下面我们来探讨这个问题。(以UserService为例)

第一种方法:将UserService定义成static的(不推荐)
//实现了JBPM中AssignmentHandler的类
public class RoleAssignmentHandler03 implements AssignmentHandler {
	
	@Resource
	private UserService userService;

    @Override
	public void assign(Assignable assignable, ExecutionContext executionContext) throws Exception {
       userSerivce.xxxx //调用业务逻辑
    }
}


如果我们按照上面的方法来写userSerivice是不会被Spring来注入的,因为如果你想向一个类中注入一个属性的话,那么这个类必须也要交给Spring来管理所以在Spring的配置文件中:
 <bean id="roleAssignmentHandler03" class="com.bjsxt.oa.service.handler.RoleAssignmentHandler03">
  	<property name="userService" ref="userService"></property>
  </bean>

即便我们在Spring的配置文件中定义了这个类,那么userSerivce还是不会有值的,为什么呢?当web服务器启动的时候Spring的确将这个类进行了实例化,但是当我们的系统在运行调用这个类的时候JBPM会再次的创建一个这个类的一个对象,所以他不会使用Spring给我们创建的那个对象。那么怎么办呢? 我们可以将它定义成静态的:
@Resource
private static UserService userService

为什么定义成静态的就可以呢?我们都知道静态变量时类级别的变量,所有这个类的实例共享一份,那么第一次Spring给我们创建这个对象的时候,userService有值了等到第二次JBPM给我们创建这个对象的时候由于UserService是static的,所以他依然会有值 所以通过这种方法我们可以得到UserService对象,但是我们并不推荐这种方法,因为确实有点浪费内存资源 Spring明明已经把这个对象创建好了但是我们却没有去使用这个对象而是去使用了另一个由JBPM给我们创建的一个对象,但这种方法是可行的

第二种方法:通过创建一个BeanFactory来得到相应的Bean对象(错误的做法)
我们知道如果能够得到一个BeanFactory对象然后通过getBean(对象id)就可以拿到一个对象,所以就想当然的使用下面这种方法来得到一个Beanfactory对象:
BeanFacotory factory = new ClassPathXmlApplicationContext("xxx.xml);

但是请注意:如果你这样写相当于重新创建了一个容器环境,这个与当前我们tomcat启动的时候自动创建的那个容器环境完全的就是两套东西,他们的事务控制、包括bean对象的获取都完全是处在两个不同的环境中了而且如果这样写,程序会报错的。

第三种方法:通过相应的辅助类来得到tomcat启动时创建的BeanFactory对象(不推荐)
上面那种方法无法得到一个BeanFactory对象。那么我们可以通过一些辅助类来得到tomcat启动时创建的BeanFactory对象:因为我们在web.xml的配置文件中配置了Spring的Listener以及Spring的配置文件的位置等等,那么在tomcat启动的 时候就会初始化这个容器环境创建一个BeanFactory对象,放置到
ServletContext中。我们如何才能拿到tomcat创建的这个BeanFactory呢?要用到一个辅助类

WebApplicationContextUtils.getRequiredWebApplicationContext(ServletActionContext.getServletActionContxt());

但是我们不推荐这样做为什么?因为ServletActionContext是struts的东西,这样spring或者说JBPM都依赖于Struts,我们在业务逻辑层不要依赖于呈现层的东西。但是这种方法也是可行的。

第四种方法:用JBPM给我们提供的方法
这个时候我们要用到Spring和Jbpm集成时候的一个第三方的类库:spring-modules 在他的文档中(spring-modules-0.8\docs\reference\html\jbpm31.html)他有一个题目叫做:9.3. Accessing Spring beans from jBPM actions,就是在JBPM的Action中访问Spring的Bean对象的方法,正好是我们想解决的问题。按照他的意思我们这个例子应该这样来做:
Spring的配置文件中还是要加入:
 <bean id="roleAssignmentHandler03" class="com.bjsxt.oa.service.handler.RoleAssignmentHandler03">
  	<property name="userService" ref="userService"></property>
  </bean>

然后在JBPM的流程定义文件中:
<task-node name="部门领导审批">
      <task>
      	<assignment class="org.springmodules.workflow.jbpm31.JbpmHandlerProxy">
      		 <targetBean>roleAssignmentHandler03</targetBean>
      	</assignment>
      </task>
      <transition name="结束审批" to="结束"></transition>
   </task-node>


在JBPM的Handler类中:
public class RoleAssignmentHandler03 implements AssignmentHandler {
	
	//由JBPM来进行注入
	private String roleName;
	
	@Resource
	private UserService userService;
	
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
}

这样就可以注入了。这是什么意思呢?在JBPM的流程定义文件中
	<assignment class="org.springmodules.workflow.jbpm31.JbpmHandlerProxy">
      		 <targetBean>roleAssignmentHandler03</targetBean>
      	</assignment>

class所指定的这个类是JBPM提供给我们的,然后targetBean所指定的类就是我们在Spring文件中让Spring给我们实例化的那个Handler类在上面的spring配置文件中可以看到而且我们要把我们想要注入的属性Userservice写到里面,然后我们在Handler类中定义UserService的set方法,他就可以帮我们注入了
原理:在这种的解决方法中是由org.springmodules.workflow.jbpm31.JbpmHandlerProxy这个类和Spring打交道,他可以拿到Beanfactory,然后通过 <targetBean>所指定的Spring容器中的那个bean对象的id他就可以帮我们注入进去了。但是这样方法有一个很大的缺点:在Handler类中你看到我们还有一个roleName属性他是我们查询条件的参数的院线我们通过:
<assignment class="com.bjsxt.oa.service.handler.RoleAssignmentHandler02">
      		<roleName>部门领导</roleName>
      	</assignment>
这种方式传递进去,但是现在class换成了org.springmodules.workflow.jbpm31.JbpmHandlerProxy这个类他是不支持比如你在下面加一个<roleName>部门领导</roleName>这种方法传值的。当然我们可以把这个属性定义到spring配置文件中:
 <bean id="roleAssignmentHandler03" class="com.bjsxt.oa.service.handler.RoleAssignmentHandler03">
  	<property name="userService" ref="userService"></property>
         <property name="roleName" ref="系统管理员"></property>

  </bean>

但是这种方法把属性就写死了,而且如果我有很多的属性要进行传递,那么spring配置文件就太臃肿了。所以这种方法我们依然是不推荐的,但是如果你不需要进行属性的传递,这种方法依然是可行的。

第五种方法:我们的Handler类实现BeanFactoryAware这个接口:
这个接口里面有一个方法:
@Override
	public void setBeanFactory(BeanFactory arg0) throws BeansException {
		
	}

通过这个方法我们就可以拿到这个Beanfactory对象了。上面这种方法我们有点想当然了,因为beanFactory是没有值的 为什么呢?我们说上面这种情况成立的前提必须是实现了BeanFactroyAware这个接口的类也要交给Spring管理但是我们这个类并没有交给Spring来管理它还是由JBPM来创建的。所以这种方式依然行不通。

第六种方法:最终可行方案
我们定义自己的一个BeanFactoryHelper 类这个类中有一个静态变量Beanfactory,然后我们让spring帮助我们生成这个类,那么这个时候Beanfactory就有值了我们向外提供一个静态的方法返回Beanfactory就可以了。
public class BeanFactoryHelper implements BeanFactoryAware {
	
	private static BeanFactory beanFactory;
	
	@Override
	public void setBeanFactory(BeanFactory f) throws BeansException {
		this.beanFactory = f;
	}
	
	public static BeanFactory getBeanfactory() {
		return beanFactory;
	}

}


spring配置文件:
<bean id="beanFactoryHelper" class="com.bjsxt.oa.service.handler.BeanFactoryHelper">
  </bean>

在我们的Handler类中,我们可以这样使用:
public class RoleAssignmentHandler03 implements AssignmentHandler {
	
	//由JBPM来进行注入
	private String roleName;
	
	@Resource
	private UserService userService;
	
	public void setUserService(UserService userService) {
		this.userService = userService;
	}



	@Override
	public void assign(Assignable assignable, ExecutionContext executionContext) throws Exception {
		if(roleName == null) {
			throw new RuntimeException("必须首先指定角色");
		}
		
		BeanFactory bf = BeanFactoryHelper.getBeanfactory();
		UserService userService = (UserService)bf.getBean("userService");
UserService.xxxxx//调用业务逻辑方法
}

用这个方法是最好的,但是这个方法不用我们自己写有人已经帮我们写好了。

我们先借鉴一下JbpmHandlerProxy这个类是怎么拿到Beanfactory对象的。我们要关联上源代码了解一下他的运行机制:
JbpmHandlerProxy的运行机制:
jbpmhandlerProxy通过一个JbpmFactoryLocator来得到一个Beanfactory对象,那么他是怎么得到的呢,jbpmfactoryLocator实现了一个BeanFactoryAwre接口,所以有个
setBeanfacotry(BeanFactory factory) 方法,那么是哪个类来调用的这个方法 呢?是LocalJbpmConfigurationFactoryBean他也实现了BeanFactoryAwre接口所以他也有一个
setBeanfacotry(BeanFactory factory) 方法,因为这个类的对象我们是让spring帮我们生成的,所以在tomcat启动的时候spring会把Beanfactory对象放作为参数传递给
LocalJbpmConfigurationFactoryBean实现的setBeanfacotry(BeanFactory factory) 中,然后再这个方法中LocalJbpmConfigurationFactoryBean又去调用jbpmfactoryLocator
类的setBeanfacotry(BeanFactory factory) 关键就在这里,JbpmFactoryLocator中有一个protected static BeanFactory defaultFactory = null; 他把setFactory方法传递给他的
Beanfactory对象赋值给了静态变量defaultFactory。
然后在JbpmHandlerProxy类的retrieveBeanFactory方法中new JbpmFaotoryLocator对象,因为他里面的Beanfactory属性是静态的所以不管你怎么new他都是有值的,然后返回这个值
protected BeanFactory retrieveBeanFactory() {
		BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
		BeanFactoryReference factory = factoryLocator.useBeanFactory(factoryKey);
		if (factory == null)
			throw new IllegalArgumentException("no beanFactory found under key=" + factoryKey);

		try {
			return factory.getFactory();
		}
		finally {
			factory.release();
		}
	}

这就是JbpmHandlerProxy的运行机制





那我们怎么做的,我们可以把这个方法拷贝到我们的类中,然后直接调用就可以拿到Beanfactory对象了,但是这样有点麻烦我们要把这个方法封装一下

自定义BaseAutowire类:
public class BaseAutowire {
	//arg1:向哪个类进行属性注入
           //arg2:按照那种方式注入:按类型、或者名称....此处按照类型
           //arg2:是否检查依赖关系,一般情况下为true要检查依赖关系。
	public BaseAutowire() {
		((AutowireCapableBeanFactory)retrieveBeanFactory())
			.autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
	}
	
	protected BeanFactory retrieveBeanFactory() {
		BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
		BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
		if (factory == null)
			throw new IllegalArgumentException("no beanFactory found under key=" + null);

		try {
			return factory.getFactory();
		}
		finally {
			factory.release();
		}
	}
}


public class RoleAssignmentHandler03 extends BaseAutowire implements AssignmentHandler {
	//由JBPM来进行注入
	private String roleName;
	
	@Resource
	private UserService userService;

	@Override
	public void assign(Assignable assignable, ExecutionContext executionContext) throws Exception {
		if(roleName == null) {
			throw new RuntimeException("必须首先指定角色");
     userService.xxxx//调用业务逻辑
}
}

我们说如果你想要往一个类的对象中注入一个spring管理的对象的时候,这个类也必须要交给spring管理,其实这种说法也不是完全正确为什么我们在Junit单元测试中的相关属性上面定义@Resource注解就会将对象注入进去呢?都是使用了;类似我们下面讲解的这种方法: 我们可以不让spring帮助我们注入,我们自己来注入:在jbpm来构建RoleAssignmentHandler03对象的时候因为他继承了BaseAutowire类所以首先会调用BaseAutowire类的构造方法,在这个类的构造方法中我们调用retrieveBeanFactory()方法返回个Beanfactory对象,然后将它强制转换成AutowireCapableBeanFactory对象,然后调用autowireBeanProperties()方法,这样我们在RoleAssignmentHandler03类中:
@Resource
	private UserService userService;
就有用了加上@Resource就表明了一种依赖关系。我们在BaseAutowire类的构造方法中定义了自动注入的特性。因为RoleAssignmentHandler03继承了他,而且在UserService上加上了@Resource注解,表明了依赖关系所以会自动的将UserService这个类的对象注入进来。然后我们直接使用就可以了。
  • 大小: 35.1 KB
6
0
分享到:
评论

相关推荐

    jbpm4整合struts2+spring2.5+hibernate3.3

    在Spring中配置jbpm4,主要涉及以下几点: 1. 配置jbpm的数据源,使其与Hibernate共用,以确保事务的一致性。 2. 注册jbpm的SessionFactory,使Spring能够管理SessionFactory的生命周期。 3. 配置jbpm的JobExecutor...

    jbpm+spring配置

    在Spring中,你需要配置一个数据源,并确保jbpm能使用这个数据源。这可以通过Spring的`DataSource`bean来完成。 3. **创建jbpm的工作空间和部署单元**:jbpm的流程定义(即bpmn2模型文件)需要部署到工作空间中。在...

    jBPM4与Spring整合的2种方式

    1. **事务边界**:在Spring中,确保jBPM4的操作与数据库操作处于同一事务范围内,以保证数据一致性。 2. **日志和异常处理**:利用Spring的日志管理和AOP切面,对jBPM4的异常进行统一处理,提高系统的健壮性。 3. **...

    spring2_struts2_jbpm3.2.rar_jbpm struts2_jbpm-demo_jbpm3 spring_

    在Spring中,我们可以创建一个Service Bean来调用JBPM的工作流API,处理流程的启动、暂停、继续和结束等操作。同时,Struts2的动作类可以通过Spring的代理访问这些Service Bean,从而在用户交互时触发流程的执行。...

    jbpm4.3与spring整合

    在企业级应用开发中,流程管理引擎JBPM(JBoss Business Process Management)与Spring框架的结合使用是常见的一种技术方案。JBPM是一个灵活、强大的业务流程管理工具,而Spring框架则以其优秀的依赖注入(DI)和...

    Jbpm4.4+hibernate3.5.4+spring3.0.4+struts2.1.8整合

    开发者需要定义请假流程的jpdl文件,创建对应的数据库表,然后在Struts2的Action中调用JBPM的服务来启动、完成任务和查询流程状态。 **6. 总结及参考文章** 整合完成后,通常需要进行详尽的测试以确保所有功能正常...

    JBPM4.3 Spring会签 实例

    总之,这个JBPM4.3与Spring的会签实例展示了如何在企业级应用中有效地管理和控制业务流程。通过学习和实践这样的实例,开发者能够掌握如何利用这两个强大的工具集,设计和实现符合业务需求的高效流程管理系统。

    JBPM使用实例,sql spring

    2. **项目源代码(全,不含jar包).rar**:这可能是一个完整的JBPM项目源代码,包含了流程定义、服务实现、配置文件等,用于展示如何在实际项目中使用JBPM和Spring进行流程管理。 3. **sql.rar**:这个压缩包可能...

    spring与jbpm的集成包(符集成方法)

    Spring 和 JBPM 集成是一项关键的技术任务,它允许开发者在基于 Spring 的应用程序中无缝地集成业务流程管理(BPM)功能。JBPM 是一个开源的 BPM 解决方案,提供工作流服务、流程建模、执行和监控等功能。下面我们将...

    jbpm4整合struts2+spring2[1].5+hibernate3.3

    - **IOC容器统一**:jbpm4有自己的IOC容器,但在与Spring集成时,我们通常会将jbpm4的服务迁移到Spring的IOC容器中,利用Spring的强大功能进行服务管理和事务处理。 - **Spring事务管理**:Spring提供了声明式事务...

    jbpm4 集成 spring 的试用代码

    将jbpm4集成到Spring中,可以充分利用Spring的管理优势,提高流程服务的可测试性和可配置性。 在“jbpm4 集成 spring”的场景中,我们需要关注以下几个关键知识点: 1. **集成配置**:首先,我们需要在Spring的...

    JBPM工作原理及表结构详解

    本文将深入探讨JBPM的工作原理、表结构及其在实际操作中的应用。 1. **JBPM特色** - **灵活的建模**:JBPM支持BPMN 2.0标准,允许用户通过图形化界面设计复杂的工作流程。 - **持久化存储**:JBPM将流程实例和...

    spring与JBPM整合ppt

    标题中的“spring与JBPM整合ppt”指的是将Spring框架与JBPM(Business Process Management,业务流程管理)系统相结合,以实现更加高效、灵活的企业级应用流程管理。在本PPT中,我们预计会探讨以下几个核心知识点: ...

    jbpm5.4 spring mvc 集成

    jbpm5.4与Spring MVC的集成是企业级应用开发中的常见组合,它结合了jbpm(业务流程管理)的强大功能和Spring MVC的灵活控制层架构。以下将详细阐述这一集成涉及的关键知识点: 1. **jbpm5.4**:jbpm是一个开源的...

    jbpm4.0.0alpha2整合到spring

    将Jbpm整合到Spring中,可以利用Spring的强大功能来管理和控制Jbpm的工作流实例,提高系统的可维护性和可扩展性。 在集成过程中,关键知识点包括: 1. **Spring配置**:首先,需要在Spring的配置文件中引入Jbpm的...

    Jbpm4.4 整合Spring Hibernate4

    在Jbpm4.4中整合Spring,可以利用Spring的这些优势,比如将Jbpm的流程实例管理、任务分配等操作集成到Spring容器中,实现流程服务的声明式配置和管理。 **3. Hibernate4整合** Hibernate4是流行的ORM(对象关系映射...

    JBPM4.4+spring+ext整合

    【JBPM4.4+Spring+EXT 整合详解】 JBPM(Java Business Process Management)是一个开源的工作流管理系统,主要用于处理业务流程自动化。版本4.4是JBPM的一个重要里程碑,它提供了强大的工作流设计、执行和监控能力...

    jbpm4.3-spring2.5整合

    jbpm4.3-spring2.5整合是一个关键的话题,涉及到企业级...在实践中,需要对Jbpm的工作原理、Spring的IoC和AOP有深入理解,同时具备良好的XML配置和Java编程能力。通过不断的调试和测试,才能实现稳定可靠的系统集成。

    提前试用spring 集成 jbpm4

    将jbpm4集成到Spring中,可以实现灵活的业务流程自动化,提高开发效率。 在"提前试用spring 集成 jbpm4"这个主题中,我们主要关注的是如何将这两个强大的工具结合在一起,以实现更高效、更灵活的业务流程控制。首先...

Global site tag (gtag.js) - Google Analytics