当前位置: 首页 > 编程日记 > 正文

工作流编程循序渐进(9:使用本地服务在宿主和工作流之间通信)

工作流编程循序渐进(9:使用本地服务在宿主和工作流之间通信


作者  朱先忠

[摘要]

      在本篇中,首先详细分析本地服务有关概念,探讨本地服务在工作流运行时、工作流实例及工作流宿主间的地位及作用。然后,通过一个简单的例子来说明使用本地服务在宿主和工作流之间的具体通信方法。

一、简介

      WWF中的服务可分为核心服务和本地服务。核心服务由WWF定义,而本地服务(也称为“数据交换服务”)则是开发人员自定义的。本地服务可以是任何想在WWF中实现的服务,通常的用处是:使用本地服务在工作流实例与宿主之间进行通信。比如,数据最初从宿主应用程序的某个运行结果中传入工作流,工作流实例在处理完数据后返还给宿主。
      在本篇中,我想首先详细分析本地服务有关概念,探讨本地服务在工作流运行时、工作流实例及工作流宿主间的地位及作用。然后,通过一个简单的例子来说明使用本地服务在宿主和工作流之间的具体通信方法。

二、与本地服务相关的两个重要活动-HandleExternalEventActivityCallExternalMethodActivity

      首先,让我们看一下MSDN中有关解释。
Windows Workflow Foundation支持工作流的承载环境中的本地通信和使用 Web 服务在工作流之间进行的通信。

有关在工作流中使用 Web 服务的实例,将在后面文章中陆续给出。

WWF工作流通信服务向工作流开发人员公开了一个用户自定义服务类,通过在此服务类中定义一系列的方法和事件处理程序,以达到简化工作流与宿主间数据通信的建模目的。
      实际开发中,实现本地服务的目的要根据当前应用程序的需求来定,比如需要查询或设置应用程序的状态,从数据库获取或更新数据,或者是与其他不属于工作流的对象组件进行通信,等等。当将功能实现为本地服务后,本地服务对多个工作流实例都可以有效。
下图演示本地(通信)服务如何与其主机(也称“宿主”,即Host)应用程序之间进行通信(图片改编自MSDN)。
本地主机通信

      从上图中可以看出,工作流实例上的定义的两个活动HandleExternalEventActivityCallExternalMethodActivity活动(也就是说,典型情况下,在创建我们的工作流时需要加入这两个“特殊”的活动)的任务是:与在自定义接口(请看本文后面的介绍)中声明并在自定义本地服务中实现的事件和方法交互。
      具体来看,[1]HandleExternalEventActivity 活动响应由主机应用程序引发且由本地服务实现的特定事件。 [2]CallExternalMethodActivity负责调用本地服务中定义的方法。
      有关两个活动HandleExternalEventActivityCallExternalMethodActivity活动,请继续阅读下面来自于MSDN的重要解释。

来自MSDN:
[1]HandleExternalEventActivity 活动与  CallExternalMethodActivity 活动结合使用,可输入或输出与本地服务的通信。 可以直接对一般通信使用这些活动。 或者,可以创建 HandleExternalEventActivity 和 CallExternalMethodActivity 类的子类,以创建严格绑定到某个接口上的特定事件和方法的活动,并具有  ExternalDataExchangeAttribute 属性。
     
      HandleExternalEventActivity 基类阻止工作流,直到通过 WorkflowRuntime 注册的相应本地服务引发由 InterfaceType 和 EventName 属性指定的事件。 引发该事件后,或者如果该事件在活动开始执行前引发,则将传入数据分配给在 ParameterBindings 集合中定义的绑定位置。
 
       [2]CallExternalMethodActivity 活动和 HandleExternalEventActivity 活动可用于与本地服务进行输入和输出通信。 您可以直接使用这些活动进行一般通信,也可以创建 CallExternalMethodActivity 和 HandleExternalEventActivity类的子类以创建一些活动,这些活动严格绑定到具有 ExternalDataExchangeAttribute属性的接口上的特定事件和方法。
 
      CallExternalMethodActivity 基类调用由向 WorkflowRuntime 注册的相应本地服务的 InterfaceType 和 MethodName 属性指定的方法。 此调用是使用从绑定位置的 ParameterBindings 集合中收集的参数以同步方式执行的。 如果该方法具有返回值,则会在活动执行完毕前将这些值设置为绑定位置。


三、局部步骤归纳

    为了让工作流运行时与本地服务进行交互,需要完成如下步骤:
    (1)使用标准的C#接口定义一个服务契约(你必须先定义符合这一特征的一个接口),在该接口中定义工作流实例中可以使用的方法和事件。
    (2)在接口前面修饰以ExternalDataExchangeAttribute特性,使该接口能被识别为一个本地服务接口。
接口定义举例(来自MSDN):
[ExternalDataExchange]
public interface ICommunicationService
{
void HelloHost(string message);
event EventHandler<ExternalDataEventArgs> HelloWorkflow;
}


    (3)编写一个实现了第2步定义的接口的标准C#类(即自定义本地服务类)。
自定义本地服务类举例(来自MSDN)
public class CommunicationService : ICommunicationService
{
public event EventHandler<ExternalDataEventArgs> HelloWorkflow;

public void HelloHost(string message)
{
Console.WriteLine("This is the message: {0}", message);

//引发HelloWorkflow事件
HelloWorkflow(null, new
ExternalDataEventArgs(WorkflowEnvironment.WorkflowInstanceId));
}
}

    (4)创建一个系统提供的本地服务类ExternalDataExchangeService的实例,再创建上面自定义服务类的实例,把本地服务类ExternalDataExchangeService的实例添加到工作流运行时引擎中,然后把自定义服务类的实例加载到本地服务类ExternalDataExchangeService的实例中。这个过程需要在工作流运行时引擎初始化期间(在正式启动工作流之前)进行创建。
   
在启动工作流之前需要完成的任务示例:
ExternalDataExchangeService externalService = new ExternalDataExchangeService();
workflowRuntime.AddService(externalService);
externalService.AddService(new CommunicationService());

      注意:所有本地服务必须经由接口类型进行唯一的识别。也就是说,每个服务接口仅允许有一个实例。但是可以在工作流运行时引擎中注册多个本地服务,只要每个服务实现了不同的接口。
注意:因为每个服务只能具有单个实例,因而有可能有多个工作流实例同时调用服务中的方法和事件。因此在设计时需要考虑线程安全的数据访问问题。

    当本地服务向工作流运行时引擎注册后,便可以被任何工作流引擎使用。有两种方法可以调用本地服务中的方法。
  [1]使用GetService()方法获取服务的引用,并调用定义在服务接口中的方法。
  [2]使用CallExtemalMethodActivity活动以声明性方式调用一个方法,使之作为工作流的一个步骤。当使用工作流时,不需要工作流或者是活动的代码。

四、案例分析


一)创建控制台顺序工作流示例框架

