Java动态代理

所谓代理,又分为静态代理和动态代理两种。在介绍动态代理之前,我们先了解下在Java中静态代理的使用方式和局限性。

假设当前我们有一个功能接口,需要通过代理类来调用该功能接口的实现类。我们可以使用静态代理调用的方式进行处理,在代理中可以执行额外的处理代码(如日志打印、执行时间的统计等等),代码如下:

/**
 * 功能接口
 */
interface Duck {
    void info();

    void say();
}

/**
 * 功能接口实现类
 */
class RealDuck implements Duck {

    @Override
    public void info() {
        System.out.println("鸭子");
    }

    @Override
    public void say() {
        System.out.println("我是一只鸭子");
    }
}


/**
 * 代理类
 */
class DuckProxy implements Duck {

    private Duck duck;

    public DuckProxy(Duck duck) {
        this.duck = duck;
    }

    @Override
    public void info() {
        System.out.println("调用前--->");
        duck.info();
        System.out.println("调用后--->");
    }

    @Override
    public void say() {
        System.out.println("调用前--->");
        duck.say();
        System.out.println("调用后--->");
    }
}

public class TestStaticProxy {

    public static void main(String[] args) {
        // 创建被代理类对象
        Duck realDuck = new RealDuck();
        
        // 创建代理类对象,将通过该对象进行被代理类的调用
        Duck duckProxy = new DuckProxy(realDuck);

        // 调用代理类对象的方法,转而调用被代理类的方法
        duckProxy.info();
        // 同上
        duckProxy.say();

    }


}

 以上,我们实现了一个静态代理。其存在一个弊端:假设要增加另外的一个接口则需要一个与之配对的另一个代理,这样会导致类的爆炸。。。此时我们可以引入动态代理来规避此类问题,减少代码的冗余

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

/**
 * @author luhuancheng
 * @since 2018/2/8 23:15
 */

interface Human {
    void info();

    void say();
}

/**
 * 被代理类
 */
class SuperMan implements Human {

    @Override
    public void info() {
        System.out.println("超人来了......");
    }

    @Override
    public void say() {
        System.out.println("我是超人......");
    }
}

/**
 * 日志工具
 */
class LogUtils {
    public static void before() {
        System.out.println("调用前时间" + System.currentTimeMillis());
    }

    public static void after() {
        System.out.println("调用后时间" + System.currentTimeMillis());
    }
}

class MyInvocationHandler implements InvocationHandler {

    private Object object;

    public void setObject(Object object) {
        this.object = object;
    }

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

class MyProxy {
    public static Object getProxy(Object object) {
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.setObject(object);
        // 返回一个代理类对象。该代理类实现了与对象object一致的接口。
        // 并且在调用该代理类对象的相关方法时,转而调用其 invoke(Object proxy, Method method, Object[] args)方法;
        // 实现了对模版代码的重用,并且避免了代理类与被代理类必须成对存在的弊端
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), handler);
    }
}



public class TestDynamicProxy {

    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        Object object = MyProxy.getProxy(superMan);
        Human man = (Human) object;

        man.info();

        man.say();
    }
}

 

posted on 2018-02-08 23:48  luhuancheng1992  阅读(136)  评论(0编辑  收藏  举报

导航