java静态代理和JDK动态代理

静态代理

编译阶段就生产了对应的代理类

 

public interface IBussiness {
    void execute();
}

 

public class BussinessImpl implements IBussiness{
    @Override
    public void execute() {
        System.out.println("执行业务逻辑...");
    }
}
public class BussinessProxy implements IBussiness{
    
    private IBussiness bussinessImpl;
     
    public BussinessProxy(IBussiness bussinessImpl) {
        this.bussinessImpl = bussinessImpl;
    }
    
    @Override
    public void execute() {
        System.out.println("前拦截...");
        bussinessImpl.execute();
        System.out.println("后拦截...");
    }
}

 

 

 

public class Test {

    public static void main(String[] args) {
        
        IBussiness bussiness = new BussinessImpl();
        BussinessProxy  proxy = new BussinessProxy(bussiness);
        proxy.execute();
        
    }
}

 

 

JDK动态代理

动态生成字节码,加载到内存中,利用反射去执行真正的方法

关键代码:

 

Proxy.newProxyInstance(ClassLoader, Interfaces, InvocationHandler);

生成代理类时,要将类加载器,接口和InvocationHandler传递过去,

类加载器的作用是,生成的字节码要加载到JVM当中

接口的作用是,生成的代理类要知道代理的有哪些方法

InvocationHandler的作用是,在代理类中实际执行的是InvocationHandler的invoke方法

 

public interface Person {
    /**
     * 唱歌
     */
    void sing();
    /**
     * 跳舞
     * @param name 舞曲名
     * @return
     */
    String dance(String name);
}

 

 

public class PersonImpl implements Person{

    @Override
    public void sing() {
        System.out.println("开始唱歌");
    }

    @Override
    public String dance(String name) {
        System.out.println("" + name);
        return "不好玩";
    }
}

 

public class PersonImplProxy {
    
    private Person person = new PersonImpl();
    
    /**
     * 创建代理
     * @return 返回值是接口类型
     */
    public Person createProxy() {
        /**
         * 产生某个对象的代理对象
         * ClassLoader loader    当前代理对象的类加载器
         * Class<?>[] interfaces 代理对象的接口
         * InvocationHandler h   InvocationHandler对象
         */
        return (Person) Proxy.newProxyInstance(PersonImplProxy.class.getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() {
            
            /**
             * @param proxy 把代理对象自身传进去
             * @param method 代表当前调用的方法
             * @param args 当前调用方法的参数
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 获取方法名
                String methodName = method.getName();
                if ("sing".equals(methodName)) {
                    System.out.println();
                    System.out.println("前置通知... 唱歌开始");
                    method.invoke(person, args);
                    System.out.println("后置通知... 唱歌结束");
                } else if ("dance".equals(methodName)) {
                    System.out.println();
                    System.out.println("前置通知 ... 跳舞开始");
                    Object res = method.invoke(person, args);
                    System.out.println("后置通知 ... 跳舞结束");
                    return  res;
                }
                return null;
            }
        });
    }
    
}

 

public class Test {
    public static void main(String[] args) {
        //设置为true后,可以保存生成的代理类的字节码,
        //注意字节码文件用jd-gui.exe打开,用javap打开显示不全,javap是JDK自带的工具,他们之间的具体实现是不一样的
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        PersonImplProxy proxy = new PersonImplProxy();
        Person person = proxy.createProxy();
        person.sing();
        System.out.println(person.dance("华尔兹三章"));
        System.out.println();
        System.out.println("生成的代理类的名称: " + person.getClass().getName());

    }

}

测试结果

 

 

生成字节码文件

 

 将字节码文件反编译后

public final class $Proxy0 extends Proxy implements Person {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;
    private static Method m0;

    public $Proxy0(InvocationHandler paramInvocationHandler) {
        super(paramInvocationHandler);
    }

    public final boolean equals(Object paramObject) {
        try {
            return ((Boolean) this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        } catch (Error | RuntimeException localError) {
            throw localError;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final String toString() {
        try {
            return (String) this.h.invoke(this, m2, null);
        } catch (Error | RuntimeException localError) {
            throw localError;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final void sing() {
        try {
            this.h.invoke(this, m3, null);
            return;
        } catch (Error | RuntimeException localError) {
            throw localError;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final String dance(String paramString) {
        try {
            return (String) this.h.invoke(this, m4, new Object[] { paramString });
        } catch (Error | RuntimeException localError) {
            throw localError;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final int hashCode() {
        try {
            return ((Integer) this.h.invoke(this, m0, null)).intValue();
        } catch (Error | RuntimeException localError) {
            throw localError;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals",
                    new Class[] { Class.forName("java.lang.Object") });
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.irish.deligate.Person").getMethod("sing", new Class[0]);
            m4 = Class.forName("com.irish.deligate.Person").getMethod("dance",
                    new Class[] { Class.forName("java.lang.String") });
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            return;
        } catch (NoSuchMethodException localNoSuchMethodException) {
            throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        } catch (ClassNotFoundException localClassNotFoundException) {
            throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
    }
}

 

可以看到代理类继承了Proxy,实现了我们传递的接口,当调用dance方法时,会转调InvocationHandler的invoke方法,将方法和参数传递过去,由invoke来具体执行代理的逻辑,InvocationHandler持有真正的对象,一般是在调用真正的对象方法前后,执行我们要进行增强的操作。

 

posted @ 2019-05-29 11:18  踏月而来  阅读(328)  评论(0编辑  收藏  举报