JAVA设计模式——代理模式

1,代理模式

2012年8月,在伦敦奥运会乒乓球男单决赛中,张继科以4-1战胜王皓夺得冠军;同时,他也实现了世锦赛、世界杯、奥运会三项冠军的大满贯,成为在中国男乒历史上继刘国梁和孔令辉之后的第三位大满贯选手。
​
作为一名职业运动员,毫无疑问  他的能力非常厉害 一直都是我的偶像
​
他的乒乓球技术非常高超,但是他因为要参加日常的训练,所以没有多余的时间来管理日常琐事。
​
所以张继科会找一个人来帮助他专门处理这一类事务,我们称呼这个人为-经纪人

1.1 静态代理

首先我们创建一个接口,定义张继科的一些能力
public interface Ability {
    
    // 比赛
    public abstract void game();
​
    // 日常
    public abstract void daily();
​
    // 代言
    public abstract void endorsement();
​
​
}
接下来创建我们的张继科
// 张继科
public class ZhangJike implements Ability{
​
​
    @Override
    public void game() {
        System.out.println("张继科 参加一场奥林匹克运动会乒乓球总决赛      痛失亚军,含泪夺冠");
    }
​
    @Override
    public void daily() {
        System.out.println("张继科 与粉丝互动切磋,向福利院捐赠了乒乓运动器械,并和兴奋的小球迷爱心互动   进行高强度的训练");
    }
​
    @Override
    public void endorsement() {
        System.out.println("张继科 代言 华润怡宝矿泉水等品牌");
    }
}
    紧接着创建张继科的经纪人
// 经济人
public class ProxyPerson implements Ability{
​
    ZhangJike zjk;
​
    public ProxyPerson(ZhangJike zjk){
        this.zjk = zjk;
    }
​
​
    @Override
    public void game() {
        System.out.println("安排往返机票,酒店住宿");
        zjk.game();
    }
​
    @Override
    public void daily() {
        System.out.println("安排近期的事务");
        zjk.daily();
    }
​
    @Override
    public void endorsement() {
        System.out.println("与一些企业签约代言");
        zjk.endorsement();
    }
}

最后我们创建一个环境类  测试一下静态代理
 

// 测试    静态代理
public class TestPro {
​
    public static void main(String[] args) {
​
        ZhangJike zhangJike = new ZhangJike();
        ProxyPerson proxyPerson = new ProxyPerson(zhangJike);
        proxyPerson.daily();
        proxyPerson.endorsement();
        proxyPerson.game();
​
    }
​
}

打印结果如下:

1.2 动态代理

随着张继科的`经纪人`越来越厉害,找他当`经纪人`的运动员们越来越多,当然 我们的`男足`也来找他当`经纪人`。
​
这个`经纪人`非常厉害,不管你有什么能力都可以给你安排的妥妥当当
​
此时,我们创建这个`经纪人`就可以使用`反射`的方法就可以实现——反射

通过反射创建更厉害的经纪人

public class MyInvocationHandler implements InvocationHandler {
​
    //这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象
   private Object object;
​
    /*
           parameter:    实例化被代理的对象
           return:       返回代理类对象
     */
    public Object Binding(Object object){
        this.object = object;
        /**
         * param1 ->  loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
         *
         * param2 ->   interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,
         *                  如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),
         *                  这样我就能调用这组接口中的方法了
         * param3 ->   h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
         */
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
    }
​
​
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我是一个万能经纪人,什么都能给你安排得妥妥当当!");
​
        //  这里的参数为什么为 this.object , 之后进行讲解
        return method.invoke(this.object,args);
    }
}

创建我们的男足

// 男足能力接口
public class MaleFoot implements Ability {
​
​
    @Override
    public void game() {
        System.out.println("提前杀入本届亚洲杯");
    }
​
    @Override
    public void daily() {
        System.out.println("优秀射手-武磊");
    }
​
    @Override
    public void endorsement() {
        System.out.println("...  nothing");
    }
}

测试动态代理

// 测试
public class TestPro {
​
    public static void main(String[] args) {
​
        // 动态代理
        MaleFoot maleFoot = new MaleFoot();
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        Ability binding = (Ability) myInvocationHandler.Binding(maleFoot);
        binding.daily();
        binding.endorsement();
        binding.game();
    }

打印结果如下:

 

            

 

1.3 invoke

接下来讲解一下关于 InvocationHandler 的 invoke 方法

大家可能都有一个疑问

我们从始至终都没有调用过 invoke 方法,为什么它会被执行呢?

 @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我是一个万能经纪人,什么都能给你安排得妥妥当当!");
         
    return method.invoke(this.object,args);
}

 

这里我们从 newProxyInstance 的方法开始入手

return Proxy.newProxyInstance(object.getClass().getClassLoader(),
                              object.getClass().getInterfaces(),this);

首先 我们进入源码

/**
*loader     ->   定义代理类 proxy class
*interfaces ->   代理类实现的接口列表
*h          ->   调用方法调用的调用处理程序
*/
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    // 判断 h 是否为null 如果为null 则抛出 NullPointerException();
    Objects.requireNonNull(h);
