异步编程模式BeginInvoke和EndInvoke方法

article/2025/9/30 6:30:17

转载自:异步编程模式BeginInvoke与EndInvoke方法

为什么要进行异步回调?众所周知,普通方法运行,是单线程的,如果中途有大型操作(如:读取大文件,大批量操作数据库,网络传输等),都会导致方法阻塞,表现在界面上就是,程序卡或者死掉,界面元素不动了,不响应了。异步方法很好的解决了这些问题,异步执行某个方法,程序立即开辟一个新线程去运行你的方法,主线程包括界面就不会死掉了。异步调用并不是要减少线程的开销, 它的主要目的是让调用方法的主线程不需要同步等待在这个函数调用上, 从而可以让主线程继续执行它下面的代码.

      BeginInvoke方法可以使用线程异步地执行委托所指向的方法。然后通过EndInvoke方法获得方法的返回值(EndInvoke方法的返回值就是被调用方法的返回值),或是确定方法已经被成功调用。当使用BeginInvoke异步调用方法时,如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕。


异步调用通用模板


//……
//普通的代码:处于同步执行模式
IAsyncResultret=委托变量.BeginInvoke(……);  //启动异步调用
//可以在这一部分干其他一些事,程序处于异步执行模式
用于保存方法结果的变量=委托变量.EndInvoke(ret);  //结束异步调用
//普通的代码:处于同步执行模式
//……

对照上一篇文章中的计算指定文件夹的容量的例子(例2)
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. namespace AsyncCalculateFolderSize1
  6. {
  7. class Program
  8. {
  9. //计算指定文件夹的总容量
  10. private static long CalculateFolderSize(string FolderName)
  11. {
  12. if (Directory.Exists(FolderName) == false)
  13. {
  14. throw new DirectoryNotFoundException( "文件夹不存在");
  15. }
  16. DirectoryInfo RootDir = new DirectoryInfo(FolderName);
  17. //获取所有的子文件夹
  18. DirectoryInfo[] ChildDirs = RootDir.GetDirectories();
  19. //获取当前文件夹中的所有文件
  20. FileInfo[] files = RootDir.GetFiles();
  21. long totalSize = 0;
  22. //累加每个文件的大小
  23. foreach (FileInfo file in files)
  24. {
  25. totalSize += file.Length;
  26. }
  27. //对每个文件夹执行同样的计算过程:累加其下每个文件的大小
  28. //这是通过递归调用实现的
  29. foreach (DirectoryInfo dir in ChildDirs)
  30. {
  31. totalSize += CalculateFolderSize(dir.FullName);
  32. }
  33. //返回文件夹的总容量
  34. return totalSize;
  35. }
  36. //定义一个委托
  37. public delegate long CalculateFolderSizeDelegate(string FolderName);
  38. static void Main(string[] args)
  39. {
  40. //定义一个委托变量引用静态方法CalculateFolderSize
  41. CalculateFolderSizeDelegate d = CalculateFolderSize;
  42. Console.WriteLine( "请输入文件夹名称(例如:C:\\Windows):");
  43. string FolderName = Console.ReadLine();
  44. //通过委托异步调用静态方法CalculateFolderSize
  45. IAsyncResult ret=d.BeginInvoke(FolderName, null, null);
  46. Console.WriteLine( "正在计算中,请耐心等待……");
  47. //阻塞,等到调用完成,取出结果
  48. long size = d.EndInvoke(ret);
  49. Console.WriteLine( "\n计算完成。文件夹{0}的容量为:{1}字节\n", FolderName, size);
  50. }
  51. }
  52. }

异步调用的奥秘

异步调用是通过委托来进行的,我们看看是如何定义委托的:
public delegate long CalculateFolderSizeDelegate(string FolderName);
通过Reflactor反编译结果如下:                                    
  1. public sealed class CalculateFolderSizeDelegate: MulticastDelegate
  2. {
  3. public CalculateFolderSizeDelegate(Object target , intmethodPtr)
  4. { …… }
  5. public virtual long invoke(string FolderName)
  6. { …… }
  7. public virtual IAsyncResult BeginInvoke( string FolderName,
  8. AsyncCallbackcallback , object asyncState)
  9. { …… }
  10. public virtual long EndInvoke( IAsyncResultresult )
  11. { …… }
  12. }
