一、什么是代理
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。详细介绍请参考:java设计模式之代理模式。为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。
二、动态代理相关类的介绍
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。
1、InvocationHandler
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
我们看到这个方法一共接受三个参数,那么这三个参数分别代表如下:
- proxy: 指代JDK动态生成的最终代理对象
- method: 指代的是我们所要调用真实对象的某个方法的Method对象
- args: 指代的是调用真实对象某个方法时接受的参数
2、Proxy
Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义:
- loader: 一个ClassLoader对象,定义了由哪个ClassLoader来对生成的代理对象进行加载
- interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
- 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
其实我们所说的DynamicProxy(动态代理类)是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。如此一来,我们可以把该class的实例当作这些interface中的任何一个来用(可以强转为相应的接口类型)。当然,这个DynamicProxy其实就是一个Proxy,它不会做实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
三、实例演示
1、定义接口
通过JDK实现的代理对象必须是一个接口的实现。
package com.kang.proxy;
//需要动态代理的接口
public interface Subject {
public void hello(String name);
public String bye();
}
2、被代理的类(实际处理业务的类)
这个类实现上面定义的接口。
package com.kang.proxy;
//被代理类
public class RealSubject implements Subject{
@Override
public void hello(String name) {
System.out.println("hello "+name);
}
@Override
public String bye() {
System.out.println("bye");
return "bye";
}
}
3、InvocationHandler实现类
package com.kang.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//每次生成动态代理类对象时都需要指定一个实现了InvocationHandler接口的调用处理器对象
public class InvocationHandlerImpl implements InvocationHandler {
private Object subject; // 这个就是我们要代理的真实对象,也就是真正执行业务逻辑的类
public InvocationHandlerImpl(Object subject) {
// 通过构造方法传入这个被代理对象
this.subject = subject;
}
/**
* 该方法负责集中处理动态代理类上的所有方法调用。 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
*
* @param proxy
* 最终生成的代理类实例
* @param method
* 被调用的方法对象
* @param args
* 调用上面method时传入的参数
* @return method对应的方法的返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("可以在调用实际方法前做一些事情");
System.out.println("当前调用的方法是" + method.getName());
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
result = method.invoke(subject, args);// 需要指定被代理对象和传入参数
System.out.println(method.getName() + "方法的返回值是" + result);
System.out.println("可以在调用实际方法后做一些事情");
System.out.println("------------------------");
return result;// 返回method方法执行后的返回值
}
}
4、测试类
package com.kang.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;