说明:本文创建的LocalServiceDemo示例演示了如何在一个状态机工作流内部调用另外的一个工作SubWorkflow,并且定义了本地服务接口实现,使用HandleExternalEvent活动调用外部事件以等待被调用的工作流实例执行完成。该活动需要等待一个事件的触发才能够继续工作流的运行,而在Program.cs中,设置了只有当指定非宿主工作流执行完毕后,才触发事件。因此这实现了一种等待被调用工作流执行完成才继续执行的效果。

请遵循如下步骤创建一个控制台状态机工作流示例程序:
1. 启动VS2008,单击菜单”文件“|”新建“|”项目“,选择“Sequential Workflow Console Application”
模板创建一个名字为LocalServiceDemo的控制台状态机工作流示例程序。
2.之后,系统自动打开工作流设计器界面。
3. 从工具箱中拖动几个活动到工作流设计器中得到如图所示的情形。
File?id=d25b9pk_297dxz5hjdj_b

在上图中,我们依次把三个活动:Code,CallExternalMethod和Listen拖动到工作流设计器中,其他没有作任何更改,具体的修改操作将在后面步骤中给出。

(二)创建自定义事件参数类


创建自定义事件参数类(用于在宿主与工作流间传递参数之用):

class CustomServiceEventArgs:ExternalDataEventArgs
{
    private string name;
    //这个公共属性用于在宿主与工作流间传递参数之用,可以是复杂的类,也可以是简单的字符串
    public string Name
    {
        get { return this.name; }
    }

    public CustomServiceEventArgs(Guid instanceID, string name)
        : base(instanceID)
    {
        this.name = name;
    }
}




(三)定义本地服务接口


