Java基础之反射生成JDK动态代理
阅读原文时间:2023年07月09日阅读:3

在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口。通过这个类和接口可以生成JDK动态代理类或动态代理对象。

JDK动态代理例子:

// 抽象主题角色
public interface Sleep {
void sleep();
}

// 真实主题角色
public class SleepImpl implements Sleep {
@Override
public void sleep() {
System.out.println("熟睡中");
}
}

//动态处理器
public class DynamicProxyHandler implements InvocationHandler {
private Object obj ;
public DynamicProxyHandler(final Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("睡觉前要刷牙");
Object result = method.invoke(obj, args);
System.out.println("睡醒后要吃早饭");
return null;
}
}
//测试代码
public class ProxyTest {
public static void main(String[] args) {
Sleep sleep = new SleepImpl();
DynamicProxyHandler dph = new DynamicProxyHandler(sleep);
Sleep sleepProxy = (Sleep) Proxy.newProxyInstance(sleep.getClass().getClassLoader(),
sleep.getClass().getInterfaces(), dph);
sleepProxy.sleep();
}
}

结果:睡觉前要刷牙
熟睡中
睡醒后要吃早饭

JDK动态代理源码分析:

生产代理类主要是通过:Proxy.newProxyInstance方法:

@CallerSensitive
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);  
    }  
}