精华内容
下载资源
问答
  • Flex与Java的简易消息推送机制举例-

    万次阅读 2011-12-19 15:51:30
    Flex与Java的简易消息推送机制举例 使用adobe提供的java flex通信包blazeDS中提供的推送功能实现Java到Flex的数据推送过程 1. 从adobe官网下载blazeds.war,这是一个压缩包,里面的包含META-INF和WEB-INF两个文件夹...

    Flex与Java的简易消息推送机制举例

    使用adobe提供的java flex通信包blazeDS中提供的推送功能实现Java到Flex的数据推送过程

    1.        从adobe官网下载blazeds.war,这是一个压缩包,里面的包含META-INF和WEB-INF两个文件夹,目录结构如下:其中含META-INF仅包含MANIFEST.MF文件, WEB-INF中包含classes、flex、lib及src四个文件夹,其中flex文件夹中包含四个配置文件,lib中包含java和flex通讯所需要的jar包。

    Flex文件夹中包含:

    Lib文件夹包含:

    2.        创建Java后台的推送服务项目

    新建一个DynamicWeb Project,如:JavaPushServer

    点击Next

    点击Next

    点击Finish,这时候创建了一个空的动态web项目,使用Tomcat6运行.这时候Eclipse中的见到的项目信息如下:Java Resources中的src为java源代码,Libraries中为java运行所依赖的jar包,如果已经配置好了Tomcat运行环境,则Apache Tomcat v6.0…目录下自动加载了Tomcat的jar包,和JRE System Library目录下的jar包

    因为通讯需要blazeds,所以,这时候,可以将blazeds.war解压出来的两个文件夹替换掉刚才创建的web工程中WebContent文件目录下的内容.替换之后可以看到WebContent文件夹下内容变化情况:

    以及Java Sources中的Libraries中Web App Libraries中增加了很多jar包,这些就是blazeds.war中所包含的jar包

    引入blazeds.war之后,开始写Java代码:

    创建名为Tick的java实体类:

    package com.eunut.vo;

    //实体类

    public class Tick {

        privateString seqno;

        publicString getSeqno(){

           returnseqno;

        }

        //字符类型,为测试用仅仅加了一个属性,可以为多个

        publicvoid setSeqno(String seqno)

        {

           this.seqno=seqno;

        }

     

    }

    然后再创建一个名为TickCacheServlet的Servlet

    举例代码如下:

     

     

    import java.io.IOException;

    importjavax.servlet.ServletException;

    importjavax.servlet.http.HttpServlet;

    importjavax.servlet.http.HttpServletRequest;

    importjavax.servlet.http.HttpServletResponse;

     

    import com.eunut.vo.Tick;

     

    importflex.messaging.MessageBroker;

    importflex.messaging.messages.AsyncMessage;

    importflex.messaging.util.UUIDUtils;

     

    /**

     * Servlet implementation classTickCacheServlet

     */

    public class TickCacheServletextends HttpServlet {

        privatestatic final long serialVersionUID = 1L;

        //线程

        privatestatic FeedThread thread;

          

        /**

         * @see HttpServlet#HttpServlet()

         */

        public TickCacheServlet() {

            super();

            // TODO Auto-generated constructor stub

        }

     

        /**

         * @see HttpServlet#doGet(HttpServletRequestrequest, HttpServletResponse response)

         */

        protectedvoid doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {

           //TODO Auto-generated method stub

           Stringcmd=request.getParameter("cmd");

           if(cmd.equals("start"))

           {

               start();

           }

           if(cmd.equals("stop"))

           {

               stop();

           }

          

        }

     

        /**

         * @see HttpServlet#doPost(HttpServletRequestrequest, HttpServletResponse response)

         */

        protectedvoid doPost(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {

           //TODO Auto-generated method stub

           super.doPost(request,response);

          

        }

        //初始化

        publicvoid init() throws ServletException{

           super.init();

        }

        publicvoid destroy(){

           super.destroy();

        }

       

        //启动监听

        publicvoid start(){

           if(thread==null)

           {

               thread=newFeedThread();

               thread.start();

           }

           System.out.println("start!!!");

        }

       

        //停止监听

        publicvoid stop(){

           thread.running=false;

           thread=null;

        }

       

        //循环发送消息进程

        publicstatic class FeedThread extends Thread

        {

           publicboolean running=true;

           publicvoid run(){

               //总是无法获取msgBroker,web.xml需要有MessageBrokerServlet的配置信息

               MessageBrokermsgBroker=MessageBroker.getMessageBroker(null);

               StringclientID=UUIDUtils.createUUID();

               inti=0;

               while(running){

                  Ticktick=new Tick();

                  tick.setSeqno(String.valueOf(i));            

                  System.out.println(i);

                 

                  AsyncMessagemsg=new AsyncMessage();

                  msg.setDestination("tick-data-feed");

                  msg.setHeader(AsyncMessage.SUBTOPIC_HEADER_NAME,"tick");

                  msg.setClientId(clientID);

                  msg.setMessageId(UUIDUtils.createUUID());

                  msg.setTimestamp(System.currentTimeMillis());

                  msg.setBody(tick);

                  msgBroker.routeMessageToService(msg,null);

                  i++;

                  try

                  {

                      Thread.sleep(2000);

                     

                  }

                  catch(InterruptedExceptione)

                  {

                     

                  }

                 

               }

           }

        }

     

    }

     

    3.        修改Java后台的推送服务项目的配置文件:

    WebContent\WEB-INF\messaging-config.xml

    <?xml version="1.0"encoding="UTF-8"?>

    <serviceid="message-service"

       class="flex.messaging.services.MessageService">

     

        <adapters>

            <adapter-definitionid="actionscript"class="flex.messaging.services.messaging.adapters.ActionScriptAdapter"default="true" />

            <!-- <adapter-definitionid="jms"class="flex.messaging.services.messaging.adapters.JMSAdapter"/>-->

       </adapters>

     

        <default-channels>

            <channelref="my-polling-amf"/>

        </default-channels>

        <!-- 增加配置信息 -->

        <destination id="tick-data-feed"> 

               <properties> 

                   <server> 

                       <allow-subtopics>true</allow-subtopics> 

                       <subtopic-separator>.</subtopic-separator> 

                   </server> 

               </properties> 

               <channels> 

                   <channel ref="my-polling-amf" /> 

                   <channel ref="my-streaming-amf" /> 

               </channels> 

           </destination> 

    </service>

     

    以及services-config.xml中补充:

    <!-- 补充my-streaming-amf通道配置信息 -->

                <channel-definitionid="my-streaming-amf"class="mx.messaging.channels.StreamingAMFChannel"> 

                    <endpointurl="http://{server.name}:{server.port}/{context.root}/messagebroker/streamingamf"class="flex.messaging.endpoints.StreamingAMFEndpoint"/> 

                    <properties> 

                       <idle-timeout-minutes>0</idle-timeout-minutes> 

                       <max-streaming-clients>10</max-streaming-clients> 

                       <server-to-client-heartbeat-millis>5000</server-to-client-heartbeat-millis> 

                       <user-agent-settings> 

                            <user-agent match-on="MSIE"kickstart-bytes="2048"max-streaming-connections-per-session="1"/> 

                            <user-agentmatch-on="Firefox" kickstart-bytes="2048"max-streaming-connections-per-session="1"/> 

                       </user-agent-settings> 

                    </properties> 

                </channel-definition>  

    同时,还要确保web.xml中包含下面的内容:

    <!-- MessageBroker Servlet-必须的,否则获取不到MessageBrokerServlet,无法发送消息 -->

        <servlet>

           <servlet-name>MessageBrokerServlet</servlet-name>

            <display-name>MessageBrokerServlet</display-name>

           <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>

            <init-param>

               <param-name>services.configuration.file</param-name>

               <param-value>/WEB-INF/flex/services-config.xml</param-value>

           </init-param>

           <load-on-startup>1</load-on-startup>

        </servlet>

     

        <servlet-mapping>

           <servlet-name>MessageBrokerServlet</servlet-name>

           <url-pattern>/messagebroker/*</url-pattern>

        </servlet-mapping>

     <!-- 下面的是自动生成的 -->

     <servlet>

       <javaee:description></javaee:description>

       <javaee:display-name>TickCacheServlet</javaee:display-name>

       <servlet-name>TickCacheServlet</servlet-name>

       <servlet-class>TickCacheServlet</servlet-class>

     </servlet>

     <servlet-mapping>

       <servlet-name>TickCacheServlet</servlet-name>

       <url-pattern>/TickCacheServlet</url-pattern>

     </servlet-mapping>

     

    4.        创建Flex客户端应用程序FlexPushClient.mxml:

    <?xml version="1.0"encoding="utf-8"?>

    <s:Applicationxmlns:fx="http://ns.adobe.com/mxml/2009"

                 xmlns:s="library://ns.adobe.com/flex/spark"

                 xmlns:mx="library://ns.adobe.com/flex/mx"minWidth="955" minHeight="600">

        <fx:Declarations>

           <!--将非可视元素(例如服务、值对象)放在此处 -->

        </fx:Declarations>

        <fx:Script>

           <![CDATA[

               importcom.eunut.Tick;

              

               importmx.controls.Alert;

               importmx.messaging.ChannelSet;

               importmx.messaging.Consumer;

               importmx.messaging.channels.StreamingAMFChannel;

               importmx.messaging.events.ChannelEvent;

               importmx.messaging.events.MessageEvent;

              

               [Bindable] 

               publicvar tick:Tick;

              

               publicfunction submsg():void

               {

                  varconsumer:Consumer=new Consumer();

                  consumer.destination="tick-data-feed";

                  consumer.subtopic="tick";

                  consumer.addEventListener(MessageEvent.MESSAGE,messageHandler);

                  varurl:String ="http://localhost:8080/JavaPushServer/";

                  varmyStreamingAMF:StreamingAMFChannel =  newStreamingAMFChannel(url+"my-streaming-amf",url+"messagebroker/streamingamf"); 

                  varchannelSet:ChannelSet = new ChannelSet();

                  channelSet.addChannel(myStreamingAMF);

                  consumer.channelSet= channelSet; 

                 

                  //              consumer.channelSet = newChannelSet(["my-streaming-amf"]); 

                  consumer.subscribe();  //开始接收

                  Alert.show("消费者初始化完毕!");  

               }

              

               privatefunction messageHandler(event:MessageEvent):void 

               { 

                  vartick:Tick = event.message.body as Tick; 

                  txtTick.text= tick.seqno; 

               } 

           ]]>

        </fx:Script>

        <mx:Panelx="24" y="35" width="362" height="302"layout="absolute" title="Watch Tick"> 

           <mx:Labelx="72" y="43" text="Label"id="txtTick"/> 

           <mx:Buttonx="132" y="41" label="Button"click="submsg()"/> 

        </mx:Panel> 

    </s:Application>

    还要创建Tick的as类:

    package com.eunut

    {

        importmx.rpc.remoting.RemoteObject;

     

        [RemoteClass(alias="com.eunut.vo.Tick")]  //用于和java后台类转换alias为java类的命名空间,否则不能转换

        [Bindable] 

        publicclass Tick

        {

           publicfunction Tick()

           {

           }

           publicvar seqno:String; 

        }

    }


    配置此flex的应用程序的服务器为刚才创建好的JavaPushServer

    好了,这样就可以了哦,现在就是如果看到推送的效果了,启动方式如下:

    首先运行发布到Tomcat上的JavaPushServer,然后,打开客户端网址: http://localhost:8080/JavaPushServer/FlexPushClient.html

    这时候显示的界面如下:

    此时,点击Button按钮,启动监听程序.

    然后,需要启动服务器端的监听:

    http://localhost:8080/JavaPushServer/TickCacheServlet?cmd=start

    如果一切顺利,则可以看到Label显示的数字从0开始逐个增加.

    通过调用:

    http://localhost:8080/JavaPushServer/TickCacheServlet?cmd=stop

    就关闭服务器端的监听程序

    注意:途中可能出现这样那样的问题,绝大部分都是因为配置文件不正确引起的,所以,遇到问题时,一定要仔细查看配置文件中的内容是否正确.



    展开全文
  • IOS-Foundation-runtime使用举例

    千次阅读 2015-04-30 09:11:05
    上一节,我介绍了runtime的基本概念,如有...这一节,举例说明runtime的常用使用场合。一. 动态获取一个类的属性列表信息首先定义一个Person类,代码如下:@interface Person : NSObject @property (nonatomic,copy...

    本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看。

    上一节,我介绍了runtime的基本概念,如有不清楚的地方,请猛点这里

    这一节,举例说明runtime的常用使用场合。


    一. 动态获取一个类的属性列表信息


    首先定义一个Person类,代码如下:

    @interface Person : NSObject
    @property (nonatomic,copy) NSString *name;
    @property (nonatomic,assign) int age;
    @property (nonatomic,assign) BOOL gender;
    @end

    然后就可以使用runtime机制动态的获取属性信息了。代码如下:

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            // 1.获取类信息
            id personClass = objc_getClass("Person");
            
            unsigned int outCount,i;
            objc_property_t *properties =  class_copyPropertyList(personClass, &outCount);
            
            // 2. 获取属性信息
            for(i=0;i<outCount;i++){
                objc_property_t property = properties[i];
                NSLog(@"Name:%s;Attribute:%s",property_getName(property),property_getAttributes(property));
            }
            
        }
        return 0;
    }

    需要注意的是,需要导入头文件 #import<objc/runtime.h>, 因为 objc_property_t,property_getName 这些方法都是 #import <objc/runtime.h> 动态库中提供的


    二. 用runtime实现归档解档


    一般的实现方式:(弊端:1. 必须针对指定的类写类似的代码;2. 如果属性比较多的话,代码量就比较大)

    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
        [aCoder encodeObject:self.name forKey:@"name"];
        [aCoder encodeBool:self.gender forKey:@"gender"];
        [aCoder encodeInteger:self.age forKey:@"age"];
        
    }
    
    - (id)initWithCoder:(NSCoder *)aDecoder
    {
        if(self = [super init])
        {
            self.name = [aDecoder decodeObjectForKey:@"name"];
            self.gender = [aDecoder decodeBoolForKey:@"gender"];
            self.age = [aDecoder decodeIntegerForKey:@"age"];
        }
        return self;
    }

    runtime的实现方式

    // 解档
    - (id)initWithCoder:(NSCoder *)aDecoder
    {
        if(self = [super init])
        {
            unsigned int count;
            Ivar *ivars = class_copyIvarList([Person class], &count);
            for(int i=0;i<count;i++){
                Ivar ivar = ivars[i];
                const char *name = ivar_getName(ivar);
                NSString *strName = [NSString stringWithUTF8String:name];
                // 进行解档取值
                id value = [aDecoder decodeObjectForKey:strName];
                // 利用KVC对属性赋值
                [self setValue:value forKey:strName];
            }
        }
        return self;
    }
    
    // 归档
    -(void)encodeWithCoder:(NSCoder *)aCoder
    {
        unsigned int count;
        Ivar *ivars = class_copyIvarList([Person class], &count);
        for(int i=0;i<count;i++){
            Ivar ivar = ivars[i];
            const char *name = ivar_getName(ivar);
            NSString *strName = [NSString stringWithUTF8String:name];
            // 利用KVC取值
            id value = [self valueForKey:strName];
            // 进行归档赋值
            [aCoder encodeObject:value forKey:strName];
            
        }
    }


    也许大家对上面所涉及到的很多runtime方法有点陌生 ,点击这里 可以查看详细使用列表。


    三.  Swizzle

    在Objective-C中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用Objective-C的动态特性,可以实现在运行时偷换selector对应的方法实现,达到给方法挂钩的目的。

    每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。IMP有点类似函数指针,指向具体的Method实现。  

     

    我们可以利用 method_exchangeImplementations 来交换2个方法中的IMP,

    我们可以利用 class_replaceMethod 来修改类,

    我们可以利用 method_setImplementation 来直接设置某个方法的IMP,
    ……

    归根结底,都是偷换了selector的IMP,如下图所示:



    上面的图解释的也许有点抽象了,下面举一个具体来说明。

    假如你现在的项目有一个需求,项目中所有的图片全部要跟新为UI部门所设计的新图片(而且图片名称全部以"_os8")结尾,这个时候,也许开发人员就要奔溃了! 全局搜索  "imageNamed:"方法,然后在图片名称后面全部加上"_os8"后缀,可想而知,这纯粹是体力活啊!

    这个时候,我们就可以考虑使用Swizzle了,大致实现代码如下:

    @implementation UIImage (Extension)
    /**
     *  分类被装载到内存中,就会调用1次
     */
    +(void)load {
        Method older = class_getClassMethod(self, @selector(imageNamed:));
        Method newer = class_getClassMethod(self, @selector(lFImageNamed:));
        // 交换两个方法
        method_exchangeImplementations(older, newer);
    }
    
    + (UIImage *)lFImageNamed:(NSString *)name {
        BOOL iOS8 = [[UIDevice currentDevice].systemVersion floatValue] >= 8.0;
            
        if(iOS8) {
             name = [name stringByAppendingString:@"_os8"];
        }
        
        return [self lFImageNamed:name];
    }
    @end


    写一个UIImage的分类就可以了。上面的代码需要解释的地方是: 当调用
    [self lFImageNamed:name]
    这一句的时候,大家也许会认为造成死循环。其实不然,它其实调用的是 imageName: 方法,只不过偷偷的将传进来的参数名称加上了_os8, 之所以可以进行方法的交换操作,是因为
    method_exchangeImplementations
    这个方法,它完成了 lFImageNamed: 与 imageNamed: 方法的交换工作。

    关于runtime的使用就介绍这么多,下一节,我为大家介绍一个基于runtime实现的

    字典模型转换插件“MJExtension”。

    展开全文
  • 回调函数举例

    千次阅读 2009-07-04 15:21:00
    赋值可以发生在运行时,这样使你能实现动态绑定。 2.2 参数传递规则 到目前为止,我们只讨论了函数指针及回调而没有去注意ANSI C/C++的编译器规范。许多编译器有几种调用规范。如在Visual C++...

    转自:http://blog.163.com/william_djj@126/blog/static/351665012009324114710982/

     

    1 什么是回调


    软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执 行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制, 不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我 们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。同步调用是三者当中最简单的,而回调又常常是异步调用的基础,因此,下面我们着重讨论回 调机制在不同软件架构中的实现。



    回调函数举例 - william_djj@126 - 我的博客

    对于不同类型的语言(如结构化语言和对象语言)、平台(Win32、JDK)或构架(CORBA、DCOM、WebService),客户和服务的 交互除了同步方式以外,都需要具备一定的异步通知机制,让服务方(或接口提供方)在某些情况下能够主动通知客户,而回调是实现异步的一个最简捷的途径。

    对于一般的结构化语言,可以通过回调函数来实现回调。回调函数也是一个函数或过程,不过它是一个由调用方自己实现,供被调用方使用的特殊函数(如下 面例子中的callback指向的函数fCallback与调用者,即调用GetCallBack的函数在同一个文件中实现,而GetCallBack则 在其他文件中实现。直观的理解就是调用GetCallBack(),但实际上真正的实现在本身这个模块里面,所以叫做回调)。

    在面向对象的语言中,回调则是通过接口或抽象类来实现的,我们把实现这种接口的类称为回调类,回调类的对象成为回调对象。对于象C++或Object Pascal这些兼容了过程特性的对象语言,不仅提供了回调对象、回调方法等特性,也能兼容过程语言的回调函数机制。

    Windows平台的消息机制也可以看作是回调的一种应用,我们通过系统提供的接口注册消息处理函数(即回调函数),从而实现接收、处理消息的目的。由于Windows平台的API是用C语言来构建的,我们可以认为它也是回调函数的一个特例。

    对于分布式组件代理体系CORBA,异步处理有多种方式,如回调、事件服务、通知服务等。事件服务和通知服务是CORBA用来处理异步消息的标准服务,他们主要负责消息的处理、派发、维护等工作。对一些简单的异步处理过程,我们可以通过回调机制来实现。

    下面我们集中比较具有代表性的语言(C、Object Pascal)和架构(CORBA)来分析回调的实现方式、具体作用等。

     

    2 过程语言中的回调(C)

    2.1 函数指针

    回调在C语言中是通过函数指针来实现的,通过将回调函数的地址传给被调函数从而实现回调。因此,要实现回调,必须首先定义函数指针,请看下面的例子:

    void Func(char *s);// 函数原型
    void (*pFunc) (char *);//函数指针

     

    可以看出,函数的定义和函数指针的定义非常类似。

    一般的化,为了简化函数指针类型的变量定义,提高程序的可读性,我们需要把函数指针类型自定义一下。

    typedef void(*pcb)(char *);

     

    回调函数可以象普通函数一样被程序调用,但是只有它被当作参数传递给被调函数时才能称作回调函数。

    被调函数的例子:

    void GetCallBack(pcb callback)
    {
    /*do something*/
    }
    用户在调用上面的函数时,需要自己实现一个pcb类型的回调函数:
    void fCallback(char *s)
    {
    /* do something */
    }
    然后,就可以直接把fCallback当作一个变量传递给GetCallBack,
    GetCallBack(fCallback);

     

    如果赋了不同的值给该参数,那么调用者将调用不同地址的函数。赋值可以发生在运行时,这样使你能实现动态绑定。


    2.2 参数传递规则

    到目前为止,我们只讨论了函数指针及回调而没有去注意ANSI C/C++的编译器规范。许多编译器有几种调用规范。如在Visual C++中,可以在函数类型前加_cdecl,_stdcall或者_pascal来表示其调用规范(默认为_cdecl)。C++ Builder也支持_fastcall调用规范。调用规范影响编译器产生的给定函数名,参数传递的顺序(从右到左或从左到右),堆栈清理责任(调用者或 者被调用者)以及参数传递机制(堆栈,CPU寄存器等)。

    将调用规范看成是函数类型的一部分是很重要的;不能用不兼容的调用规范将地址赋值给函数指针。例如:

    // 被调用函数是以int为参数,以int为返回值
    __stdcall int callee(int);
    // 调用函数以函数指针为参数
    void caller( __cdecl int(*ptr)(int));
    // 在p中企图存储被调用函数地址的非法操作
    __cdecl int(*p)(int) = callee; // 出错

     

    指针p和callee()的类型不兼容,因为它们有不同的调用规范。因此不能将被调用者的地址赋值给指针p,尽管两者有相同的返回值和参数列

    2.3 应用举例

    C语言的标准库函数中很多地方就采用了回调函数来让用户定制处理过程。如常用的快速排序函数、二分搜索函数等。

    快速排序函数原型:

    void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const void *));
    二分搜索函数原型:
    void *bsearch(const void *key, const void *base, size_t nelem,
    size_t width, int (_USERENTRY *fcmp)(const void *, const void *));

     

    其中fcmp就是一个回调函数的变量。

    下面给出一个具体的例子:

    #include <stdio.h>
    #include <stdlib.h>
    int sort_function( const void *a, const void *b);
    int list[5] = { 54, 21, 11, 67, 22 };
    int main(void)
    {
    int x;
    qsort((void *)list, 5, sizeof(list[0]), sort_function);
    for (x = 0; x < 5; x++)
    printf("%i/n", list[x]);
    return 0;
    }
    int sort_function( const void *a, const void *b)
    {
    return *(int*)a-*(int*)b;
    }

     

    2.4 面向对象语言中的回调(Delphi)

    Dephi与C++一样,为了保持与过程语言Pascal的兼容性,它在引入面向对象机制的同时,保留了以前的结构化特性。因此,对回调的实现,也有两种截然不同的模式,一种是结构化的函数回调模式,一种是面向对象的接口模式。

    2.4.1 回调函数

    回调函数类型定义:

    type
    TCalcFunc=function (a:integer;b:integer):integer;

     

    按照回调函数的格式自定义函数的实现,如

    function Add(a:integer;b:integer):integer
    begin
    result:=a+b;
    end;
    function Sub(a:integer;b:integer):integer
    begin
    result:=a-b;
    end;

     

    回调的使用

    function Calc(calc:TcalcFunc;a:integer;b:integer):integer

     

    下面,我们就可以在我们的程序里按照需要调用这两个函数了

    c:=calc(add,a,b);//c=a+b
    c:=calc(sub,a,b);//c=a-b

     

    2.4.2 回调对象

    什么叫回调对象呢,它具体用在哪些场合?首先,让我们把它与回调函数对比一下,回调函数是一个定义了函数的原型,函数体则交由第三方来实现的一种动 态应用模式。要实现一个回调函数,我们必须明确知道几点:该函数需要那些参数,返回什么类型的值。同样,一个回调对象也是一个定义了对象接口,但是没有具 体实现的抽象类(即接口)。要实现一个回调对象,我们必须知道:它需要实现哪些方法,每个方法中有哪些参数,该方法需要放回什么值。

    因此,在回调对象这种应用模式中,我们会用到接口。接口可以理解成一个定义好了但是没有实现的类,它只能通过继承的方式被别的类实现。Delphi 中的接口和COM接口类似,所有的接口都继承与IInterface(等同于IUnknow),并且要实现三个基本的方法QueryInterface, _AddRef, 和_Release。

    • 定义一个接口
      type IShape=interface(IInterface)
      procedure Draw;
      end
    • 实现回调类
      type TRect=class(TObject,IShape)
      protected
      function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
      function _AddRef: Integer; stdcall;
      function _Release: Integer; stdcall;
      public
      procedure Draw;
      end;
      type TRound=class(TObject,IShape)
      protected
      function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
      function _AddRef: Integer; stdcall;
      function _Release: Integer; stdcall;
      public
      procedure Draw;
      end;
    • 使用回调对象
      procedure MyDraw(shape:IShape);
      var
      shape:IShape;
      begin
      shape.Draw;
      end;

    如果传入的对象为TRect,那么画矩形;如果为TRound,那么就为圆形。用户也可以按照自己的意图来实现IShape接口,画出自己的图形:

    MyDraw(Trect.Create);
    MyDraw(Tround.Create);

     

    2.4.3 回调方法

    回调方法(Callback Method)可以看作是回调对象的一部分,Delphi对windows消息的封装就采用了回调方法这个概念。在有些场合,我们不需要按照给定的要求实现整个对象,而只要实现其中的一个方法就可以了,这是我们就会用到回调方法。

    回调方法的定义如下:

    TNotifyEvent = procedure(Sender: TObject) of object; 
    TMyEvent=procedure(Sender:Tobject;EventId:Integer) of object;

     

    TNotifyEvent 是Delphi中最常用的回调方法,窗体、控件的很多事件,如单击事件、关闭事件等都是采用了TnotifyEvent。回调方法的变量一般通过事件属性的方式来定义,如TCustomForm的创建事件的定义:

    property OnCreate: TNotifyEvent read FOnCreate write FOnCreate stored IsForm;

     

    我们通过给事件属性变量赋值就可以定制事件处理器。

    用户定义对象(包含回调方法的对象):

    type TCallback=Class
    procedure ClickFunc(sender:TObject);
    end;
    procedure Tcallback.ClickFunc(sender:TObject);
    begin
    showmessage('the caller is clicked!');
    end;

     

    窗体对象:

    type TCustomFrm=class(TForm)
    public
    procedure RegisterClickFunc(cb:procedure(sender:Tobject) of object);
    end;
    procedure TcustomFrm..RegisterClickFunc(cb:TNotifyEvent);
    begin
    self.OnClick=cb;
    end;

     

    使用方法:

    var
    frm:TcustomFrm;
    begin
    frm:=TcustomFrm.Create(Application);
    frm.RegisterClickFunc(Tcallback.Create().ClickFunc);
    end;

     

    3 回调在分布式计算中的应用(CORBA)

    3.1 回调接口模型

    CORBA的消息传递机制有很多种,比如回调接口、事件服务和通知服务等。回调接口的原理很简单,CORBA客户和服务器都具有双重角色,即充当服务器也是客户客户。

    回调接口的反向调用与正向调用往往是同时进行的,如果服务端多次调用该回调接口,那么这个回调接口就变成异步接口了。因此,回调接口在CORBA中 常常充当事件注册的用途,客户端调用该注册函数时,客户函数就是回调函数,在此后的调用中,由于不需要客户端的主动参与,该函数就是实现了一种异步机制。

    从CORBA规范我们知道,一个CORBA接口在服务端和客户端有不同的表现形式,在客户端一般使用桩(Stub)文件,服务端则用到框架 (Skeleton)文件,接口的规格采用IDL来定义。而回调函数的引入,使得服务端和客户端都需要实现一定的桩和框架。下面是回调接口的实现模型:



    3.1.1 范例
    回调函数举例 - william_djj@126 - 我的博客

    下面给出了一个使用回调的接口文件,服务端需要实现Server接口的框架,客户端需要实现CallBack的框架:

    module cb
    {
    interface CallBack;
    interface Server;
    interface CallBack
    {
    void OnEvent(in long Source,in long msg);
    };
    interface Server
    {
    long RegisterCB(in CallBack cb);
    void UnRegisterCB(in long hCb);
    };
    };

    客户端首先通过同步方式调用服务端的接口RegistCB,用来注册回调接口CallBack。服务端收到该请求以后,就会保留该接口引用,如果发生某种事件需要向客户端通知的时候就通过该引用调用客户方的OnEvent函数,以便对方及时处理。

    展开全文
  • asp xmlHttp用法举例

    千次阅读 2007-03-15 17:28:00
    小偷程序实际上是通过了XML中的XMLHTTP组件调用其它网站上的网页,动态载入内存后,再对别人网页的内容进行分析过滤。所以,原则上只要别人网页上能显示出来的信息,你都可以使用(关于连接,一般的下载网站的连接你...
    一般来说,我们做网站,数据都是在我们自己的数据库中的,但有些数据,我们不想也不能自己去收集数据,比如新闻\天气预报,(我们无法天天更新),所以我们就需要借助别人的网站来显示这些内容 。但如果直接链接到别人的网站,那就不是自己的站点了,所以我们通过xmlhttp对象来在后台把别人的网页内容载入到内存中,经过筛选,将别人的网页内容显示出来 ,这就是所谓的“小偷程序”。 
    



    小偷程序实际上是通过了XML中的XMLHTTP组件调用其它网站上的网页,动态载入内存后,再对别人网页的内容进行分析过滤。所以,原则上只要别人网页上能显示出来的信息,你都可以使用(关于连接,一般的下载网站的连接你是截不到的,因为它进行了隐藏)。现在有很多新闻小偷程序,很多都是调用了sina的新闻网页,对其中的html进行了一些替换,同时对广告也进行过滤。除了新闻截取,你还可以利用小偷程序去截取一些别的信息,比如天气预报等。



    小偷程序的优点有:

    1、无须维护网站,因为小偷程序中的数据来自其他网站,它将随着该网站的更新而更新;

    2、可以节省服务器资源,一般小偷程序就几个文件,所有网页内容都是来自其他网站。 



    其缺点有:

    1、不稳定,如果目标网站出错,程序也会出错。目标网站进行升级维护,小偷程序也要进行相应修改;

    2、速度慢,因为是远程调用,速度和在本地服务器上读取数据比起来,肯定要慢一些。 



    小偷程序一般是使用xmlhttp组件来下载别人的网页,将别人的网页内容载到了你的内存中,再经过分析,过滤掉不需要的内容,最终实现按照自己的格式来显示内容。比如这个网页:http://www.itb2b.com.cn/thief/index.asp ,就是截取了新浪的内容。 



    以下是小偷程序代码:

    <%

    '常用函数

    '1、输入url目标网页地址,返回值getHTTPPage是目标网页的html代码

    function getHTTPPage(url)

    dim Http

    set Http=server.createobject("MSXML2.XMLHTTP")

    Http.open "GET",url,false

    Http.send()

    if Http.readystate<>4 then 

    exit function

    end if

    getHTTPPage=bytesToBSTR(Http.responseBody,"GB2312")

    set http=nothing

    if err.number<>0 then err.Clear 

    end function

    %> 



    换句话说,要做小偷程序,你必须了解xmlhttp组件的使用。微软提供的Microsoft.XMLHTTP对象,能够完成从数据包到Request对象的转换以及发送任务。



    XMLHTTP对象及其方法:

    创建XMLHTTP对象的语句如下: 



    Set objXML = CreateObject("Msxml2.XMLHTTP") 



    Set objXML = CreateObject(“Microsoft.XMLHTTP”)

    其中Set objXML = CreateObject("Msxml2.XMLHTTP")是最新的版本



    对象创建后调用Open方法对Request对象进行初始化,语法格式为: 

    poster.open http-method, url, async, userID, password 

    Open方法中包含了5个参数,前三个是必要的,后两个是可选的(在服务器需要进行身份验证时提供)。



    参数的含义如下所示: 

    http-method: HTTP的通信方式,比如GET或是 POST 

    url: 接收XML数据的服务器的URL地址。通常在URL中要指明ASP或CGI程序 

    async: 一个布尔标识,说明请求是否为异步的。如果是异步通信方式(true),客户机就不等待服务器的响应;如果是同步方式(false),客户机就要等到服务器返回消息后才去执行其他操作 

    userID:用户ID,用于服务器身份验证 

    password:用户密码,用于服务器身份验证 



    比如,我们要调用百度的网页,我们可以: 

    dim Http

    set Http=server.createobject("MSXML2.XMLHTTP")

    Http.open "GET","http://www.baidu.com",false

    Http.send()



    Send方法是用来发送XML数据的,用法如下:

    poster.send() 



    如果不用send来发参数,而你要调用的网页又要接收参数,可以这样简单处理

    dim Http

    set Http=server.createobject("MSXML2.XMLHTTP")

    Http.open "GET","http://要调用的网页?id=1&name=abc",false

    Http.send() 

    Http.send()以后,xmlhttp对象会返回一个对象,这个对象里面就包含了所调用网页的内容,就象从浏览器里打开一样,只不过网页内容是在内存中,还没有显示出来。但在调用过程中可能会出错,所以XMLHTTP对象中的readyState属性能够反映出服务器在处理请求时的进展状况。



    0 Response对象已经创建,但XML文档上载过程尚未结束 

    1 XML文档已经装载完毕 

    2 XML文档已经装载完毕,正在处理中 

    3 部分XML文档已经解析 

    4 文档已经解析完毕,客户端可以接受返回消息 



    所以我们一般这样处理:

    dim Http

    set Http=server.createobject("MSXML2.XMLHTTP")

    Http.open "GET","http://要调用的网页?id=1&name=abc",false

    Http.send()

    '检查是否完成,readystate值为4说明载入完毕

    if Http.readystate<>4 then

    exit function 

    end if 



    Http.send()后,经检测Http.readystate==4,说明载入完毕,这时网页内容已经载入到了Http.responseBody中了 ,但是如果是中文网页,Http.responseBody中会有乱码,这需要我们转换一下乱码 ,所以完整的调用是这样的:

    dim http 

    set http=Server.createobject("Microsoft.XMLHTTP") 

    Http.open "GET","你要调用的网址",false 

    Http.send() 

    if Http.readystate<>4 then '如果不等于4,说明出错了

    exit function 

    end if 

    getHTTPPage=bytesToBSTR(Http.responseBody,"GB2312")

    set http=nothing 

    其中,bytesToBSTR是一个自己写的函数 

    Function BytesToBstr(body,Cset)

    dim objstream

    set objstream = Server.CreateObject("adodb.stream")

    objstream.Type = 1

    objstream.Mode =3

    objstream.Open

    objstream.Write body

    objstream.Position = 0

    objstream.Type = 2

    objstream.Charset = Cset

    BytesToBstr = objstream.ReadText 

    objstream.Close

    set objstream = nothing

    End Function 



    所以,getHTTPPage=bytesToBSTR(Http.responseBody,"GB2312")表示,将Http.responseBody的内容按GB2312编码转换一下,放到getHTTPPage变量中。

    最后,你再对getHTTPPage变量进行分析,取出你想显示的数据就行了。



    需要注意的是,BytesToBstr函数中用到了adodb.stream组件,这需要你的服务器有执行它的权限。



    下面我们讲个实例,我们显示一下新浪的新闻。要想显示新浪的新闻,我们就要先找到新浪的新闻网址是什么。新浪有个动态新闻页网址:http://news.sina.com.cn/old1000/news1000_日期.shtml 。比如,我们要显示6月18日的新闻,就输入

    http://news.sina.com.cn/old1000/news1000_20050618.shtml ,打开网页你会发现是一个新闻列表,下面我们就要分析一下它的结构,右键查看源代码。里面很乱,但你可以找到<!--新闻开始-->和<!--新闻结束-->,中间的内容就是列表的内容。好了,也就是我说,我们想显示6月18号的新闻,就这样调用:

    dim http 

    set http=Server.createobject("Microsoft.XMLHTTP") 

    Http.open "GET","http://news.sina.com.cn/old1000/news1000_20050618.shtml",false 

    Http.send() 

    if Http.readystate<>4 then

    exit function 

    end if 

    getHTTPPage=bytesToBSTR(Http.responseBody,"GB2312")

    set http=nothing

    start=Instr(wstr,"<!--新闻开始-->")

    over=Instr(wstr,"<!--新闻结束-->")

    wstr=mid(wstr,start+11,over-start-11)



    这样wstr就是新闻列表的内容。为什么start+11和over-start-11呢?因为<!--新闻开始-->和<!--新闻结束-->都是11的长度。wstr取出来后,还要进行分析,把它的网址链接替换成你的链接,把不必要的字符过滤掉,这个工作很烦琐,你可以用replace或者用正则表达式来替换,比如:

    wstr=replace(wstr,"href=""","href=""show.asp?url=")

    wstr=replace(wstr,"<ul>","")

    wstr=trim(replace(wstr,"</ul>","")) '完成对页面内容的截取加工

    wstr=Replace(wstr,"http://news.sina.com.cn","NewsNews")

    wstr=Replace(wstr,"http://tech.sina.com.cn","TechNews")

    wstr=Replace(wstr,"http://sports.sina.com.cn","SportsNews")

    wstr=Replace(wstr,"http://ent.sina.com.cn","EntNews")

    wstr=Replace(wstr,"http://eladies.sina.com.cn","EladiesNews")

    wstr=Replace(wstr,"http://jczs.sina.com.cn","jczs")

    wstr=Replace(wstr,"http://auto.sina.com.cn","AutoNews")

    wstr=Replace(wstr,"http://finance.sina.com.cn","FinanceNews")

    wstr=Replace(wstr,"http://www.eladies.com.cn","wwwEladies 
    展开全文
  • javascript常见的设计模式举例

    千次阅读 2014-05-23 18:15:34
    js作为动态语言,实现这四种模式的实例相对简单,当然既然称之为模式,那么吃透思想更重要,那么下面,由乐帝来实例讲解四种模式。  1.单例模式  顾名思义,对象构造出来的是实例,从字面上理解,单例即单实例,这...
  • 在一个项目中需要调用外部接口,此接口一次只能处理8个请求,多于8个请求过来,nginx会为了保护接口直接踢回请求(返回500null错误),而在本项目中使用了消息队列机制,所以有可能会一次从消息队列中消费多条数据,...
  • 面向对象基本概念及举例理解

    千次阅读 2017-06-29 10:31:24
    动态绑定:即消息的接收对象根据接收的消息动态地确定调用自己的那个操作。 类属:即服务的参数类型是参数化的,根据这些参数类型,动态地确定调用自己的那个操作。 定义接口类:另一种实现多态的方式是定义一...
  • ArcEngine除了其内置120多种常用...这种自定义工具的最大的优点是极大的提高了代码的可重用性,如上生成的dll动态链接库可以在任意程序中引用以实现该工具的功能。此外工具的外观和鼠标样式也是可以修改的。  以下
  • 《操作系统》试题举例-简答题

    千次阅读 2018-07-17 21:21:48
    通信:完成进程间的通信或消息传递等。   Give a brief explanation of three major methods of allocating disk space: contiguous, linked, and indexed. Which types FAT and Unix File System ...
  • 文章目录概述消息队列消息队列特性为什么需要消息队列消息队列的好处消息队列举例应用拆分应用拆分的原则应用拆分的思考应用拆分常用的组件DubboSpring Cloud应用限流限流算法 -- 计数器法 ,简单但是有临界问题限流...
  • 1. 概述 Qt Quick 技术的引入,使得你能够快速构建 UI ,具有动画、各种绚丽效果的 UI 都不在话下。在许多情况下基于QML开发的漂亮的... QML开发的模块编译成可以在VS环境中直接使用的DLL库文件,并举例使用QZXing
  • 另外,还可以将较慢的处理逻辑、有并发数量限制的处理逻辑,通过消息队列放在后台处理,例如FLV视频转换、发送手机短信、发送电子邮件等。( 数据结构里最重要的两个结构就是树和图。比如一个公司由上到下的成员...
  • 一、基本概念1.1什么是库在windows平台和linux平台下都大量存在着库。本质上来说库是一种可执行代码的二进制... 1.2库的种类linux下的库有两种:静态库和共享库(动态库)。二者的不同点在于代码被载入的时刻不同。静
  • 进程本来就具有动态的含义,然而实质上是通过线程来执行体现的,从这个意义上说,Windows中进程的动态性意义已经不是很明显了,只算是给程序所占的资源划定一个范围而已,真正具有动态性意义的是线程。 其实,Java...
  • 目录 零、简介 一、MpAndroidChart的基本使用 ...3.举例 4.常用API 二、MpAndroidChart-LineChart的基本使用配置 1.XAxis(X轴) 2.YAxis(Y轴) 3.Legend(图例:即上图所示的曲线图下面的 温度) 4.Desc...
  • 17.Handler消息传递机制

    2019-01-05 19:14:15
    内含源代码。举例:在文本框中动态的生成一个随机产生得数。 1、尝试通过子线程改变主线程界面,动态生成随机数。
  • MQ消息中间件

    千次阅读 2014-09-23 17:35:27
    消息队列技术是分布式应用间交换信息的一种技术。消息队列可驻留在内存或磁盘上,队列存储消息直到它们被应用程序读走。通过消息队列,应用程序可独立地执行--它们不需要知道彼此的位置、或在继续执行前不需要等待...
  • MQ消息队列详解、四大MQ的优缺点分析

    万次阅读 多人点赞 2020-03-07 16:05:28
    MQ消息队列详解 近期有了想跳槽的打算,所以自己想巩固一下自己的技术,想了解一些面试比较容易加分的项,近期准备深入研究一下redis和mq这两样,这总体上都是为了解决服务器并发的原因,刚翻到了一篇有关于mq的,...
  • 前一篇文章中,我们介绍了runtime相关的术语的数据结构,查看链接:runtime相关的术语的数据结构。本文主要讲解与runtime相关的消息发送和消息转发两个重要模块。
  • 浅谈动态追踪技术

    千次阅读 2019-04-18 17:00:00
    本文主要介绍了动态追踪技术,并举例说明动态追踪技术的应用。往期回顾:论萌新开发与大佬开发的不同?身为一个SRE,工作中经常会遇到各种奇奇怪怪的服务异常问题。这些问题在st...
  • 静态代理与动态代理

    千次阅读 2017-05-19 18:42:02
    本文对静态代理和动态代理做了一个比较详细的分析和对比,用通俗贴切的例子来举例说明,以便让读者更容易理解和学习 代理模式:代理模式是为另一个对象提供一个替身来控制对这个对象的访问。代理类负责为这个对象...
  • NSQ消息队列调研与使用

    千次阅读 2019-04-23 09:48:14
    消息队列解决的问题 模块间解耦:将一个流程加入一层数据接口拆分成两个部分,上游专注通知,下游专注处理,服务接口依赖变为数据依赖 消息的异步:上游发送消息以后可以马上返回,处理工作交给下游进行,最终一致...
  • 算法:动态规划

    千次阅读 2016-04-23 09:36:18
    1.首先来看看维基百科怎么定义的动态规划 引自wiki:Dynamic programming In mathematics, management science, economics, computer science, and bioinformatics, dynamic programming (also known as dynamic...
  • Delphi 的消息机制浅探 - Delphi编程

    千次阅读 2012-03-21 15:47:44
     了解 Win32 消息循环和窗口过程  基本了解 TObject、TControl 和 TWinControl 实现的内容  熟悉 Delphi 对象的重载与多态 推荐配置为:  熟悉 Win32 SDK 编程  熟悉 Delphi 的对象机制  熟悉 ...
  • runtime的消息机制前面提到过编译器最终会把我们的消息发送转化为函数调用 消息发送 [object sendMassage] 首先编译器会在运行时将上面的例子转化为objc_msgSend(obj,@selector(sendMassage))这个函数,转换的时候...
  • 简单介绍一下,动态绑定列名的业务场景:当系统存在角色、权限信息时,可能需要对表格进行字段权限分配,举例说:A角色能查看员工表A、B、C、D字段,B角色能查看员工A、B、D、F、G字段,C角色能查
  • 消息队列 (Message Queue)

    千次阅读 2013-06-13 18:33:34
    消息队列 (Message Queue) 消息队列为构造以同步或异步方式实现的分布式应用提供了松耦合方法。消息队列的API调用被嵌入到新的或现存的应用中,通过消息发送到内存或基于磁盘的队列或从它读出而提供信息交换。消息...
  • SpringBoot+RabbitMQ_动态的队列名称

    千次阅读 2020-10-23 10:45:11
    举例:一个服务要将客户发过来的消息进行分类,是水果的调用处理水果的服务器,是蔬菜的调用处理蔬菜的服务器,也就是每台服务器要处理自己队列里的消息。 二、集成MQ 2.1 pom文件引入jar <...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 51,309
精华内容 20,523
关键字:

动态消息举例