JDK dynamic proxies are based on interfaces, while Cglib does not require dynamic proxies.

So why should JDK dynamic proxies be based on interfaces?

Let’s start with a simple JDK dynamic proxy

Interface class

public interface Person {
    void say(a);
}
Copy the code

The implementation class

public class Man implements Person{
    @Override
    public void say(a) {
        System.out.println("man"); }}Copy the code

The proxy class implements the InvocationHandler interface and overwrites the Invoke method

public class JDKDynamicProxy implements InvocationHandler {
    private Object target;

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

    public <T> T getProxy(a) {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Do something before");
        Object result = method.invoke(target, args);
        System.out.println("Do something after");
        returnresult; }}Copy the code

Call the

public class Test {
    public static void main(String[] args) {
        Person person = new JDKDynamicProxy(newMan()).getProxy(); person.say(); }}Copy the code

The result of the call is

Do something before
man
Do something after
Copy the code

The dynamic proxy takes effect.

JDK dynamic proxy requires the invoke class to implement the InvocationHandler interface. The invoke method can be overridden to implement dynamic proxy, and the constructor can inject Object. Object is not required to be based on the interface. And essentially getProxy() gets the proxy class (the original Object class) by inheriting the Object.

So define another wonman. class without implementing the interface, and let’s test it

public class Woman {
    public void say(a){
        System.out.println("woman"); }}Copy the code

Call interface

Woman woman = new JDKDynamicProxy(new Woman()).getProxy();
woman.say();
Copy the code

The results are as follows

Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.ganhuojun.demo.proxy.Woman
	at com.ganhuojun.demo.proxy.Test.main(Test.java:8)
Copy the code

Object dynamic proxies without interfaces are not supported.

Let’s take a look at the source code and see why only interfaces are supported. Because the core of dynamic proxies is getting the proxy class, let’s start with the following method

Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
Copy the code

Because the source code is a lot, just say a simple core part, the source code is as follows, the red part is to get the proxy class

Take a look at the getProxyClass0 method and extract the core for easy comprehension as follows

private static finalWeakCache<ClassLoader, Class<? >[], Class<? >> proxyClassCache =new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

private staticClass<? > getProxyClass0(ClassLoader loader, Class<? >... interfaces) {if (interfaces.length > 65535) {
        throw new IllegalArgumentException("interface limit exceeded");
    }

    // If the proxy class defined by the given loader implementing
    // the given interfaces exists, this will simply return the cached copy;
    // otherwise, it will create the proxy class via the ProxyClassFactory
    return proxyClassCache.get(loader, interfaces);
}
Copy the code

ProxyClassCache is WeakCache, then look at get method, look down step by step, finally see call to ProxyClassFactory class apply() method, as follows

Here you can see that the red part is the method to generate the real proxy class. Go ahead and see that you can view the generated proxy class locally by setting saveGeneratedFiles to true, as shown below

The values of saveGeneratedFiles are as follows,

private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
Copy the code

At this point we change the test code to look like this

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles"."true");
Person person = new JDKDynamicProxy(new Man()).getProxy();
person.say();
Copy the code

After execution, a local proxy class is found, as shown in the following figure

$Proxy0 inherits a Proxy class. Java does not support multiple inheritance, so it cannot implement dynamic Proxy

public final class $Proxy0 extends Proxy implements Person {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    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 newUndeclaredThrowableException(var4); }}public final String toString(a) throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw newUndeclaredThrowableException(var3); }}public final void say(a) throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw newUndeclaredThrowableException(var3); }}public final int hashCode(a) throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw newUndeclaredThrowableException(var3); }}static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.ganhuojun.demo.proxy.Person").getMethod("say");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw newNoClassDefFoundError(var3.getMessage()); }}}Copy the code

Conclusion:

The generated Proxy class inherits Proxy. Since Java is single inheritance, it can only be implemented through interfaces