本地服务接口定义:
[ExternalDataExchange]
internal interface ICustService
{
    event EventHandler<CustomServiceEventArgs> Approved;
    event EventHandler<CustomServiceEventArgs> Rejected;

    void CreateBallot(string name);//产生一次新的投票

}




(四)定义本地服务类


IVotingService接口的类。该类将实现CreateBallot(),并触发这两个事件,代码如下所示。

定义本地服务类:
internal class CustServiceImpl : ICustService
{

    #region ICustService 成员

    public event EventHandler<CustomServiceEventArgs> Approved;

    public event EventHandler<CustomServiceEventArgs> Rejected;

    public void CreateBallot(string name)
    {
        Console.WriteLine("现在为{0}投票。", name);
        ShowDlg(new CustomServiceEventArgs(WorkflowEnvironment.WorkflowInstanceId, name));
    }
    #endregion

    public void ShowDlg(CustomServiceEventArgs args)
    {
        DialogResult result;
        string name = args.Name;

        result = MessageBox.Show(string.Format("是否同意,{0}", name),
            string.Format("当前为{0}投票", name), MessageBoxButtons.YesNo);

        if (DialogResult.Yes == result)
        {
            EventHandler<CustomServiceEventArgs> approved = this.Approved;
            if (approved != null)
                approved(null, args);
        }
        else
        {
            EventHandler<CustomServiceEventArgs> rejected = this.Rejected;
            if (rejected != null)
                rejected(null, args);
        }
    }
}

[注意]为了使用MessageBox和DialogResult,需要在项目上右击“引用”菜单,添加对System.Windows.Forms的引用。


(五)工作流编程


1. 添加CallExtemalMethodActivity活动

进入工作流设计视图,首先添加一个CallExtemalMethodActivity。该活动的InterfaceType被设置为ICustService,指定方法名为CreateBallot,可以在属性窗口中使用弹出式窗口选择InterfaceType,如图所示。此外,MethodName属性列出可用的方法名称供应用进行选择,选择接口中声明的方法“CreateBallot”。

[注意]后面还要进一步这个CallExtemalMethodActivity修改活动。

File?id=d25b9pk_298cc45qjfn_b


File?id=d25b9pk_299cxjhqxcg_b


2. 添加ListenActivity活动

然后,在CallExtemalMethodActivity的下面添加一个ListenActivity。有关ListenActivity活动,我们后面还会专门撰文探讨。在此只需了解,ListenActivity是一个组合活动,该活动将在活动继续前使工作流等待多个可能事件中的任何一个事件发生。
然后,在ListenActivity活动中,添加2个HandleExternalEventActivity活动,分别使之负责监听接口ICustService中的Approved和Rejected两个事件。
当然,HandleExternalEventActivity也需要指定InterfaceType属性,如下图所示。
File?id=d25b9pk_300dc9mbbcm_b

然后分别指定2个HandleExternalEventActivity活动的EventName属性为ICustService中定义的Approved和Rejected两个事件,如下面二图所示。
File?id=d25b9pk_301snsdvbdm_b

File?id=d25b9pk_302hgzd4wgg_b

到目前为止,工作流设计视图如下图所示。

File?id=d25b9pk_303ctxjdrgz_b

3. 在工作流类中定义公共属性

目前为止,我们必须强调:在工作流类中需要定义了一个公共属性,以便于接收从宿主传入的投票人信息,代码如下所示。
///定义了一个公共根属性,以便于接收从宿主传入的投票人信息。
//定义一个表示投票人姓名信息的属性
private string votername;
public string VoterName
{
    set { this.votername = value; }
    get { return this.votername; }
}



4. 进一步修改CallExternalMethodActivity活动

要想使外部方法获取到工作流实例中传入的参数信息,需要进一步修改CallExternalMethodActivity活动的属性值,单击CallExternalMethodActivity活动的属性对话框中的name属性(而不是(Name)属性!!!),弹出如下图所示的对话框:
File?id=d25b9pk_307fnn27s5c_b

从图中选择前面定义的属性VoterName,单击“确定”按钮,得到如下图所示的属性对话框。
File?id=d25b9pk_308df9hz8ck_b


最后,我们来看一下控制台宿主的编程内容。

(六)控制台宿主编程

最后,需要在工作流运行时引擎中注册本地服务,并且为工作流实例传递参数。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;

