zoukankan      html  css  js  c++  java
  • 动态代理与静态代理的区别

    JAVA的静态代理与动态代理比较
    一、概念
    代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。按照代理类的创建时期,代理类可分为两种。

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

    二、静态代理类
    如下, HelloServiceProxy 类是代理类,HelloServiceImpl类是委托类,这两个类都实现了HelloService接口。其中HelloServiceImpl类是HelloService接口的真正实现者,而HelloServiceProxy类是通过调用HelloServiceImpl 类的相关方法来提供特定服务的。HelloServiceProxy类的echo()方法和getTime()方法会分别调用被代理的HelloServiceImpl 对象的echo()方法和getTime()方法,并且在方法调用前后都会执行一些简单的打印操作。

    由此可见,代理类可以为委托类预处理消息、把消息转发给委托类和事后处理消息等。

    例程1 HelloService.java
    package proxy;
    import java.util.Date;
    public interface HelloService{
    public String echo(String msg);
    public Date getTime();
    }
    例程2 HelloServiceImpl.java
    package proxy;
    import java.util.Date;
    public class HelloServiceImpl implements HelloService{
    public String echo(String msg){
    return "echo:"+msg;
    }
    public Date getTime(){
    return new Date();
    }
    }
    例程3 HelloServiceProxy.java
    package proxy;
    import java.util.Date;
    public class HelloServiceProxy implements HelloService{
    private HelloService helloService; //表示被代理的HelloService 实例
    public HelloServiceProxy(HelloService helloService){
    this.helloService=helloService;
    }
    public void setHelloServiceProxy(HelloService helloService){
    this.helloService=helloService;
    }
    public String echo(String msg){
    System.out.println("before calling echo()"); //预处理
    String result=helloService.echo(msg); //调用被代理的HelloService 实例的echo()方法
    System.out.println("after calling echo()"); //事后处理
    return result;
    }
    public Date getTime(){
    System.out.println("before calling getTime()"); //预处理
    Date date=helloService.getTime(); //调用被代理的HelloService 实例的getTime()方法
    System.out.println("after calling getTime()"); //事后处理
    return date;
    }
    }
    在Client1 类的main()方法中,先创建了一个HelloServiceImpl对象,又创建了一个HelloServiceProxy对象,最后调用HelloServiceProxy对象的echo()方法。
    例程4 Client1.java
    package proxy;
    public class Client1{
    public static void main(String args[]){
    HelloService helloService=new HelloServiceImpl();
    HelloService helloServiceProxy=new HelloServiceProxy(helloService);
    System.out.println(helloServiceProxy.echo("hello"));
    }
    }
    运行Client1 类,打印结果如下:
    before calling echo()
    after calling echo()
    echo:hello
    例程3 的HelloServiceProxy 类的源代码是由程序员编写的,在程序运行前,它的.class文件就已经存在了,这种代理类称为静态代理类。

    三、动态代理类
    与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。

    Proxy类提供了创建动态代理类及其实例的静态方法。
    (1)getProxyClass()静态方法负责创建动态代理类,它的完整定义如下:

    public static Class<?> getProxyClass(ClassLoader loader, Class<?>[] interfaces) throws IllegalArgumentException

    参数loader 指定动态代理类的类加载器,参数interfaces 指定动态代理类需要实现的所有接口。

    (2)newProxyInstance()静态方法负责创建动态代理类的实例,它的完整定义如下:

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

    参数loader 指定动态代理类的类加载器,参数interfaces 指定动态代理类需要实现的所有接口,参数handler 指定与动态代理类关联的 InvocationHandler 对象。

    以下两种方式都创建了实现Foo接口的动态代理类的实例:
    /**** 方式一 ****/
    //创建InvocationHandler对象
    InvocationHandler handler = new MyInvocationHandler(...);

    //创建动态代理类
    Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class });

    //创建动态代理类的实例
    Foo foo = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).
    newInstance(new Object[] { handler });

    /**** 方式二 ****/
    //创建InvocationHandler对象
    InvocationHandler handler = new MyInvocationHandler(...);

    //直接创建动态代理类的实例
    Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[] { Foo.class }, handler);

    由Proxy类的静态方法创建的动态代理类具有以下特点:
    动态代理类是public、final和非抽象类型的;
    动态代理类继承了java.lang.reflect.Proxy类;
    动态代理类的名字以“$Proxy”开头;
    动态代理类实现getProxyClass()和newProxyInstance()方法中参数interfaces指定的所有接口;

    Proxy 类的isProxyClass(Class<?> cl)静态方法可用来判断参数指定的类是否为动态代理类。只有通过Proxy类创建的类才是动态代理类;

    动态代理类都具有一个public 类型的构造方法,该构造方法有一个InvocationHandler 类型的参数。

    由Proxy类的静态方法创建的动态代理类的实例具有以下特点:
    1. 假定变量foo 是一个动态代理类的实例,并且这个动态代理类实现了Foo 接口,那么“foo instanceof Foo”的值为true。把变量foo强制转换为Foo类型是合法的:
    (Foo) foo //合法

    2.每个动态代理类实例都和一个InvocationHandler 实例关联。Proxy 类的getInvocationHandler(Object proxy)静态方法返回与参数proxy指定的代理类实例所关联的InvocationHandler 对象。

    3.假定Foo接口有一个amethod()方法,那么当程序调用动态代理类实例foo的amethod()方法时,该方法会调用与它关联的InvocationHandler 对象的invoke()方法。

    InvocationHandler 接口为方法调用接口,它声明了负责调用任意一个方法的invoke()方法:
    Object invoke(Object proxy,Method method,Object[] args) throws Throwable

    参数proxy指定动态代理类实例,参数method指定被调用的方法,参数args 指定向被调用方法传递的参数,invoke()方法的返回值表示被调用方法的返回值。

    四、最后看一个实例:
    HelloServiceProxyFactory 类的getHelloServiceProxy()静态方法负责创建实现了HelloService接口的动态代理类的实例。

    例程5 HelloServiceProxyFactory.java
    package proxy;
    import java.lang.reflect.*;
    public class HelloServiceProxyFactory {
    /** 创建一个实现了HelloService 接口的动态代理类的实例
    * 参数helloService 引用被代理的HelloService 实例
    */
    public static HelloService getHelloServiceProxy(final HelloService helloService){
    //创建一个实现了InvocationHandler接口的匿名类的实例
    InvocationHandler handler=new InvocationHandler(){
    public Object invoke(Object proxy,Method method,Object args[])throws Exception{
    System.out.println("before calling "+method); //预处理
    Object result=method.invoke(helloService,args);
    //调用被代理的HelloService 实例的方法
    System.out.println("after calling "+method); //事后处理
    return result;
    }
    };
    Class classType=HelloService.class;
    return (HelloService)Proxy.newProxyInstance(classType.getClassLoader(),
    new Class[]{classType},
    handler);
    }
    }
    如下所示的Client2 类先创建了一个HelloServiceImpl 实例,然后创建了一个动态代理类实例helloServiceProxy,最后调用动态代理类实例的echo()方法。
    例程6 Client2.java
    package proxy;
    public class Client2{
    public static void main(String args[]){
    HelloService helloService=new HelloServiceImpl();
    HelloService helloServiceProxy=HelloServiceProxyFactory.getHelloServiceProxy(helloService);
    System.out.println("动态代理类的名字为"+helloServiceProxy.getClass().getName());
    System.out.println(helloServiceProxy.echo("Hello"));
    }
    }
    运行Client2,打印结果如下:
    动态代理类的名字为$Proxy0
    before calling public abstract java.lang.String proxy.HelloService.echo(java.lang.String)
    after calling public abstract java.lang.String proxy.HelloService.echo(java.lang.String)
    echo:Hello
    从结果看出,动态代理类的名字为$Proxy0。
    评论(3)|100

    yh114long |来自团队java开发 |五级采纳率30%
    擅长:编程语言足球大连市
    按默认排序|按时间排序
    其他1条回答
    2011-07-08 14:12MySelf_Beyond|四级
    楼上说的太多了,没看。动态代理直接看多态的资料。
    我只简单是说一下:
    比如你继承了一个类或一个接口。
    在你重写了父类的方法后,那么当你声明了一个父类引用指向子类对象的实例时
    这个实例调用重写的方法时就会自动的绑定为子类的方法。

    例:public class A{
    public void a1(){
    System.out.println("父A");
    }
    }

    class B extends A{
    public void a1(){
    System.out.println("子B");
    }

    }

    class C{
    public static void main(String arg[]){
    A a = new B();
    a.a1();
    }
    }

    输出结果就是 子B

  • 相关阅读:
    python--模块与包
    内置函数 的总结
    迭代器 生成器 列表推导式 生成器表达式的一些总结
    函数的有用信息 带参数的装饰器 多个装饰器装饰一个函数
    函数名的应用(第一对象) 闭包 装饰器
    动态参数 名称空间 作用域 作用域链 加载顺序 函数的嵌套 global nonlocal 等的用法总结
    函数的初识 函数的返回值 参数
    文件操作 常用操作方法 文件的修改
    遍历字典的集中方法 集合的作用 以及增删查的方法
    计算机硬件的小知识
  • 原文地址:https://www.cnblogs.com/peijie-tech/p/3409113.html
Copyright © 2011-2022 走看看