Java动态代理原理分析

JDK动态代理原理分析

interface Foo {
    void foo();
}

class Target implements Foo {

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

public class A13 {

    public static void main(String[] args) {
        $Proxy0 proxy = new $Proxy0();
        proxy.foo();
    }
}


public class $Proxy0 {

}

如果$Proxy0就是jdk创建的动态代理对象

我要增强foo方法,可以这样

public class $Proxy0 {

    public void foo() {
        System.out.println("增强");
        new Target().foo();
    }
}

但是我们希望通过public static void main(String[] args)来控制增强,那么我们的代码改成了这样

interface Foo {
    void foo();
}

class Target implements Foo {

    @Override
    public void foo() {
        System.out.println("foo..");
    }
}
interface InvocationHandler {
    void invoke();
}
public class A13 {

    public static void main(String[] args) {
        $Proxy0 proxy = new $Proxy0(() -> {
            System.out.println("增强");
            new Target().foo();
        });
        proxy.foo();
    }
}
public class $Proxy0 {

    private InvocationHandler h;

    public $Proxy0(InvocationHandler invocationHandler){
        h = invocationHandler;
    }

    public void foo() {
        h.invoke();
    }
}

现在有一个问题这个只能增强foo这个方法,当要增强别的方法,就不能这么写了。于是我在代理类里面通过反射创建了存放当前方法的参数

public class $Proxy0 implements Foo {

    private InvocationHandler h;

    public $Proxy0(InvocationHandler invocationHandler) {
        h = invocationHandler;
    }

    @Override
    public void foo() {
        try {
            Method method = Foo.class.getMethod("foo");
            h.invoke(method, new Object[0]);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void bar() {
        try {
            Method method = Foo.class.getMethod("bar");
            h.invoke(method, new Object[0]);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
}
interface Foo {
    void foo();

    void bar();
}


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

public class A13 {

    static class Target implements Foo {

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

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

    public static void main(String[] args) {
        $Proxy0 proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public void invoke(Method method, Object[] args) throws RuntimeException, IllegalAccessException, InvocationTargetException {
                Target target = new Target();
                System.out.println("增强");
//            new Target().foo();
                method.invoke(target, args);
            }
        });
        proxy.foo();
        proxy.bar();
    }
}

现在我们这个软件又有一个问题就是无法返回参数这时我们需要改变一下InvocationHandler的invoke方法让他返回Object,同时我们由于我们不能每次调用方法都去反射获取方法,可以生成一个静态变量,方便方法的调用

    static public Method foo;
    static public Method bar;

    static {
        try {
            bar = Foo.class.getMethod("bar");
            foo = Foo.class.getMethod("foo");
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
interface Foo {
    void foo();

    int bar();
}


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

public class A13 {

    static class Target implements Foo {

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

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

    public static void main(String[] args) {
        $Proxy0 proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                Target target = new Target();
                System.out.println("增强");
//            new Target().foo();
                return method.invoke(target, args);
            }
        });
        proxy.foo();
        int bar = proxy.bar();
        System.out.println(bar);
    }
}
public class $Proxy0 implements Foo {

    private InvocationHandler h;

    public $Proxy0(InvocationHandler invocationHandler) {
        h = invocationHandler;
    }

    @Override
    public void foo() {
        try {
            h.invoke(this, foo, new Object[0]);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

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

    static public Method foo;
    static public Method bar;

    static {
        try {
            bar = Foo.class.getMethod("bar");
            foo = Foo.class.getMethod("foo");
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}

JDK反射调用会利用JVM中的ASM指令生成字节码,同时由于反射调用类方法是比较消耗性能的,在jdk中超过16次的反射调用jvm就会给他生成一个动态代理类来提供反射调用

cglib动态代理的实现原理

cglib动态代理是基于子类继承父类的代理

这是我们创建的代理类

public class Proxy extends Target {

    private MethodInterceptor methodInterceptor;

    public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    static Method save0;
    static Method save1;
    static Method save2;

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

    // >>>>>>>>>带增强功能的方法

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

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

    @Override
    public void save(long j) {
        try {
            methodInterceptor.intercept(this, save2, new Object[]{j}, save2Proxy);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
}

他继承了这个接口

public class Target {

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

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

    public void save(long i){
        System.out.println("save(long)");
    }
}

调用

public class A13 {
    public static void main(String[] args) {
        Proxy proxy = new Proxy();
        Target target = new Target();
        proxy.setMethodInterceptor(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);//反射调用
                return methodProxy.invokeSuper(o, objects);
            }
        });
        proxy.save();
        proxy.save(1);
        proxy.save(1L);

    }
}

可以很直观的感觉到cglib不再需要通过接口来增强方法。同时cglib通过FastClass的两个实现来不需要通过反射来增强ProxyFastClass(代理类)和TargetFastClass(目标类),FastClass有两个重要的方法getIndex(获取代理类方法的编号)和invoke(调用原始方法)一个代理类只需要创建两个FastClass可以匹配多个方法,比jdk(一个方法对应一个类)产生数目少一些

public class TargetFastClass {

    static Signature s0 = new Signature("save","()V");
    static Signature s1 = new Signature("save","(I)V");
    static Signature s2 = new Signature("save","(J)V");

    //获取目标方法的编号
    public int getIndex(Signature signature) {
        if (s0.equals(signature)){
            return 0;
        } else if (s1.equals(signature)) {
            return 1;
        } else if (s2.equals(signature)) {
            return 2;
        } else {
            throw new RuntimeException("without this parameter");
        }
    }

    public Object invoke(int index,Object target,Object[] args) {
        if (index == 0){
            ((Target) target).save();
            return null;
        } else if (index == 1) {
            ((Target) target).save((int) args[0]);
            return null;
        } else if (index == 2) {
            ((Target) target).save((long) args[0]);
            return null;
        } else {
            throw new RuntimeException("without this parameter");
        }
    }

    public static void main(String[] args) {
        TargetFastClass targetFastClass = new TargetFastClass();
        int index = targetFastClass.getIndex(new Signature("save", "()V"));
        targetFastClass.invoke(index,new Target(),new Object[0]);
    }
}
ublic class ProxyFastClass {
    static Signature s0 = new Signature("saveSuper","()V");
    static Signature s1 = new Signature("saveSuper","(I)V");
    static Signature s2 = new Signature("saveSuper","(J)V");

    //获取代理类方法的编号
    public int getIndex(Signature signature) {
        if (s0.equals(signature)){
            return 0;
        } else if (s1.equals(signature)) {
            return 1;
        } else if (s2.equals(signature)) {
            return 2;
        } else {
            throw new RuntimeException("without this parameter");
        }
    }

    public Object invoke(int index,Object proxy,Object[] args) {
        if (index == 0){
            ((Proxy) proxy).saveSuper();
            return null;
        } else if (index == 1) {
            ((Proxy) proxy).saveSuper((int) args[0]);
            return null;
        } else if (index == 2) {
            ((Proxy) proxy).saveSuper((long) args[0]);
            return null;
        } else {
            throw new RuntimeException("without this parameter");
        }
    }

    public static void main(String[] args) {
        ProxyFastClass proxyFastClass = new ProxyFastClass();
        int index = proxyFastClass.getIndex(new Signature("saveSuper", "()V"));
        System.out.println(index);
        proxyFastClass.invoke(index,new Proxy(),new Object[0]);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值