动态代理实现原理

JDK Proxy

public interface Rent {
    void rent();
}


public class Target implements Rent{
    @Override
    public void rent() {
        System.out.println("target rent");
    }
}


public class $Proxy0 implements Rent {

    @Override
    public void rent() {
        // 1.功能增强
        System.out.println("before");
        // 2.调用目标
        new Target().rent();
    }
}


    public static void main(String[] args) {

        $Proxy0 proxy0 = new $Proxy0();
        proxy0.rent();
    }

由于功能增强是不确定的,所以抽象出来

在触发(invoke)真实角色的方法之前或者之后做一些额外的业务。那么,为了构造出具有通用性和简单性的代理类,可以将所有的触发真实角色动作交给一个触发的管理器,让这个管理器统一地管理触发。这种管理器就是Invocation Handler 

public interface InvocationHandler {
    void invoke();
}

public class $Proxy0 implements Rent {

    private InvocationHandler h;

    public $Proxy0(InvocationHandler h) {
        this.h = h;
    }

    @Override
    public void rent() {
        h.invoke();
    }
}

    public static void main(String[] args) {

        $Proxy0 proxy0 = new $Proxy0(() -> {
            System.out.println("before proxy0");
            new Target().rent();
        });
        proxy0.rent();
    }

问题:调用目标是写死的,如果被代理类中有多个方法

public interface Rent {

    void rent() throws NoSuchMethodException;

    void host();
}


public class Target implements Rent{
    @Override
    public void rent() {
        System.out.println("target rent");
    }

    @Override
    public void host() {
        System.out.println("target host");
    }
}


public interface InvocationHandler {
    void invoke(Method method, Object[] args) throws InvocationTargetException, IllegalAccessException;
}


public class $Proxy0 implements Rent {

    private InvocationHandler h;

    public $Proxy0(InvocationHandler h) {
        this.h = h;
    }

    @Override
    public void rent() {
        Method rent = null;
        try {
            rent = Rent.class.getMethod("rent");
            h.invoke(rent, new Object[0]);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public void host() {
        Method host = null;
        try {
            host = Rent.class.getMethod("host");
            h.invoke(host, new Object[0]);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}


    public static void main(String[] args) {

        $Proxy0 proxy0 = new $Proxy0((method, params) -> {
            System.out.println("before proxy0");
            method.invoke(new Target(), params);
        });
        proxy0.rent();
        proxy0.host();
    }

代理和目标需要实现同一个接口,为了让代理内的代码不固定死,需要设计一个接口 InvocationHandler 来回调代理内的抽象操作 invoke

动态代理工作的基本模式就是将自己的方法功能的实现交给 InvocationHandler角色,外界对Proxy角色中的每一个方法的调用,Proxy角色都会交给InvocationHandler来处理,而InvocationHandler则调用具体对象角色的方法。

问题:返回值处理

public interface Rent {
    void rent() throws NoSuchMethodException;
    int host();
}


public class Target implements Rent{
    @Override
    public void rent() {
        System.out.println("target rent");
    }

    @Override
    public int host() {
        System.out.println("target host");
        return 100;
    }
}


public interface InvocationHandler {
    Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException;
}


public class $Proxy0 implements Rent {

    private InvocationHandler h;

    public $Proxy0(InvocationHandler h) {
        this.h = h;
    }


    static Method rent;
    static Method host;

    static {
        try {
            rent = Rent.class.getMethod("rent");
            host = Rent.class.getMethod("host");
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public void rent() {
        try {

            h.invoke(this, rent, new Object[0]);
        } catch (RuntimeException | Error e) {
            throw new RuntimeException(e);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }

    }

    @Override
    public int host() {
        try {
            return (int) h.invoke(this, host, new Object[0]);
        } catch (RuntimeException | Error e) {
            throw new RuntimeException(e);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
}


    public static void main(String[] args) {

        $Proxy0 proxy0 = new $Proxy0((proxy, method, params) -> {
            System.out.println("before proxy0");
            return method.invoke(new Target(), params);
        });
        proxy0.rent();
        int host = proxy0.host();
        System.out.println(host);
    }

向 JDK 靠拢,继承 Proxy 类

public class $Proxy0 extends Proxy implements Rent {


    static Method rent;
    static Method host;

    static {
        try {
            rent = Rent.class.getMethod("rent");
            host = Rent.class.getMethod("host");
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }


    protected $Proxy0(InvocationHandler h) {
        super(h);
    }


    @Override
    public void rent() {
        try {

            h.invoke(this, rent, new Object[0]);
        } catch (RuntimeException | Error e) {
            throw new RuntimeException(e);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }

    }

    @Override
    public int host() {
        try {
            return (int) h.invoke(this, host, new Object[0]);
        } catch (RuntimeException | Error e) {
            throw new RuntimeException(e);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
}

 

Cglib Proxy

public class Target {

    public void save1(){
        System.out.println("save1");
    }

    public void save2(int i){
        System.out.println("save2" + i);
    }
}


public class Proxy extends Target{

    private MethodInterceptor methodInterceptor;

    public Proxy(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }


    static Method save1;
    static Method save2;

    static {
        try {
            save1 = Target.class.getMethod("save1");
            save2 = Target.class.getMethod("save2", int.class);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void save1() {
        try {
            methodInterceptor.intercept(this, save1,new  Object[0], null);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void save2(int i) {
        try {
            methodInterceptor.intercept(this, save2,new  Object[]{i}, null);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
}


public static void main(String[] args) {

    Target target = new Target();

    Proxy proxy = new Proxy(new MethodInterceptor() {
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("before");
            return method.invoke(target, objects);
        }
    });

    proxy.save1();
    proxy.save2(10);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值