首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

jbpm5.4应用一-资源加载分析

2013-11-15 
jbpm5.4应用1-资源加载分析jbpm:kbase idkbasejbpm:resourcesjbpm:resource typeBPMN2 source

jbpm5.4应用1-资源加载分析
<jbpm:kbase id="kbase"><jbpm:resources><jbpm:resource type="BPMN2" source="classpath:HelloWorld.bpmn2"/></jbpm:resources></jbpm:kbase>

?这样如果资源特别多的时候,配置起来会很麻烦,那有没有一种方式可以配置制定一个目录呢,比如这样

<jbpm:kbase id="kbase"><jbpm:resources><jbpm:resource type="BPMN2" source="classpath:jbpm"/></jbpm:resources></jbpm:kbase>

?由于资料比较少,另外也想大概研究下其源码,于是跟踪了下,大体过程是这样的

1.spring加载其核心xml配置由根beans这个根元素开始加载,然后每个命名空间都有对应的解析类,比如jbpm这个命名空间对应的解析类是org.drools.container.spring.namespace.SpringDroolsHandler

具体怎么看这个解析类是什么呢,可以看下drools-spring的包下的META-INF下有两个文件

? spring.handlers:主要配置解析类,内容如下

http\://drools.org/schema/drools-spring=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.2.0=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.3.0=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.4.0=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.5.0=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.6.0=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.7.0=org.drools.container.spring.namespace.SpringDroolsHandler

?前边是命名空间,后边对应的是解析类

然后是另一个文件

spring.schemas:命名空间xsd与包中实际xsd的对应关系,主要用作xsd的校验

内容如下

http\://drools.org/schema/drools-spring=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.2.0=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.3.0=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.4.0=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.5.0=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.6.0=org.drools.container.spring.namespace.SpringDroolsHandlerhttp\://drools.org/schema/drools-spring-1.7.0=org.drools.container.spring.namespace.SpringDroolsHandler

2.解析类是如何处理的

来看下其源码

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;public class SpringDroolsHandler extends NamespaceHandlerSupport {    public void init() {        registerBeanDefinitionParser( "resource",                                      new ResourceDefinitionParser() );        registerBeanDefinitionParser( "resource-change-scanner",                                      new ResourceChangeScannerDefinitionParser() );        registerBeanDefinitionParser( "model",                                      new ResourceDefinitionParser() );        registerBeanDefinitionParser( "kbase",                                      new KnowledgeBaseDefinitionParser() );        registerBeanDefinitionParser( "kagent",                                      new KnowledgeAgentDefinitionParser() );        registerBeanDefinitionParser( "kstore",                                      new KnowledgeStoreDefinitionParser() );        registerBeanDefinitionParser( "ksession",                                      new KnowledgeSessionDefinitionParser() );        registerBeanDefinitionParser( "grid",                                      new GridDefinitionParser() );        registerBeanDefinitionParser( "grid-node",                                      new GridNodeDefinitionParser() );        registerBeanDefinitionParser( "eventListeners",                                      new EventListenersDefinitionParser() );        registerBeanDefinitionParser( "fileLogger",                new KnowledgeLoggerDefinitionParser() );        registerBeanDefinitionParser( "consoleLogger",                new KnowledgeLoggerDefinitionParser() );        registerBeanDefinitionParser( "environment",                new EnvironmentDefinitionParser() );    }}

?可以看到该类只提供了一个init方法,并且注册了每个元素对应的具体的解析类,这里和资源有关的是

registerBeanDefinitionParser( "resource",                                      new ResourceDefinitionParser() );registerBeanDefinitionParser( "kbase",                                      new KnowledgeBaseDefinitionParser() );

?

?根据xml的关系会先执行kbase对应的解析类,其中和resource有关的代码如下

   public static ManagedList getResources(Element element,                                           ParserContext parserContext,                                           BeanDefinitionBuilder factory) {        Element resourcesElm = DomUtils.getChildElementByTagName( element,                                                                  "resources" );        ManagedList resources = null;        if ( resourcesElm != null ) {            List<Element> childElements = DomUtils.getChildElementsByTagName( resourcesElm,                                                                              "resource" );            if ( childElements != null && !childElements.isEmpty() ) {                resources = new ManagedList();                for ( Element childResource : childElements ) {                    BeanDefinition resourceDefinition = parserContext.getDelegate().parseCustomElement( childResource,                                                                                                        factory.getBeanDefinition() );                    resources.add( resourceDefinition );                }            }        }        return resources;    }

?在执行parserContext.getDelegate().parseCustomElement的时候会调用resource对应的解析类,如下

