代理模式

浪子不回头ぞ 提交于 2019-11-26 14:21:53

一、代理模式:

  代理模式是对象的结构模式;

  代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用;

  常见的代理模式分类:静态代理,jdk动态代理,CGlib动态代理;

二、静态代理:

  静态代理一个代理类:只能代理一种接口的类;如果代理类的业务都是一样的,就造成了大量重复代理类;

  1)真实对象和代理对象共同的接口:

//抽象角色:声明真实对象和代理对象的共同接口;
public interface ITicketManager {
    /**
     * 售票
     */
    void  soldTicket();
    /**
     * 改签
     */
    void changeTicket();
    /**
     * 退票
     */
    void returnTicket();
}

  2)真实对象实现类:

public class TicketManagerImpl implements ITicketManager {
    @Override
    public void soldTicket() {
        System.out.println("售票");
    }

    @Override
    public void changeTicket() {
        System.out.println("改签");
    }

    @Override
    public void returnTicket() {
        System.out.println("退票");
    }

    /**
     * 身份验证
     */
    public void checkIdentity(){
        System.out.println("身份验证");
    }
}

  3)代理1:

public class StaticProxyTicketManager implements ITicketManager {
    ITicketManager iTicketManager;//目标对象的引用

    public StaticProxyTicketManager(ITicketManager iTicketManager) {
        this.iTicketManager = iTicketManager;
    }

    @Override
    public void soldTicket() {
        checkIdentity();
      iTicketManager.soldTicket();
    }

    @Override
    public void changeTicket() {
        checkIdentity();
        iTicketManager.changeTicket();
    }

    @Override
    public void returnTicket() {
        checkIdentity();
        iTicketManager.changeTicket();
    }

    /**
     * 身份验证
     */
    public void checkIdentity(){
        System.out.println("身份验证--------------");
    }
}
StaticProxyTicketManager

  4)代理2:

public class LogProxy implements ITicketManager {
    private ITicketManager iTicketManager;

    public LogProxy(ITicketManager iTicketManager){
        this.iTicketManager = iTicketManager;
    }

    @Override
    public void soldTicket() {
        iTicketManager.soldTicket();
        log();//后置增强
    }

    @Override
    public void changeTicket() {
        iTicketManager.changeTicket();
        log();
    }

    @Override
    public void returnTicket() {
        iTicketManager.returnTicket();
        log();
    }

    //增强
    private void log() {
        System.out.println("日志...");

    }
}
LogProxy

  5)测试:

public class Test {
    public static void main(String[] args) {
        ITicketManager tm = new LogProxy(new StaticProxyTicketManager(new TicketManagerImpl()));

        tm.soldTicket();
        tm.changeTicket();
        tm.returnTicket();
    }
}

  6)结果:

身份验证--------------
售票
日志...
身份验证--------------
改签
日志...
身份验证--------------
改签
日志...

三、jdk动态代理:

  通过让代理类(DynamicProxy)实现JDK自带的java.lang.reflect.InvocationHandler接口,该接口中的invoke() 方法能够让代理类(DynamicProxy)实例在运行时调用被代理类的“对外服务”,即调用被代理类需要对外实现的所有接口中的方法,也就是完成对真实方法的调用;

  缺点:需要代理的业务类有实现的接口作为参数,因为需要调用接口中定义的方法;如果没有实现接口的业务类,JDK动态代理就无能为力了;

  1)接口:

public interface ITicketManager {
    /**
     * 售票
     */
    void  soldTicket();
    /**
     * 改签
     */
    void changeTicket();
    /**
     * 退票
     */
    void returnTicket();
}
ITicketManager

  2)接口实现类:

public class TicketManagerImpl implements ITicketManager {
    @Override
    public void soldTicket() {
        System.out.println("售票");
    }

    @Override
    public void changeTicket() {
        System.out.println("改签");
    }

    @Override
    public void returnTicket() {
        System.out.println("退票");
    }
}
TicketManagerImpl

  3)代理类:

