设计模式——代理模式

一、概念

代理模式(Proxy Pattern)是指为其他对象提供一种代理,以控制对这个对象的访问,属于结构型 模式。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标 对象之间起到中介的作用。

二、分类

代理分为静态代理和动态代理。

静态代理

例子:

有一些闲置的物品需要放在一些平台进行代售,本文根据这个案例模拟静态设计模式。

public interface ITicket {
    void sellTicket();
}
public class SellUser implements ITicket{

    @Override
    public void sellTicket() {
        System.out.println("闲置物品");
    }
}
public class PlatFormProxy implements ITicket{
    private ITicket ticket;

    public PlatFormProxy(ITicket ticket){
        this.ticket = ticket;
    }

    @Override
    public void sellTicket() {
        System.out.println("xx平台出售物品如下");
        ticket.sellTicket();
    }
}
public class Client {
    public static void main(String[] args) {
        SellUser sellUser = new SellUser();
        PlatFormProxy platFormProxy = new PlatFormProxy(sellUser);
        platFormProxy.sellTicket();
    }
}

 动态代理

从静态代理的代码中可以发现,静态代理的缺点显而易见,那就是当真实类的方法越来越多的时候,这样构建的代理类的代码量是非常大的,所以就引进动态代理.动态代理允许使用一种方法的单个类(代理类)为具有任意数量方法的任意类(真实类)的多个方法调用提供服务,看到这句话,可以容易的联想到动态代理的实现与反射密不可分。

Jdk代理涉及到java.lang.reflect包中的InvocationHandler接口和Proxy类,核心方法是

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 

jdk动态代理过程中实际上代理的是接口,是因为在创建代理实例的时候,依赖的是java.lang.reflect包中Proxy类的newProxyInstance方法,该方法的生效就恰恰需要这个参数;

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException{
        ……
        }

 我们就以房东出租房子作为例子模拟动态代理

public interface Rent {
    public void rent();
}
public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东出租屋子");
    }
}
public class ProxyInvocationHandler implements InvocationHandler {

    private Rent rent;

    public void setRent(Rent rent){
        this.rent = rent;
    }

    public Object getProxy(){
        Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
        return o;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //动态代理本质就是使用反射
        seeHouse();
        Object invoke = method.invoke(rent, args);
        return invoke;
    }

    public void seeHouse(){
        System.out.println("中介带你看房子");
    }
}
public class Client {
    public static void main(String[] args) {
        Host host = new Host();//代理角色
        //代理角色
        ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
        proxyInvocationHandler.setRent(host);
        Rent proxy = (Rent) proxyInvocationHandler.getProxy();
        proxy.rent();
    }
}
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {    
        //检查InvocationHandler是否为空,为空抛出空指针异常
        Objects.requireNonNull(h);
        //克隆拿到接口
        final Class<?>[] intfs = interfaces.clone();
        //进行安全校验
        final SecurityManager sm = System.getSecurityManager();
        //检查是否能被代理
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
 
        /*
         * Look up or generate the designated proxy class.
         * 得到代理类
         */
        Class<?> cl = getProxyClass0(loader, intfs);
 
        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            //通过构造方法得到代理类的对象
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //new得到代理对象
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

概况的说,上面通过反射获取代理类的构造器生成代理类对象。

为什么会自动执行里面的invoke方法呢?


//以下代码由$Proxy0.class反编译得到
public final class $Proxy0 extends Proxy implements PorxyInte {
	private static Method m3;	
	static {		
		m3 = Class.forName("cn.itcast.web.Test.PorxyInte").getMethod("test", new Class[0]);			
		}    
    
	//构造方法。将invocationhandler实例从代理类赋值到父类
	public $Proxy0(InvocationHandler invocationhandler)
	{
		super(invocationhandler);//创建父类对象
	}

	//此处可以看出,当调用代理类的test方法,会执行父类对象属性h的invoke方法,
	//h即为通过匿名内部类创建的处理器对象
	public final void test() {
		super.h.invoke(this, m3, null);	//这里的this是代理对象,m3为test方法
}

参考:

Java动态代理invoke方法自动执行的原因_java proxy invocation 被执行两次-CSDN博客

Java设计模式(5):代理模式_java委托模式和代理模式-CSDN博客 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值