protected AbstractBeanDefinition parseInternal(Element element,                                                   ParserContext parserContext) {        BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition( DroolsResourceAdapter.class );        if ( StringUtils.hasText( element.getAttribute( REF ) ) ) {            String ref = element.getAttribute( REF );            emptyAttributeCheck( element.getLocalName(),                                 REF,                                 ref );            return (AbstractBeanDefinition) parserContext.getRegistry().getBeanDefinition( ref );        }        String source = element.getAttribute( SOURCE_ATTRIBUTE );        emptyAttributeCheck( element.getLocalName(),                             SOURCE_ATTRIBUTE,                             source );        factory.addPropertyValue( "resource",                                  source );        String type = element.getAttribute( TYPE_ATTRIBUTE );        String resourceType = type == null || type.length() == 0 ? ResourceType.DRL.getName() : type;        factory.addPropertyValue( "resourceType",                                  resourceType );        boolean basicAuthenticationEnabled = element.getAttribute( BASIC_AUTHENTICATION_ATTRIBUTE ) != null && element.getAttribute( BASIC_AUTHENTICATION_ATTRIBUTE ).equalsIgnoreCase( "enabled" );        factory.addPropertyValue( "basicAuthenticationEnabled",                                  basicAuthenticationEnabled );        if ( basicAuthenticationEnabled ) {            String username = element.getAttribute( USERNAME_ATTRIBUTE );            factory.addPropertyValue( "basicAuthenticationUsername",                                      username );            String password = element.getAttribute( PASSWORD_ATTRIBUTE );            factory.addPropertyValue( "basicAuthenticationPassword",                                      password );        }                String name = element.getAttribute( NAME );        factory.addPropertyValue( "name",                                  org.drools.core.util.StringUtils.isEmpty(name) ? null : name);                String description = element.getAttribute( DESCRIPTION );        factory.addPropertyValue( "description",                                  org.drools.core.util.StringUtils.isEmpty(description) ? null : description);                if ( "xsd".equals( resourceType.toLowerCase() ) ) {            XsdParser.parse( element,                             parserContext,                             factory );        } else if ( "dtable".equals( resourceType.toLowerCase() ) ) {            List<Element> childElements = DomUtils.getChildElementsByTagName( element,                                                                              "decisiontable-conf" );            if ( !childElements.isEmpty() ) {                Element conf = childElements.get( 0 );                DecisionTableConfigurationImpl dtableConf = new DecisionTableConfigurationImpl();                String inputType = conf.getAttribute( INPUT_TYPE_ATTRIBUTE );                emptyAttributeCheck( conf.getLocalName(),                                     INPUT_TYPE_ATTRIBUTE,                                     inputType );                dtableConf.setInputType( DecisionTableInputType.valueOf( inputType ) );                String worksheetName = conf.getAttribute( WORKSHEET_NAME_ATTRIBUTE );                emptyAttributeCheck( conf.getLocalName(),                                     WORKSHEET_NAME_ATTRIBUTE,                                     worksheetName );                dtableConf.setWorksheetName( worksheetName );                factory.addPropertyValue( "resourceConfiguration",                                          dtableConf );            }        }        return factory.getBeanDefinition();    }

?然后将其封装为DroolsResourceAdapter返回。

这部分主要是将xml转换为bean对象,基本也是按照xml配置的方式去读取dom元素,并没有提供类似查找路径下具体文件的行为。

下边是运行时的截图


jbpm5.4应用一-资源加载分析
?这个图片展现了解析的一个堆栈情况,其实具体解析还是调用spring的NamespaceHandlerSupport下的parse来进行处理的,而每个元素的解析是通过spring的AbstractBeanDefinitionParser来控制过程,然后每个子元素的实现来执行具体的功能。

?3.真正加载的时候

之前分析了解析xml的过程,但是并未见到加载资源的踪迹,那么下面看来一下这个过程。

既然resource是在kbase下,那么加载的过程也应该是在kbase中进行,来看一下kbase对应的bean factory的afterPropertiesSet方法

?

public void afterPropertiesSet() throws Exception {        /*上边的代码先忽略 来看看资源加载的过程*/        for ( DroolsResourceAdapter res : resources ) {            if ( res.getResourceType().equals( ResourceType.XSD ) ) {                xsds.add( (JaxbConfigurationImpl) res.getResourceConfiguration() );            }            if ( res.getResourceConfiguration() == null ) {                kbuilder.add( res.getDroolsResource(),                              res.getResourceType() );            } else {                kbuilder.add( res.getDroolsResource(),                              res.getResourceType(),                              res.getResourceConfiguration() );            }        }        KnowledgeBuilderErrors errors = kbuilder.getErrors();        if ( !errors.isEmpty() ) {            throw new RuntimeException( errors.toString() );        }        kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );        KnowledgeBaseImpl kbaseImpl = (KnowledgeBaseImpl) kbase;        kbaseImpl.jaxbClasses = new ArrayList<List<String>>();        for ( JaxbConfigurationImpl conf : xsds ) {            kbaseImpl.jaxbClasses.add( conf.getClasses() );        }    }
?

?

?可以看到其实和官网给的例子一样,是用kbuilder来处理的,那么来跟踪一下这个处理类只有一个实现类org.drools.builder.impl.KnowledgeBuilderImpl

