Java之动态代理实践

功能概述

  • Java的动态代理,是代理模式的具体实现,即为其他对象提供一个代理以控制对某个对象的访问。Java的动态代理主要涉及两个类:java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler,内部使用了缓存机制和反射机制实现。

功能实践

场景1:为Map接口生成代理

用例代码

@Test
public void test_jdk_dynamic_proxy_v1() {
    Map mapProxyInstance = (Map) Proxy.newProxyInstance(
            ProxyTest.class.getClassLoader(), new Class[] { Map.class },
            new MyInvocationHandler(new HashMap<>()));

    mapProxyInstance.put("hello", "world"); //为接口创建代理对象后,就可以直接操作接口中的方法了(使用向上转型)

    mapProxyInstance.get("hello");

    CharSequence csProxyInstance = (CharSequence) Proxy.newProxyInstance(
            ProxyTest.class.getClassLoader(),
            new Class[] { CharSequence.class },
            new MyInvocationHandler("Hello World"));

    csProxyInstance.charAt(0);
    csProxyInstance.length();
}


// 自定义的调用处理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {

    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        Object result = method.invoke(target, args);
        System.out.println("执行方法:" + method.getName() + ",结果值:" + result);

        return result;
    }
}
    

    

运行结果

执行方法:put,结果值:null
执行方法:get,结果值:world
执行方法:charAt,结果值:H
执行方法:length,结果值:11

结果分析

  • 为Map接口创建代理对象。并自定义调用处理器MyInvocationHandler,在使用代理接口调用方法时,就会回调MyInvocationHandler的invoke方法,传入代理对象、调用的方法、参数列表等

场景2:为自定义接口生成代理

用例代码

public void test_jdk_dynamic_proxy_v2() throws IOException {

    IHelloProxy helloProxy = (IHelloProxy) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(),
            new Class[]{IHelloProxy.class}, new MyInvocationHandler(new HelloProxyImpl())); //要指定接口的实现类,在回调处理器的invoke方式时,调用目标类对应方法

   helloProxy.setProxyName("hello");

   String proxyName = helloProxy.getProxyName("hello");
   System.out.println("结果值:" + proxyName);
}

public interface IHelloProxy {

   String getProxyName(String name);

   void setProxyName(String name);
}

public class HelloProxyImpl implements IHelloProxy {

    private String proxyName;

    private static final String PREFIX = "proxy_";

    @Override
    public String getProxyName(String name) {
        return proxyName;
    }

    @Override
    public void setProxyName(String name) {
        proxyName = PREFIX + name;
    }
}
  • 注明:该场景用到的MyInvocationHandler,在场景1中有声明。

运行结果

执行方法:setProxyName,结果值:null
执行方法:getProxyName,结果值:proxy_hello
结果值:proxy_hello

结果分析

  • 在创建代理对象时,指定代理的接口IHelloProxy,以及调用处理器MyInvocationHandler,调用处理器指定了接口实现类,即目标对象
  • 在调用接口方法时,即调用调用代理对象的方法,会回调InvocationHandler中的invoke方法,可在该方法中做增强处理

原理分析

Proxy#newProxyInstance创建代理对象分析】

public class Proxy implements java.io.Serializable {

    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
            proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); //代码1)
    
    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); // 代码2)
    
            /*
             * Invoke its constructor with the designated invocation handler.
             */
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
    
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                //...代码省略...
                return cons.newInstance(new Object[]{h}); // 代码3)
            } catch (IllegalAccessException|InstantiationException e) 
                // ...代码省略...
            }
        }

    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
        return proxyClassCache.get(loader, interfaces); //代码4)
    }
}
  • 代码解析:
    • 代码1)处:WeakCache用来存储代理类的缓存,若无缓存,会通过ProxyClassFactory创建
    • 代码2)处:从缓存中查找代理类,若没有创建代理类
    • 代码3)处:找到代理类包含InvocationHandler为参数的构造器Constructor,通过反射机制创建代理对象
    • 代码4)处:从缓存中去查代理类

ProxyClassFactory#apply创建代理类分析

private static final class ProxyClassFactory
    implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
    //...代码省略...

    @Override
    public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

        Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
        for (Class<?> intf : interfaces) {
            Class<?> interfaceClass = null;
            try {
                interfaceClass = Class.forName(intf.getName(), false, loader); // 代码1)
            } catch (ClassNotFoundException e) {
            }
            if (interfaceClass != intf) {
                throw new IllegalArgumentException(
                    intf + " is not visible from class loader");
            }
            if (!interfaceClass.isInterface()) { // 代码2)
                throw new IllegalArgumentException(
                    interfaceClass.getName() + " is not an interface");
            }
            /*
             * Verify that this interface is not a duplicate.
             */
            if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                throw new IllegalArgumentException(
                    "repeated interface: " + interfaceClass.getName());
            }
        }
        // ...代码省略...

        /*
         * Generate the specified proxy class.
         */
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
            proxyName, interfaces, accessFlags); // 代码3)
        try {
            return defineClass0(loader, proxyName,
                                proxyClassFile, 0, proxyClassFile.length); //代码4)
        } 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());
        }
    }
}
  • 代码分析:
    • 代码1)处:判断如是否能够通过当前加载器加载Class
    • 代码2)处:判断代理的是否是接口,不是接口不能代理
    • 代码3)处:产生代理类Class的字节数组
    • 代码4)处:将字节数组通过native方法得到代理类的Class

功能总结

  • CGLIB与JDK动态代理区别
    • a)JDK代理只能对实现接口的类生成代理;CGLib是针对类实现代理
    • b)JDK代理使用的是反射机制实现aop的动态代理,CGLib代理使用字节码处理框架ASM
    • c)JDK动态代理机制是委托机制,CGLib则使用的继承机制

你可能感兴趣的:(Java,java,开发语言)