跟踪activiti创建流程引擎源码
默认情况下activiti是通过XML⽂件l来配置Activiti流程引擎,当然如果整合了spring的话,这种做法不太适合了。
获取流程引擎ProcessEngine最简单的⽅法就是借助⼯具类 ine.ProcessEngines来创建默认的流程引擎。
ProcessEngine processEngine = DefaultProcessEngine()
跟踪源码,看看内部如何实现的。
⾸先查⽅法getDefaultProcessEngine,看到本⽅法内调⽤了类内部⽅法getProcessEngine来实现。
public static ProcessEngine getDefaultProcessEngine() {
return getProcessEngine(NAME_DEFAULT);
}
继续跟踪内部⽅法getProcessEngine
/** obtain a process engine by name.
* @param processEngineName is the name of the process engine or null for the default process engine. */
public static ProcessEngine getProcessEngine(String processEngineName) {
if (!isInitialized) {
init();
}
(processEngineName);
}
关键⽅法init
/** Initializes all process engines that can be found on the classpath for
* resources <code>l</code> (plain Activiti style configuration)
* and for resources <code&l</code> (Spring style configuration). */
初始化所有的在classpath路径上资源(activiti风格的⽂件l)和资源(spring风格的⽂件l)中搜索到的流程引擎
public synchronized static void init() {
if (!isInitialized) {
if(processEngines == null) {
// Create new map to store process-engines if current map is null
processEngines = new HashMap<String, ProcessEngine>();
}
ClassLoader classLoader = ClassLoader();
Enumeration<URL> resources = null;
try {
resources = Resources("l");
} catch (IOException e) {
throw new ActivitiException("problem retrieving l resources on the classpath: "+Property("java.class.path"), e);
}
// Remove duplicated configuration URL's using set. Some classloaders may return identical URL's twice, causing duplicate startups
Set<URL> configUrls = new HashSet<URL>();
while (resources.hasMoreElements()) {
configUrls.add( Element() );
}
for (Iterator<URL> iterator = configUrls.iterator(); iterator.hasNext();) {
URL resource = ();
initProcessEnginFromResource(resource);
}
try {
resources = Resources("l");
} catch (IOException e) {
throw new ActivitiException("problem l resources on the classpath: "+Property("java.class.path"), e);
}
while (resources.hasMoreElements()) {
URL resource = Element();
initProcessEngineFromSpringResource(resource);
}
isInitialized = true;
} else {
log.info("Process engines already initialized");
}
}
如果没有初始化
通过类加载器获取l的资源
借助Set的防重性,去掉重复的资源
遍历l资源,调⽤⽅法initProcessEnginFromResource初始化流程引擎,待会详细说明此⽅法
通过类加载器获取l
遍历资源,调⽤⽅法initProcessEngineFromSpringResource,来初始化流程引擎。
设置初始化标识
如果已初始化,log记录。
分析: 从activiti风格的⽂件l或者spring风格的⽂件l来加载流程引擎,两种⽅式任何⼀种均可完成。疑问: 为什么⽂件l资源需要去重,⽽⽂件l不需要防重。
源码描述如下:// Remove duplicated configuration URL's using set. Some classloaders may return identical URL's twice, causing duplicate startups
接着跟踪⽅法initProcessEnginFromResource和initProcessEngineFromSpringResource
a initProcessEnginFromResource
private static ProcessEngineInfo initProcessEnginFromResource(URL resourceUrl) {
ProcessEngineInfo processEngineInfo = (resourceUrl);
/
/ if there is an existing process engine info
if (processEngineInfo!=null) {
// remove that process engine from the member fields
if (Exception()==null) {
String processEngineName = Name();
}
}
String resourceUrlString = String();
try {
log.info("initializing process engine for resource " + resourceUrl);
ProcessEngine processEngine = buildProcessEngine(resourceUrl);
String processEngineName = Name();
log.info("initialised process engine " + processEngineName);
processEngineInfo = new ProcessEngineInfoImpl(processEngineName, resourceUrlString, null);
processEngines.put(processEngineName, processEngine);
processEngineInfosByName.put(processEngineName, processEngineInfo);
} catch (Throwable e) {
log.log(Level.SEVERE, "Exception while initializing process engine :" + e.getMessage(), e);
processEngineInfo = new ProcessEngineInfoImpl(null, resourceUrlString, getExceptionString(e));
}
processEngineInfosByResourceUrl.put(resourceUrlString, processEngineInfo);
processEngineInfos.add(processEngineInfo);
return processEngineInfo;
}
总体来说⽐较好理解,先查缓存map中是否存在此url资源,如果存在就清理掉,然后根据新传来的url来获取流程引擎,并缓存起来。
我们可以注意到⽅法buildProcessEngine(String urlString),
private static ProcessEngine buildProcessEngine(URL resource) {
InputStream inputStream = null;
try {
inputStream = resource.openStream();
ProcessEngineConfiguration processEngineConfiguration = ateProcessEngineConfigurationFromInputStream(inputStream); return processEngineConfiguration.buildProcessEngine();
} catch (IOException e) {
throw new ActivitiException("couldn't open resource stream: "+e.getMessage(), e);
} finally {
IoUtil.closeSilently(inputStream);
}
}
借助类ProcessEngineConfiguration的⽅法createProcessEngineConfigurationFromInputStream来完成资源的读取。
public static ProcessEngineConfiguration createProcessEngineConfigurationFromInputStream(InputStream inputStream) {
return createProcessEngineConfigurationFromInputStream(inputStream, "processEngineConfiguration");
}
public static ProcessEngineConfiguration createProcessEngineConfigurationFromInputStream(InputStream inputStream, String beanName) {
return BeansConfigurationHelper.parseProcessEngineConfigurationFromInputStream(inputStream, beanName);
}
马上就要揭开庐⼭真⾯⽬了。
public static ProcessEngineConfiguration parseProcessEngineConfiguration(Resource springResource, String beanName) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
xmlBeanDefinitionReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
xmlBeanDefinitionReader.loadBeanDefinitions(springResource);
ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) Bean(beanName);
processEngineConfiguration.setBeans(new SpringBeanFactoryProxyMap(beanFactory));
return processEngineConfiguration;
}
createprocessapublic static ProcessEngineConfiguration parseProcessEngineConfigurationFromInputStream(InputStream inputStream, String beanName) {
Resource springResource = new InputStreamResource(inputStream);
return parseProcessEngineConfiguration(springResource, beanName);
}
public static ProcessEngineConfiguration parseProcessEngineConfigurationFromResource(String resource, String beanName) {
Resource springResource = new ClassPathResource(resource);
return parseProcessEngineConfiguration(springResource, beanName);
}
从上⾯的代码可获知,真正读取⽂件的⽅式,是使⽤spring的beanFacotry来完成的。相信⼤家读到这⾥已经明⽩了activiti资源的加载过程。
b spring风格的⽅式 initProcessEngineFromSpringResource
protected static void initProcessEngineFromSpringResource(URL resource) {
try {
Class< ? > springConfigurationHelperClass = ReflectUtil.loadClass("org.activiti.spring.SpringConfigurationHelper");
Method method = Method("buildProcessEngine", new Class<?>[]{URL.class});
ProcessEngine processEngine = (ProcessEngine) method.invoke(null, new Object[]{resource});
String processEngineName = Name();
ProcessEngineInfo processEngineInfo = new ProcessEngineInfoImpl(processEngineName, String(), null);
processEngineInfosByName.put(processEngineName, processEngineInfo);
processEngineInfosByResourceUrl.String(), processEngineInfo);
} catch (Exception e) {
throw new ActivitiException("couldn't initialize process engine from spring configuration resource "+String()+": "+e.getMessage(), e);
}
}
写到这⾥,我们来尝试解决刚才提到的疑问。activiti风格的实现并不是程序启动的时候,把所有配置⽂件加载起来了,更像是调⽤静态⽅法,主动加载资源,假设某些类加载器可能对同⼀个url返回两次,那么主动加载两次就会引起重复加载资源,进⽽导致流程引擎启动两次。⽽spring风格的⽅式是从applicationContext上下⽂中来获取bean的,是程序启动加载的时候,已经把这些配置⽂件分析并读取完毕,只等着调⽤⽅来使⽤。另外spring配置的bean默认情况下均是单例,获取的bean也是同⼀个。所以spring风格的资源才没有过滤吧。
通过阅读源码,有很多值得我们学习的地⽅,⾸先是编写可阅读,可维护的代码。⽐如上述的类及⽅法,每个⽅法基本只做属于⾃⼰的事情-单⼀职能,⽅法尽量短⼩。返回接⼝或抽象类等等;其次是记录认为处理⽐较好的⽅法,⽐如加载并解析⽂件等功能。
要勤于思考,勤于总结。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论