动态代理模式

什么是代理

就是某一个对象要执行某个任务,但是呢,这个任务又不是由它自己来完成的,而是由另外一个代理对象来代替它完成的,这就是代理模式的定义。

看图:

 

 

( https://www.jianshu.com/p/6e962d1e7ddd)

 

为什么要使用代理

这个问题非常重要,如果搞不清它的使用场景,就不要滥用设计模式。考虑这样一种场景,很多对象X1,X2....Xn的执行逻辑都要包含同一个任务,如果把这个任务提取出来单独作为一个任务,交给Y来执行,Y就是代理对象。其他对象在执行的时候,不是由他们本人来执行,而是由Y来分别调用X1,X2...Xn中的方法来执行,Y就可以在执行X中的方法之前,执行公共任务。这就是Spring AOP的动态代理实现机制。

 

静态代理

先上代码。有一个接口Person,抽象地表示人,它有一个动作吃饭

/*
author:chxy
data:2020/3/31
description:
*/
package proxy2;

public interface Person {

    public void dinner();
}

有一个实现类Man,它具体地实现了吃饭这个动作

/*
author:chxy
data:2020/3/31
description:
*/
package proxy2;

public class Man implements Person{

    @Override
    public void dinner() {
        System.out.println("man is having dinner");
    }
}

Man的吃饭动作无法直接执行,而是由代理类来代替它执行,代理类加入了自己的执行逻辑

/*
author:chxy
data:2020/3/31
description:
*/
package proxy2;

public class ManProxy implements Person{

    private Person target;

    public ManProxy(Person p){
        this.target = p;
    }

    @Override
    public void dinner() {
        //饭前洗手
        System.out.println("washing hands");
        target.dinner();
    }
}

在Demo中执行

/*
author:chxy
data:2020/3/31
description:
*/
package proxy2;

public class Main {

    public static void main(String[] args) {

        Person p = new ManProxy(new Man());
        //dinner是由代理类ManProxy来执行的
        p.dinner();
    }
}

执行结果如下:


washing hands
man is having dinner

静态代理就是一个目标类要有一个代理类,如果增加一个类Women,也要有相应的代理类WomenProxy,如果目标类有N个,代理类也要有N个,会导致类的数目爆炸。因此出现了动态代理,目标是:N个目标类,1个代理类。看代码:

增加一个Person的实现类Women

/*
author:chxy
data:2020/3/31
description:
*/
package proxy2;

public class Women implements Person{

    @Override
    public void dinner() {
        System.out.println("women is having dinner");
    }
}

增加一个Handler继承InvocationHandler,实现其中的invoke方法,它是实现动态代理的核心,代理接口中定义的方法的每次调用,都会“经过“这个方法

/*
author:chxy
data:2020/3/31
description:
*/
package proxy2;

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

public class PersonHandler implements InvocationHandler {

    //被代理对象
    Person p;

    public PersonHandler(Person p) {
        this.p = p;
    }

    @Override
    //proxy:代理对象
    //method:被代理的方法
    //args:该方法的参数
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //如果吃饭这个动作被调用了,
        if(method.getName().equals("dinner")){
            System.out.println("washing hands");
            method.invoke(p);
        }
        return null;
    }
}

在main方法,通过Proxy的newProxyInstance()方法得到代理对象,该代理对象实现了第二个参数中的多个接口。直接调用代理对象中的方法实现目标对象中的执行逻辑:

/*
author:chxy
data:2020/3/31
description:
*/
package proxy2;

import java.lang.reflect.Proxy;

public class Main {

    public static void main(String[] args) {

        PersonHandler handlerForMan = new PersonHandler(new Man());
        final Person man = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),//代理的接口
                new Class[]{Person.class},//代理类要实现的接口
                handlerForMan);//处理器
        man.dinner();

        PersonHandler handlerForWomen = new PersonHandler(new Women());
        final Person woman = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),
                new Class[]{Person.class},
                handlerForWomen);
        woman.dinner();
    }
}

实现的效果是:只用一个代理类(并没有显示写出来)代理了Man类和Women类。

posted @ 2020-03-31 21:24  盛夏群岛  阅读(241)  评论(0编辑  收藏  举报