加载资源通过add方法

?

public void add(Resource resource,                            ResourceType type,                            ResourceConfiguration configuration) {        pkgBuilder.registerBuildResource(resource);        pkgBuilder.addKnowledgeResource( resource, type, configuration );    }
?是通过pkgBuilder来实现的,对应类为org.drools.compiler.PackageBuilder

?

通过addKnowledgeResource方法来进行处理

?

public void addKnowledgeResource( Resource resource,            ResourceType type,            ResourceConfiguration configuration ) {        try {            ( (InternalResource) resource ).setResourceType( type );            if (ResourceType.DRL.equals( type )) {                addPackageFromDrl( resource );            } else if (ResourceType.DESCR.equals( type )) {                addPackageFromDrl( resource );            } else if (ResourceType.DSLR.equals( type )) {                addPackageFromDslr( resource );            } else if (ResourceType.DSL.equals( type )) {                addDsl( resource );            } else if (ResourceType.XDRL.equals( type )) {                addPackageFromXml( resource );            } else if (ResourceType.BRL.equals( type )) {                addPackageFromBrl( resource );            } else if (ResourceType.DRF.equals( type )) {                addProcessFromXml( resource );            } else if (ResourceType.BPMN2.equals( type )) {                BPMN2ProcessFactory.configurePackageBuilder( this );                addProcessFromXml( resource );            } else if (ResourceType.DTABLE.equals( type )) {                addPackageFromDecisionTable( resource, configuration );            } else if (ResourceType.PKG.equals( type )) {                addPackageFromInputStream(resource);            } else if (ResourceType.CHANGE_SET.equals( type )) {                addPackageFromChangeSet(resource);            } else if (ResourceType.XSD.equals( type )) {                addPackageFromXSD(resource, (JaxbConfigurationImpl) configuration);            } else if (ResourceType.PMML.equals( type )) {                addPackageFromPMML(resource, type, configuration);            } else {                addPackageForExternalType(resource, type, configuration);            }        } catch (RuntimeException e) {            throw e;        } catch (Exception e) {            throw new RuntimeException( e );        }    }
?在分析了具体的处理类之后,发现当type为CHANGE_SET的时候对应的处理方法为addPackageFromChangeSet

?

?

void addPackageFromChangeSet(Resource resource) throws SAXException, IOException {        XmlChangeSetReader reader = new XmlChangeSetReader( this.configuration.getSemanticModules() );        if (resource instanceof ClassPathResource) {            reader.setClassLoader( ( (ClassPathResource) resource ).getClassLoader(),                                   ( (ClassPathResource) resource ).getClazz() );        } else {            reader.setClassLoader( this.configuration.getClassLoader(),                                   null );        }        Reader resourceReader = null;        try {            resourceReader = resource.getReader();            ChangeSet changeSet = reader.read( resourceReader );            if (changeSet == null) {                // @TODO should log an error            }            for (Resource nestedResource : changeSet.getResourcesAdded()) {                InternalResource iNestedResourceResource = (InternalResource) nestedResource;                //注意看这里判断是否为目录 然后循环目录中的文件                if (iNestedResourceResource.isDirectory()) {                    for (Resource childResource : iNestedResourceResource.listResources()) {                       //这里的代码显示并不支持2级目录                        if (( (InternalResource) childResource ).isDirectory()) {                            continue; // ignore sub directories                        }                        ( (InternalResource) childResource ).setResourceType( iNestedResourceResource.getResourceType() );                        addKnowledgeResource( childResource,                                              iNestedResourceResource.getResourceType(),                                              iNestedResourceResource.getConfiguration() );                    }                } else {                    addKnowledgeResource( iNestedResourceResource,                                          iNestedResourceResource.getResourceType(),                                          iNestedResourceResource.getConfiguration() );                }            }        } finally {            if (resourceReader != null) {                resourceReader.close();            }        }    }
?以上代码的大体过程是解析type为CHANGE_SET的资源文件(xml文件,具体格式见下面),然后找到配置的具体文件或者路径,判断是否为目录,如果是目录的话加载目录下的文件,但并不支持目录下的目录,然后将对应的文件加载。

?

修改后的xml如下

spring配置文件

?

<jbpm:kbase id="kbase"><jbpm:resources><jbpm:resource type="CHANGE_SET" source="classpath:bpmnChangeSet.xml"/></jbpm:resources></jbpm:kbase>
?bpmnChangeSet.xml<change-set xmlns='http://drools.org/drools-5.0/change-set' xmlns:xs='http://www.w3.org/2001/XMLSchema-instance' xs:schemaLocation='http://drools.org/drools-5.0/change-set change-set-1.0.0.xsd'> <add> <resource source="classpath:bpmn" type="BPMN2"/> </add></change-set>?这样就可以将所有的资源文件指定到具体的目录了。

其实如果细心的话,在kbuilder的接口里有文档说明了这个情况,感兴趣的朋友可以去看看

?

?

热点排行