由此我们发现,当我们定义一个委托的时候,实际上是定义了一个委托类型,这个类型有invoke、BeginInvoke()、EndInvoke()这样几个成员方法,而这几个成员方法可以实现一步调用机制。我们看看这几个方法格式怎么定义的:

(1)BeginInvoke方法用于启动异步调用


BeginInvoke()的函数声明:

public IAsyncResult BeginInvoke(

         <输入和输出变量>,回调函数callback , 附加信息AsyncState)

函数返回值类型:

public interface IAsyncResult

{

        object AsyncState{ get;}  //如果有回调函数的话该参数用于保存要传递给回调函数的参数值

        WaitHandle AsyncWaitHandle{ get;}

        bool CompletedSynchronously{ get;}

        bool IsCompleted{ get;} //保存方法是否执行结束,我们可以通过该属性的值来判断异步方法是否执行结束

}

1.BeginInvoke返回IasyncResult,可用于监视调用进度。

2.结果对象IAsyncResult是从开始操作返回的,并且可用于获取有关异步开始操作是否已完成的状态。

3.结果对象被传递到结束操作,该操作返回调用的最终返回值。

4.在开始操作中可以提供可选的回调。如果提供回调,在调用结束后,将调用该回调;并且回调中的代码可以调用结束操作。

5.如果需要将一些额外的信息传送给回调函数,就将其放入BeginInvoke()方法的第3个参数asyncState中。注意到这个参数的类型为Object,所以可以放置任意类型的数据。如果有多个信息需要传送给回调函数,可以将所有要传送的信息封状到一个Struct变量,或者干脆再定义一个类,将信息封装到这个类所创建的对象中,再传送给BeginInvoke()方法。

(2)EndInvoke方法用于检索异步调用结果。


方法声明:

      public <方法返回值类型>EndInvoke(<声明为ref或out的参数>, IAsyncResult result )

1.result参数由BeginInvoke()方法传回。.NET借此以了解方法调用是否完成。

2.当EndInvoke方法发现异步调用完成时,它取出此异步调用方法的返回值作为其返回值,如果异步调用方法有声明为ref和out的参数,它也负责填充它。

3.在调用BeginInvoke后可随时调用EndInvoke方法,注意:始终在异步调用完成后调用EndInvoke.
4.如果异步调用未完成,EndInvoke将一直阻塞到异步调用完成。
5.EndInvoke的参数包括需要异步执行的方法的out和ref参数以及由BeginInvoke返回的IAsyncResult。


应用实例:


1.使用轮询等待异步调用完成:使用IAsyncResultIsCompleted属性来判断异步调用是否完成

 虽然上面的方法可以很好地实现异步调用,但是当调用EndInvoke方法获得调用结果时,整个程序就象死了一样,依然要等待异步方法执行结束,这样做用户的感觉并不会太  好,因此,我们可以使用 asyncResult来判断异步调用是否完成,并显示一些提示信息。这样做可以增加用户体验。代码如下:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. namespace AsyncCalculateFolderSize2
  6. {
  7. class Program
  8. {
  9. //计算指定文件夹的总容量
  10. private static long CalculateFolderSize(string FolderName)
  11. {
  12. if (Directory.Exists(FolderName) == false)
  13. {
  14. throw new DirectoryNotFoundException( "文件夹不存在");
  15. }
  16. DirectoryInfo RootDir = new DirectoryInfo(FolderName);
  17. //获取所有的子文件夹
  18. DirectoryInfo[] ChildDirs = RootDir.GetDirectories();
  19. //获取当前文件夹中的所有文件
  20. FileInfo[] files = RootDir.GetFiles();
  21. long totalSize = 0;
  22. //累加每个文件的大小
  23. foreach (FileInfo file in files)
  24. {
  25. totalSize += file.Length;
  26. }
  27. //对每个文件夹执行同样的计算过程:累加其下每个文件的大小
  28. //这是通过递归调用实现的
  29. foreach (DirectoryInfo dir in ChildDirs)
  30. {
  31. totalSize += CalculateFolderSize(dir.FullName);
  32. }
  33. //返回文件夹的总容量
  34. return totalSize;
  35. }
  36. //定义一个委托
  37. public delegate long CalculateFolderSizeDelegate(string FolderName);
  38. static void Main(string[] args)
  39. {
  40. //定义一个委托变量引用静态方法CalculateFolderSize
  41. CalculateFolderSizeDelegate d = CalculateFolderSize;
  42. Console.WriteLine( "请输入文件夹名称(例如:C:\\Windows):");
  43. string FolderName = Console.ReadLine();
  44. //通过委托异步调用静态方法CalculateFolderSize
  45. IAsyncResult ret = d.BeginInvoke(FolderName, null, null);
  46. Console.Write ( "正在计算中,请耐心等待");
  47. //每隔2秒检查一次,输出一个“."
  48. while (ret.IsCompleted == false)
  49. {
  50. Console.Write( ".");
  51. System.Threading.Thread.Sleep( 200);
  52. }
  53. //阻塞,等到调用完成,取出结果
  54. long size = d.EndInvoke(ret);
  55. Console.WriteLine( "\n计算完成!\n文件夹{0}的容量为:{1}字节", FolderName, size);
  56. }
  57. }
  58. }
