设计模式系列--代理篇

代理模式属于 GoF 中的结构型设计模式。也是我们最常见到的设计模式之一,典型的 Controller、Service、Dao 分层设计中,上层就是对下层的静态代理;Spring 中 AOP 的实现是基于动态代理。

代理模式起到保护被代理对象的目的,同时对被代理功能进行增强,同时由于代理对象的引入,增加了系统的复杂度,也使类的调用变得复杂。代理模式分为静态代理和动态代理两种。

1. 静态代理

静态代理适合对固定功能的代理,实现也比较简单,只需要代理对象持有被代理对象的引用,在被代理对象现有功能的基础上进行增强即可,典型的示例如下:

@Controller("hello")
public class HelloController {
    @Autowired
    private HelloService service;

    public String sayHello(String name) {
        // do something here
        return service.sayHello(name);
    }
}

@Service
public class HelloService {
    public String sayHello(String name) {
        return "Hello, " + name + "!";
    }
}

2. 动态代理

动态代理,动态代理最典型的案例就是 Spring 中的 AOP 的实现,在 Spring 中默认会根据被代理对象是否实现了接口来选择动态代理的实现方式,如果实现了接口会默认选择 JDK 提供的动态代理实现,否则采用 cglib 提供的动态代理实现;此外,MyBatis 中的拦截器也是基于动态代理来实现,等等。我们通过 Spring AOP 的两种方式的实现来了解动态代理的实现。

2.1 JDK 动态代理

// 先定义一个消费者接口,对有购买需求的人进行抽象
public interface IConsumer {
    void buySth();
}

// Foo 同学实现了消费者接口,由于头冷他需要买一个头套
// 但他是有追求的程序猿,头套也要进口的,因此他需要代购
public class Foo implements IConsumer {
    @Override
    public void buySth() {
        System.out.println("我要买一个头套!!!");
    }
}

// 代购的实现
public class BuyerAgent implements InvocationHandler {
    private IConsumer target;

    public BuyerAgent(IConsumer target) {
        this.target = target;
    }

    public IConsumer newInstance() {
        return (IConsumer) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object r = method.invoke(target, args);
        after();

        return r;
    }

    private void before() {
        System.out.println("我是海外代购,现在帮你挑选。。。");
    }

    private void after() {
        System.out.println("已经选好发货了,请等待查收。。。");
    }
}

在调试的时候我们会发现,生成的代理对象是一个名为 $Proxy0 的实例,通过 JDK 中的工具我们将其持久化到磁盘。
在这里插入图片描述

public class Main {
    public static void main(String[] args) throws Exception {
        IConsumer consumer = new BuyerAgent(new Foo()).newInstance();
        consumer.buySth();

        byte[] classBytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{IConsumer.class});
        OutputStream os = new FileOutputStream("D:\\$Proxy0.class");
        os.write(classBytes);
        os.close();
    }
}

在 D 盘下我们可以找到持久化的 .class 文件,使用 jad 工具将其反编译成 jad 文件将其改为 .java 后缀文件后打开。


D:\>jad $Proxy0.class
Parsing $Proxy0.class... Generating $Proxy0.jad
Overlapped try statements detected. Not all exception handlers will be resolved in the method equals
Overlapped try statements detected. Not all exception handlers will be resolved in the method hashCode
Overlapped try statements detected. Not all exception handlers will be resolved in the method buySth
Overlapped try statements detected. Not all exception handlers will be resolved in the method toString

D:\>

反编译后的文件如下:

// 生成的类 $Proxy0 继承了 Proxy,同时实现了我们自定义的 IConsumer 接口
public final class $Proxy0 extends Proxy
    implements IConsumer
{

    public $Proxy0(InvocationHandler invocationhandler)
    {
        // 调用父类 Proxy 的构造方法
        // 这里的 invocationhandler 其实就是 BuyerAgent
        super(invocationhandler);
    }

    public final boolean equals(Object obj)
    {
        try
        {
        	return ((Boolean)super.h.invoke(this, m1, new Object[] {
                obj
            })).booleanValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode()
    {
        try
        {
            return ((Integer)super.h.invoke(this, m0, null)).intValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void buySth()
    {
        try
        {
            // 父类的 h 就是我们在上面调用父类构造方法时传入的 BuyerAgent 实例
        	// 因此这里最终调用的是 BuyerAgent.invoke() 方法
        	// Method 类型的 m3 在下面静态代码块中初始化,为 IConsumer.buySth()
            super.h.invoke(this, m3, null);
            return;
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString()
    {
        try
        {
            return (String)super.h.invoke(this, m2, null);
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    private static Method m1;
    private static Method m0;
    private static Method m3;
    private static Method m2;

    static 
    {
        try
        {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
                Class.forName("java.lang.Object")
            });
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            m3 = Class.forName("phantom.designpattern.proxy.jdkproxy.IConsumer").getMethod("buySth", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
        }
        catch(NoSuchMethodException nosuchmethodexception)
        {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        }
        catch(ClassNotFoundException classnotfoundexception)
        {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
        }
    }
}

由上面的分析我们可以知道,JDK 的动态代理是基于接口来获得被代理类的方法的,因此被代理类必须是某个或某些接口的实现,否则无法进行代理。它是通过动态生成字节码的方式生成代理对象的。

2.2 cglib 动态代理

cglib(Code Generation Library)动态代理是一种高效的动态代理实现,基于 asm 字节码重组框架实现,因此我们在引入 cglib 依赖时需要同时引入 asm 依赖。基于 cglib 的动态代理实现示例如下:

// 天气转凉,Foo 同学需要购买一件格子衫,而且要外国货
// 因此他需要找一个代购为其实现这个需求
public class Foo {
    public void buySth() {
        System.out.println("我需要一件格子衫!");
    }
}

// 代理类需要实现 cglib 中定义的 MethodInterceptor 接口
// 实现 intercept() 方法,该实现将在调用时被动态织入代理类中
public class BuyerAgent implements MethodInterceptor {

    public Object newProxyInstance(Class clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);

        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object r = methodProxy.invokeSuper(o, objects);
        after();

        return r;
    }

    private void before() {
        System.out.println("我是代理商,请说出你的需求");
    }

    private void after() {
        System.out.println("已收集你的需求,正在处理中,请等待。。。");
    }
}

// 测试类
public class Main {
    public static void main(String[] args) {
    	// 设置属性,将动态生成的 class 输出到指定位置
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:/cglib_classes");

        Foo foo = (Foo) new BuyerAgent().newProxyInstance(Foo.class);
        foo.buySth();
    }
}

测试结果如下:

CGLIB debugging enabled, writing to 'E:/cglib_classes'
我是代理商,请说出你的需求
我需要一件格子衫!
已收集你的需求,正在处理中,请等待。。。

Process finished with exit code 0

进入 E:/cglib_classes 目录下找到生成的 class 文件:
在这里插入图片描述
我们重点看一下 Foo$$EnhancerByCGLIB$$171cc3a4.class 这个文件:

// 这里生成的代理类继承了被代理类 Foo
public class Foo$$EnhancerByCGLIB$$171cc3a4 extends Foo implements Factory {
    private boolean CGLIB$BOUND;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static final Method CGLIB$buySth$0$Method;
    private static final MethodProxy CGLIB$buySth$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$finalize$1$Method;
    private static final MethodProxy CGLIB$finalize$1$Proxy;
    private static final Method CGLIB$equals$2$Method;
    private static final MethodProxy CGLIB$equals$2$Proxy;
    private static final Method CGLIB$toString$3$Method;
    private static final MethodProxy CGLIB$toString$3$Proxy;
    private static final Method CGLIB$hashCode$4$Method;
    private static final MethodProxy CGLIB$hashCode$4$Proxy;
    private static final Method CGLIB$clone$5$Method;
    private static final MethodProxy CGLIB$clone$5$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        // 调用 intercept() 时会传入此参数
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.foo.bar.Foo$$EnhancerByCGLIB$$171cc3a4");
        Class var1;
        // 调用 intercept() 时会传入此参数
        CGLIB$buySth$0$Method = ReflectUtils.findMethods(new String[]{"buySth", "()V"}, (var1 = Class.forName("com.foo.bar.Foo")).getDeclaredMethods())[0];
        // 调用 intercept() 时会传入此参数
        CGLIB$buySth$0$Proxy = MethodProxy.create(var1, var0, "()V", "buySth", "CGLIB$buySth$0");
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$finalize$1$Method = var10000[0];
        CGLIB$finalize$1$Proxy = MethodProxy.create(var1, var0, "()V", "finalize", "CGLIB$finalize$1");
        CGLIB$equals$2$Method = var10000[1];
        CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
        CGLIB$toString$3$Method = var10000[2];
        CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
        CGLIB$hashCode$4$Method = var10000[3];
        CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
        CGLIB$clone$5$Method = var10000[4];
        CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
    }

    final void CGLIB$buySth$0() {
        super.buySth();
    }

    public final void buySth() {
    	// MethodInterceptor 类型对象就是我们定义的 BuyerAgent 的实例
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            // 调用 BuyerAgent 中的 intercept() 方法,原方法签名如下:
            // public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
            // Method 对象 CGLIB$buySth$0$Method 是被代理的方法 Foo.buySth()
            // CGLIB$emptyArgs 是方法参数
            // CGLIB$buySth$0$Proxy 是生成的代理方法
            //     final void CGLIB$buySth$0() {
        	//         super.buySth();
    		//     }
            var10000.intercept(this, CGLIB$buySth$0$Method, CGLIB$emptyArgs, CGLIB$buySth$0$Proxy);
        } else {
            super.buySth();
        }
    }

    final void CGLIB$finalize$1() throws Throwable {
        super.finalize();
    }

    protected final void finalize() throws Throwable {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$finalize$1$Method, CGLIB$emptyArgs, CGLIB$finalize$1$Proxy);
        } else {
            super.finalize();
        }
    }

    final boolean CGLIB$equals$2(Object var1) {
        return super.equals(var1);
    }

    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$2$Method, new Object[]{var1}, CGLIB$equals$2$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }

    final String CGLIB$toString$3() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString();
    }

    final int CGLIB$hashCode$4() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    final Object CGLIB$clone$5() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -1574182249:
            if (var10000.equals("finalize()V")) {
                return CGLIB$finalize$1$Proxy;
            }
            break;
        case -786250220:
            if (var10000.equals("buySth()V")) {
                return CGLIB$buySth$0$Proxy;
            }
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$5$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$2$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$3$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$4$Proxy;
            }
        }

        return null;
    }

    public Foo$$EnhancerByCGLIB$$171cc3a4() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        Foo$$EnhancerByCGLIB$$171cc3a4 var1 = (Foo$$EnhancerByCGLIB$$171cc3a4)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        Foo$$EnhancerByCGLIB$$171cc3a4 var10000 = new Foo$$EnhancerByCGLIB$$171cc3a4();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        Foo$$EnhancerByCGLIB$$171cc3a4 var10000 = new Foo$$EnhancerByCGLIB$$171cc3a4();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        Foo$$EnhancerByCGLIB$$171cc3a4 var10000 = new Foo$$EnhancerByCGLIB$$171cc3a4;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        default:
            var10000 = null;
        }

        return var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        default:
        }
    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}

从上面动态生成的类我们可以发现,cglib 是基于继承来实现动态代理的,代理类通过继承被代理类,重写被代理的方法时织入代理的功能。由此我们不难推断出被代理类中的 final 方法时无法被 cglib 代理的。

3. 总结

类别实现性能
静态代理代理对象持有被代理对象的引用-
JDK 动态代理JDK 动态生成字节码性能较差
cglib 动态代理基于字节码重组框架动态生成字节码性能较高
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值