说到代理首先想到的是代理卖东西,比如你帮某个衣服品牌代理卖衣服,客户告诉你选中的衣服款式,你再转告给卖家,实际上发货和衣服还是在卖家那里,你在中间只是做一个前置和后置,卖家发货了,买家如果需要售后服务还是会先联系你,由你转告卖家处理。

那么java上为什么会用到代理模式呢?再说一个例子:你的项目中有一个商店的类,这个商店在初期时候被定义只有两个方法:买和卖。现在项目越做越大,需求商店有搜索等功能,那么这时候应该怎么办呢?

想到的方法有:1、修改这个商店类,给它加上搜索等功能;

       2、写个子类继承它,子类中加上搜索等功能;

以上方法都可以,但是和代理并没有什么关系,为什么要举上面的例子呢?是为了对比区分真正需要代理的情况。 

注意区分:还是那个原来的商店类,新的需求是需要在“买“的方法中先判断商品是否还有剩余、顾客金钱是否足够支付等;和”卖“中先判断这个商品是否过期等。这个时候能想到办法有:

1、修改这个商店类里的“买”和“卖”方法,加上前置或者后置的需求;

2、写子类覆写“买”和“卖”的方法。

3、代理。

以上两个方法都可以,但是如果这个类不是你写的,或者是第三方jar包,那么修改起来的成本可能会非常大。这时候我们就需要用到代理模式。

第一种:静态代理

有一个商店类,功能单一,只有买和卖两个方法。

public class Shop {

    
    public void buy(String shopName){
        //
    }
    
    public void sell(String shopName){
        //
    }
}

代理商店类,给买和卖方法加入一些前置或者后置的操作:

public class AgentShop {

    private Shop shop = new Shop();
    
    
    public void buy(String shopName){
        //假如 shopName = 可乐;检查可乐是否还有库存
        shop.buy(shopName);
    }
    
    public void sell(String shopName){
        //假如 shopName = 雪碧; 检查雪碧是否合法
        shop.sell(shopName);
    }
    
}

从上面可以看出来,每一个代理类只能服务一个类或者接口,代码很多,类很多,有没有更优化的方法呢,java提供了一种动态代理机制,可以动态生成一个代理类。

第二种:动态代理

还是有一个功能单一的商店,这次不是类换成接口演示:

public interface IShop {

    public void buy(String shopName);
    
    public void sell(String shopName);
}

写一个子类:

public class NewShop implements IShop {

    @Override
    public void buy(String shopName) {

    }

    @Override
    public void sell(String shopName) {

    }

}

使用java提供的InvocationHandler接口:

/**
 * 代理商店  实现InvocationHandler接口
 * 
 *
 */
public class DynamicAgentShop implements InvocationHandler {
    private Object mTarget;
    
    /**
     * DOC 通过反射动态生成一个代理对象,调用该代理对象中的任何方法,都会进入invoke方法中。
     * @param target
     * @return
     */
    public Object bind(Object target){
        this.mTarget = target;
        return java.lang.reflect.Proxy.newProxyInstance(mTarget.getClass().getClassLoader(), mTarget.getClass().getInterfaces(), this);
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result = null;
        //这里写前置
        result = method.invoke(mTarget, args);
        //这里写后置
        return result;
    }

}

 

测试的写法:

private void testDynamicAgent() {
        DynamicAgentShop dynamicAgentShop  =new DynamicAgentShop();
        IShop newShop = (IShop) dynamicAgentShop.bind(new NewShop());
        newShop.buy("可乐");
    }