这样,当程序在执行CalculateFolderSize这个异步方法的时候主线程并不是“假死”,而是每隔0.2毫秒输出一个“.",这就是异步调用的妙处!
这里需要用到BeginInvoke的返回值IAsyncResult的IsCompleted这个属性来判断异步线程是否执行结束。

2. 使用轮询等待异步调用完成:使用IAsyncResultAsyncWaitHandle.WaitOne

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. namespace AsyncCalculateFolderSize3
  7. {
  8. class Program
  9. {
  10. //计算指定文件夹的总容量
  11. private static long CalculateFolderSize(string FolderName)
  12. {
  13. if (Directory.Exists(FolderName) == false)
  14. {
  15. throw new DirectoryNotFoundException( "文件夹不存在");
  16. }
  17. DirectoryInfo RootDir = new DirectoryInfo(FolderName);
  18. //获取所有的子文件夹
  19. DirectoryInfo[] ChildDirs = RootDir.GetDirectories();
  20. //获取当前文件夹中的所有文件
  21. FileInfo[] files = RootDir.GetFiles();
  22. long totalSize = 0;
  23. //累加每个文件的大小
  24. foreach (FileInfo file in files)
  25. {
  26. totalSize += file.Length;
  27. }
  28. //对每个文件夹执行同样的计算过程:累加其下每个文件的大小
  29. //这是通过递归调用实现的
  30. foreach (DirectoryInfo dir in ChildDirs)
  31. {
  32. totalSize += CalculateFolderSize(dir.FullName);
  33. }
  34. //返回文件夹的总容量
  35. return totalSize;
  36. }
  37. //定义一个委托
  38. public delegate long CalculateFolderSizeDelegate(string FolderName);
  39. static void Main(string[] args)
  40. {
  41. //定义一个委托变量引用静态方法CalculateFolderSize
  42. CalculateFolderSizeDelegate d = CalculateFolderSize;
  43. Console.WriteLine( "请输入文件夹名称(例如:C:\\Windows):");
  44. string FolderName = Console.ReadLine();
  45. //通过委托异步调用静态方法CalculateFolderSize
  46. IAsyncResult ret = d.BeginInvoke(FolderName, null, null);
  47. Console.Write( "正在计算中,请耐心等待");
  48. while(!ret.AsyncWaitHandle.WaitOne( 2000))
  49. {
  50. //等待2秒钟,输出一个“.”
  51. Console.Write( ".");
  52. }
  53. //阻塞,等到调用完成,取出结果
  54. long size = d.EndInvoke(ret);
  55. Console.WriteLine( "\n计算完成。文件夹{0}的容量为:{1}字节\n", FolderName, size);
  56. }
  57. }
  58. }

 WaitOne的第一个参数表示要等待的毫秒数,在指定时间之内,WaitOne方法将一直等待,直到异步调用完成,并发出通知,WaitOne方法才返回true。当等待指定时间之后,异步调用仍未完成,WaitOne方法返回false,如果指定时间为0,表示不等待,如果为-1,表示永远等待,直到异步调用完成。

