JDK动态代理模式

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

代理方式有两种:
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 Throwable

proxy:  指代我们所代理的那个真实对象
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 IllegalArgumentException

loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代
理对象进行加载,可以是实现类的ClassLoader也可以是接口的ClassLoader

interfaces:一个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对象只能得到接口对象,不能得到实现类对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值