Featured image of post Java设计模式-代理模式Proxy

Java设计模式-代理模式Proxy

相关文章

【合集】Java设计模式

静态代理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
interface SellTickets {
    void sell();
}

public static class ProxyPoint implements SellTickets {
    private final TrainStation STATION = new TrainStation();
    public void sell() {
        System.out.println("代理点收取一些服务费用");
        STATION.sell();
    }
}

ProxyPoint proxyPoint = new ProxyPoint();
proxyPoint.sell();

JDK动态代理

使用

动态代理原理:利用了多态、反射

总结:创建代理对象时传入重写invoke方法的InvocationHandler实现类。执行代理方法时实际上是执行invoke方法。invoke方法内调用真实对象的方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
interface SellTickets {
    void sell();
}

class TrainStation implements SellTickets {
    @Override
    public void sell() {
        System.out.println("火车站卖票");
    }
}

SellTickets proxy = (SellTickets) Proxy.newProxyInstance(
        TrainStation.class.getClassLoader(), // 类加载器,用于加载代理类,使用真实对象的类加载器即可
        new Class[]{SellTickets.class}, // 真实对象所实现的接口,代理模式真实对象和代理对象实现相同的接口
        (p, method, args) -> { // InvocationHandler
            System.out.println("before...");
            Object result = method.invoke(new TrainStation(), args);
            System.out.println("after....");
            return result;
        });

proxy.sell();

JDK代理类的主要源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class $Proxy0 extends Proxy implements SellTickets {
    public $Proxy0(InvocationHandler h) {
        super(h);
    }
    static Method sell;

    static {
        try {
            sell = TrainStation.class.getMethod("sell");
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }

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

Spring-cglib动态代理

使用

cglib 不要求目标实现接口,它生成的代理类是目标的子类,因此代理与目标之间是子父关系

final 类无法被 cglib 增强

JDK1.8的时候,jdk代理效率高于cglib代理。所以如果有接口使用jdk动态代理,如果没有接口使用Cglib动态代理。

cglib 如何避免使用反射

方式1:配合目标对象Target(Spring 用的这种)使用,具体实现见TargetFastClass

方式2:配合代理对象Proxy使用,在proxy类里面会多几个…Super方法。(不增强, 仅是调用父类目标对象的方法) 具体实现见ProxyFastClass

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Student {
    public void save() {
        System.out.println("save()");
    }
    public void save(int i) {
        System.out.println("save(int)");
    }
    public void save(long j) {
        System.out.println("save(long)");
    }
}

Student proxy = (Student) Enhancer.create(Student.class,
        (MethodInterceptor) (p, method, args, methodProxy) -> {
            System.out.println("before...");
            
            // 方式1. 反射调用,必须调用到足够次数才会进行优化
            // Object result = method.invoke(new Student(), args);
            
            // 方式2. 不反射调用,它会正常(间接)调用目标对象的方法(Spring 采用)
            // Object result = methodProxy.invoke(new Student(), args); 

            // 方式3. 不反射调用,它会正常(间接)调用代理对象的方法,可以省略目标对象
            Object result = methodProxy.invokeSuper(p, args); 
            
            System.out.println("after...");
            return result;
        });

proxy.save();
proxy.save(1);
proxy.save(2L);

Spring-cglib代理类的源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Proxy extends Student {
    private MethodInterceptor methodInterceptor;
    public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }
    static Method save0;
    static Method save1;
    static Method save2;
    static MethodProxy save0Proxy;
    static MethodProxy save1Proxy;
    static MethodProxy save2Proxy;

    static {
        try {
            save0 = Student.class.getMethod("save");
            save1 = Student.class.getMethod("save", int.class);
            save2 = Student.class.getMethod("save", long.class);
            save0Proxy = MethodProxy.create(Student.class, Proxy.class, "()V", "save", "saveSuper");
            save1Proxy = MethodProxy.create(Student.class, Proxy.class, "(I)V", "save", "saveSuper");
            save2Proxy = MethodProxy.create(Student.class, Proxy.class, "(J)V", "save", "saveSuper");
        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }

    public void saveSuper() {
        super.save();
    }
    public void saveSuper(int i) {
        super.save(i);
    }
    public void saveSuper(long j) {
        super.save(j);
    }
    @Override
    public void save() {
        try {
            methodInterceptor.intercept(this, save0, new Object[0], save0Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
    @Override
    public void save(int i) {
        try {
            methodInterceptor.intercept(this, save1, new Object[]{i}, save1Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
    @Override
    public void save(long j) {
        try {
            methodInterceptor.intercept(this, save2, new Object[]{j}, save2Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
}

methodProxy.invoke(new Student(), args); 怎么记录Student中方法与编号的对应关系

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class ProxyFastClass {
    public static void main(String[] args) {
        ProxyFastClass fastClass = new ProxyFastClass();
        int index = fastClass.getIndex(new Signature("saveSuper", "()V"));
        System.out.println(index);
        fastClass.invoke(index, new ProxyFastClass(), new Object[0]);
    }

    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;
        }
        return -1;
    }
    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("无此方法");
        }
    }
}

method.invoke(new Student(), args); 怎么记录Student中方法与编号的对应关系

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class TargetFastClass {
    public static void main(String[] args) {
        TargetFastClass fastClass = new TargetFastClass();
        int index = fastClass.getIndex(new Signature("save", "(I)V"));
        System.out.println(index);
        fastClass.invoke(index, new Student(), new Object[]{100});
    }

    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;
        }
        return -1;
    }
    public Object invoke(int index, Object target, Object[] args) {
        if (index == 0) {
            ((Student) target).save();
            return null;
        } else if (index == 1) {
            ((Student) target).save((int) args[0]);
            return null;
        } else if (index == 2) {
            ((Student) target).save((long) args[0]);
            return null;
        } else {
            throw new RuntimeException("无此方法");
        }
    }
}

方法反射优化

前 16 次反射性能较低

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

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

注意:运行时请添加 –add-opens java.base/java.lang.reflect=ALL-UNNAMED –add-opens java.base/jdk.internal.reflect=ALL-UNNAMED

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class 方法反射优化 {
    public static void main(String[] args) throws Exception {
        Method foo = 方法反射优化.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");
    }
}
皖ICP备2024056275号-1
发表了80篇文章 · 总计150.57k字
本站已稳定运行