我们在使用JBPM定义流程的时候经常要在流程定义文件中加入一个继承xxxHandler的类来实现我们的业务逻辑判断或者其他的需求,在这个类中一般都是用Spring的Application来获取,而这种情况每次都需要加载配置。
假设使用的Handle类是RoleAssignmentHandler,需要注入的属性石UserService, 以下有几种解决办法:
1、在RoleAssignmentHandler中把UserService声明成static
- //@Component
- public class RoleAssignmentHandler implements AssignmentHandler {
- private static final long serialVersionUID = 1L;
- //(注解式的Resource不能用在static修饰的字段)
- //@Resource(name="userService")//配置static的userService
- private static UserService userService;
- public void assign(Assignable arg0, OpenExecution arg1) throws Exception {
- userService.getUserById("");//调用userService的方法
- }
- public void setUserService(UserService userService) {
- RoleAssignmentHandler.userService = userService;
- }
- }
为什么定义成静态的就可以呢?我们都知道静态变量时类级别的变量,所有这个类的实例共享一份,那么第一次Spring给我们创建这个对象的时 候,userService有值了等到第二次JBPM给我们创建这个对象的时候由于UserService是static的,所以他依然会有值 所以通过这种方法我们可以得到UserService对象,但是我们并不推荐这种方法,因为确实有点浪费内存资源 Spring明明已经把这个对象创建好了但是我们却没有去使用这个对象而是去使用了另一个由JBPM给我们创建的一个对象,但这种方法是可行的。
2、自动注入。
首先定义一个类BeanAutowire实现BeanFactoryAware接口,并把这个类交给spring管理。
- @Component
- public class BeanAutowire implements BeanFactoryAware{
- private static BeanFactory beanFactory;
- public BeanAutowire() {
- if (null != beanFactory) {
- ((AutowireCapableBeanFactory)beanFactory).autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true);
- }
- }
- public void setBeanFactory(BeanFactory arg0) throws BeansException {
- // TODO Auto-generated method stub
- BeanAutowire.beanFactory=arg0;
- }
- }
然后让RoleAssignmentHandler类继承BeanAutowire:
- public class RoleAssignmentHandler extends BeanAutowire implements AssignmentHandler {
- private static final long serialVersionUID = 1L;
- @Resource(name="userService")
- private UserService userService;
- public void assign(Assignable arg0, OpenExecution arg1) throws Exception {
- // TODO Auto-generated method stub
- userService.getUserById("");//调用userService的方法
- }
- public void setUserService(UserService userService) {
- RoleAssignmentHandler.userService = userService;
- }
- }
这样,在spring初始化的时候会把BeanFactory注入到BeanAutowire中去,在jbpm每次使用Handle类时候会new一个Handle的实例,这时候会首先调用父类的构造方法:
- public BeanAutowire() {
- if (null != beanFactory) {
- ((AutowireCapableBeanFactory)beanFactory).autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, true);
- }
- }
把需要注入的对象注入到Handle类的实例中去。
3、参考springmodules.jar的方法
我们先借鉴一下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(null);
- if (factory == null)
- throw new IllegalArgumentException("no beanFactory found under key=" + null);
- try {
- return factory.getFactory();
- }
- finally {
- factory.release();
- }
- }
以下是这个方法的具体实施办法:
这里,由于springmodules跟jbpm4.4的集成有些问题,所以单独把JbpmFactoryLocator这个类拿了出来,修改一下相关类的引入就可以使用:
- /**
- * Created on Jan 24, 2006
- *
- * $Id: JbpmFactoryLocator.java,v 1.3 2006-12-06 14:13:18 costin Exp $
- * $Revision: 1.3 $
- */
- package com.founder.jbpm.util;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.FatalBeanException;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.beans.factory.BeanFactoryAware;
- import org.springframework.beans.factory.BeanNameAware;
- import org.springframework.beans.factory.access.BeanFactoryLocator;
- import org.springframework.beans.factory.access.BeanFactoryReference;
- /**
- * BeanFactoryLocator used for injecting Spring application context into JBPM.
- * The difference/advantage over the traditional SingletonBeanFactoryLocator is
- * that it does not parse a bean factory definition; it is used internally by
- * the jbpmSessionFactoryBean and it will register the bean factory/application
- * context containing it automatically under the name and and aliases of the
- * bean. If there is only one BeanFactory registered then a null value can be
- * used with setBeanName method. <p/> Note that in most cases, you don't have to
- * use this class directly since it is used internally by
- * LocalJbpmConfigurationFactoryBean.
- *
- * @author Costin Leau
- *
- */
- public class JbpmFactoryLocator implements BeanFactoryLocator, BeanFactoryAware, BeanNameAware {
- private static final Log logger = LogFactory.getLog(JbpmFactoryLocator.class);
- // default factory name (for nested classes)
- private String factoryName = JbpmFactoryLocator.class.getName();
- // alias/bean name to BeanFactory
- protected static final Map<String, BeanFactory> beanFactories = new HashMap<String, BeanFactory>();
- // beanfactory to alias/bean name map
- protected static final Map<BeanFactory,List<String>> beanFactoriesNames = new HashMap<BeanFactory, List<String>>();
- protected static final Map<BeanFactory, Integer> referenceCounter = new HashMap<BeanFactory, Integer>();
- protected static boolean canUseDefaultBeanFactory = true;
- protected static BeanFactory defaultFactory = null;
- /**
- * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory)
- */
- public void setBeanFactory(final BeanFactory beanFactory) throws BeansException {
- // add the factory as default if possible (if it's the only one)
- synchronized (JbpmFactoryLocator.class) {
- if (canUseDefaultBeanFactory) {
- if (defaultFactory == null) {
- defaultFactory = beanFactory;
- if (logger.isDebugEnabled())
- logger.debug("default beanFactoryReference=" + defaultFactory);
- }
- else {
- if (logger.isDebugEnabled())
- logger.debug("more then one beanFactory - default not possible to determine");
- canUseDefaultBeanFactory = false;
- defaultFactory = null;
- }
- }
- }
- // add name
- addToMap(factoryName, beanFactory);
- Integer counter = (Integer) referenceCounter.get(beanFactory);
- if (counter == null)
- referenceCounter.put(beanFactory, new Integer(0));
- // add aliases
- String[] aliases = beanFactory.getAliases(factoryName);
- List<String> names = new ArrayList<String>(1 + aliases.length);
- names.add(factoryName);
- for (int i = 0; i < aliases.length; i++) {
- addToMap(aliases[i], beanFactory);
- names.add(aliases[i]);
- }
- // append previous found names
- List<String> previousNames = (List<String>) beanFactoriesNames.get(beanFactory);
- if (previousNames != null)
- names.addAll(previousNames);
- beanFactoriesNames.put(beanFactory, names);
- }
- protected void addToMap(String fName, BeanFactory factory) {
- if (logger.isDebugEnabled())
- logger.debug("adding key=" + fName + " w/ reference=" + factory);
- synchronized (beanFactories) {
- // override check
- if (beanFactories.containsKey(fName))
- throw new IllegalArgumentException("a beanFactoryReference already exists for key " + factoryName);
- beanFactories.put(fName, factory);
- }
- }
- protected void removeReference(BeanFactory factory) {
- synchronized (referenceCounter) {
- Integer count = (Integer) referenceCounter.get(factory);
- // decrement counter
- int counter = count.intValue();
- counter--;
- if (counter == 0) {
- if (logger.isDebugEnabled())
- logger.debug("removing factory references under key " + factoryName);
- referenceCounter.remove(factory);
- // reset also default beanFactory
- if (referenceCounter.isEmpty()) {
- canUseDefaultBeanFactory = true;
- defaultFactory = null;
- }
- List<String> names = (List<String>) beanFactoriesNames.get(factory);
- beanFactoriesNames.remove(factory);
- synchronized (beanFactories) {
- for (Iterator iter = names.iterator(); iter.hasNext();) {
- beanFactories.remove(iter.next());
- }
- }
- }
- else
- referenceCounter.put(factory, new Integer(counter));
- }
- }
- /**
- * @see org.springframework.beans.factory.access.BeanFactoryLocator#useBeanFactory(java.lang.String)
- */
- public BeanFactoryReference useBeanFactory(String factoryKey) throws BeansException {
- // see if there is a default FactoryBean
- BeanFactory factory;
- if (factoryKey == null) {
- if (!canUseDefaultBeanFactory)
- throw new IllegalArgumentException(
- "a non-null factoryKey needs to be specified as there are more then one factoryKeys available ");
- factory = defaultFactory;
- }
- else {
- factory = (BeanFactory) beanFactories.get(factoryKey);
- if (factory == null)
- throw new IllegalArgumentException("there is no beanFactory under key " + factoryKey);
- }
- // increment counter
- synchronized (referenceCounter) {
- Integer counter = (Integer) referenceCounter.get(factory);
- referenceCounter.put(factory, new Integer(counter.intValue() + 1));
- }
- final BeanFactory finalFactory = factory;
- // simple implementation
- return new BeanFactoryReference() {
- private BeanFactory fact = finalFactory;
- public BeanFactory getFactory() {
- if (this.fact == null)
- throw new IllegalArgumentException("beanFactory already released");
- return this.fact;
- }
- public void release() throws FatalBeanException {
- if (fact != null) {
- removeReference(fact);
- // remove the factory reference
- this.fact = null;
- }
- }
- };
- }
- /**
- * @see org.springframework.beans.factory.BeanNameAware#setTargetBean(java.lang.String)
- */
- public void setBeanName(String name) {
- factoryName = name;
- }
- }
把这个类配置成spring的bean:
- <bean id="baseAutowire" class="com.founder.jbpm.util.JbpmFactoryLocator">
- </bean>
定义一个类BaseAutowire:
- package com.founder.jbpm.util;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.beans.factory.access.BeanFactoryLocator;
- import org.springframework.beans.factory.access.BeanFactoryReference;
- import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
- 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();
- }
- }
- }
让RoleAssignmentHandler继承BaseAutowire即可:
- public class RoleAssignmentHandler extends BaseAutowire implements AssignmentHandler {
- private static final long serialVersionUID = 1L;
- private UserService userService;
- public void assign(Assignable arg0, OpenExecution arg1) throws Exception {
- // TODO Auto-generated method stub
- userService.getUserById("");//调用userService的方法
- }
- public ProcessEngine getProcessEngine() {
- return processEngine;
- }
- public void setProcessEngine(ProcessEngine processEngine) {
- this.processEngine = processEngine;
- }
- }