设计模式之代理模式

代理模式是应用最广泛的设计模式之一,例如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实现的动态代理基本一致,以上就是两种动态代理模式的使用。

代理模式是一种结构型设计模式,它提供一个代理对象来代表另一个对象。在代理模式中,有一个被称为实际对象(Subject)和一个被称为代理对象(Proxy)的中介,代理对象持有实际对象的引用,并且可以控制对实际对象的访问。代理模式的主要目的是在不修改原始对象的情况下,为原始对象添加额外的逻辑处理。 代理模式分为多种类型,如远程代理、虚拟代理、保护代理等,它们各自有不同的应用场景: - 远程代理:为远程对象提供一个本地代表。 - 虚拟代理:根据需要创建开销大的对象,通过虚拟代理控制访问这些对象的过程。 - 保护代理:控制对原始对象的访问权限,例如进行权限检查。 代理模式的优点包括: 1. 能够控制对真实对象的访问,并在访问前后添加额外的逻辑。 2. 可以通过代理对象实现延迟加载,即在实际需要时才创建真实对象。 3. 增强了对真实对象的封装,并且可以避免对真实对象的重复引用。 在C#中实现代理模式通常涉及以下步骤: 1. 定义一个接口或抽象类,声明真实对象和代理对象需要实现的方法。 2. 实现真实对象的类,按照接口或抽象类的要求实现具体方法。 3. 实现代理类,它同样实现接口或抽象类,并在方法中持有真实对象的引用,通过调用真实对象的方法来执行所需的操作,同时可以添加额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值