代理模式

一,静态代理(房产中介)

在代理模式中的角色:

  ●  抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。

  ●  目标对象角色:定义了代理对象所代表的目标对象。

  ●  代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。

/**
 * 抽象角色,真实角色和代理角色都要实现的接口
 * @author marcopan
 */
public interface IAbstractSubject {

    // 代理对象和真实角色共有的方法,租房()
    public void rentHouse();
}

/**
 * 真实角色--房东
 * @author marcopan
 *
 */
public class RealSubject implements IAbstractSubject {

    @Override
    public void rentHouse() {
        System.out.println("rentHouse from RealSubject");
    }
}

package proxy.staticProxy;

/**
 * 代理角色,中介,含有真实角色的引用
 * @author marcopan
 * 代理角色做两件事:
 * 1. 关联真实角色对象
 * 2. 调用真实对象方法
 */
public class StaticProxySubject implements IAbstractSubject {
    // 含有真实角色的引用
    private RealSubject realSubject = null;

    public StaticProxySubject(RealSubject subject) {
        this.realSubject = subject;
    }

    @Override
    public void rentHouse() {
        realSubject.rentHouse();
    }
}

public class Client {
    public static void main(String[] args) {
        IAbstractSubject proxySubject = new StaticProxySubject(new RealSubject());
        proxySubject.rentHouse();
    }
}

二,动态代理

public class DynamicProxySubject implements InvocationHandler {
    private ISubject target = null;

    public DynamicProxySubject(ISubject target) {
        this.target = target;
    }

    public Object getProxyInstance() {
        Class<?> clazz = target.getClass();
        /**
         * Proxy这个类的作用就是用来动态创建一个代理对象的类
         * Proxy.newProxyInstance返回的是一个代理对象:com.sun.proxy.$Proxy0
         */
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    /**
     * proxy:指被代理的对象,$Proxy0是系统自动生成的实现ISubject接口的代理类,并持有InvocationHandler引用
     * method:指代的是我们所要调用真实对象的某个方法的Method对象
     * args:指代的是调用真实对象某个方法时接受的参数
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 增强消息......
        return method.invoke(target, args);
        // 增强消息......
    }
}

/**
 * //        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{IAbstractSubject.class});
 * //        try {
 * //            String filePath = IAbstractSubject.class.getResource("").getPath();
 * //            FileOutputStream fos = new FileOutputStream(filePath + "/$Proxy0.class");
 * //            fos.write(bytes);
 * //            fos.close();
 * //        } catch (Exception e) {
 * //            e.printStackTrace();
 * //        }
 */


public class Client {
    public static void main(String[] args) {
        ISubject target = new RealSubject();
        ISubject dynamicInstance = (ISubject) new DynamicProxySubject(target).getProxyInstance();
        dynamicInstance.requestHouse1();
        dynamicInstance.requestHouse2();
    }
}

三、Cglib动态代理:

public class CglibProxySubject implements MethodInterceptor {

    public Object getCglibInstance(Class<?> clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);

        return enhancer.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        // before
        Object obj = methodProxy.invokeSuper(o, objects);
        // after
        return obj;
    }
}

public class Client {
    public static void main(String[] args) {
        String filePath = ISubject.class.getResource("").getPath();
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, filePath);

        ISubject target = new RealSubject();
        ISubject cglibInstance = (ISubject) new CglibProxySubject().getCglibInstance(target.getClass());
        System.out.println(cglibInstance);
        cglibInstance.requestHouse1();
        cglibInstance.requestHouse2();
    }
}

CGLib 和 JDK 动态代理对比:

1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。

2.JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM 框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。

3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法, CGLib 执行效率更高。

原文地址:https://www.cnblogs.com/panning/p/7747754.html