3.使用异步回调函数
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. namespace AsyncCalculateFolderSize4
  6. {
  7. class Program
  8. {
  9. //计算指定文件夹的总容量
  10. private static long CalculateFolderSize(string FolderName)
  11. {
  12. if (Directory.Exists(FolderName) == false)
  13. {
  14. throw new DirectoryNotFoundException( "文件夹不存在");
  15. }
  16. DirectoryInfo RootDir = new DirectoryInfo(FolderName);
  17. //获取所有的子文件夹
  18. DirectoryInfo[] ChildDirs = RootDir.GetDirectories();
  19. //获取当前文件夹中的所有文件
  20. FileInfo[] files = RootDir.GetFiles();
  21. long totalSize = 0;
  22. //累加每个文件的大小
  23. foreach (FileInfo file in files)
  24. {
  25. totalSize += file.Length;
  26. }
  27. //对每个文件夹执行同样的计算过程:累加其下每个文件的大小
  28. //这是通过递归调用实现的
  29. foreach (DirectoryInfo dir in ChildDirs)
  30. {
  31. totalSize += CalculateFolderSize(dir.FullName);
  32. }
  33. //返回文件夹的总容量
  34. return totalSize;
  35. }
  36. public delegate long CalculateFolderSizeDelegate(string FolderName);
  37. private static CalculateFolderSizeDelegate task = CalculateFolderSize;
  38. //用于回调的函数
  39. public static void ShowFolderSize(IAsyncResult result)
  40. {
  41. long size = task.EndInvoke(result);
  42. Console.WriteLine( "\n文件夹{0}的容量为:{1}字节\n", (String)result.AsyncState, size);
  43. }
  44. static void Main(string[] args)
  45. {
  46. string FolderName;
  47. while ( true)
  48. {
  49. Console.WriteLine( "请输入文件夹名称(例如:C:\\Windows),输入quit结束程序");
  50. FolderName = Console.ReadLine();
  51. if (FolderName == "quit")
  52. break;
  53. task.BeginInvoke(FolderName, ShowFolderSize, FolderName); //第一个参数是异步函数的参数,第二个参数是回调函数,第三个参数是回调函数的参数,回调函数会在异步函数执行结束之后被调用。
  54. }
  55. }
  56. }
  57. }
这个例子中通过循环的输入文件夹名称计算文件夹容量,计算的操作放在异步调用函数中,因此我们在输入下一个文件夹名称时不必等待上一个计算结束,异步函数执行完成之后会自动调用回调函数ShowFolderSize进行结果处理。
(今天就学到这里,下午去嘉禾看期待已久的3D《复仇者联盟》,吼吼......)
2012/5/20 23:05补充

对于上面最后一个异步回调的例子有一个缺陷,就是当异步调用的函数与主线程都需要访问同一资源时,要注意解决资源共享的问题。如下图:

修改程序如下:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. namespace AsyncCalculateFolderSize6
  6. {
  7. class Program
  8. {
  9. //计算指定文件夹的总容量
  10. private static long CalculateFolderSize(string FolderName)
  11. {
  12. if (Directory.Exists(FolderName) == false)
  13. {
  14. throw new DirectoryNotFoundException( "文件夹不存在");
  15. }
  16. DirectoryInfo RootDir = new DirectoryInfo(FolderName);
  17. //获取所有的子文件夹
  18. DirectoryInfo[] ChildDirs = RootDir.GetDirectories();
  19. //获取当前文件夹中的所有文件
  20. FileInfo[] files = RootDir.GetFiles();
  21. long totalSize = 0;
  22. //累加每个文件的大小
  23. foreach (FileInfo file in files)
  24. {
  25. totalSize += file.Length;
  26. }
  27. //对每个文件夹执行同样的计算过程:累加其下每个文件的大小
  28. //这是通过递归调用实现的
  29. foreach (DirectoryInfo dir in ChildDirs)
  30. {
  31. totalSize += CalculateFolderSize(dir.FullName);
  32. }
  33. //返回文件夹的总容量
  34. return totalSize;
  35. }
  36. //定义一个委托
  37. public delegate long CalculateFolderSizeDelegate(string FolderName);
  38. private static CalculateFolderSizeDelegate d = new CalculateFolderSizeDelegate(CalculateFolderSize);
  39. //用于回调的函数
  40. public static void ShowFolderSize(IAsyncResult result)
  41. {
  42. try
  43. {
  44. long size = d.EndInvoke(result);
  45. while (Console.CursorLeft != 0) //只有用户不输入,且光标位于第一列时,才输出信息。
  46. {
  47. //等待2秒
  48. System.Threading.Thread.Sleep( 2000);
  49. }
  50. Console.WriteLine( "\n文件夹{0}的容量为:{1}字节\n", (String)result.AsyncState, size);
  51. }
  52. catch (DirectoryNotFoundException e)
  53. {
  54. Console.WriteLine( "您输入的文件夹不存在");
  55. }
  56. }
  57. static void Main(string[] args)
  58. {
  59. string FolderName;
  60. while ( true)
  61. {
  62. Console.WriteLine( "请输入文件夹名称(例如:C:\\Windows),输入quit结束程序");
  63. FolderName = Console.ReadLine();
  64. if (FolderName == "quit")
  65. break;
  66. d.BeginInvoke(FolderName, ShowFolderSize, FolderName);
  67. }
  68. }
  69. }
  70. }

