一、概述
1. 什么是代理
我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品。关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,“委托者”对我们来说是不可见的;其次,微商代理主要以朋友圈的人为目标客户,这就相当于为厂家做了一次对客户群体的“过滤”。我们把微商代理和厂家进一步抽象,前者可抽象为代理类,后者可抽象为委托类(被代理类)。通过使用代理,通常有两个优点,并且能够分别与我们提到的微商代理的两个特点对应起来:
优点一:可以隐藏委托类的实现;
优点二:可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。
2. 静态代理
若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。
二、动态代理
代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。 这么说比较抽象,下面我们结合一个实例来介绍一下动态代理的这个优势是怎么体现的。
现在,假设我们要实现这样一个需求:在执行委托类中的方法之前输出“before”,在执行完毕后输出“after”。我们还是以上面例子中的Vendor类作为委托类,BusinessAgent类作为代理类来进行介绍。首先我们来使用静态代理来实现这一需求,相关代码如下:
public class BusinessAgent implements Sell {
private Vendor mVendor;
public BusinessAgent(Vendor vendor) {
this.mVendor = vendor;
}
public void sell() {
System.out.println("before");
mVendor.sell();
System.out.println("after");
}
public void ad() {
System.out.println("before");
mVendor.ad();
System.out.println("after");
}
}
从以上代码中我们可以了解到,通过静态代理实现我们的需求需要我们在每个方法中都添加相应的逻辑,这里只存在两个方法所以工作量还不算大,假如Sell接口中包含上百个方法呢?这时候使用静态代理就会编写许多冗余代码。通过使用动态代理,我们可以做一个“统一指示”,从而对所有代理类的方法进行统一处理,而不用逐一修改每个方法。下面我们来具体介绍下如何使用动态代理。
1. 创建统一的接口
interface Sell{
public void add();
public void sell();
}
2. 创建被代理类
动态带来中,要求被代理类必须实现某个接口,我们这里实现的是Sell接口。委托类的定义如下:
// 被代理类
class Vendor implements Sell{
@Override
public void add() {
System.out.println("厂家加货");
}
@Override
public void sell() {
System.out.println("厂家出售衣服");
}
}
3. 创建中介类
3.1 InvocationHandler接口
在使用动态代理时,我们需要定义一个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接口,这个接口的定义如下:
此接口可以帮我们动态的决定调用的是哪一个被代理类中的哪一个方法,并且可以将该方法的返回值拿到。
/**
* 调用处理程序
*/
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args);
}
3.2 中介类
上面我们提到过,中介类必须实现InvocationHandler接口,作为调用处理器”拦截“对代理类方法的调用。中介类的定义如下:
// 动态代理需要的中介类
class MYInvocationHandler implements InvocationHandler {
private Object object;
public MYInvocationHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用方法之前...");
Object result = method.invoke(object,args);
System.out.println("调用方法之后...");
return result;
}
}
从以上代码中我们可以看到,中介类持有一个委托类对象引用,在invoke方法中调用了委托类对象的相应方法,看到这里是不是觉得似曾相识?
通过聚合方式持有委托类对象引用,把外部对invoke的调用最终都转为对委托类对象的调用。这不就是我们上面介绍的静态代理的一种实现方式吗?
实际上,中介类与委托类构成了静态代理关系,在这个关系中,中介类是代理类,委托类就是委托类;
代理类与中介类也构成一个静态代理关系,在这个关系中,中介类是委托类,代理类是代理类。
也就是说,动态代理关系由两组静态代理关系组成,这就是动态代理的原理。下面我们来介绍一下如何”指示“以动态生成代理类。
4. 代理类工厂
我们创建一个代理类的工厂,然后根据传入被代理类对象的不同,动态的生产对应的代理类对象
而在这个工厂中,很重要的一个方法就是:Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h);
// 代理类工厂
class ProxyClassFactory{
public static Object newProxyInstance(Object obj){
MYInvocationHandler handler = new MYInvocationHandler(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
}
}
5. 动态生成代理类
public class DynamicTest {
@Test
public void dynamicTest(){
Vendor vendor = new Vendor();
Sell o = (Sell) ProxyClassFactory.newProxyInstance(vendor);
o.add();
o.sell();
}
}