12AOP-jdk代理实现及特点

模拟 jdk 动态代理

版本1.0
package com.butch.a12;

public class A12 {

    //目标类和代理类都需要实现的公共接口
    interface Foo{
        void foo();
    }

    //目标类
    static class Target implements Foo{
        @Override
        public void foo() {
            System.out.println("target foo");
        }

        public static void main(String[] args) {
            Foo foo = new $Proxy0();
            foo.foo();
        }
    }
}
package com.butch.a12;

//代理类
public class $Proxy0 implements A12.Foo {


    @Override
    public void foo() {
        //增强功能
        System.out.println("========before=========");
        //调用目标
        new A12.Target().foo();

    }
}

可以看到代码将增强的功能和目标方法调用写死到了代理中,可用性很差,版本二将增强和目标方法分离

版本2.0
package com.butch.a12;


public class A12 {

    //目标类和代理类都需要实现的公共接口
    interface Foo{
        void foo();
    }

    //目标类
    static class Target implements Foo {
        @Override
        public void foo() {
            System.out.println("target foo");
        }
    }
    //2.0解耦的关键接口
    interface InvocationHandler{
        void invoke();
    }

    public static void main(String[] args) {
        //2.0这里就必须通过有参构造器实例化invcationhandle,在实现的invoke方法中自定义增强逻辑,注意要使用我们自己定义接口
        Foo proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public void invoke() {
                //增强功能
                System.out.println("========before=========");
                //调用目标
                new A12.Target().foo();

            }
        });
        proxy.foo();
    }
}

 

package com.butch.a12;


//代理类
public class $Proxy0 implements A12.Foo {

    //2.0增加InvocationHandler处理
    private A12.InvocationHandler h;

    //2.0通过有参构造器实例化
    public $Proxy0(A12.InvocationHandler h) {
        this.h = h;
    }


    @Override
    public void foo() {
        //2.0在这里调用 接口的代理方法
        h.invoke();
    }
}

理解一下InvocationHandler

  1. 在代理类中定义成员变量,类型为InvocationHandler,并且提供唯一构造器,参数为InvocationHandler

  2. 当要创建代理类对象的时,就必须通过带有InvocationHandler的构造器实例化,就必须重写接口的invoke

  3. 在invoke实现增强的逻辑,调用目标方法

  4. 当使用代理类对象调用目标方法,就是去执行实例化代理类时InvocationHandler的增强逻辑了

但是此时如果公共接口新增了一个方法,被调用的时候也需要增强,2.0版本明显不能满足需求

版本3.0
package com.butch.a12;


import java.lang.reflect.Method;

//代理类
public class $Proxy0 implements A12.Foo {


    //2.0增加InvocationHandler处理
    private A12.InvocationHandler h;

    //2.0通过有参构造器实例化
    public $Proxy0(A12.InvocationHandler h) {
        this.h = h;
    }


    @Override
    public void foo() {
        //3.0使用反射调用对应的方法,以增强不同的方法
        Method foo = null;
        try {
            foo = A12.Foo.class.getDeclaredMethod("foo");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //2.0在这里调用 接口的代理方法
        h.invoke(foo,new Object[0]);
    }

    @Override
    public void bar() {
        //3.0使用反射调用对应的方法,以增强不同的方法
        Method bar = null;
        try {
            bar = A12.Foo.class.getDeclaredMethod("bar");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //3.0增加方法
        h.invoke(bar,new Object[0]);
    }
}
package com.butch.a12;


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class A12 {

    //目标类和代理类都需要实现的公共接口
    interface Foo{
        void foo();
        //3.0增加方法
        void bar();
    }

    //目标类
    static class Target implements Foo {
        //3.0增加方法
        @Override
        public void bar() {
            System.out.println("target bar");

        }

        @Override
        public void foo() {
            System.out.println("target foo");
        }
    }
    //2.0解耦的关键接口
    interface InvocationHandler{
        void invoke(Method method,Object[] objects);
    }

    public static void main(String[] args) {
        //2.0这里就必须通过有参构造器实例化invcationhandle,在实现的invoke方法中自定义增强逻辑,注意要使用我们自己定义接口
        Foo proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public void invoke(Method method,Object[] Obj) {
                //增强功能
                System.out.println("========before=========");
                //调用目标
                try {
                    method.invoke(new Target(),Obj);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        });
        proxy.foo();
        proxy.bar();
    }
}

3.0使用到反射去调用对应的目标方法,很好的适配了不同方法的增强,4.0将新增返回结果的目标方法及代码的精简

版本4.0
  1. 处理返回参数,并抛出异常

  2. 将反射匹配调用目标方法放入静态代码块中

  3. 在InvocationHandler中 新增参数Object proxy

  4. 使用jdk提供的InvocationHandler替换,并且代理类继承proxy

package com.butch.a12;


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

public class A12 {

    //目标类和代理类都需要实现的公共接口
    interface Foo{
        void foo();
        //3.0增加方法
        //4.0将方法变为有返回值的
        int bar();
    }

    //目标类
    static class Target implements Foo {
        //3.0增加方法
        @Override
        public int bar() {
            System.out.println("target bar");
            return 100;

        }

        @Override
        public void foo() {
            System.out.println("target foo");
        }
    }
    //2.0解耦的关键接口
//    interface InvocationHandler{
//        //4.0解耦的接口新增返回参数
//        Object invoke(Object proxy,Method method,Object[] objects) throws Throwable;
//    }

    public static void main(String[] args) {
        //2.0这里就必须通过有参构造器实例化invcationhandle,在实现的invoke方法中自定义增强逻辑,注意要使用我们自己定义接口
        Foo proxy = new $Proxy0(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy,Method method,Object[] Obj) throws Throwable {
                //增强功能
                System.out.println("========before=========");
                //调用目标
                //返回到代理类中
                return method.invoke(new Target(),Obj);
            }
        });
        proxy.foo();
        proxy.bar();
    }
}
package com.butch.a12;


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