个人代码:

    class Program{public delegate string MyTestDelegate(string str);static void Main(string[] args){string param = "123";MyTestDelegate d = Method;AsyncCallback callBkcak = MethodCallKback;IAsyncResult result = d.BeginInvoke(param, callBkcak, param);string returnValue = d.EndInvoke(result);Console.WriteLine(returnValue);Console.ReadKey();}private static string Method(string str){Console.WriteLine("异步操作开始了!" + "你传入的参数是:" + str);return "异步操作反回了一段话给你!";}private static void MethodCallKback(IAsyncResult result){Console.WriteLine("回调函数传入参数:" + (string)result.AsyncState);Console.WriteLine("异步操作结束了!");}}
以下是输出内容:




http://chatgpt.dhexx.cn/article/gG913mlw.shtml

相关文章

C# 异步委托 BeginInvoke EndInvoke

1. 简单主线程中委托: static void Main(string[] args) {//定义一个委托&#xff0c;并初始化Func<int, int, string> delFunc (a, b) > (a b).ToString();//黄色底纹部分换成{ return (a b).ToString(); }更好理解//同步方法调用&#xff08;跟调用一个方法一样…

Invoke and BeginInvoke

本文转自&#xff1a;http://www.cnblogs.com/worldreason/archive/2008/06/09/1216127.html 在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate&#xff0c;至于委托的本质请参考我的另一随笔&#xff1a;对.net事件的看法。 一、为什么Control类提供了Invoke和…

C# Thread Delegate MethodInvoker Invoke BeginInvoke 关系

异步调用是CLR为开发者提供的一种重要的编程手段&#xff0c;它也是构建高性能、可伸缩应用程序的关键。在多核CPU越来越普及的今天&#xff0c;异步编程允许使用非常少的线程执行很多操作。我们通常使用异步完成许多计算型、IO型的复杂、耗时操作&#xff0c;去取得我们的应用…

C#中Delegate/Control的Invoke/BeginInvoke/EndInvoke

目录 一、前言 二、背景 三、Delegate的Invoke/BeginInvoke/EndInvoke 1、基于[需求1] 1.1、直接在主线程中运行“耗时操作” 1.2、通过Thread将“耗时操作”放在子线程中运行 1.3、通过Delegate.BeginInvoke()将“耗时操作”放在子线程中运行 1.4、总结 2、基于[需求…

Invoke和BeginInvoke理解

在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate&#xff0c;至于委托的本质请参考我的另一随笔&#xff1a;对.net事件的看法。 一、为什么Control类提供了Invoke和BeginInvoke机制&#xff1f; 关于这个问题的最主要的原因已经是dotnet程序员众所周知的&…

C#的Invoke与BeginInvoke区别

【分析】浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别&#xff08;SamWang&#xff09; 今天无意中看到有关Invoke和BeginInvoke的一些资料&#xff0c;不太清楚它们之间的区别。所以花了点时间研究了下。 据msdn中介绍&#xff0c;它们最大的区别就是Be…

c# Invoke和BeginInvoke 区别详解

Control.Invoke 方法 (Delegate):在拥有此控件的基础窗口句柄的线程上执行指定的委托。 Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句柄所在线程上异步执行指定委托。 以下为实际应用中碰到的问题&#xff0c;在主线程中启动一个线程&#xff0c;然后在这个线程…

C# beginInvoke

摘要 异步这东西&#xff0c;真正用起来的时候&#xff0c;发现事情还是挺多的&#xff0c;最近在项目中用到了异步的知识&#xff0c;发现对它还是不了解&#xff0c;处理起来&#xff0c;走了不少弯路。觉得还是补一补还是很有必要的。 MSDN原文地址&#xff1a;https://ms…

[C#基础]c#中的BeginInvoke和EndEndInvoke

摘要 异步这东西,真正用起来的时候,发现事情还是挺多的,最近在项目中用到了异步的知识,发现对它还是不了解,处理起来,走了不少弯路。觉得还是补一补还是很有必要的。 MSDN原文地址:https://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.110).aspx 正文 .Net framewo…

C# BeginInvoke实现异步编程

C# BeginInvoke实现异步编程 BeginInvoke实现异步编程的三种模式&#xff1a; 1.等待模式 在发起了异步方法以及做了一些其他处理之后&#xff0c;原始线程就中断并且等异步方法完成之后再继续&#xff1b; eg&#xff1a; using System; using System.Collections.Generic;…

This.invoke和this.begininvoke的区别?

应用场景 在多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误的做法,Invoke和BeginInvoke就是为了解决这个问题。 个人总结 ①This.begininvoke和this.invoke注册委托调用的方法都是等UI主线程执行到“windows消息泵”的时候才…

C#——invoke和begininvoke 区别

invoke和begininvoke 区别 一直对invoke和begininvoke的使用和概念比较混乱&#xff0c;这两天看了些资料&#xff0c;对这两个的用法和原理有了些新的认识和理解。 首先说下&#xff0c;invoke和begininvoke的使用有两种情况&#xff1a; 1. control中的invoke、begininvoke。…

C#Invoke和BeginInvoke应用详解

最近&#xff0c;在研究Invoke的使用&#xff0c;但是真的是一头雾水&#xff0c;网上看了很多资料&#xff0c;感觉还是看不懂&#xff0c;因为对于入门级的小白&#xff0c;想像不出Invoke的应用场景&#xff0c;更谈不上如何用了&#xff1f; 1、Invoke到底是什么&#xff…

Java工作流框架:探索流程引擎的实现和应用

目前&#xff0c;市面上有很多基于SpringBootVue前后端分离的Java快速开发框架和工作流开发框架可供选择。以下是一些比较流行的框架&#xff1a; 1. Spring Cloud&#xff1a;Spring Cloud是一套基于Spring Boot的开发工具&#xff0c;用于快速构建分布式系统中的服务。它利用…

Java工作流框架和应用场景

一&#xff1a;Java工作流框架是一种用于设计、执行和管理工作流程的技术。以下是几个常见的Java工作流框架&#xff1a; Activiti&#xff1a;Activiti是一款流行的开源Java工作流引擎&#xff0c;它基于BPMN 2.0标准&#xff0c;支持复杂的工作流程设计和管理。Activiti具有高…

工作流使用

#&#x1f33b; 工作流使用 无需开发代码&#xff0c;即可快速创建工作流、表单&#xff0c;并完成审批、监控等操作。 #功能脑图 #特点 基于 Flowable&#xff08;Activiti&#xff09;生来具有的稳定工作流引擎。使用flowable官方流程设计器&#xff0c;功能强大&#xff…

工作流 开源(java工作流框架jbpm)

工作流(工作流) :“在部分或整个业务流程的计算机应用环境中实现自动化” l简单来说&#xff0c;就是用程序管理工作流程&#xff0c;以表格审核和任务处理为主体&#xff0c;实现办公室自动化 工作流帮助器管理业务流程&#xff0c;业务操作保持不变。 工作流是通知流程&…

java工作流开源框架可以提高工作效率吗?

要想回答这个问题&#xff0c;就需要了解什么是java工作流开源框架&#xff0c;以及java工作流开源框架的主要特点是什么。随着大数据时代的拓展发展&#xff0c;低代码开发平台已经在数字化管理时代中深受欢迎&#xff0c;是做好数据管理和提升企业数字化发展步伐的重要工具。…

Java开源 开源工作流

Willow 点击次数&#xff1a;18942 由Huihoo Power开发详细可到其中文主页查看。 OpenWFE 点击次数&#xff1a;17672 OpenWFE是一个开放源码的Java工作流引擎。它是一个完整的业务处理管理套件&#xff1a;一个引擎&#xff0c;一个工作列表&#xff0c;一个Web界面和一个…

Java实现自定义工作流

这篇文章实现java自定义工作流程&#xff0c;对工作流不太熟悉的可以先看下工作流相关文章&#xff1a; 工作流 相关表结构、实体创建 流程主表&#xff1a;tbl_workflow_requestbase&#xff08;这里以项目工地工作流为例&#xff09; CREATE TABLE tbl_workflow_requestba…