引言

设计模式-代理模式

849321706886049700e73f7.png

  • Subject 抽象主题角色:可以是抽象类,也可以是接口。抽象主题是一个普通的业务类型,无特殊要求。
  • RealSubject 具体主题角色:也叫做被委托角色或被代理角色,是业务逻辑的具体执行者。
  • Proxy 代理主题角色:也叫做委托类或代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后处理工作。

优点:

  • 职责清晰(业务类只实现自己具体的业务逻辑,而不用关心其他业务功能,由上层代理类进行完成)
  • 高扩展性(在不改变原有类的基础上,通过代理类增加额外的功能)

使用场景:

  • 日志打印
  • 事务处理
  • 数据的过滤,预处理,后处理等

代码示例:

# 业务接口定义
public interface IPeople {

    void eat();
}
# 业务实现类
public class WangPeople implements IPeople {

    @Override
    public void eat() {
        System.out.println("吃个苹果");
    }
}
# 代理类
public class PeopleProxy implements IPeople {

    private IPeople peopleManager;

    public PeopleProxy(IPeople peopleManager) {
        this.peopleManager = peopleManager;
    }

    @Override
    public void eat() {
        peopleManager.eat();
        System.out.println("加个鸡腿");
    }
}
## 测试
public class MainTest {

    public static void main(String[] args) {
        IPeople people = new WangPeople();
        PeopleProxy proxy = new PeopleProxy(people);
        proxy.eat();
    }
}

1、JDK动态代理

在代码中不编写具体接口的代理类,在运行期间通过反射实现代理功能
java.lang.reflect.InvocationHandler
java.lang.reflect.Proxy

1.1、代码示例

public class PeopleProxyHandler implements InvocationHandler {

    private IPeople target;

    private PeopleProxyHandler() {
    }

    public static IPeople newProxyInstance(IPeople target) {
        PeopleProxyHandler proxy = new PeopleProxyHandler();
        proxy.target = target;
        return (IPeople) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), proxy);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object ret = null;
        try {
            ret = method.invoke(target, args);
            System.out.println("加个鸡腿");
        } catch (Exception e) {
            System.err.println("PeopleDynamicProxy 执行业务方法异常");
        }
        return ret;
    }
}

public class MainTest2 {

    public static void main(String[] args) {
        IPeople people = new WangPeople();
        IPeople wangPeople = PeopleProxyHandler.newProxyInstance(people);
        wangPeople.eat();
    }
}

运行效果:
AE0C24CDFAAC477881F362F5BF84A1C6.png
image.png

1.2、动态生成代理类

public final class $Proxy0 extends Proxy implements IPeople {
    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);
        }
    }
	// 重写所有被代理类方法,并声明为final
	// 传入代理类,执行方法,和参数
    public final void eat() throws  {
        try {
            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("com.docker.test.dockertest.proxy.jdk.IPeople").getMethod("eat");
            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());
        }
    }
}

调用的时序图
image.png

1.3、源码分析

public interface InvocationHandler {

    /**
    * proxy – 调用该方法的代理实例(被代理的对象)
    * method – 与在代理实例上调用的接口方法对应的Method实例(要调用的方法)
    * args – 包含在代理实例的方法调用中传递的参数值的对象数组
    * return  从代理实例上的方法调用返回的值
    **/
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
public class Proxy implements java.io.Serializable {
  
   /**
   *
   *  loader 定义代理类的类加载器
   *  interfaces  代理类要实现的接口列表
   *  h  将方法调用分派到的调用处理程序
   *  return  具有代理类的指定调用处理程序的代理实例
   **/
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }
  
}

1.4、优缺点

  • 优点:当需要对业务类中的每个方法加统一逻辑时,不需要对每个方法都实现一个代理方法,而是使用invoke进行统一处理
  • 缺点:它必须依赖于interface 来实现动态代理,否则将不能使用

2、Cglib

cglib 是一个强大、高性能和高质量的代码生成库。它用于扩展 JAVA 类并在运行时实现接口,为JDK的动态代理提供了很好的补充。开源免费
https://github.com/cglib/cglib

0B5F58254B7D40AFB380AB2C48A8EF1D.png

  • CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问
  • CGLIB主要依赖于ASM包实现对字节码的操作
  • Java 字节码是Java代码编译之后的一种低级语言表示,Java虚拟机执行的就是字节码文件,以.class为扩展名的文件

2.1、代码示列:

# 拦截方法,实现附加功能
public class PeopleMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object object = methodProxy.invokeSuper(o, args);
        System.out.println("加个鸡腿");
        return object;
    }
}