//代理类
public class $Proxy0 extends Proxy implements A12.Foo {


    //2.0增加InvocationHandler处理
    private InvocationHandler h;

    //2.0通过有参构造器实例化
    //4.0
    public $Proxy0(InvocationHandler h) {
        super(h);
    }


    @Override
    public void foo() {
        //3.0使用反射调用对应的方法,以增强不同的方法
//        Method foo = null;
//        try {
//            foo = A12.Foo.class.getDeclaredMethod("foo");
//        } catch (NoSuchMethodException e) {
//            e.printStackTrace();
//        }
//        //2.0在这里调用 接口的代理方法
        try {
            h.invoke(this,foo,new Object[0]);
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public int bar() {
        //3.0使用反射调用对应的方法,以增强不同的方法
//        Method bar = null;
//        try {
//            bar = A12.Foo.class.getDeclaredMethod("bar");
//        } catch (NoSuchMethodException e) {
//            e.printStackTrace();
//        }
        //3.0增加方法
        try {
            Object invoke = h.invoke(this,bar, new Object[0]);
            return (int)invoke;
        } catch (RuntimeException | Error e) {
            throw e;
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    //4.0
    static Method foo;
    static Method bar;
    static {
        try {
            foo = A12.Foo.class.getMethod("foo");
            bar = A12.Foo.class.getMethod("bar");
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }
}
流程
  1. 初始化代理对象,需要通过构造器InvocationHandler,在重写方法中定义增强逻辑,然后根据反射方法参数调用代理方法

  2. 使用代理对象调用增强方法,回调到InvocationHandler的重写方法中,执行增强逻辑,执行代理的增强方法,进入代理类

  3. 通过反射调用,执行目标方法的增强方法

总结

jdk代理实现原理

  1. 方法重写可以增强逻辑,只不过这【增强逻辑】千变万化,不能写死在代理内部

  2. 通过接口回调将【增强逻辑】置于代理类之外

  3. 配合接口方法反射(是多态调用),就可以再联动调用目标方法

  4. 会用 arthas 的 jad 工具反编译代理类

  5. 限制⛔:代理增强是借助多态来实现,因此成员变量、静态方法、final 方法均不能通过代理实现

方法反射优化

package com.butch.a12;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

// 运行时请添加 --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/jdk.internal.reflect=ALL-UNNAMED
public class TestMethodInvoke {
    public static void main(String[] args) throws Exception {
        Method foo = TestMethodInvoke.class.getMethod("foo", int.class);
        for (int i = 1; i <= 17; i++) {
            show(i, foo);
            foo.invoke(null, i);
        }
        System.in.read();
    }

    // 方法反射调用时, 底层 MethodAccessor 的实现类
    private static void show(int i, Method foo) throws Exception {
        Method getMethodAccessor = Method.class.getDeclaredMethod("getMethodAccessor");
        getMethodAccessor.setAccessible(true);
        Object invoke = getMethodAccessor.invoke(foo);
        if (invoke == null) {
            System.out.println(i + ":" + null);
            return;
        }
        Field delegate = Class.forName("jdk.internal.reflect.DelegatingMethodAccessorImpl").getDeclaredField("delegate");
        delegate.setAccessible(true);
        System.out.println(i + ":" + delegate.get(invoke));
    }

    public static void foo(int i) {
        System.out.println(i + ":" + "foo");
    }
}
  1. 前 16 次反射性能较低

  2. 第 17 次调用会生成代理类,优化为非反射调用

  3. 会用 arthas 的 jad 工具反编译第 17 次调用生成的代理类

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值