单例模式之代理模式

Posted kancy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式之代理模式相关的知识,希望对你有一定的参考价值。

代理模式在生活中的应用常见随处可见,例如:快递员、中介、媒婆、黄牛等等。代理模式可以实现AOP,拦截器,代码解耦等功能。一般有3中实现方式:

  1. 静态代理
  2. JDK实现的动态代理(创建目标对象的所有接口的代理实现类)
  3. CGLIB实现的动态代理(创建目标对象的代理子类)

实现代理模式,代理对象需要拿到目标对象的引用且能够调用目标对象的方法。当然也有些代理不需要目标对象的引用,例如Mybatis的Mapper代理对象就不需要目标对象,不过Mapper也没有具体实现的类。

1.静态代理

这种代理实现的功能比较单一,因为在代理运行前,目标对象是明确的(类型明确),同时也不易扩展,扩展时需要同时改造目标类和代理类,不遵守开闭原则。属于需要人工干预的代理,不具有智能自动化,一般很少使用。

 

2.动态代理(JDK)

动态代理在运行前,所有的东西都是未知的,只有到运行时才知道,容易扩展。属于智能自动化的代理,应用的比较广泛。

使用JDK实现的动态代理代码:

package com.kancy.pattern.proxy;

import pattern.ApplePhone;
import pattern.Phone;

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

public class JDKDynamicProxy<T> implements InvocationHandler {
    private T target;
    public JDKDynamicProxy() {
    }
    public JDKDynamicProxy(T target) {
        this.target = target;
    }
    public T getProxyObject(){
        return (T) Proxy.newProxyInstance(
                target.getClass().getClassLoader() //加载动态生成的class到JVM
                ,target.getClass().getInterfaces() //代理对象需要实现的接口
                ,this // 代理对象具体代理实现,这里为了方便,使用当前类
        );
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理处理------------start");
        Object invoke = method.invoke(target, args);
        System.out.println("代理处理------------end");
        return invoke;
    }

    public static void main(String[] args) {
        // 手机Phone接口类型的代理
        JDKDynamicProxy<Phone> proxy = new JDKDynamicProxy(new ApplePhone());
        Phone proxyObject = proxy.getProxyObject();
        proxyObject.getName();
    }
}

 

原理解析:(字节码重组)

  1. 拿到目标对象的引用,并获取他的所有接口和类加载器
  2. 使用sun.misc.ProxyGenerator类生成一个实现了目标对象所有接口的实现类(java源码),并且动态编译成class字节码数组。
    1. 生成类的格式:目标类名.$Proxy{序号n}
  3. 使用目标对象的类加载器,把编译后的字节码加载到JVM使用。
  4. 删除代理创建过程中的产生的class文件。
/*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }

 

3.动态代理(CGLIB)

CGLIB实现的动态代理与JDK实现的动态代理,不同点在于CGLIB动态生成的是目标对象的子类,而JDK动态生成的是目标对象所有接口的实现类,其他原理基本类似。

使用CGLIB实现的动态代理代码:

package com.kancy.pattern.proxy;

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

import java.lang.reflect.Method;

public class CGLIBDynamicProxy<T> implements MethodInterceptor {
    private T target;
    public CGLIBDynamicProxy() {
    }
    public CGLIBDynamicProxy(T target) {
        this.target = target;
    }
    public T getProxyObject(){
        Object proxy = Enhancer.create(target.getClass(), this);
        return (T) proxy;
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理处理------------start");
        Object invoke = method.invoke(target, objects);
        System.out.println("代理处理------------end");
        return invoke;
    }
    
    public static void main(String[] args) {
        ApplePhone target = new ApplePhone();//目标对象
        CGLIBDynamicProxy<ApplePhone> proxy = new CGLIBDynamicProxy(target);
        ApplePhone proxyObject = proxy.getProxyObject();
        proxyObject.getName();
    }
}
Enhancer.create()代码:
public static Object create(Class type, Callback callback) {
        Enhancer e = new Enhancer();
        e.setSuperclass(type);
        e.setCallback(callback);
        return e.create();
    }

 

在附上sun.misc.ProxyGenerator创建Class字节码代码:

package com.kancy.pattern.proxy;

import pattern.ApplePhone;
import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.io.IOException;

public class ProxyGeneratorTest {
    public static void main(String[] args) throws IOException {
        // 生成ApplePhone类的代理类CLASS文件
        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0",
                ApplePhone.class.getInterfaces());
        FileOutputStream out = new FileOutputStream("$Proxy0.class");
        out.write(bytes);
        out.close();
    }
}

 

创建的class反编译代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import pattern.Phone;

public final class $Proxy0 extends Proxy implements Phone {
    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});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String getName() throws  {
        try {
            return (String)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);
        } 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("pattern.Phone").getMethod("getName");
            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());
        }
    }
}

以上是关于单例模式之代理模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之单例模式

设计模式之——单例模式

设计模式之单例模式

Java 面试之单例模式

设计模式之单例模式

设计模式之代理模式