# 通过CGLIB增强类创建实例,执行业务方法
public class CglibMainTest {

    public static void main(String[] args) {
		// 生产CGLIB动态代理类到指定的目录中
		System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/haoyin/work/personal/docker-test/code");
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(WangPeople.class);
        enhancer.setCallback(new PeopleMethodInterceptor());
        WangPeople people = (WangPeople) enhancer.create();
        people.eat();
    }
}

运行效果:
image.png
image.png

2.2 、动态生成的代理类

一共动态生产了三个类:
image.png

  • classNameEnhancerByCGLIBxxxxxx        代理类
  • classNameEnhancerByCGLIBxxxxxFastClassByCGLIBxxxxxx    FastClass f2   代理类的增强类
  • classNameFastClassByCGLIBxxxxxx     FastClass f1  原始类的增加类

WangPeopleEnhancerByCGLIBb9fd69a8.class(删除了一些无关代码)

public class WangPeople$$EnhancerByCGLIB$$b9fd69a8 extends WangPeople implements Factory {
    private boolean CGLIB$BOUND;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static final Method CGLIB$eat$0$Method;
    private static final MethodProxy CGLIB$eat$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.docker.test.dockertest.proxy.jdk.WangPeople$$EnhancerByCGLIB$$b9fd69a8");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$eat$0$Method = ReflectUtils.findMethods(new String[]{"eat", "()V"}, (var1 = Class.forName("com.docker.test.dockertest.proxy.jdk.WangPeople")).getDeclaredMethods())[0];
        CGLIB$eat$0$Proxy = MethodProxy.create(var1, var0, "()V", "eat", "CGLIB$eat$0");
    }
	// 调用被代理类原始方法
	// methodProxy.invokeSuper调用此方法
    final void CGLIB$eat$0() {
        super.eat();
    }
	
	// 判断是否是有拦截器配置,如果有就执行拦截器方法,否则执行被代理类原始方法
	// methodProxy.invoke 会调用此方法,如果在拦截方法中调用methodProxy.invoke会出现死循环
    public final void eat() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$eat$0$Method, CGLIB$emptyArgs, CGLIB$eat$0$Proxy);
        } else {
            super.eat();
        }
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -1310345955:
            if (var10000.equals("eat()V")) {
                return CGLIB$eat$0$Proxy;
            }
            break;
        return null;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        WangPeople$$EnhancerByCGLIB$$b9fd69a8 var1 = (WangPeople$$EnhancerByCGLIB$$b9fd69a8)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        WangPeople$$EnhancerByCGLIB$$b9fd69a8 var10000 = new WangPeople$$EnhancerByCGLIB$$b9fd69a8();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        WangPeople$$EnhancerByCGLIB$$b9fd69a8 var10000 = new WangPeople$$EnhancerByCGLIB$$b9fd69a8();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        WangPeople$$EnhancerByCGLIB$$b9fd69a8 var10000 = new WangPeople$$EnhancerByCGLIB$$b9fd69a8;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }

    static {
        CGLIB$STATICHOOK1();
    }
}

WangPeopleEnhancerByCGLIBb9fd69a8FastClassByCGLIBa91fce25(删除了一些无关代码)

public class WangPeople$$EnhancerByCGLIB$$b9fd69a8$$FastClassByCGLIB$$a91fce25 extends FastClass {
    public WangPeople$$EnhancerByCGLIB$$b9fd69a8$$FastClassByCGLIB$$a91fce25(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -1526958892:
            if (var10000.equals("CGLIB$eat$0()V")) {
                return 2;
            }
            break;
        case -1310345955:
            if (var10000.equals("eat()V")) {
                return 13;
            }
            break;
        }

        return -1;
    }

    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case 100184:
            if (var1.equals("eat")) {
                switch(var2.length) {
                case 0:
                    return 13;
                }
            }
            break;
        }
		case 1111931649:
            if (var1.equals("CGLIB$eat$0")) {
                switch(var2.length) {
                case 0:
                    return 2;
                }
            }
            break;
        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        b9fd69a8 var10000 = (b9fd69a8)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 2:
                var10000.CGLIB$eat$0();
                return null;
            case 13:
                var10000.eat();
                return null;
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
		// 这里new出来的是代理类实例
        b9fd69a8 var10000 = new b9fd69a8;
        b9fd69a8 var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 26;
    }
}

WangPeopleFastClassByCGLIB1a9bb430