using System.Workflow.Activities;//ExternalDataExehangeService
namespace LocalServiceDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
            {

                //加载本地服务
                ExternalDataExchangeService dataService = new ExternalDataExchangeService();
                workflowRuntime.AddService(dataService);

                //将自定义的本地通信服务加载到本地服务中
                CustServiceImpl ls = new CustServiceImpl();
                dataService.AddService(ls);

                AutoResetEvent waitHandle = new AutoResetEvent(false);
                workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
                {
                    waitHandle.Set();
                };
                workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
                {
                    Console.WriteLine(e.Exception.Message);
                    waitHandle.Set();
                };

                //向工作流实例传递参数,注意格式
                Dictionary<string, object> paras = new Dictionary<string, object>();
                paras.Add("VoterName", "爱因斯坦");

                WorkflowInstance instance = workflowRuntime.CreateWorkflow(
                    typeof(LocalServiceDemo.Workflow1),paras );
                instance.Start();

                waitHandle.WaitOne();

                Console.Read();
            }
        }
    }
}



注意,在上面控制台程序中代码没有特殊的内容,开始时的加载本地服务编码在以前的文章中已经作过介绍。接下来,后面的代码基本是系统自动生成的。

最后,请注意向工作流实例传递参数的格式

总体来看,上面的代码关键之处还在于前面的围绕本地服务的编程,以及工作流中相应活动的关联设置方面。而本篇编程逻辑的根本在于深入理解工作流运行时与本地服务进行交互的原理,以及理解工作流编程中的HandleExternalEventActivity CallExternalMethodActivity两个活动的重要作用。

(七)观察运行结果

按F5运行控制台程序,一般顺利的话,将得到如下图所示运行时快照。
File?id=d25b9pk_309c7sfbzx5_b
单击“是”按钮后,得到如下结果:
File?id=d25b9pk_310gdwt63cm_b

最后一句:本篇是实战环境下比较重要的一篇,必须理解透彻,烂熟于心。

五、部分参考资料

