代理模式总结

 

         代理模式在设计模式中是一种比较重要的设计模式,关于它的变种很多,比如远程代理,虚拟代理,动态代理,但是其本质都是一致的,即为另一个对象提供一个替身或占位符以控制这个对象的访问,现在就代理模式进行一个总结

 

下图是代理模式的一般类图


RealSubject通常是真正做事的对象,proxy会控制对RealSubject的访问

Proxy持有Subject的引用,所以必要时它可以将请求转发给Subject,并且负责创建RealSubject对象

Proxy和RealSubject都实现了Subject接口,这允许任何客户都可以像处理RealSubject对象一样地处理proxy对象

 

1.      远程代理:

即是对远程对象的代理,客户方法调用本地代理对象上的方法,再由代理处理所有网络通信的低层细节,实现对远程对象的方法调用,java的RMI已经实现了远程调用的功能

如何使用java RMI

(1)    远程接口

import java.rmi.*;

public interface MyRemote extends Remote {

    public StringsayHello() throws RemoteExceptoin;

}

远程方法的变量和返回值,必须属于原语类型或者实现了可序列化

(2)远程实现

public class MyRemoteImpl extends UnicastRemoteimplementsMyRemote {

public String sayHello() {

    Return “server say hello”;

}

public MyRemoteImpl() throws RemoteException{ }

public static void main(String[] args) {

    try {

         MyRemote service =new MyRemoteImpl();

        Naming.rebind(“RemoteHello”, service); //注册这个实现对象时,RMI注册的是stub

    }catch (Exception ex) {

         ex.printStackTrace();

}

 

执行rmic,为服务类产生stub和skeleton

rmic MyRemoteImpl   产生两个新类:MyRemoteImpl_Stub.class和MyRemoteImpl_Skel.class

 

执行rmiregistry

rmiregistry

 

java MyRemoteImpl   实例化服务对象,然后到RMIregistry中注册

 

客户端代码

import java.rmi.*;

public class MyRemoteClient {

public staticvoid main(String[] args) {

    try {

        MyRemote service =(MyService)Naming.lookup(rmi://127.0.0.1/RemoteHello); //客户需要到RMI registry中去寻找,RMI返回stub给客户端

        System.out.println(service.sayHello());//客户通过stub来调用远程方法

    } catch (Exception ex) {

        ex.printStackTrace();

}

}

 

远程代理类如何套用RMI框架

服务端

public interface ServiceRemote extendsRemote {

public String hello()throws RemoteException;

}

 

要代理的类实现这个远程接口

pulic class Service extendsUnicastRemoteObject implements ServiceRemote {

public Service()throws RemoteException {}

public Stringhello() { return “Hello”;}

}

 

客户端

代理类实现

Import java.rmi.*;

Public class ProxyService {

ServiceRemoteser;

PublicProxyService(ServiceRemote ser) {

    this.ser = ser;

}                            

 

public String SayHello(){

    try {

        ser.hello();

    } catch (RemoteExceptoin e) {

        e.printStacekTrace();

}

}

 

2.什么是虚拟代理

 

当需要创建一个开销比较大的对象的时候,同时需要给客户返回一个请等待的信息,这时可用到虚拟代理,当对象在创建前和创建中时,由虚拟代理来扮演对象的替身,对象创建后代理就会将请求直接委托给对象

当创建开销大的对象时,一般是新开一个线程来创建对象,当对象创建完毕时再通过事件来通知代理,对象创建成功,这时代理可再次调用对象的方法

 

3.什么是动态代理

利用java的反射机制,我们可以在运行时动态地创建一个代理类,实现一个或多个接口,并将方法的调用转发到所指定的类,实际的代理类是在运行时创建的,所以叫做动态代理

 

Proxy是由java产生的,而且实现了完整的Subject接口,我们可以提供一个InvocationHandlerImpl的实现类,Proxy上的任何方法调用都会被传入此类,InvocationHandlerImpl控制对RealSubject方法的访问

 

代码实现举例

public interface Hello {

void sayHello(Stringstr);

}

 

public class HelloImpl implements Hello {

public void sayHello(Stringstr) {

    System.out.println(str);

}

 

importjava.lang.reflect.*;

public classHelloInvocationHandler implements InvocationHandler {

    Object delegate;

    public OwnerInvocationHandler ( Object hello){

        this.delegate = hello;

    }

    //通过代理调用的方法最终都会调用invoke

    public Object invoke ( Object proxy, Methodmethod, Object[] args) throws IllegalAccessException {

        try{

            System.out.println(“before invoke”);

            method.invoke(delegate, args);

System.out.println(“before invoke”);

}catch (InvocationTargetException e) {

            e.printStackTrace();

}

}

 

//动态生成代理类

public Hello getHelloProxy(Hello hello) {

    Return (Hello) Proxy.newProxyInstance(

                 hello.getClass().getClassLoader(),

                 hello.getClass().getInterfaces(),

                 this);

}

 

Public class ProxyTest {

   public static void main(String[] args) { 

       Hello impl = new HelloImpl(); 

       HelloInvocationHandler handler = new HelloInvocationHandler (impl); 

       //这里把handler与impl新生成的代理类相关联 

       Hello hello = handler. getHelloProxy(impl);

       

       //这里无论访问哪个方法,都是会把请求转发到handler.invoke 

       hello.print("All the test"); 

       hello.sayHello("Denny"); 

   } 

 

Java动态代理实现机制分析:

通过实现 InvocationHandler 接口创建自己的调用处理器;

通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;

通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;

通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

对照代码是:

 

/ InvocationHandlerImpl 实现了InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发

// 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用

InvocationHandler handler = newInvocationHandlerImpl(..);

 

// 通过 Proxy 为包括 Interface接口在内的一组接口动态创建代理类的类对象

Class clazz = Proxy.getProxyClass(classLoader,new Class[] { Interface.class, ... });

 

// 通过反射从生成的类对象获得构造函数对象

Constructor constructor =clazz.getConstructor(new Class[] { InvocationHandler.class });

 

// 通过构造函数对象创建动态代理类实例

Interface Proxy =(Interface)constructor.newInstance(new Object[] { handler });

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值