代理模式小结

作为23种设计模式中的结构型模式,代理模式是比较常用的,这里简单做一下总结;

一、静态代理:

1.创建Shape接口

public interface Shape {
    public void draw();
}

2.创建被代理对象Rectangle ;

public class Rectangle implements Shape {
    public void draw() {
        System.out.println("        draw Rectangle ... ");
    }
}

3.创建代理对象StaticProxy ;

public class StaticProxy implements Shape {
    private Shape shape;

    public StaticProxy(Shape shape){

        this.shape = shape;
    }

    public void draw() {
        System.out.println("Start agent work ... ");
        shape.draw();
        System.out.println("end agent work ... ");
    }
}

 其结构图如下:

简单测试

public class ProxyTest {
    public static void main(String[] args) {
        Shape staticProxy = new StaticProxy(new Rectangle());
        staticProxy.draw();
    }
}

 运行结果如下:

二、JDK动态代理

这里还是使用上面的接口

1.创建被代理类

public class Circle implements Shape{
    public void draw() {
        System.out.println(" start draw Circle ... ");
    }
}

2.创建InvocationHandler实现类;(这里可以将InvocationHandler 认为是一个回调接口)

public class JDKProxy implements InvocationHandler {

    private Shape shape;
    public JDKProxy(Shape shape){
        this.shape = shape;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(" start proxy work ... ");
        Object invoke = method.invoke(shape, args);
        System.out.println(" end proxy work ... ");
        return invoke;
    }
}

3.测试代码如下:

public class DynamicProxyTest {
    public static void main(String[] args) throws Exception {
//      将JDK动态代理类生成的class文件保存到本地
//        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        Circle circle = new Circle();
        JDKProxy jdkProxy = new JDKProxy(circle);

        Shape shape = (Shape)  Proxy.newProxyInstance(circle.getClass().getClassLoader(), new Class[]{Shape.class}, jdkProxy);
//      也可写成如下内容
//        Class<?> proxyClass = Proxy.getProxyClass(circle.getClass().getClassLoader(), Shape.class);
//        Shape shape = (Shape) proxyClass.getConstructor(InvocationHandler.class).newInstance(jdkProxy);

        shape.draw();
    }
}

这里要想看到真正的代理类就要在JDKProxy的invoke方法里打个断点,就会看到如下的一个类 $Proxy0;

要想看$Proxy0的代码就要在测试类中加入如下代码;

 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

项目下会出现如下的目录; 

代码种实现了draw() 方法,并回调了 InvocationHandler 实现类的invoke() 方法;

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.sun.proxy;

import design.pattern.dynamicproxy.Shape;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Shape {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void draw() throws Exception {
        try {
            //回调InvocationHandler实现类的invoke方法
            super.h.invoke(this, m3, (Object[])null);
        } catch (Exception | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("design.pattern.dynamicproxy.Shape").getMethod("draw");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

 这里代码生成可了解一下ASM Java 字节码操纵框架

三、cglib动态代理

1. 创建被代理类Rectangle,这里Rectangle类 无需实现任何接口

public class Rectangle{
    public void draw() {
        System.out.println("        draw Rectangle ... ");
    }
}

2.创建MethodInterceptor 接口实现类;

public class CglibProxy implements MethodInterceptor {
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib start ... ");
        Object invoke = methodProxy.invokeSuper(o, objects);
        System.out.println("cglib end ... ");
        return invoke;
    }
    public  Object newProxyInstance(Class<?> c) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(c);
        enhancer.setCallback(this);
        return enhancer.create();
    }
}

3.编写测试类

public class CglibProxyTest {
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        Rectangle rectangle = (Rectangle) cglibProxy.newProxyInstance(Rectangle.class);
        rectangle.draw();
    }
}

测试结果如下:

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值