JDK动态代理模式

来源:互联网 发布:淘宝上聚划算的要求 编辑:程序博客网 时间:2024/05/22 09:44

动态代理模式是对方法的横向增强,它不同于继承,继承通过对父类方法的覆盖,重新对方法进行定义,而横向增强是对方法执行前和执行后的一个增加,不重新定义方法。

代理方式有两种:
jdk代理模式:对接口或实现接口的类进行代理
CGLib代理模式:对类进行代理

jdk动态代理机制中必不可少的类和接口,一个是InvocationHandler(接口)、另一个是Proxy(类)。

必须有一个类实现InvocationHandler接口,从而实现其中的invoke()方法,在invoke()方法中对代理的方法进行增强。我们来看看API文档中对这个类是怎么描述的:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:

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

我们来看看Proxy类的描述:

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. 

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

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

这个方法的作用就是得到一个动态代理的对象,通过这个对象可以调用类中被增强后的方法,实际就是调用h中的invoke()方法。

示例代码:

//接口package com.zhangyike.proxy;public interface Person {    public void speak();    public void eat();}
//接口的实现类,可有可无package com.zhangyike.proxy;public class ImpPerson implements Person {    @Override    public void speak() {        System.out.println("实现类中说话");    }    @Override    public void eat() {        System.out.println("实现类中吃");    }}
//InvocationHander的实现类package com.zhangyike.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class Hander implements InvocationHandler {    Object t;    Hander(Object t){        this.t = t;    }    Hander(){    }    public Object creatImplementsClass(){        //对接口的实现类对方法进行增强,参数将接口、接口的实现类与InvocationHandler对象关联,也就是说调用代理类中的方法就是调用InvocationHandler实现类中的invoke()        Object instance = Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), this);        return instance;    }    public Object creatInterfaceClass(Class<?> ifClass){        //只有接口没有接口实现类去得到代理对象。将接口与InvocationHandler对象关联,也就是说调用代理类中的方法就是调用InvocationHandler实现类中的invoke()        Object instance = Proxy.newProxyInstance(ifClass.getClassLoader(), new Class[]{ifClass}, this);        return instance;    }    //调用该方法    @Override    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        String name = method.getName();        if (name.equals("speak")) {//对说方法增强            System.out.println("人在说话前");            //t!=null表示有实现接口的类,只提供接口不能调用该方法            if (t != null) {                method.invoke(t, args);            }            System.out.println("人在说话后");        }else{//对吃方法增强            if (t != null) {                method.invoke(t, args);            }            System.out.println(name);        }        return null;    }}
Demo测试类:package com.zhangyike.proxy;public class DemoTest {    public static void main(String[] args) {        test1();        test();    }    public static void test(){        Hander hander = new Hander();        //获取没有接口实现类的对象        Person person = (Person)hander.creatInterfaceClass(Person.class);        System.out.println("对接口增强:");        person.speak();        System.out.println("------------------------------------------------------");        person.eat();    }    public static void test1(){        ImpPerson impPerson = new ImpPerson();        Hander hander = new Hander(impPerson);        //获取没有接口实现类的对象        Person person = (Person) hander.creatImplementsClass();        System.out.println("对实现类增强:");        person.speak();        System.out.println("*******************************************************");        person.eat();    }}

注意事项:
在测试类的test1()方法中,获取代理类后,将代理对象转换,只能转换为接口类,不能转换为接口的实现类,否则会出现异常:
Exception in thread “main” java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.zhangyike.proxy.ImpPerson
at com.zhangyike.proxy.DemoTest.test1(DemoTest.java:23)
at com.zhangyike.proxy.DemoTest.main(DemoTest.java:5)
这个也很好理解:JDK动态代理必须要有接口,对接口中的方法进行增强,而实现类中有他特有的方法,代理类无法对他进行增强,通过Proxy对象只能得到接口对象,不能得到实现类对象。

0 0