设计模式 之 代理模式

1. 关于java - 代理模式

  • 代理模式的组成:被代理类代理类

2. 静态代理

  • 代理类对象,通过聚合被代理类对象,调用对方的方法。eg: Thread的run方法实现。
  • 主要组成:接口实现类代理类

其中接口定义标准,是为了使代理更加规范可控,以及实现多级代理,实现类 也就是被代理类

package com.demo.design.proxy;

/**
 * 代理模式组成:接口、实现类、代理类
 * 代理模式-静态代理:通过聚合持有被代理类实例,进行功能增强. eg: Thread的run方法的实现
 */
public class ProxyPatternDemo {
    public static void main(String[] args) {
        Movable proxyObj = new ProxyMovable(new Bike());
        proxyObj.move();
    }
}

/**
 * 接口:可移动的
 */
interface Movable {
    void move();
}

/**
 * 被代理类(实现类):自行车
 */
class Bike implements Movable {
    @Override
    public void move() {
        System.out.println(String.format("I am %s, speed %d km/h .", this.getClass().getName(), 20));
    }
}

/**
 * 代理类(静态代理)
 */
class ProxyMovable implements Movable {

    private Movable moveObj;

    ProxyMovable(Movable moveObj) {
        this.moveObj = moveObj;
    }

    @Override
    public void move() {
        System.out.println("proxy handler  start------");
        if (moveObj != null) {
            moveObj.move();
        }
        System.out.println("proxy handler  end------");
    }
}

3. 动态代理

  • 通过动态生成代理类,进行代理。
3.1 JDK的Proxy类
  • 通过接口动态生成代理类,聚合被代理类对象,调用对方的方法。
  • 主要组成:接口实现类代理类处理器

其中接口定义标准,用来生成代理类,以及实现多级代理 ,处理器 用来聚合被代理类对象,调用对方的方法。

package com.demo.design.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 代理模式组成:接口、实现类、代理类、处理器。
 * 代理模式-动态代理:用JDK的Proxy类,通过接口创建代理对象(类加载器、接口、处理类实例)进行代理,处理类进行功能增强. eg: spring aop 功能
 * 缺点:必须有接口实现,根据接口生成代理类
 */
public class ProxyPatternDemo {

    public static void main(String[] args) {
        // 項目目录下,会保存生成的代理对象(不是target目录下)
        System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        proxy3();
    }

    /**
     * 代理方法3
     */
    private static void proxy3() {
        InvocationHandler handler = new LogHandler(new Bike());
        Movable proxyObj = (Movable) Proxy.newProxyInstance(Movable.class.getClassLoader(), new Class[]{Movable.class}, handler);
        proxyObj.move();
    }

}

/**
 * 接口:可移动的
 */
interface Movable {
    void move();
}

/**
 * 被代理类(实现类):自行车
 */
class Bike implements Movable {
    @Override
    public void move() {
        System.out.println(String.format("I am %s, speed %d km/h .", this.getClass().getName(), 20));
    }
}


/**
 * 处理类:日志处理
 */
class LogHandler implements InvocationHandler {
    Movable moveObj;

    public LogHandler(Movable moveObj) {
        this.moveObj = moveObj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(String.format("proxy %s method start------", method.getName()));
        Object result = method.invoke(moveObj, args);
        System.out.println(String.format("proxy %s method end------", method.getName()));
        return result;
    }
}
3.1 cglib类库
  • 通过生成被代理类的子类,进行方法重写。
  • 主要组成:实现类代理类方法拦截器(处理器)

方法拦截器 用做代理方法实现,为子类生成做准备的。

package com.demo.design.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 代理模式组成:实现类、代理类
 * 代理模式-动态代理:通过生成被代理类的子类,进行方法重写,实现功能增强. eg: spring aop 功能
 * 缺点:必须有接口实现,根据接口生成代理类
 */
public class ProxyPatternDemo {

    public static void main(String[] args) {
        // 項目目录下,会保存生成的代理对象(不是target目录下)
        System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        proxy();
    }

    /**
     * 代理创建过程
     */
    private static void proxy() {
        Enhancer enhancer = new Enhancer(); // 增强器
        enhancer.setSuperclass(Bike.class); // 设置父类
        enhancer.setCallback(new LogMethodInterceptor()); // 设置方法拦截处理器

        Bike bike = (Bike) enhancer.create();
        bike.move();
    }

}

/**
 * 被代理类:自行车
 */
class Bike {
    public void move() {
        System.out.println(String.format("I am %s, speed %d km/h .", this.getClass().getName(), 20));
    }
}

/**
 * 方法拦截处理器
 */
class LogMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println(String.format("proxy %s method start------", method.getName()));
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println(String.format("proxy %s method end------", method.getName()));
        return result;
    }
}

4. asm 和 instrument

  • asm:通过修改二进制代码,实现对类定义的操作修改(jdk 和 cglib 的动态代理也是用这个实现的)。
  • instrument :在类字节码载入JVM前,通过修改二进制代码,实现对类定义进行操作修改。