【设计模式】结构型01代理模式(Proxy Pattern)

代理模式(Proxy Pattern)


定义:顾名思义,增加中间层,为其他对象提供一种代理以控制对这个对象的访问。核心在于代理二字。

1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。

2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

静态代理与动态代理:

静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理类:在程序运行时,运用反射机制动态创建而成。
静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。

动态代理是实现JDK里的InvocationHandler接口的invoke方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过Proxy里的newProxyInstance得到代理对象。

代码:静态代理:

这里笔者通过一个替考的例子,演示了小学生王小虎找人替考被骗子骗的故事:

package com.pat.proxy.staticproxy;
/**
 * 统一接口
 * @author ZX
 *
 */
public interface Student {
	void exam();
}
/**
 * 被代理类-学生王小虎
 * @author ZX
 *
 */
class BadStudent implements Student{
	private String name="王小虎";

	@Override
	public void exam() {
		System.out.println(name+"参加考试");
		
	}
	public BadStudent(){
	}
	public BadStudent(String name){
		this.name=name;
	}
}
/**
 * 代理类-替考的骗子
 * 静态代理只代理固定的类
 * @author ZX
 *
 */
class Swindler implements Student{
	private String name;
	private BadStudent badStudent;
	
	@Override
	public void exam() {
		//非重点,前后可以添加某些操作
		System.out.println(name+"进入考场");
		badStudent= new BadStudent(name);
		badStudent.exam();
		System.out.println(name+"没交试卷");
		
	}
	public Swindler(String name){
		this.name=name;
	}
}

测试类:

package com.pat.proxy.staticproxy;

public class Test {
	public static void main(String[] args) {
		Student s = new Swindler("老司机");
		s.exam();
	}
}

结果:

老司机进入考场
老司机参加考试
老司机没交试卷
这就说明了一个问题,做生意得讲诚信,你好好搞替考业务,发展起来说不定还能开个连锁。这样子做生意是不会走的长远的!但是考虑到这个替考人没上过小学,也只能怪小虎人品不好了。

代码:动态代理:

以下是动态代理的演示,采用了JDK提供的工具,省了几十行代码:

package com.pat.proxy;
/**
 * 本类中
 */

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 被代理类接口
 */
public interface People {
    public int getNum() ;
}

/**
 * 被代理类实现类
 */
class Peopleimpl implements People{
     private int num=100;

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}
/**
 *代理类,需要实现InvocationHandler接口
 */
class MyInv implements InvocationHandler{
    //被代理对象
    Object obj;

    public  MyInv(Object obj){
        this.obj=obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(obj, args);
        return result;
    }
}

测试类:

package com.pat.proxy;

import java.lang.reflect.Proxy;
import java.util.Objects;

/**
 * 测试类:
 * 补充,非空判断这么用比较装逼:
 * People p2=null;
 * Objects.requireNonNull(p2,"第二个对象不能为空");
 */
public class Test2 {
    public static void main(String[] args) {
        //动态代理有JDK和CGLIB两种工具,cglib是更底层的写法,所以效率会高一些
        People p = new Peopleimpl();
        //真正的代理者。
        MyInv my = new MyInv(p);
        //第一个参数是类加载器,第二个参数是这个代理者实现哪些接口(与被代理者实现的是相同的接口)
        People pp= (People)Proxy.newProxyInstance(p.getClass().getClassLoader(),p.getClass().getInterfaces(),my);
        System.out.println(pp.getNum());




    }
}

结果:

100

动态代理JDK中的实现:

每日手记:
2018年5月15日11:16:07
Returns an instance of a proxy class for the specified interfaces
返回一个指定接口的代理实例
that dispatches method invocations to the specified invocation
handler.
将方法调用分派到指定的处理程序


    /**
     //糊上注释是为了看一下老外是怎么写注释的,即使看不懂全部,也可以对比自己的注释参考一下,其实注释写得多也给人感觉很牛逼
     * Returns an instance of a proxy class for the specified interfaces
     * that dispatches method invocations to the specified invocation
     * handler.
     *
     * <p>{@code Proxy.newProxyInstance} throws
     * {@code IllegalArgumentException} for the same reasons that
     * {@code Proxy.getProxyClass} does.
     *
     * @param   loader the class loader to define the proxy class
     * @param   interfaces the list of interfaces for the proxy class
     *          to implement
     * @param   h the invocation handler to dispatch method invocations to
     * @return  a proxy instance with the specified invocation handler of a
     *          proxy class that is defined by the specified class loader
     *          and that implements the specified interfaces
     * @throws  IllegalArgumentException if any of the restrictions on the
     *          parameters that may be passed to {@code getProxyClass}
     *          are violated
     * @throws  SecurityException if a security manager, <em>s</em>, is present
     *          and any of the following conditions is met:
     *          <ul>
     *          <li> the given {@code loader} is {@code null} and
     *               the caller's class loader is not {@code null} and the
     *               invocation of {@link SecurityManager#checkPermission
     *               s.checkPermission} with
     *               {@code RuntimePermission("getClassLoader")} permission
     *               denies access;</li>
     *          <li> for each proxy interface, {@code intf},
     *               the caller's class loader is not the same as or an
     *               ancestor of the class loader for {@code intf} and
     *               invocation of {@link SecurityManager#checkPackageAccess
     *               s.checkPackageAccess()} denies access to {@code intf};</li>
     *          <li> any of the given proxy interfaces is non-public and the
     *               caller class is not in the same {@linkplain Package runtime package}
     *               as the non-public interface and the invocation of
     *               {@link SecurityManager#checkPermission s.checkPermission} with
     *               {@code ReflectPermission("newProxyInPackage.{package name}")}
     *               permission denies access.</li>
     *          </ul>
     * @throws  NullPointerException if the {@code interfaces} array
     *          argument or any of its elements are {@code null}, or
     *          if the invocation handler, {@code h}, is
     *          {@code null}
     */
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        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.查找或生成指定的代理类。           
           //如果由给定的加载器定义的代理类。
           //给定的接口存在,这将简单地返回缓存的副本(这个缓存取自哪里?猜想:类加载???);
           //否则,它将通过ProxyClassFactory创建代理类。
	         //如果没有接口参数intfs,则会抛出空指针
         */
        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;
                    }
                });
            }
            //返回创建的代理对象
            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);
        }
    }

原文地址:https://www.cnblogs.com/the-fool/p/11054141.html