​
    // 克隆接口列表
    final Class<?>[] intfs = interfaces.clone();
    // 获取安全管理器
    /**
    *当运行未知的Java程序的时候,该程序可能有恶意代码(删除系统文件、重启系统等),为了防止运行恶意代码对系统产生影响,需要对运行的代码的权限进行控制,这时候就要启用Java安全管理器。
    */
    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);
        }
        
        /**
        cons即是形参为InvocationHandler类型的公共构造方法
        private static final Class<?>[] constructorParams =
        { InvocationHandler.class };
        */
        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;
                }
            });
        }
        // 获取cons的实例
        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);
    }
}

以下的部分内容参考了网络上的内容,在此对原作者表示感谢!

至此我们得知,newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) 这个方法做了一下两个操作:

1.根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类. 

 2.实例化$Proxy0并在构造方法中把DynamicSubject传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值,

如下:

class Proxy{
    InvocationHandler h=null;
    protected Proxy(InvocationHandler h) {
        this.h = h;
    }
    ...
}
    来看一下这个继承了Proxy的$Proxy0的源代码: 
public final class $Proxy0 extends Proxy implements Subject {
    private static Method m1;
    private static Method m0;
    private static Method m3;
    private static Method m2;
​
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals",
                    new Class[] { Class.forName("java.lang.Object") });
​
            m0 = Class.forName("java.lang.Object").getMethod("hashCode",
                    new Class[0]);
​
            m3 = Class.forName("***.RealSubject").getMethod("request",
                    new Class[0]);
​
            m2 = Class.forName("java.lang.Object").getMethod("toString",
                    new Class[0]);
​
        } catch (NoSuchMethodException nosuchmethodexception) {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        } catch (ClassNotFoundException classnotfoundexception) {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
        }
    } //static
​
    public $Proxy0(InvocationHandler invocationhandler) {
        super(invocationhandler);
    }
​
    @Override
    public final boolean equals(Object obj) {
        try {
            return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
​
    @Override
    public final int hashCode() {
        try {
            return ((Integer) super.h.invoke(this, m0, null)).intValue();
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
​
    public final void request() {
        try {
            super.h.invoke(this, m3, null);
            return;
        } catch (Error e) {
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
​
    @Override
    public final String toString() {
        try {
            return (String) super.h.invoke(this, m2, null);
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}
    接着把得到的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.request()方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。 

                

注: 在一位神秘大佬的帮助下,我们终于明白了proxy参数的作用了

在上图中,程序通过newProxyInstance方法将我们的binding类转换成了代理类 proxy。

具体操作如下:

  

 接着把得到的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.request()方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。 

                                                                                                                      ps: 在此由衷感谢神秘大佬提供的帮助

2.4 AOP动态代理

                                  

定义接口

// 定义插入类的接口
public interface Insert {
​
    public abstract void ist();
​
}

实现接口

public class InsertImpl implements Insert {
    @Override
    public void ist() {
        System.out.println("我是被插入的代码片段!!!");
    }
}

定义被插入类的方法

public class Code {
​
    public void method1(){
        System.out.println("============== 方法1  =============");
    }
    public void method2(){
        System.out.println("============== 方法2  =============");
    }
​
}

创建其子类

public class Section extends Code {
      public void method1(){
        System.out.println("子类 ============== 方法1  =============");
    }
}

实现切面代理

public class MyInvocationHandlerAop implements InvocationHandler {
​
    private Object object;
​
    /*
          parameter:    实例化被代理的对象
          return:       返回代理类对象
    */
    public Object Binding(Object object){
        this.object = object;
        /**
         * param1 ->  loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
         *
         * param2 ->   interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,
         *                  如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),
         *                  这样我就能调用这组接口中的方法了
         * param3 ->   h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
         */
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
    }
​
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 多态
        Code code = new Section();
        code.method1();
        Object invoke = method.invoke(this.object, args);
        code.method2();
        return invoke;
    }
}
创建环境类
// 测试aop动态代理
public class TestProAop {
​
    public static void main(String[] args) {
        InsertImpl insert = new InsertImpl();
        MyInvocationHandlerAop myInvocationHandlerAop = new MyInvocationHandlerAop();
        Insert binding = (Insert) myInvocationHandlerAop.Binding(insert);
        binding.ist();
    }
​
}

打印结果如下:

                 

同理,插入我们的其他类也可以

// 测试aop动态代理
public class TestProAop {
​
    public static void main(String[] args) {
        InsertImpl insert = new InsertImpl();
        MyInvocationHandlerAop myInvocationHandlerAop = new MyInvocationHandlerAop();
        Ability binding = (Ability) myInvocationHandlerAop.Binding(zhangJike);
        binding.endorsement();
        System.out.println();
        binding.daily();
        System.out.println();
        binding.game();
    }
​
}

打印结果如下:

通过以上的方法就能够动态切入我们所需添加的代码啦

 

                {\__/}                                          {\__/}
                ( ·-·)                                          (·-· )
                / >------------------------------------------------< \
                         |      ☆                            |
                         |         ☆                         |
                         |  ★                                |
                         |         ☆                         |
                         |      ☆                            |
                         |                                   |
                         -------------------------------------

      如有兴趣可以关注我的公众号:

                                                                 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值