public class WangPeople$$FastClassByCGLIB$$1a9bb430 extends FastClass {
    public WangPeople$$FastClassByCGLIB$$1a9bb430(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -1310345955:
            if (var10000.equals("eat()V")) {
                return 0;
            }
            break;
        }
        return -1;
    }

    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case 100184:
            if (var1.equals("eat")) {
                switch(var2.length) {
                case 0:
                    return 0;
                }
            }
            break;
        
        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        WangPeople var10000 = (WangPeople)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                var10000.eat();
                return null;
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
		// 这里new出来的是被代理类实例
        WangPeople var10000 = new WangPeople;
        WangPeople var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 9;
    }
}

image.png

2.3、源码分析:

2.3.1、代理类的创建过程

enhancer.create();

image.png

2.3.2、FastClass怎么来的?

通过MethodProxy进行创建,在调用invoke方法的时候进行懒加载

public class MethodProxy {
  	// 保存原方法的签名
    private Signature sig1;
   //  CGLIB生成的代理方法签名
    private Signature sig2;
   //  保存创建代理时的类信息(原类、代理类)
   //  为了懒加载的时候创建FastClassInfo
    private CreateInfo createInfo;
    
    private final Object initLock = new Object();
    private volatile FastClassInfo fastClassInfo;
    
    /**
     * For internal use by {@link Enhancer} only; see the {@link net.sf.cglib.reflect.FastMethod} class
     * for similar functionality.
     */
    public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
        MethodProxy proxy = new MethodProxy();
        proxy.sig1 = new Signature(name1, desc);
        proxy.sig2 = new Signature(name2, desc);
        proxy.createInfo = new CreateInfo(c1, c2);
        return proxy;
    }
   
    private void init()
    {
        /* 
         * Using a volatile invariant allows us to initialize the FastClass and
         * method index pairs atomically.
         * 
         * Double-checked locking is safe with volatile in Java 5.  Before 1.5 this 
         * code could allow fastClassInfo to be instantiated more than once, which
         * appears to be benign.
         */
        if (fastClassInfo == null)
        {
            synchronized (initLock)
            {
                if (fastClassInfo == null)
                {
                    CreateInfo ci = createInfo;

                    FastClassInfo fci = new FastClassInfo();
                    fci.f1 = helper(ci, ci.c1);
                    fci.f2 = helper(ci, ci.c2);
                    fci.i1 = fci.f1.getIndex(sig1);
                    fci.i2 = fci.f2.getIndex(sig2);
                    fastClassInfo = fci;
                    createInfo = null;
                }
            }
        }
    }

    private static class FastClassInfo
    {
        FastClass f1;
        FastClass f2;
        int i1;
        int i2;
    }
	// 生成代理类或者被代理类的 fastClass
	private static FastClass helper(CreateInfo ci, Class type) {
        FastClass.Generator g = new FastClass.Generator();
        g.setType(type);
        g.setClassLoader(ci.c2.getClassLoader());
        g.setNamingPolicy(ci.namingPolicy);
        g.setStrategy(ci.strategy);
        g.setAttemptLoad(ci.attemptLoad);
        return g.create();
    }	
	/**
     * 调用原始方法
     * Invoke the original method, on a different object of the same type.
     * @param obj the compatible object; recursion will result if you use the object passed as the first
     * argument to the MethodInterceptor (usually not what you want)
     * @param args the arguments passed to the intercepted method; you may substitute a different
     * argument array as long as the types are compatible
     * @see MethodInterceptor#intercept
     * @throws Throwable the bare exceptions thrown by the called method are passed through
     * without wrapping in an <code>InvocationTargetException</code>
     */
    public Object invoke(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            return fci.f1.invoke(fci.i1, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (IllegalArgumentException e) {
            if (fastClassInfo.i1 < 0)
                throw new IllegalArgumentException("Protected method: " + sig1);
            throw e;
        }
    }

    /**
     * 调用代理类的方法
     * Invoke the original (super) method on the specified object.
     * @param obj the enhanced object, must be the object passed as the first
     * argument to the MethodInterceptor
     * @param args the arguments passed to the intercepted method; you may substitute a different
     * argument array as long as the types are compatible
     * @see MethodInterceptor#intercept
     * @throws Throwable the bare exceptions thrown by the called method are passed through
     * without wrapping in an <code>InvocationTargetException</code>
     */
    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            init();
            FastClassInfo fci = fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

}

时序图:
image.png

优点:

  • 不使用反射方式调用方法,而通过生成FastClass进行缓存,进行直接调用