精华内容
下载资源
问答
  • 分布式认知无线电网络中基于智能代理的动态入侵检测机制
  • DiffServ网络架构基于带宽代理的QoS接纳控制机制的研究,郑明明,王琼,在Internet技术和实时业务需求迅猛发展的现今,为满足业务对带宽、延迟和延迟抖动等服务质量方面的需求,引入的提供端到端QoS保证的�
  • 代理记忆机制的P2P网络模型。在该模型,数据被分成若干个数据块,节点访问结束后对数据块的服务进行评 价,数据块内容和服务评价更新存储于邻域节点及后继节点;节点访问信息时,根据本地策略优化搜索代理记忆;...
  • IOCP机制网络代理服务器实现方法 ]IOCP是一种在Windows服务平台上比较成熟的I/O方法,针对大量并发客户[摘要摘要] 请求问题,采用IOCP多线程控制模型建立高效网络代理服务器思想,能够较好地代理服务器的多...

    IOCP机制与网络代理服务器实现方法

    ]IOCP是一种在Windows服务平台上比较成熟的I/O方法,针对大量并发客户[摘要摘要]

    请求问题,采用IOCP多线程控制模型建立高效网络代理服务器思想,能够较好地代理服务器中的多线程竞争问题。本文在比较基于该模型的两种编程方案的基础上,给出了基于Windows2000的网络代理服务器的设计与代理实现过程。

    关键词:完成端口重叠I/O多线程

    1、引言

    网络代理服务器的主要作用是将客户端的访问请求转发到远程服务端,并将应答信息回传给客户端。随着Internet应用的迅速发展和应用,代理服务器的作用及其性能已显得越来越重要了。

    一个好的代理服务器应该具备高可靠性和可扩展性并能在不丧失性能的前提下,可同时为多个客户端提供服务。开发代理服务器程序的难点在于代理程序应该具有可扩展性,并能处理从单个连接到乃至数千个连接请求。代理服务程序一般采用“以客户/一线程”的工作模式,即为每一个连接创建一个线程。然而,当请求连接的客户增多,线程的数目就会大量增加,因此,操作系统必须花费额外的资源和时间来协调众多的线程,一旦处理不当,将会造成系统资源负荷过重,甚至可能导致整个系统瘫痪。

    针对上述问题,利用IOCP机制可以较好地解决代理服务器的多线程竞争所带来的问题。

    2、IOCP机制

    IOCP(I/OCompletionPort输入/输出完成端口)是一种能能够合理利用与管理多线程的机制。该机制使用完成端口,用一定数量的线程处理重叠I/O的技术,帮助处理大量客户端请求的网络代理服务问题,特别适合于开发像代理服务器一类的应用程序,并可使系统的性能达到较佳状态。IOCP模型结构如图1所示。

    图1完成端口模型结构

    完成端口模式要求创建一个Win32完成端口对象来对重叠I/O请求进行管理,并通过创建一定数量的工作者线程(WorkThread),来为已经完成的重叠I/O请求提供服务。其实,可以把完成端口看成系统维护的一个队列,操作系统把重叠I/O操作完成的事件通知放入该队列,由于是“操作完成”的事件通知,故取名为“完成端口”。一个完成端口被创建以后,可以和多个文件句柄进行关联

    IOCP机制与网络代理服务器实现方法


    件句柄可以是真正的文件句柄,也可以是Socket句柄或命名管道),并在关联后的句柄上进行重叠I/O操作。当I/O操作完成后,一个重叠I/O完成的事件通知就会被排在此端口的完成队列上,此时,某个工作者线程将会被唤醒来为完成端口服务,执行特定的处理工作。一般来说,一个应用程序可以创建多个工作者线程来处理端口上的通知事件,工作者线程的数量依赖于程序的具体需要。

    3、编程方法

    利用IOCP机制的编程方式不是唯一的,我了解到以下两种方法:

    方法1:使用CreateCompletionPort()函数

    函数的形式定义如下:

    HANDLECreateCompletionPort

    (

    HANDLEFileHandle,

    //文件句柄(可以是Socket,命名管道等)

    HANDLEExistingCompletionPort,//存在的完成端口句柄

    DWORDCompletionKey,

    );

    首先,使用该函数实现两项任务:创建一个完成端口对象,用此函数将所要用到的文件句柄关联到完成端口对象上。然后,创建一个或多个工作者线程来处理完成通知事件,每个线程都可以循环调用GetQueuedCompletionStatus()函数,用以检查完成端口上的通知事件。该函数的形式定义如下:

    BOOLGetQueuedCompletionStatus

    (

    HANDLECompletionPort,//关联的完成端口

    LPDWORDlpNumberOfBytesTransferred,

    //I/O完成后得到的字节数

    LPDWORDlpCompletionKey,//完成键

    LPOVERLAPPED*lpOverlapped,

    //重叠I/O操作所设的Overlapped结构

    DWORDdwMinlliseconds

    //等待的时间,取INFINITE时则一直等待

    );

    一旦该函数得到了完成端口上的通知事件,则等待在完成端口上的工作者线//完成键DWORDNumberOfConcurrentThreads//并发的线程数量

    程就会被唤醒,并根据I/O操作的类型做出相应的处理。

    方法2:使用BindIoCompletionCallBack()函数

    函数的形式定义如下:

    BOOLBindIoCompletionCallback

    (

    HANDLEFileHandle,

    //文件句柄(可以是Socket,命名管道等)

    LPOVERLAPPED_COMPLETION_ROUTINEFunction,

    //回调函数

    ULONGFlags

    );

    其中,回调函数的形式定义如下:

    VOIDCALLBACKWorkthreadFunction

    (

    DWORDdwErrorCode,//错误码

    //Overlapped结构DWORDdwNumberOfBytesTransfered,//传输的字节数LPOVERLAPPEDlpOverlapped

    );

    BindIoCompletionCallBack()函数将FileHandle与完成端口相绑定,绑定工作完成后,一旦FileHandle上有重叠的I/O操作完成,操作系统就会自动调用已与FileHandle相绑定的回调函数来对重叠I/O完成后得到的数据进行相应的处理。

    上述两种方法各有优点,前者由程序员自己创建完成端口,自行创建、管理工作者线程,并能自主控制系统的流程;而采用后者时,开发者无需自行创建完成端口对象及工作者线程,而应用程序调用BindIoCompletionCallBack()函数时,Windows系统会自动创建和管理一个完成端口对象和若干个工作者线程,以减轻对线程创建、挂起和唤醒等一系列管理操作的负担。

    4、代理服务器实例

    代理服务器模型如图2所示://保留(为0)

    图2代理服务器模型图

    在设计具体实现方案时,为充分利用Windows2000

    IOCP机制与网络代理服务器实现方法

    的线程管理机制,减少

    编程及调试的工作量,本实例采用了第二种方法。

    代理主要算法

    1)创建一个监听套接字Listener;

    2)调用BindIoCompletionCallBack()函数,将监听套接字与I/O完成端口进行关联;

    3)创建并初始化若干个与客户端连接的套接字S_ClientToProxy

    _i;

    4)创建并初始化若干个与目标服务器端连接的套接字S_ProxyTo

    Server_j;

    5)利用AcceptEx函数接收所到达的客户端请求,并使用某个已建好的客户端与代理之间的套接字来处理,并调用BindIoCompletion

    CallBack()函数将此套接字与完成端口相关联,一旦有客户端请求完成,就启动回调函数进行相应处理;

    6)调用BindIoCompletionCallBack()函数,将某个已建立好的代理与目标服务器之间的套接字与完成端口相关联,一旦有I/O操作完成,就启动回调函数进行相应处理;

    7)返回5)直到收到强制退出信号,关闭对应套接字并结束代理。

    代理过程

    启动程序之后,利用IOCP机制开始进行代理。

    工作者线程执行回调函数WorkThreadFunction()流程如图3所示,具体工作步骤如下:

    1)检查是哪种I/O操作完成;

    2)通过传递的Overlapped结构指针,判断是哪一种I/O操作完成;

    3)根据判断结果,选择不同的分支作适当的处理;

    如果是从客户端读信息操作完成,则工作者线程发起向服务器的写操作,将

    IOCP机制与网络代理服务器实现方法

    所读的信息发往目标服务器;


    图3工作线程执行的回调函数流程图

    如果是写信息到服务器操作完成,则工作者线程发起从服务器端的读操作,将返回的信息从目标服务器取到代理服务器;

    如果是从目标服务器端读信息操作完成,则工作者线程向客户端的写操作,将信息发往客户端;

    如果是写信息到客户端操作完成,则工作者线程结束本次代理过程。

    4)返回到1)继续检查是否有重叠I/O操作完成。

    由于整个代理过程均是采用重叠I/O操作,所以代理服务器能够同时并行执行读/写操作,异步处理大量客户请求,并且最大限度地提高了系统的性能和速度。

    编写网络代理应用程序的难点在于程序的“可扩展性”即如何开发出大容量且能处理大量并发SocketI/O请求的高性能代理应用程序。IOCP机制通过完成端口对象来对重叠I/O请求进行管理,并且利用多线程来处理重叠I/O操作完成后得到的数据,是一种与Win32Socket结合度较高的实现高效率I/O的有效方法。

    实际应用表明:利用IOCP机制实现的网络代理应用程序能够针对大量的客户请求进行相应代理,且在速度和性能上体现出其良好的特征,不失为一种实现网络代理的好选择。

    展开全文
  • 动态代理机制

    2018-02-01 20:03:45
    Java动态代理机制 retrofit是一个解耦性非常高的网络请求框架,最近在研究的时候发现了动态代理这个非常强大且实用的技术,这篇文章将作为retrofit的前置知识,让大家认识:动态代理有哪些应用场景,什么是动态代理,...

    Java动态代理机制

    retrofit是一个解耦性非常高的网络请求框架,最近在研究的时候发现了动态代理这个非常强大且实用的技术,这篇文章将作为retrofit的前置知识,让大家认识:动态代理有哪些应用场景,什么是动态代理,怎样使用,它的局限性在什么地方?

    1. AOP—面向切面编程,程序解耦
      简言之当你想要对一些类的内部的一些方法,在执行前和执行后做一些共同的的操作,而在方法中执行个性化操作的时候--用动态代理。在业务量庞大的时候能够降低代码量,增强可维护性。

    2. 想要自定义第三放类库中的某些方法
      我引用了一个第三方类库,但他的一些方法不满足我的需求,我想自己重写一下那几个方法,或在方法前后加一些特殊的操作--用动态代理。但需要注意的是,这些方法有局限性,我会在稍后说明。

    什么是动态代理

    类图

    以上的图太过于抽象,我们从生活中的例子开始切入。

    假如你是一个大房东(被代理人),你有很多套房子想要出租,而你觉得找租客太麻烦,不愿意自己弄,因而你找一个人来代理你(代理人),帮打理这些东西,而这个人(代理人也就是中介)在帮你出租房屋的时候对你收取一些相应的中介费(对房屋出租的一些额外操作)。对于租客而言,中介就是房东,代理你做一些事情。

    以上,就是一个代理的例子,而他为什么叫动态代理,“动态”两个字体现在什么地方?

    我们可以这样想,如果你的每一套房子你都请一个代理人帮你打理,每当你想再出租一套房子的时候你得再请一个,这样你会请很多的代理人,花费高额的中介成本,这可以看作常说的“静态代理”。

    但假如我们把所有的房子都交给一个中介来代理,让他在多套房子之间动态的切换身份,帮你应付每一个租客。这就是一个“动态代理”的过程。动态代理的一大特点就是编译阶段没有代理类在运行时才生成代理类。

    我们用一段代码来看一下

    房屋出租的操作

    /*
    定义一个借口
    **/
    public interface RentHouse {
    void rent();//房屋出租
    void charge(String str);//出租费用收取
    }
    房东

    public class HouseOwner implements RentHouse {
    public void rent() {
    System.out.println("I want to rent my house");
    }

    public void charge(String str) {
    System.out.println("You get : " + str + " RMB HouseCharge.");
    }
    }
    中介

    public class DynamicProxy implements InvocationHandler {

    // 这个就是我们要代理的真实对象,即房东
    private Object subject;

    // 构造方法,给我们要代理的真实对象赋初值
    public DynamicProxy(Object subject) {
    this.subject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //  在代理真实对象前我们可以添加一些自己的操作,中介收取中介费
    System.out.println("before "+method.getName()+" house");

    System.out.println("Method:" + method.getName());
    
    //        如果方法是 charge 则中介收取100元中介费
    if (method.getName().equals("charge")) {
    
        method.invoke(subject, args);
        System.out.println("I will get 100 RMB ProxyCharge.");
    
    } else {
        //    当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        method.invoke(subject, args);
    }
    
    //  在代理真实对象后我们也可以添加一些自己的操作
    System.out.println("after "+method.getName()+" house");
    
    return null;

    }
    客人

    public class Client {
    public static void main(String[] args)
    {
    // 我们要代理的真实对象--房东
    HouseOwner houseOwner = new HouseOwner();

    //    我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
    InvocationHandler handler = new DynamicProxy(houseOwner);
    
    /*
     * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
     * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
     * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
     * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
     */
    RentHouse rentHouse = (RentHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner
            .getClass().getInterfaces(), handler);//一个动态代理类,中介
    
    System.out.println(rentHouse.getClass().getName());
    rentHouse.rent();
    rentHouse.charge("10000");

    }
    }
    我们来看一下输出

    com.sun.proxy.$Proxy0
    before rent house
    Method:rent
    I want to rent my house
    after rent house
    before charge house
    Method:charge
    You get : 10000 RMB HouseCharge.
    I will get 100 RMB ProxyCharge.
    after charge house

    Process finished with exit code 0
    输出里有 before rent house以及after rent house,说明我们可以在方法的前后增加操作。再看输出 I will get 100 RMB ProxyCharge. 中介收取了100块的中介费,说明我们不仅可以增加操作,甚至可以替换该方法或者直接让该方法不执行。

    刚开始看代码你可能会有很多疑惑,我们通过以下的内容来看看动态代理应该怎么用。

    #动态代理该如何使用
    在java的动态代理机制中,有两个重要的类和接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。

    每一个动态代理类都必须要实现InvocationHandler这个接口(代码中的中介),并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke(对方法的增强就写在这里面) 方法来进行调用。

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    //proxy:  指代我们所代理的那个真实对象
    //method:  指代的是我们所要调用真实对象的某个方法的Method对象
    //args:  指代的是调用真实对象某个方法时接受的参数
    接下来我们来看看Proxy这个类

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
    Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
    这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

    //loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    //interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
    //h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
    这样一来,结合上面给出的代码,我们就可以明白动态代理的使用方法了

    #动态代理的局限性
    从动态代理的使用方法中我们看到其实可以被增强的方法都是实现了借口的(不实现借口的public方法也可以通过继承被代理类来使用),代码中的HouseOwner继承了RentHouse 。而对于private方法JDK的动态代理无能为力!
    以上的动态代理是JDK的,对于java工程还有大名鼎鼎的CGLib,但遗憾的是CGLib并不能在android中使用,android虚拟机相对与jvm还是有区别的。

    转载于:https://blog.51cto.com/13591463/2067902

    展开全文
  • 针对以太网主机之间存在大量的地址解析协议(ARP)的广播流量,导致以太网规模受限问题的研究,提出基于软件定义网络的地址解析协议代理机制(SDARP)。利用软件定义网络范式,集中处理地址解析协议报文,应答地址...
  • 在研究中,我们重点研究如何将主动网络与现有的传统网络进行融合,这样即兼容延伸了传统网络,义具有主动网络的灵活性,不但使得两种本质不同的网络相互融合,而且还使得在传统网络中更快、更好地实现该技术,或者...
  • Java动态代理机制

    2018-02-02 19:51:00
    retrofit是一个解耦性非常高的网络请求框架,最近在研究的时候发现了动态代理这个非常强大且实用的技术,这篇文章将作为retrofit的前置知识,让大家认识:动态代理有哪些应用场景,什么是动态代理,怎样使用,它的...

    retrofit是一个解耦性非常高的网络请求框架,最近在研究的时候发现了动态代理这个非常强大且实用的技术,这篇文章将作为retrofit的前置知识,让大家认识:动态代理有哪些应用场景,什么是动态代理,怎样使用,它的局限性在什么地方?
    #动态代理的应用场景

    1. AOP—面向切面编程,程序解耦
    简言之当你想要对一些类的内部的一些方法,在执行前和执行后做一些共同的的操作,而在方法中执行个性化操作的时候--用动态代理。在业务量庞大的时候能够降低代码量,增强可维护性。

    2. 想要自定义第三放类库中的某些方法
    我引用了一个第三方类库,但他的一些方法不满足我的需求,我想自己重写一下那几个方法,或在方法前后加一些特殊的操作--用动态代理。但需要注意的是,这些方法有局限性,我会在稍后说明。

    什么是动态代理

    类图

    以上的图太过于抽象,我们从生活中的例子开始切入。

    假如你是一个大房东(被代理人),你有很多套房子想要出租,而你觉得找租客太麻烦,不愿意自己弄,因而你找一个人来代理你(代理人),帮打理这些东西,而这个人(代理人也就是中介)在帮你出租房屋的时候对你收取一些相应的中介费(对房屋出租的一些额外操作)。对于租客而言,中介就是房东,代理你做一些事情。

    以上,就是一个代理的例子,而他为什么叫动态代理,“动态”两个字体现在什么地方?

    我们可以这样想,如果你的每一套房子你都请一个代理人帮你打理,每当你想再出租一套房子的时候你得再请一个,这样你会请很多的代理人,花费高额的中介成本,这可以看作常说的“静态代理”。

    但假如我们把所有的房子都交给一个中介来代理,让他在多套房子之间动态的切换身份,帮你应付每一个租客。这就是一个“动态代理”的过程。动态代理的一大特点就是编译阶段没有代理类在运行时才生成代理类。

    我们用一段代码来看一下

    房屋出租的操作

    /**
    *定义一个借口
    **/
    public interface RentHouse {
    void rent();//房屋出租
    void charge(String str);//出租费用收取
    }

     

    房东

    public class HouseOwner implements RentHouse {
    public void rent() {
        System.out.println("I want to rent my house");
    }
    
    public void charge(String str) {
        System.out.println("You get : " + str + " RMB HouseCharge.");
    }
    }

     

    中介

    public class DynamicProxy implements InvocationHandler {
    
    // 这个就是我们要代理的真实对象,即房东
    private Object subject;
    
    //  构造方法,给我们要代理的真实对象赋初值
    public DynamicProxy(Object subject) {
        this.subject = subject;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //  在代理真实对象前我们可以添加一些自己的操作,中介收取中介费
        System.out.println("before "+method.getName()+" house");
    
        System.out.println("Method:" + method.getName());
    
        //        如果方法是 charge 则中介收取100元中介费
        if (method.getName().equals("charge")) {
    
            method.invoke(subject, args);
            System.out.println("I will get 100 RMB ProxyCharge.");
    
        } else {
            //    当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
            method.invoke(subject, args);
        }
    
        //  在代理真实对象后我们也可以添加一些自己的操作
        System.out.println("after "+method.getName()+" house");
    
        return null;
    }

     

    客人

    public class Client {
    public static void main(String[] args)
    {
        //    我们要代理的真实对象--房东
        HouseOwner houseOwner = new HouseOwner();
    
        //    我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
        InvocationHandler handler = new DynamicProxy(houseOwner);
    
        /*
         * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
         * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
         * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
         * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
         */
        RentHouse rentHouse = (RentHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner
                .getClass().getInterfaces(), handler);//一个动态代理类,中介
    
        System.out.println(rentHouse.getClass().getName());
        rentHouse.rent();
        rentHouse.charge("10000");
    }
    }

     

    我们来看一下输出

    com.sun.proxy.$Proxy0
    before rent house
    Method:rent
    I want to rent my house
    after rent house
    before charge house
    Method:charge
    You get : 10000 RMB HouseCharge.
    I will get 100 RMB ProxyCharge.
    after charge house
    
    Process finished with exit code 0

    输出里有 before rent house以及after rent house,说明我们可以在方法的前后增加操作。再看输出 I will get 100 RMB ProxyCharge. 中介收取了100块的中介费,说明我们不仅可以增加操作,甚至可以替换该方法或者直接让该方法不执行。

    刚开始看代码你可能会有很多疑惑,我们通过以下的内容来看看动态代理应该怎么用。

    #动态代理该如何使用
    在java的动态代理机制中,有两个重要的类和接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。

    每一个动态代理类都必须要实现InvocationHandler这个接口(代码中的中介),并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke(对方法的增强就写在这里面) 方法来进行调用。

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable

    我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    //proxy:  指代我们所代理的那个真实对象
    //method:  指代的是我们所要调用真实对象的某个方法的Method对象
    //args:  指代的是调用真实对象某个方法时接受的参数

    接下来我们来看看Proxy这个类

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

     

    Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

     

    这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
    
    //loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    //interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
    //h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

     

    这样一来,结合上面给出的代码,我们就可以明白动态代理的使用方法了

    #动态代理的局限性
    从动态代理的使用方法中我们看到其实可以被增强的方法都是实现了借口的(不实现借口的public方法也可以通过继承被代理类来使用),代码中的HouseOwner继承了RentHouse 。而对于private方法JDK的动态代理无能为力!
    以上的动态代理是JDK的,对于java工程还有大名鼎鼎的CGLib,但遗憾的是CGLib并不能在android中使用,android虚拟机相对与jvm还是有区别的

     

    展开全文
  • 基于移动代理网络管理框架的中心思想是利用移动代理与驻留在设备上的传统的固定式代理进行信息交换,以完成管理功能。移动代理服务器(MAS)是整个网管框架的关键组成部分。移动代理发布者一般来说来自于网管中心...
  • 在移动IP技术,移动节点可能具有多个无线网络接口同时连接在多个外地网络,这就需要家乡代理采用多重绑定机制。提出了一种基于Linux下的Netfilter技术实现HA多重绑定机制的方案。阐述了该方案的设计思想、设计框架...
  • 互联网协议设计的一条原则是新协议的引入不为网络带来新的安全威胁,如果存在安全隐患,那么协议本身必须要设计相应的安全机制来克服。移动IP协议也不例外,下面分析移动IP所提供的安全机制。  (1)认证机制  ...
  • SOFA RPC源码解析之RPC代理机制

    千次阅读 2018-06-29 21:58:49
    1.SOFA RPC源码解析 1.1 RPC代理机制  在SOFA RPC中,服务引用采用代理模式把本地方法调用转换为远程服务调用... 简单回顾一下代理模式,以便大家理解SOFA RPC中代理机制的实现方式。  代理模式是常用的设计模...

    1.SOFA RPC源码解析

    1.1  RPC代理机制

            在SOFA RPC中,服务引用采用代理模式把本地方法调用转换为远程服务调用,从而使开发者像使用本地Java方法一样,使用远程服务,屏蔽了底层的网络通讯细节,使开发人员把精力集中在业务开发中。

            简单回顾一下代理模式,以便大家理解SOFA RPC中代理机制的实现方式。

            代理模式是常用的设计模式之一。当无法直接访问某个对象或访问某个对象存在困难时,可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,所访问的真实对象与代理对象需要实现相同的接口。

            按照代理的创建时期,代理类可以分为两种:

            1.   静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了;

            2.   动态代理:在程序运行时,运用反射机制动态创建而成。

            在SOFABoot中,对于JVM服务类型的服务引用,即可以针对某个接口创建代理对象,也可以针对某个类创建代理对象。

            在SOFA RPC中,规定只能针对某个接口创建代理对象,所以采用动态代理方式为远程服务创建本地代理对象。如果被代理的对象为Java类,而不是接口,则在创建代理对象时,抛出异常,例如:

    1.  The value of config consumer.interface[com.alipay.sofa.boot.examples.demo.rpc.bean.PersonServiceImpl2] is illegal,interfaceId must set interface class, not implement class

            在SOFA RPC中,主要有两种创建代理的方式:JDK动态代理机制和Javassist动态类库。

            在此补充说明一下,为了查看Proxy动态生成的代理对象的源文件,必须先导出字节码文件,然后通过反编译工具(如:jad)生成源文件。对于Proxy,导出字节码文件方式为在应用代码开始位置设置sun.misc.ProxyGenerator.saveGeneratedFiles为true:

    1.  @SpringBootApplication
    2.  @ImportResource({"classpath*:rpc-starter-example.xml" })
    3.  public class SofaBootRpcDemoApplication {
    4.   
    5.      public static void main(String[] args)throws InterruptedException {
    6.       
    7.        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
    8.       
    9.        ConfigurableApplicationContext ac =SpringApplication.run(SofaBootRpcDemoApplication.class, args);
    10.          
    11.  
    12.     }
    13. }

            注意,需要在工程根目录下,增加 com/sun/proxy目录,否则会报错如下:

    1.  Exception in thread "main"java.lang.InternalError: I/O exception saving generatedfile:java.io.FileNotFoundException : com\sun\proxy\$Proxy0.class (系统找不到指定的路径。)
    2.       atsun.misc.ProxyGenerator$1.run(ProxyGenerator.java:336 )
    3.       atsun.misc.ProxyGenerator$1.run(ProxyGenerator.java:327 )
    4.       at java.security.AccessController.doPrivileged( NativeMethod)
    5.       atsun.misc.ProxyGenerator.generateProxyClass( ProxyGenerator.java:326)
    6.       atjava.lang.reflect.Proxy$ProxyClassFactory.apply( Proxy.java:672)
    7.       atjava.lang.reflect.Proxy$ProxyClassFactory.apply( Proxy.java:592)
    8.       atjava.lang.reflect.WeakCache$Factory.get( WeakCache.java:244)
    9.       atjava.lang.reflect.WeakCache.get(WeakCache.java:141 )
    10.      atjava.lang.reflect.Proxy.getProxyClass0(Proxy.java:455 )
    11.      atjava.lang.reflect.Proxy.newProxyInstance( Proxy.java:738)

     1.1.1 JDK动态代理

            提到JDK动态代理,大家一定想到java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。

            1.  通过实现InvocationHandler接口,为代理对象提供调用处理器handler。当调用代理对象某个方法时,该方法调用将会被分发到handler的invoke方法,由其在调用目标对象的方法前后,进行一些额外处理。

            2.  通过Proxy类newProxyInstance方法,为实现某个接口的类创建代理对象。

            首先,看一下JDKProxy类的源码,该类对外提供了为指定接口动态创建代理对象的方法:

    1.  @Extension("jdk")
    2.  public class JDKProxy implements Proxy {
    3.   
    4.      @Override
    5.      public <T> T getProxy(Class<T>interfaceClass, Invoker proxyInvoker) {
    6.          InvocationHandler handler = new JDKInvocationHandler(interfaceClass,proxyInvoker);
    7.          ClassLoader classLoader =ClassLoaderUtils.getCurrentClassLoader();
    8.          T result = (T)java.lang.reflect.Proxy.newProxyInstance(classLoader,
    9.              new Class[] { interfaceClass },handler);
    10.         return result;
    11.     }
    12.  
    13.     @Override
    14.     public Invoker getInvoker(ObjectproxyObject) {
    15.         return parseInvoker(proxyObject);
    16.     }
    17.  
    18.     /**
    19.      * Parse proxy invoker from proxy object
    20.      *
    21.      * @param proxyObject Proxy object
    22.      * @return proxy invoker
    23.      */
    24.     public static Invoker parseInvoker(ObjectproxyObject) {
    25.         InvocationHandler handler =java.lang.reflect.Proxy.getInvocationHandler(proxyObject);
    26.         if (handler instanceofJDKInvocationHandler) {
    27.             return ((JDKInvocationHandler)handler).getProxyInvoker();
    28.         }
    29.         return null;
    30.     }
    31. }

            getProxy方法主要处理逻辑如下:

            1.  根据接口类型和Invoker接口的实现类,创建JDKInvocationHandler实例;

            2.  调用Proxy类newProxyInstance方法,创建代理对象;

            在SOFA RPC中,com.alipay.sofa.rpc.proxy.jdk.JDKInvocationHandler类实现了InvocationHandler接口。

            JDKInvocationHandler类的源代码如下:

    1.  public class JDKInvocationHandlerimplements InvocationHandler {
    2.   
    3.      /**
    4.       * 代理类
    5.       */
    6.      private Class  proxyClass;
    7.   
    8.      /**
    9.       * 代理调用器
    10.      */
    11.     private Invoker proxyInvoker;
    12.  
    13.     /**
    14.      * Instantiates a new Jdk invocationhandler.
    15.      *
    16.      * @param proxyClass   the proxy class
    17.      * @param proxyInvoker the proxy invoker
    18.      */
    19.     public JDKInvocationHandler(ClassproxyClass, Invoker proxyInvoker) {
    20.         this.proxyClass = proxyClass;
    21.         this.proxyInvoker = proxyInvoker;
    22.     }
    23.  
    24.     @Override
    25.     public Object invoke(Object proxy, Methodmethod, Object[] paramValues)
    26.         throws Throwable {
    27.         String methodName = method.getName();
    28.         Class[] paramTypes =method.getParameterTypes();
    29.         if("toString".equals(methodName) && paramTypes.length == 0) {
    30.             return proxyInvoker.toString();
    31.         } else if("hashCode".equals(methodName) && paramTypes.length == 0) {
    32.             return proxyInvoker.hashCode();
    33.         } else if("equals".equals(methodName) && paramTypes.length == 1) {
    34.             Object another = paramValues[0];
    35.             return proxy == another ||
    36.                 (proxy.getClass().isInstance(another)&& proxyInvoker.equals(JDKProxy.parseInvoker(another)));
    37.         }
    38.         SofaRequest sofaRequest =MessageBuilder.buildSofaRequest(method.getDeclaringClass(),
    39.             method, paramTypes, paramValues);
    40.         SofaResponse response =proxyInvoker.invoke(sofaRequest);
    41.         if (response.isError()) {
    42.             throw newSofaRpcException(RpcErrorType.SERVER_UNDECLARED_ERROR, response.getErrorMsg());
    43.         }
    44.         Object ret = response.getAppResponse();
    45.         if (ret instanceof Throwable) {
    46.             throw (Throwable) ret;
    47.         } else {
    48.             if (ret == null) {
    49.                 returnClassUtils.getDefaultArg(method.getReturnType());
    50.             }
    51.             return ret;
    52.         }
    53.     }
    54.  
    55.     /**
    56.      * Gets proxy class.
    57.      *
    58.      * @return the proxy class
    59.      */
    60.     public Class getProxyClass() {
    61.         return proxyClass;
    62.     }
    63.  
    64.     /**
    65.      * Gets proxy invoker.
    66.      *
    67.      * @return the proxy invoker
    68.      */
    69.     public Invoker getProxyInvoker() {
    70.         return proxyInvoker;
    71.     }
    72. }

            JDKInvocationHandler类invoke方法主要处理逻辑如下:

            1.  本地方法调用封装成SofaRequest请求对象;

            2.  通过调用Invoker接口实现类DefaultClientProxyInvoker(该类继承了ClientProxyInvoker类,而ClientProxyInvoker类实现了Invoker接口)的invoke方法,以SofaRequest为参数,进行远程服务调用,并返回处理结果SofaResponse。

            3.  从SofaResponse对象中获取实际的远程服务的处理结果,并返回给本地客户端。

            在此,以SOFABoot自带的RPC案例sofaboot-sample-with-rpc为例,看看为com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService接口创建的服务代理对象的源文件:

    1.  importcom.alipay.sofa.boot.examples.demo.rpc.bean.PersonService;
    2.  importjava.lang.reflect.InvocationHandler;
    3.  import java.lang.reflect.Method;
    4.  import java.lang.reflect.Proxy;
    5.  importjava.lang.reflect.UndeclaredThrowableException;
    6.   
    7.  public final class $Proxy0 extendsProxy  implements PersonService
    8.  {
    9.    private static Method m1;
    10.   private static Method m3;
    11.   private static Method m0;
    12.   private static Method m2;
    13.  
    14.   public $Proxy0(InvocationHandlerparamInvocationHandler)
    15.     throws
    16.   {
    17.     super(paramInvocationHandler);
    18.   }
    19.  
    20.   public final boolean equals(ObjectparamObject)
    21.     throws
    22.   {
    23.     try
    24.     {
    25.       return ((Boolean)this.h.invoke(this, m1,new Object[] { paramObject })).booleanValue();
    26.     }
    27.     catch (RuntimeExceptionlocalRuntimeException)
    28.     {
    29.       throw localRuntimeException;
    30.     }
    31.     catch (Throwable localThrowable)
    32.     {
    33.     }
    34.     throw newUndeclaredThrowableException(localThrowable);
    35.   }
    36.  
    37.   publicfinal String sayName(String paramString)
    38.     throws
    39.   {
    40.     try
    41.     {
    42.       return (String)this.h.invoke(this, m3,new Object[] { paramString });
    43.     }
    44.     catch (RuntimeExceptionlocalRuntimeException)
    45.     {
    46.       throw localRuntimeException;
    47.     }
    48.     catch (Throwable localThrowable)
    49.     {
    50.     }
    51.     throw newUndeclaredThrowableException(localThrowable);
    52.   }
    53.  
    54.   public final int hashCode()
    55.     throws
    56.   {
    57.     try
    58.     {
    59.       return ((Integer)this.h.invoke(this, m0,null)).intValue();
    60.     }
    61.     catch (RuntimeExceptionlocalRuntimeException)
    62.     {
    63.       throw localRuntimeException;
    64.     }
    65.     catch (Throwable localThrowable)
    66.     {
    67.     }
    68.     throw newUndeclaredThrowableException(localThrowable);
    69.   }
    70.  
    71.   public final String toString()
    72.     throws
    73.   {
    74.     try
    75.     {
    76.       return (String)this.h.invoke(this, m2,null);
    77.     }
    78.     catch (RuntimeException localRuntimeException)
    79.     {
    80.       throw localRuntimeException;
    81.     }
    82.     catch (Throwable localThrowable)
    83.     {
    84.     }
    85.     throw newUndeclaredThrowableException(localThrowable);
    86.   }
    87.  
    88.   static
    89.   {
    90.     try
    91.     {
    92.       m1 =Class.forName("java.lang.Object").getMethod("equals", newClass[] { Class.forName("java.lang.Object") });
    93.       m3 =Class.forName("com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService").getMethod("sayName",new Class[] { Class.forName("java.lang.String") });
    94.       m0 = Class.forName("java.lang.Object").getMethod("hashCode",new Class[0]);
    95.       m2 =Class.forName("java.lang.Object").getMethod("toString", newClass[0]);
    96.       return;
    97.     }
    98.     catch (NoSuchMethodExceptionlocalNoSuchMethodException)
    99.     {
    100.       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    101.     }
    102.     catch (ClassNotFoundExceptionlocalClassNotFoundException)
    103.     {
    104.     }
    105.     throw newNoClassDefFoundError(localClassNotFoundException.getMessage());
    106.   }
    107. }

            从上述代码可以看出,该代理对象继承了Proxy类,实现了PersonService接口。主要看一下代理对象对于PersonService接口的sayName方法实现方式。在sayName方法中,实际调用handler的invoke方法:

    1.  (String)this.h.invoke(this, m3, newObject[] { paramString })

            此处h为JDKInvocationHandler实例。

            这样,当客户端调用实现了PersonService接口的代理对象的sayName方法时,实际上是调用JDKInvocationHandler类invoke方法,完成本地方法调用到远程服务调用的转换。JDKInvocationHandler类invoke方法的主要处理逻辑如上所述。

    1.1.2 Javassist动态类库

            在SOFA RPC中,提供了另一种为远程服务创建本地代理对象的方式,即Javassist动态类库。

            Javassist是一款字节码编辑工具,可以直接编辑和生成Java字节码,以达到对.class文件进行动态修改的效果。关于Javassist,在此不详述,有兴趣的同学可以在网上搜索资料自行研究。

            首先,看一下JavassistProxy类的源码,该类对外提供了为指定接口动态创建代理对象的方法:

    1.  @Extension("javassist")
    2.  public class JavassistProxy implementsProxy {
    3.   
    4.      /**
    5.       * Logger for this class
    6.       */
    7.      private static final Logger              LOGGER          =LoggerFactory.getLogger(JavassistProxy.class);
    8.   
    9.      private static AtomicInteger             counter         = new AtomicInteger();
    10.  
    11.     /**
    12.      * 原始类和代理类的映射
    13.      */
    14.     protected final static Map<Class,Class> PROXY_CLASS_MAP = new ConcurrentHashMap<Class, Class>();
    15.  
    16.     @Override
    17.     @SuppressWarnings("unchecked")
    18.     public <T> T getProxy(Class<T>interfaceClass, Invoker proxyInvoker) {
    19.         try {
    20.             Class clazz =PROXY_CLASS_MAP.get(interfaceClass);
    21.             if (clazz == null) {
    22.                 //生成代理类
    23.                 String interfaceName =ClassTypeUtils.getTypeStr(interfaceClass);
    24.                 ClassPool mPool =ClassPool.getDefault();
    25.                 mPool.appendClassPath(newLoaderClassPath(ClassLoaderUtils.getClassLoader(JavassistProxy.class)));
    26.                 CtClass mCtc =mPool.makeClass(interfaceName + "_proxy_" +counter.getAndIncrement());
    27.                 if(interfaceClass.isInterface()) {
    28.                     mCtc.addInterface(mPool.get(interfaceName));
    29.                 } else {
    30.                     throw newIllegalArgumentException(interfaceClass.getName() + " is not aninterface");
    31.                 }
    32.  
    33.                 // 继承 java.lang.reflect.Proxy
    34.                 mCtc.setSuperclass(mPool.get(java.lang.reflect.Proxy.class.getName()));
    35.                 CtConstructor constructor = newCtConstructor(null, mCtc);
    36.                 constructor.setModifiers(Modifier.PUBLIC);
    37.                 constructor.setBody("{super(new" + UselessInvocationHandler.class.getName() + "());}");
    38.                 mCtc.addConstructor(constructor);
    39.  
    40.                 mCtc.addField(CtField.make("public" + Invoker.class.getCanonicalName() + " proxyInvoker = null;",
    41.                     mCtc));
    42.                 StringBuilder sb = null;
    43.                 if (LOGGER.isDebugEnabled()) {
    44.                     sb = new StringBuilder();
    45.                 }
    46.                 List<String> methodList =createMethod(interfaceClass);
    47.                 for (String methodStr :methodList) {
    48.                     mCtc.addMethod(CtMethod.make(methodStr,mCtc));
    49.                     if(LOGGER.isDebugEnabled()) {
    50.                         sb.append(methodStr).append("\n");
    51.                     }
    52.                 }
    53.                 if (LOGGER.isDebugEnabled()) {
    54.                     LOGGER.debug("javassistproxy of interface: {} \r\n{}", interfaceClass,
    55.                         sb != null ?sb.toString() : "");
    56.                 }
    57.                 clazz = mCtc.toClass();
    58.                 PROXY_CLASS_MAP.put(interfaceClass,clazz);
    59.             }
    60.             Object instance =clazz.newInstance();
    61.             clazz.getField("proxyInvoker").set(instance,proxyInvoker);
    62.             return (T) instance;
    63.         } catch (Exception e) {
    64.             throw newSofaRpcRuntimeException("", e);
    65.         }
    66.     }
    67.  
    68.     private List<String>createMethod(Class<?> interfaceClass) {
    69.         Method[] methodAry =interfaceClass.getMethods();
    70.         StringBuilder sb = newStringBuilder(512);
    71.         List<String> resultList = newArrayList<String>();
    72.         for (Method m : methodAry) {
    73.             if(Modifier.isNative(m.getModifiers()) || Modifier.isFinal(m.getModifiers())) {
    74.                 continue;
    75.             }
    76.             Class<?>[] mType =m.getParameterTypes();
    77.             Class<?> returnType =m.getReturnType();
    78.  
    79.             sb.append(Modifier.toString(m.getModifiers()).replace("abstract","") + " " +
    80.                 ClassTypeUtils.getTypeStr(returnType)+ " " + m.getName() + "( ");
    81.             int c = 0;
    82.  
    83.             for (Class<?> mp : mType) {
    84.                 sb.append(" " +mp.getCanonicalName() + " arg" + c + " ,");
    85.                 c++;
    86.             }
    87.             sb.deleteCharAt(sb.length() - 1);
    88.             sb.append(")");
    89.             Class<?>[] exceptions =m.getExceptionTypes();
    90.             if (exceptions.length > 0) {
    91.                 sb.append(" throws");
    92.                 for (Class<?> exception :exceptions) {
    93.                     sb.append(exception.getCanonicalName()+ " ,");
    94.                 }
    95.                 sb =sb.deleteCharAt(sb.length() - 1);
    96.             }
    97.             sb.append("{");
    98.  
    99.             sb.append(" Class clazz =" + interfaceClass.getCanonicalName() + ".class;");
    100.             sb.append(" String methodName= \"" + m.getName() + "\";");
    101.             sb.append(" Class[] paramTypes= new Class[" + c + "];");
    102.             sb.append(" Object[]paramValues = new Object[" + c + "];");
    103.             for (int i = 0; i < c; i++) {
    104.                 sb.append("paramValues["+ i + "] = ($w)$" + (i + 1) + ";");
    105.                 sb.append("paramTypes["+ i + "] = " + mType[i].getCanonicalName() + ".class;");
    106.             }
    107.  
    108.             sb.append(SofaRequest.class.getCanonicalName()+ " request = " +
    109.                 MessageBuilder.class.getCanonicalName()+
    110.                 ".buildSofaRequest(clazz,methodName, paramTypes, paramValues);");
    111.             sb.append(SofaResponse.class.getCanonicalName()+ " response = " +
    112.                 "proxyInvoker.invoke(request);");
    113.             sb.append("if(response.isError()){");
    114.             sb.append("  throw new " +SofaRpcException.class.getName() + "(" + RpcErrorType.class.getName()+
    115.                 ".SERVER_UNDECLARED_ERROR,"+
    116.                 "response.getErrorMsg());");
    117.             sb.append("}");
    118.  
    119.             if (returnType.equals(void.class)){
    120.                 sb.append("return;");
    121.             } else {
    122.                 sb.append("Object ret =response.getAppResponse();");
    123.                 sb.append("if(retinstanceof " + Throwable.class.getName() + ") {");
    124.                 sb.append("    throw (" + Throwable.class.getName() +") ret;");
    125.                 sb.append("} else{");
    126.                 sb.append("    return " + asArgument(returnType,"ret") + ";");
    127.                 sb.append("}");
    128.             }
    129.  
    130.             sb.append("}");
    131.             resultList.add(sb.toString());
    132.             sb.delete(0, sb.length());
    133.         }
    134.  
    135.         // toString()
    136.         sb.append("public StringtoString() {");
    137.         sb.append("  return proxyInvoker.toString();");
    138.         sb.append("}");
    139.         resultList.add(sb.toString());
    140.         // hashCode()
    141.         sb.delete(0, sb.length());
    142.         sb.append("public int hashCode(){");
    143.         sb.append("  return proxyInvoker.hashCode();");
    144.         sb.append("}");
    145.         resultList.add(sb.toString());
    146.         // equals()
    147.         sb.delete(0, sb.length());
    148.         sb.append("public booleanequals(Object obj) {");
    149.         sb.append("  return this == obj ||(getClass().isInstance($1) " +
    150.             "&&proxyInvoker.equals(" + JavassistProxy.class.getName() +".parseInvoker($1)));");
    151.         sb.append("}");
    152.         resultList.add(sb.toString());
    153.         return resultList;
    154.     }
    155.  
    156.     private String asArgument(Class<?>cl, String name) {
    157.         if (cl.isPrimitive()) {
    158.             if (Boolean.TYPE == cl) {
    159.                 return name +"==null?false:((Boolean)" + name + ").booleanValue()";
    160.             }
    161.             if (Byte.TYPE == cl) {
    162.                 return name +"==null?(byte)0:((Byte)" + name + ").byteValue()";
    163.             }
    164.             if (Character.TYPE == cl) {
    165.                 return name +"==null?(char)0:((Character)" + name + ").charValue()";
    166.             }
    167.             if (Double.TYPE == cl) {
    168.                 return name +"==null?(double)0:((Double)" + name + ").doubleValue()";
    169.             }
    170.             if (Float.TYPE == cl) {
    171.                 return name +"==null?(float)0:((Float)" + name + ").floatValue()";
    172.             }
    173.             if (Integer.TYPE == cl) {
    174.                 return name +"==null?(int)0:((Integer)" + name + ").intValue()";
    175.             }
    176.             if (Long.TYPE == cl) {
    177.                 return name +"==null?(long)0:((Long)" + name + ").longValue()";
    178.             }
    179.             if (Short.TYPE == cl) {
    180.                 return name +"==null?(short)0:((Short)" + name + ").shortValue()";
    181.             }
    182.             throw new RuntimeException(name +" is unknown primitive type.");
    183.         }
    184.         return "(" +ClassTypeUtils.getTypeStr(cl) + ")" + name;
    185.     }
    186.  
    187.     @Override
    188.     public Invoker getInvoker(ObjectproxyObject) {
    189.         return parseInvoker(proxyObject);
    190.     }
    191.  
    192.     /**
    193.      * Parse proxy invoker from proxy object
    194.      *
    195.      * @param proxyObject Proxy object
    196.      * @return proxy invoker
    197.      */
    198.     public static Invoker parseInvoker(ObjectproxyObject) {
    199.         Field field;
    200.         try {
    201.             field =proxyObject.getClass().getField("proxyInvoker");
    202.             if (field != null) {
    203.                 if (!field.isAccessible()) {
    204.                     field.setAccessible(true);
    205.                 }
    206.                 return (Invoker)field.get(proxyObject);
    207.             } else {
    208.                 return null;
    209.             }
    210.         } catch (Exception e) {
    211.             return null;
    212.         }
    213.     }
    214. }

            如上所示,在getProxy方法中,通过Javassist相关的API,根据接口类型和Invoker接口的实现类,动态创建代理对象的Java类文件,并编译成字节码格式的class文件。

            在此,还是以SOFABoot自带的RPC案例sofaboot-sample-with-rpc为例,看看为com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService接口创建的服务代理对象的源文件:

    1.  import com.alipay.sofa.rpc.core.exception.SofaRpcException;
    2.  importcom.alipay.sofa.rpc.core.request.SofaRequest;
    3.  importcom.alipay.sofa.rpc.core.response.SofaResponse;
    4.  import com.alipay.sofa.rpc.invoke.Invoker;
    5.  importcom.alipay.sofa.rpc.message.MessageBuilder;
    6.  import com.alipay.sofa.rpc.proxy.javassist.JavassistProxy;
    7.  importcom.alipay.sofa.rpc.proxy.javassist.UselessInvocationHandler;
    8.  import java.lang.reflect.Proxy;
    9.   
    10. public class PersonService_proxy_0 extendsProxy
    11.   implements PersonService
    12. {
    13.   public Invoker proxyInvoker = null;
    14.  
    15.   publicPersonService_proxy_0()
    16.   {
    17.     super(new UselessInvocationHandler());
    18.   }
    19.  
    20.   public String sayName(String paramString)
    21.   {
    22.     PersonService localPersonService =PersonService.class;
    23.     String str = "sayName";
    24.     Class[] arrayOfClass = new Class[1];
    25.     Object[] arrayOfObject = new Object[1];
    26.     arrayOfObject[0] = paramString;
    27.     arrayOfClass[0] = String.class;
    28.     SofaRequest localSofaRequest =MessageBuilder.buildSofaRequest(localPersonService, str, arrayOfClass,arrayOfObject);
    29.     SofaResponse localSofaResponse =this.proxyInvoker.invoke(localSofaRequest);
    30.     if (localSofaResponse.isError())
    31.       throw new SofaRpcException(199,localSofaResponse.getErrorMsg());
    32.     Object localObject =localSofaResponse.getAppResponse();
    33.     if ((localObject instanceof Throwable))
    34.       throw ((Throwable)localObject);
    35.     return (String)localObject;
    36.   }
    37.  
    38.   public String toString()
    39.   {
    40.     return this.proxyInvoker.toString();
    41.   }
    42.  
    43.   public int hashCode()
    44.   {
    45.     return this.proxyInvoker.hashCode();
    46.   }
    47.  
    48.   public boolean equals(Object paramObject)
    49.   {
    50.     if ((this == paramObject) ||((!getClass().isInstance(paramObject)) ||(this.proxyInvoker.equals(JavassistProxy.parseInvoker(paramObject)))))
    51.       break label42;
    52.     tmpTernaryOp = false;
    53.     label42: return true;
    54.   }
    55. }

            从上述代码可以看出,该代理对象继承了Proxy类,实现了PersonService接口。主要看一下代理对象对于PersonService接口的sayName方法实现方式。

            在sayName方法中,主要处理逻辑如下:

            1.  本地方法调用封装成SofaRequest请求对象;

            2.  通过调用Invoker接口实现类DefaultClientProxyInvoker(该类继承了ClientProxyInvoker类,而ClientProxyInvoker类实现了Invoker接口)的invoke方法,以SofaRequest为参数,进行远程服务调用,并返回处理结果SofaResponse。

            3.  从SofaResponse对象中获取实际的远程服务的处理结果,并返回给本地客户端。

    1.1.3 总结

            通过比较JDK Proxy创建的代理对象和Javassist创建的代理对象的源码可以看出,其内部实现方式有些不同:

            1.  对于equals、hashCode、toString方法,JDK Proxy创建的代理对象通过反射机制调用java.lang.Object对象的equals、hashCode、toString方法;而Javassist创建的代理对象则直接调用proxyInvoker的equals、hashCode、toString方法;

            2.  对于服务接口的相关方法,如上述案例中PersonService接口的sayName方法,其把本地方法调用转换为远程服务调用的实现逻辑相同,但实现方式不同。JDK Proxy创建的代理对象在JDKInvocationHandler类invoke方法中实现,Javassist创建的代理对象则直接在接口方法中实现。

    展开全文
  • 在移动网络中的安全问题主要是:当MN向家乡代理登记时不会被冒充或数据不会被截获;访问外地子网时,希望与原子网的网络通信安全得到保证,被访问子网不会因移动节点的接人而使安全性受到影响;移动节点无法访问未...
  • Java动态代理机制

    2019-05-29 12:42:23
    retrofit是一个解耦性非常高的网络请求框架,最近在研究的时候发现了动态代理这个非常强大且实用的技术,这篇文章将作为retrofit的前置知识,让大家认识:动态代理有哪些应用场景,什么是动态代理,怎样使用,它的...
  • 利用经济学中的节点信任等级的方式解决网络中存在自私节点的问题,并通过综合评价节点的用户相似度、信任度和缓存等信息,选择社会合作度大的中间代理进行数据的转发,使信息始终沿着网络中社会合作度高的方向传输。...
  • 为了解决切片化网络中由于用户移动性而导致的切片重新接入 问题, 提出了最大化网络吞吐量的用户切换机制来降低越区切换对已有网络切片的影响。该机制根据用户业务类 型的 QoS 服务等级筛选备选接入站点的归属切片...
  • 简单网络管理协议(SNMP)是目前TCP/IP网络中应用最为广泛的网络管理协议。目前SNMP协议主要包括三个版本:SNMP V1、SNMP V2以及最新的SNMP V3。SNMP V3采用了新的SNMP扩展框架,解决了SNMP协议以前版本在安全性和管理...
  • 主动网络流量均衡控制ATEC是一种在主动网络环境,基于多代理MA系统的网络性能控制机制。该方法将多路径路由和资源分配相结合,利用非线性规划启发式算法——多路径等性能策略,实现网络流量和带宽资源的均衡配置,...
  • 延迟容忍网络(DTN)的保管传递机制存在着节点资源不足,束传输不可靠等问题。分析了存储资源的受限对束传输可靠性的影响,并借鉴生物网络机理,提出了基于生物网络的保管传递机制,设计具有免疫行为的生物实体并...
  •  Java动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationHandler接口的invoke方法入手,简单说明一下Java如何实现动态代理的。   首先,invoke方法的完整形式如下:  Java...
  • 目前许多网站都有一种对抗方式,即反爬虫机制,爬虫程序如果运行太快,或访问次数太多,都容易被发现,从而封住IP,导致再也不能继续工作,代理IP的出现就解决了这一问题。采用代理IP后,可以对IP进行定时更换,不同...
  • retrofit是一个解耦性非常高的网络请求框架,最近在研究的时候发现了动态代理这个非常强大且实用的技术,这篇文章将作为retrofit的前置知识,让大家认识:动态代理有哪些应用场景,什么是动态代理,怎样使用,它的...
  • retrofit是一个解耦性非常高的网络请求框架,最近在研究的时候发现了动态代理这个非常强大且实用的技术,这篇文章将作为retrofit的前置知识,让大家认识:动态代理有哪些应用场景,什么是动态代理,怎样使用,它的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 719
精华内容 287
关键字:

网络中代理机制