Java的代理分为静态代理和动态代理,主要的思想是代理模式的运用。
(一)代理模式:
1. 什么是代理,什么是代理类,什么是委托类,什么是代理接口?
根据某个对象A提供一个对象A',之后用对象A'代替对象A与其它对象交互,这种行为就是代理;
对象A'就是对象A的一个代理类,即A'为代理类;
对象A委托了对象A'与外界联系,即对象A为委托类;
对象A可以有任意多个代理( 类),每个代理(类)都代理A需要的某一个主题,这个主题的内容就是代理接口的内容。
2. 根据类的生成时间的不同,将代理分为静态代理和动态代理。
静态代理:在程序编译前,代理类已经存在于源代码中。
动态代理:在程序编译的过程中,根据源代码生成相应的代理类。
3. 静态代理:
首先看一个例子:
Server.class:委托类
/**
* 委托类
* @author qw
*
*/
public class Server implements CalculatorProtocol{
/**
* 因为Server需要一个关于Calculator方面的代理,所以实现了CalculatorProtocol接口
*/
@Override
public int add(int a, int b) {
// TODO Auto-generated method stub
return a+b;
}
}
CalculatorProtocol.class:代理接口
/**
* 代理接口,关于Calculator这一代理主题
* @author qw
*
*/
public interface CalculatorProtocol {
public int add(int a,int b);
}
CalculatorClient.class:代理类
/**
* Server关于Calculator主题的代理类
* @author qw
*
*/
public class CalculatorClient implements CalculatorProtocol{
//代理类持有一个委托类对象的引用
private CalculatorProtocol delegate;
public CalculatorClient(CalculatorProtocol delegate){
this.delegate=delegate;
}
/**
* 代理类除了执行委托类原有的功能,还要加上委托类委托给代理类的一些功能,如本例的数据预处理
*/
@Override
public int add(int a, int b) {
// TODO Auto-generated method stub
System.out.println("进行一些预处理");
int result=delegate.add(a, b);
System.out.println("进行一些后续处理");
return result;
}
}
Demo.class:测试类
/**
* 测试类
* @author qw
*
*/
public class Demo {
public static void main(String[] args) {
Server server=new Server();//实际委托对象(被代理对象)
CalculatorProtocol proxy=new CalculatorClient(server);//关于一个代理主题的代理对象
int sum=proxy.add(1, 1);//通过proxy执行server的add功能,同时加上server交代给proxy的任务(数据预处理)
System.out.println("sum="+sum);
}
}
以上是静态代理的一个例子,可以发现静态代理的两个缺点:
(1)如果委托类Server此时需要一个关于打印PrintProtocol的代理PrintProxy,就需要再手动创建一个代理接口和一个代理类,这是不现实的。
(2)如果委托类Server给它的CalculatorProtocol代理接口增加几个方法,那么所有关于CalculatorProtocol的代理都需要实现这几个方法,增加了代码维护的复杂度。
这时就需要动态代理了!
4. 动态代理:
动态代理最重要的一点就是委托类的代理(们)是通过Java的反射机制在程序的运行过程中动态生成的。
实现动态代理需要了解以下的类和接口:
(1)java.lang.reflect.Proxy
这是api的解释: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提供了一组静态方法,用于创建动态代理类及其实例。
Modifier and Type | Field and Description |
---|---|
protected InvocationHandler | h the invocation handler for this proxy instance. 对于该代理实例的调用处理器 |
Modifier | Constructor and Description |
---|---|
protected | Proxy(InvocationHandler h) Constructs a new Proxy instance from a subclass (typically, a dynamic proxy class) with the specified value for its invocation handler.根据动态代理类生成一个它的带有一个调用处理器的实例对象 |
Modifier and Type | Method and Description |
---|---|
static InvocationHandler | getInvocationHandler(Object proxy) Returns the invocation handler for the specified proxy instance. 获取指定动态代理所关联的调用处理器 |
static Class<?> | getProxyClass(ClassLoader loader,Class<?>... interfaces) Returns the java.lang.Class object for a proxy class given a class loader and an array of interfaces.获取关于指定类加载器和一组接口的动态代理类的对象(先创建再return) |
static boolean | isProxyClass(Class<?> cl) Returns true if and only if the specified class was dynamically generated to be a proxy class using the getProxyClass method or thenewProxyInstance method.判断指定的类对象是否是一个动态代理类 |
static Object | newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler. 获取指定类加载器、一组接口以及调用处理器生成的动态代理类的一个实例 |
(2)java.lang.reflect.InvocationHandler:
这是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 theinvoke
method of its invocation handler.
它是一个接口,需要被各类调用处理器实现,每一个动态代理的实例都有一个与之关联的调用处理器,当动态代理类中的一个方法被调用时,这个方法会被动态编译并且派发到相应的调用处理器的invoke方法中。即这个接口定义了一个invoke方法,用于处理动态代理类的实例的方法调用。
通常开发人员需要实现该接口,并且在invoke方法中实现对委托类的代理访问。
Method Summary
Modifier and Type | Method and Description |
---|---|
Object | invoke(Object proxy,Method method,Object[] args) Processes a method invocation on a proxy instance and returns the result. |
最重要的:invoke这个方法会被调用处理器调用 当且仅当 一个代理实例的方法被调用且这个代理实例与这个调用处理器互相关联。这是固定的运行机制,只要传入三个参数,即:代理类实例A、被调用的方法对象b、调用处理器C,就相当于进行了一种绑定:当A.b被调用时,就会调用C.invoke方法,而这个方法是我们创建调用处理器时候需要实现的。
来个例子:
Server.class:委托类
/**
* 委托类
* @author qw
*
*/
public class Server implements CalculatorProtocol{
/**
* 因为Server需要一个关于Calculator方面的代理,所以实现了CalculatorProtocol接口
*/
@Override
public int add(int a, int b) {
// TODO Auto-generated method stub
return a+b;
}
}
CalculatorProtocol.class:代理接口
/**
* 代理接口,关于Calculator这一代理主题
* @author qw
*
*/
public interface CalculatorProtocol {
public int add(int a,int b);
}
CalculatorHandler.class:具体的调用处理器
/**
* 实现InvocationHandler接口的调用处理器
* @author qw
*
*/
public class CalculatorHandler implements InvocationHandler{
private Object delegate;
public CalculatorHandler(Object delegate){
this.delegate=delegate;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("预处理");
Object result=method.invoke(this.delegate, args);
System.out.println("后续处理");
return result;
}
}
Demo.class:测试类
/**
* 测试类
* @author qw
*
*/
public class Demo {
public static void main(String[] args) {
CalculatorProtocol server=new Server();
//生成一个关于某个委托类的handler
InvocationHandler handler=new CalculatorHandler(server);
//生成动态代理类的一个实例,这个动态代理类绑定了handler
CalculatorProtocol client=(CalculatorProtocol) Proxy.newProxyInstance(server.getClass().getClassLoader(), server.getClass().getInterfaces(), handler);
//调用代理类的add方法会将请求转发从而调用handler的invoke方法
int sum=client.add(1, 2);
System.out.println("sum="+sum);
}
}
可以看出,以上并没有代理类Proxy的代码,取而代之的是一个调用处理器handler,这是因为代理类是动态来生成的,这个处理器handle就是用来在程序的运行过程中动态的生成相应的代理类,并且进行绑定,当调用该代理类的某一个方法时,会转而去调用这个handler的invoke方法,而这个方法实现的就是代理的内容。
根据自己的理解的示意图:
在程序中我们会把 CalculatorProtocol client=(CalculatorProtocol) Proxy.newProxyInstance(...); 用作代理类,实质这个代理类是动态生成的,当调用这个代理类的方法时会转而去调用与这个代理类绑定的调用处理器类的invoke方法。