设计模式-代理模式


根据代理类是在运行前还是运行时指定,代理模式可以分为静态代理和动态代理;动态代理又可以根据实现方式不同分为:jdk动态代理、cglib动态代理,javassist动态代理。

jdk动态代理

jdk动态是基于反射实现的,只能代理有接口的类。代理的关键是实现InvocationHandler,被代理对象方法具体执行时,会通过InvocationHandler的invoke去执行,具体生成代理类需要依赖Proxy。

实例代码:
代理接口:

public interface CommonFeature {
    String doBusiness(String name);
}

具体业务实现:

public class ConcreteService implements CommonFeature{
    public String doBusiness(String name) {
       return name+",你好";
    }
}

代理类:

public class ServiceProxy implements InvocationHandler {
    private Object proxyObject;

    public ServiceProxy(Object proxyObject) {
        this.proxyObject = proxyObject;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("业务前的准备处理,比如记录日志");
        return method.invoke(this.proxyObject, args);
    }
}

客户端:

public class Client {
    public static void main(String[] args) {
        ConcreteService service = new ConcreteService();
        ServiceProxy serviceProxy = new ServiceProxy(service);
        CommonFeature proxyInstance = (CommonFeature)Proxy.newProxyInstance(service.getClass().getClassLoader(),
            new Class[] {CommonFeature.class},
            serviceProxy);
        System.out.println(proxyInstance.doBusiness("XX"));
    }
}

输出结果如下图:
在这里插入图片描述

cglib动态代理

cglib相对于jdk代理不同的是:cglib底层是依赖ASM字节码框架直接操作字节码完成对原类型的扩展以生成代理类;cglib实现代理不强制要求被代理类实现接口;cglib使用继承的方式扩展被代理类的方法的功能,因此final的类不能被代理,final的方法不能被代理执行;
cglib的关键是MethodInterceptor和Enhancer,通过Enhancer操作字节码生成被代理类的子类,然后为代理类设置回调MethodInterceptor ,从而可以在执行时,先执行MethodInterceptor 的intercept,然后执行父类的相关方法。

实现实例:
被代理类如下

public class BusinessService {
    public BusinessService() {
        System.out.println("构造方法执行。。。。。");
    }
    public final void doSomething1(){
        System.out.println("执行无法被代理的方法");
    }
    public void doSomething2(){
        System.out.println("执行被代理方法");
    }
}

实现的MethodInterceptor类如下

public class MyMethodInterceptor implements MethodInterceptor {
    /**
     *
     * @param o 生成的代理对象
     * @param method 被代理对象方法
     * @param objects 方法参数
     * @param methodProxy 代理方法
     * @return
     * @throws Throwable
     */
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("业务前的准备处理,比如记录日志");
        return methodProxy.invokeSuper(o,objects);
    }
}

客户端如下

public class Client2 {
    public static void main(String[] args) {
        MyMethodInterceptor myMethodInterceptor = new MyMethodInterceptor();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(BusinessService.class);
        enhancer.setCallback(myMethodInterceptor);
        BusinessService proxy = (BusinessService)enhancer.create();
        System.out.println("客户端执行doSomething1.................");
        proxy.doSomething1();
        System.out.println("客户端执行doSomething2.................");
        proxy.doSomething2();
    }
}

执行结果:
在这里插入图片描述

javassist生成代理类

javassist是一款操作java字节码的类库,同样也可以用它来实现代理,实现的方式有两种:第一种是直接使用官方提供util生成代理类(如代码实例);第二种是自己通过javassist的api去构造代理类(可以参考dubbo的api模块和common模块实现的代理)。
代码实例:
客户端

package lean.proxy;

import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.Proxy;
import javassist.util.proxy.ProxyFactory;

import java.lang.reflect.Method;

/**
 * @author qingh.yxb
 */
public class Client3 {
    public static void main(String[] args) throws Exception {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setSuperclass(BusinessService.class);
        proxyFactory.setFilter(new MethodFilter() {
            public boolean isHandled(Method method) {
                return method.getName().equals("doSomething2");
            }
        });
        Class c = proxyFactory.createClass();
        BusinessService instance = (BusinessService)c.newInstance();
        MethodHandler handler = new MethodHandler() {
            public Object invoke(Object o, Method method, Method method1, Object[] objects) throws Throwable {
                System.out.println("业务前的准备处理,比如记录日志");
                return method1.invoke(o, objects);
            }
        };
        ((Proxy)instance).setHandler(handler);
        System.out.println("javassist代理-客户端执行doSomething1.................");
        instance.doSomething1();
        System.out.println("javassist代理-客户端执行doSomething2.................");
        instance.doSomething2();
    }
}

执行结果如下图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值