1.《如何:发布符合 .NET Framework 准则的事件(C# 编程指南)》(http://msdn.microsoft.com/zh-cn/library/w369ty8x.aspx)。






相关文章:

使用Properties连接数据库

使用Properties连接数据库 要注意的是&#xff1a; 1.通过配置文件来连接数据库时&#xff0c;连接信息要以 mysql.XXX开头,否则会提示异常。 java.sql.SQLException: Access denied for user localhost (using password: YES)生成配置文件的实现代码 1、创建写入配置信息工…

两边横线,中间标题

<!DOCTYPE html> <html> <head> <title>两边横线&#xff0c;中间标题</title> <meta http-equiv"Content-Type" content"text/html; charsetutf-8" /> <style type"text/css"> <!--ul { mar…

交换机基础配置

请同学们下载附件中的实验并完成。转载于:https://blog.51cto.com/coffee0546/204093

python高级-模块(14)

一、python中的模块 有过C语言编程经验的朋友都知道在C语言中如果要引用sqrt函数&#xff0c;必须用语句#include <math.h>引入math.h这个头文件&#xff0c;否则是无法正常进行调用的。 那么在Python中&#xff0c;如果要引用一些其他的函数&#xff0c;该怎么处理呢&am…

RabbitMQ学习系列二:.net 环境下 C#代码使用 RabbitMQ 消息队列

上一篇已经讲了Rabbitmq如何在Windows平台安装&#xff0c;不懂请移步&#xff1a;RabbitMQ学习系列一&#xff1a;windows下安装RabbitMQ服务 一、理论&#xff1a; .net环境下&#xff0c;C#代码调用RabbitMQ消息队列&#xff0c;本文用easynetq开源的.net Rabbitmq api来实…

一步步学会使用ASP.NET 4 WEB应用程序中使用URL Routing(翻译)

创建路由 路由就是将URL路径映射到具体的物理文件。若要将路由添加到网站中&#xff0c;请使用 RouteCollection.MapPageRoute 方法将它们添加到RouteTable类的静态Routes属性。 将用于添加路由的方法添加到 Global.asax 文件中 如果网站还没有 Global.asax 文件&#xff0c;…

Properties持久的属性集

Properties 属性集合继承了Hashtable 属性包括属性名和属性值&#xff08;键值对keyvalue&#xff09; 作用 可以存储多个键值&#xff0c;与map相似可以把键值对存储到文件中可以把文件中的键值对读取到Properties对象中 构造方法&#xff1a; Properties() 创建一个无默认…

让你二十年后仍是人才

1.不管坐什么位置&#xff0c;都要保持学习的习惯出社会工作十年到十五年左右&#xff0c;会有一种「上下卡住」的闭塞感与无力感。因为&#xff0c;这个阶段的上班族虽然拥有一定的资历与经验&#xff0c;工作也得心应手&#xff0c;但上面有比自己更资深的前辈压着&#xff0…

Django ORM操作

Django ORM操作 一般操作 看专业的官网文档&#xff0c;做专业的程序员&#xff01; 必知必会13条 <1> all(): 查询所有结果<2> get(**kwargs): 返回与所给筛选条件相匹配的对象&#xff0c;返回结果有且只有一个&#xff0c;如果符合筛选…

ChineseCalendar类[转]

///<summary>///Title: ChineseCalendar类 ///Description: 中文日期工具类 ///author 万灵杰[作者] ///version 1.0.0.0 ///date 2009年7月30日 ///modify ///date ///</summary>publicclassChineseCalendar { privatestaticrea…

程序员的自我救赎---13.1:职场招聘与面试心得

《前言》 《目录》 &#xff08;一&#xff09; Winner2.0 框架基础分析 &#xff08;二&#xff09;PLSQL报表系统 &#xff08;三&#xff09;SSO单点登录 &#xff08;四&#xff09; 短信中心 &#xff08;五&#xff09;钱包系统 &#xff08;六&#xff09;GPU支付中心 &…

网络编程 UDP通信的过程 TCP通信过程 多线程文件上传

网络概述 协议 在网络之间传出数据时需要按照指定的标准来传输&#xff0c;标准中规定了数据的格式、大小、传输的方式、传输速率。形成统一规范—>按照规范开发的代码—>协议&#xff08;应用层、传输层、网络层、链路层&#xff09; InetAddress类 用来分装网络地址…

set debug mode for flex builder

1. 要具备debug功能&#xff0c;我们必须要首先安装Flash Player Debug 版本。windows版本2. 安装好debug版本后&#xff0c;我们还需要添加日志的配置文件mm.cfg。该配置文件存放的目录如下&#xff1a;Macintosh OS X MacH D:Library:Application Support:macromedia:mm.cfgM…

XML 解析XML文档 XML约束

XML 什么是XML Extensible Markup Language&#xff08;可扩展的标记语言&#xff09;他是一个语言&#xff0c;有自己的语法&#xff0c;和Java以及其他的编程无关“标记” 在文件中包含类似于张三 &#xff0c;这种用尖括号括起来的叫标记&#xff0c;使用来标记数据的。标…

Host Only、NAT和Bridge三种网络连接

Host Only、NAT和Bridge三种网络连接 在安装好了Linux镜像之后&#xff0c;如何连接物理机和虚拟机呢&#xff1f;这就需要网络连接&#xff0c;网络连接有三种&#xff1a;HostOnly、NAT、Bridge&#xff0c;它们都可用于Guest虚拟机和Host物理机之间的网络通信。 一、三者的不…

OSPF 提升 一 ----基础

ospf ccnp内容 一 link-state protocols IGP 开放式的最短路径优先协议 公有协议支持中到大型的网络 spf算法 链路状态协议1.传送的LSA link status advertisement 链路状态通告 包换拓扑信息具体包括&#xff1a;网段的前缀 掩码 连接的路由器的…

C#实现网页截图功能

//需要添加System.Drawing及System.Windows.Forms引用 using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Windows.Forms; namespace 网页截图 { class Program { [S…

微软发布全新多核心操作系统原型:Barrelfish

Windows 7完成之后&#xff0c;很多人开始把目光投向微软的下一代服务器和客户端操作系统Windows 8&#xff0c;不过今天微软放出了一套全新操作系统的原型&#xff0c;开发代号“Barrelfish”。该系统由微软剑桥研究院和苏黎世理工学院联合全新开发&#xff0c;专为现在和未来…

Docker应用:Kubernetes(容器集群)

Docker应用&#xff1a;Kubernetes&#xff08;容器集群&#xff09; 原文:Docker应用&#xff1a;Kubernetes&#xff08;容器集群&#xff09;阅读目录&#xff1a; Docker应用&#xff1a;Hello WorldDocker应用&#xff1a;Docker-compose&#xff08;容器编排&#xff09;…

通道应用——抠头发

通道应用——抠头发 原图&#xff1a; 效果图&#xff1a; 步骤&#xff1a;1、打开原图的“通道面板”&#xff0c;选择颜色对比分明的绿色通道&#xff0c;并新建一个绿色通道副本&#xff1b;2、选择“图像”-“调整”-“色阶”&#xff0c;调节色阶使得头发颜色更分明些&am…

2017 ACM/ICPC 南宁赛区小结 By JSB @ Reconquista

Statistics TYPE: Onsite ContestNAME: 2017 - ICPC - Asia NanningPLAT: pc^2TIME: 2017/11/26 09:00-14:00LOCA: Guangxi UniversityTEAM: Reconquista[shb,lsmll,jsb]RANK: 8/227 3.52%SOLVE: 8/13PENALTY: 451 ◦ A - 1 ◦ E - 123 (2) ◦ F - 8 ◦ H - 55 ◦ I - 97 (1) ◦…

用户管理系统控制台版连接数据库

建User表 CREATE TABLE user (id INT(11) NOT NULL AUTO_INCREMENT,name VARCHAR(20) DEFAULT NULL,pwd VARCHAR(20) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEINNODB AUTO_INCREMENT5 DEFAULT CHARSETutf8User对象&#xff08;javaBean&#xff09; public class User {priva…

微信小程序组件 日历

js文件 use strict;let choose_year null,choose_month null;const conf {data: {hasEmptyGrid: false,showPicker: false},onLoad() {const date new Date();const cur_year date.getFullYear();const cur_month date.getMonth() 1;const weeks_ch [ 日, 一, 二, 三, …

node编写定时任务,for循环只执行一遍的解决办法

在用node编写定时任务时候&#xff0c;发现for循环只执行i0这一次&#xff0c;就不接着循环执行了&#xff0c;下面贴上代码&#xff1a; exports.task async function(ctx){ let { app } ctx, resultArr1 [],//查询的数据库数据 resultArr2 [];//查询的数据库…

oledb读不到dbf文件内容

最近在处理一批VFP的数据库&#xff0c;使用OleDB方式读取一直很正常&#xff0c;前两天突然碰到一张表怎么也读不出数据来&#xff0c;害我瞎忙了一整天&#xff0c;在研究了DBF文件结构后发现记录前的0x20位置存储的是0x2A。 一查才知道是删除标记&#xff0c;我倒&#xff0…

好用的截图工具

好用的截图工具...简单好用而且不大转载于:https://blog.51cto.com/dd123/208983

“AS3.0高级动画编程”学习:第二章转向行为(上)

因为这一章的内容基本上都是涉及向量的&#xff0c;先来一个2D向量类&#xff1a;Vector2D.as (再次强烈建议不熟悉向量运算的童鞋&#xff0c;先回去恶补一下高等数学-07章空间解释几何与向量代数.pdf) package {import flash.display.Graphics;public class Vector2D {privat…

用Azure VM + Azure Database for MySQL搭建Web服务

仍然是一篇动手实验&#xff0c;实验演示如何在Azure的虚拟机内部署一个Web服务器&#xff0c;并且使用Azure Mysql PaaS作为本应用的数据库。此实验的目的一方面是为了演示Azure IaaS层和PaaS服务配合使用的常规操作&#xff0c;另一方面是为之后的文章打基础&#xff0c;后续…

C3P0_and_pro.properties配置文档代码

C3P0-config.xml配置文件 <c3p0-config> <!-- 默认配置&#xff0c;如果没有指定则使用这个配置 --> <default-config><property name"driverClass">com.mysql.jdbc.Driver</property><property name"jdbcUrl">jdbc:…

电视信号——行场同步

电视信号分NTSC制和PAL制两种制式, NTSC制每秒刷新60次, 而PAL制每秒刷新50次。 水平消隐&#xff1a;电子枪从左到右画出象素&#xff0c;它每次只能画一条扫描线&#xff0c;画下一条之前要先回到左边并做好画下一条扫描线的准备&#xff0c;这之间有一段时间叫做水平消隐&am…