设计模式之代理模式

代理模式是应用最广泛的设计模式之一,例如spring中的aop就是代理模式的实践。通常在java中使用比较广泛的是动态代理模式,其中实现方式比较常用的是jdk动态代理和cglib动态代理。

jdk实现动态代理

利用jdk实现动态代理代码比较简单,需要注意的是基于jdk的动态代理是必须基于接口才可以的,代码如下。

定义接口。

public interface Action {

    public void move();
}

定义被代理对象。

public class TargetAction implements Action {
    @Override
    public void move() {
        System.out.println("target doing move");
    }
}

实现InvocationHandler定义调用者。

public class InvocationHandlerAction implements InvocationHandler {
    private Action target;

    public InvocationHandlerAction(Action target){
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoker doing");
        return method.invoke(target, args);
    }
}

测试代码。

public class JdkProxyTest {
    public static void main(String[] args) throws IOException {
        Action targetAction = new TargetAction();
        Action proxyAction = (Action) Proxy.newProxyInstance(targetAction.getClass().getClassLoader(), targetAction.getClass().getInterfaces(), new InvocationHandlerAction(targetAction));
        proxyAction.move();
        //输出动态生成代理类的字节码文件
        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Action.class});
        FileOutputStream outputStream = new FileOutputStream(new File("D://$Proxy0.class"));
        outputStream.write(bytes);
        outputStream.flush();
        outputStream.close();
    }
}

根据上面的代码就可以实现一个动态代理逻辑,在InvocationHandler利用反射调用目标对象的方法的前后,可以做出一些逻辑的丰富。

需要注意的上面使用了ProxyGenerator来输出动态生成的字节码文件,内容如下。

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

import design.mode.proxy.jdk.Action;
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 Action {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    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})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

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

    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 int hashCode() throws  {
        try {
            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
        } 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"));
            m3 = Class.forName("design.mode.proxy.jdk.Action").getMethod("move");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

根据输出的字节码文件,可以知道新生成的代理类,实现了Action接口,也就是我们定义的接口,同时实现了接口方法,查看接口方法,发现方法调用逻辑主要是以下代码,h就是我们实现了InvocationHandler接口的类,通过InvocationHandler的invoke方法,进入代理逻辑,实现动态代理。

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

整个动态代理类的生成过程可以归纳为以下一个步骤。

  1. 根据接口信息,新生成一个代理类的.java文件

  2. 根据.java,编译生成.class文件

  3. classloader读取class文件信息到jvm

  4. 新建对象,设置InvocationHandler参数。

cglib动态代理实现

定义被代理对象。需要注意,cglib的代理实现不需要基于接口。

public class TargetAction {
    private String word = "default";

    public TargetAction(){

    }

    public TargetAction(String word){
        this.word = word;
    }

    public void move(){
        System.out.println("target doing move" + word);
    }
}

定义一个作用类似于InvocationHandler的类。

public class CglibCallBackInvocationHandler implements MethodInterceptor{
    private TargetAction targetAction;

    public CglibCallBackInvocationHandler(TargetAction targetAction){
        this.targetAction = targetAction;
    }

    /**
     * 类似动态代理的InvocationHandler作用
     * @param o
     * @param method
     * @param objects
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("invoker doinig move");
        //return methodProxy.invokeSuper(o, objects);
        return method.invoke(targetAction, objects);
    }
}

定义代理类创建器

public class CglibProxyCreator {
    public static <T> T create(Class<T> clazz, MethodInterceptor callbackinvoker){
        Enhancer enhancer = new Enhancer();
        //设置代理什么类
        enhancer.setSuperclass(clazz);
        //设置invoker
        enhancer.setCallback(callbackinvoker);
        return (T) enhancer.create();
    }
}

测试代码。

public class CglibTest  {
    public static void main(String[] args) {
        TargetAction targetAction = new TargetAction("defintioin word");
        TargetAction cglibProxy = CglibProxyCreator.create(TargetAction.class, new CglibCallBackInvocationHandler(targetAction));
        cglibProxy.move();
    }
}

基本的编码方式与jdk实现的动态代理基本一致,以上就是两种动态代理模式的使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Archie_java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值