public class DynamicProxyTicketManager implements InvocationHandler {
    private Object targetObject;

    /**
     * 目标的初始化方法,根据目标生成代理类
     *
     * @param targetObject
     * @return
     */
    public Object newProxyInstance(Object targetObject) {
        this.targetObject = targetObject;
        // 第一个参数,目标对象 的装载器
        // 第二个参数,目标接口已实现的所有接口,而这些是动态代理类要实现的接口列表
        // 第三个参数, 调用实现了InvocationHandler的对象生成动态代理实例,当你一调用代理,代理就会调用InvocationHandler的invoke方法
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(),
                this);
    }

    /**
     * 反射,这样你可以在不知道具体的类的情况下,根据配置的参数去调用一个类的方法。在灵活编程的时候非常有用。
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 检查
        checkIdentity();
        Object ret = null;
        try {
            // 调用目标方法
            ret = method.invoke(targetObject, args);
            // 执行成功,打印成功信息
            log();
        } catch (Exception e) {
            e.printStackTrace();
            // 失败时,打印失败信息
            System.out.println("error-->>" + method.getName());
            throw e;
        }
        return ret;
    }

    /**
     * 身份验证
     */
    public void checkIdentity() {
        System.out.println("身份验证--------------");
    }

    public void log() {
        System.out.println("日志...");
    }

}

  4)测试:

public class Test {
    public static void main(String[] args) {
        DynamicProxyTicketManager dynamicProxyTicketManager=new DynamicProxyTicketManager();
        ITicketManager tm=(ITicketManager) dynamicProxyTicketManager.newProxyInstance(new TicketManagerImpl());

        tm.soldTicket();
        tm.changeTicket();
        tm.returnTicket();
    }
}

四、GClib动态代理:

 1、无需接口就能代理类;

 2、因为时生产被代理的子类,所以被final修饰的方法无法代理;

  1)导包:asm-3.3.1.jar;cglib-2.2.2.jar;这两个版本测试可用;

  2)被代理类:

public class TicketManager {
    public void soldTicket() {
        System.out.println("售票");
    }

    public void changeTicket() {
        System.out.println("改签");
    }

    public void returnTicket() {
        System.out.println("退票");
    }
}
TicketManager

  3)代理类:

public class DynamicProxyTicketManager implements MethodInterceptor {
    private Object targetObject;

    /**
     * 目标的初始化方法,根据目标生成代理类
     *
     * @param targetObject
     * @return
     */
    public Object newProxyInstance(Object targetObject) {
        //代理类class文件存入本地磁盘
        //System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\\code");
        this.targetObject = targetObject;
        // 创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();
        // 为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        enhancer.setSuperclass(targetObject.getClass());
        // 设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方        //法进行拦
        enhancer.setCallback(this);
        // 创建动态代理类对象并返回
        Object obj = enhancer.create();
        return obj;
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 检查
        checkIdentity();
        Object ret = null;
        try {
            ret = methodProxy.invokeSuper(proxy, args);
            // 执行成功,打印成功信息
            System.out.println(1 / 0);
            log();
        } catch (Exception e) {
            e.printStackTrace();
            // 失败时,打印失败信息
            System.out.println("error-->>" + method.getName());
            throw e;
        }
        return ret;
    }

    /**
     * 身份验证
     */
    public void checkIdentity() {
        System.out.println("身份验证--------------");
    }

    public void log() {
        System.out.println("日志...");
    }
}

  4)测试:

public class Test {
    public static void main(String[] args) {
        TicketManager ticketManager = new TicketManager();
        DynamicProxyTicketManager dynamicProxyTicketManager = new DynamicProxyTicketManager();
        TicketManager instance = (TicketManager) dynamicProxyTicketManager.newProxyInstance(ticketManager);

        instance.changeTicket();
        instance.returnTicket();
        instance.soldTicket();
    }
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!