Java基础->动态代理是什么东东

2020-11-02  本文已影响0人  杨0612
什么是动态代呢

在运行期动态生成代理对象,控制被代理对象的访问,这有别于静态代理在编译期生成代理对象。

作用是什么

代理对象可以丰富被代理对象的操作,大白话,就是可以在访问前后增加若干代码处理,例如在方法前后打印日志判断方法执行时间。

动态代理例子1 - 生成代理对象

Proxy.newProxyInstance 是JDK提供生成动态代理对象的api。通过newProxyInstance动态生成Api的实现类,调用setName以及getName方法,都会回调到InvocationHandler的invoke方法,invoke就是对接口方法的具体实现。

//Api接口定义两个方法
public interface Api {
    void setName(String name);
    String getName();
}
  //调用
    public void test() {
        Api api = (Api) Proxy.newProxyInstance(Api.class.getClassLoader(), new Class[]{Api.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Log.d("test", "method name:" + method.getName());//打印调用的方法名
                if ("getName".equals(method.getName())) {//如果是调用getName则返回"yang"
                    return "yang";
                } else if ("setName".equals(method.getName())) {//如果是调用setName方法则打印请求参数
                    for (Object a : args) {//打印参数
                        Log.d("test", "args:" + a);
                    }
                }
                return null;//对应无返回值的方法,直接返回null即可。
            }
        });
        
        //调用处
        api.setName("yang");
        String name=api.getName();
        Log.d("test", "getName=" +name );
    }

打印结果如下:

2020-09-23 10:40:47.150 20218-20218/com.yang.myapplication6 D/test: method name:setName
2020-09-23 10:40:47.150 20218-20218/com.yang.myapplication6 D/test: args:yang
2020-09-23 10:40:47.150 20218-20218/com.yang.myapplication6 D/test: method name:getName
2020-09-23 10:40:47.150 20218-20218/com.yang.myapplication6 D/test: getName=yang
动态代理例子2 - 增强被代理对象的能力

MyApi 是Api接口的具体实现,同样通过Proxy.newProxyInstance生成代理对象,不同的是,在invoke方法中,增加代码处理以后需要反射调用MyApi 实现的方法。

public class MyApi implements Api {
    @Override
    public void setName(String name) {
        Log.d("test", "setName name=" + name);
    }
    @Override
    public String getName() {
        return "getName";
    }
}

     final Api api = new MyApi();//被代理对象
        //返回代理对象
        Api proxyApi = (Api) Proxy.newProxyInstance(api.getClass().getClassLoader(), api.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Log.d("test", "invoke");
                return method.invoke(api, args);//调用被代理对象方法
            }
        });

        //调用代理对象
        proxyApi.setName("yang");
        String name=proxyApi.getName();
        Log.d("test", "getName=" + name);
Proxy.newProxyInstance 接口

是JDK提供生成动态代理对象的api

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

参数解析:

InvocationHandler.invoke 回调
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{}

参数解析:

代理对象生成在哪呢

代理对象是在运行时生成的,我也没找到他具体生成的地方,以下代码是查看网上的博客得到的

public final class $Proxy0 extends Proxy implements Api { //1

    static {//2
        try {
            m1 = Class.forName("com.yang.myapplication6.Api").getMethod("setName");
            m2 = Class.forName("com.yang.myapplication6.Api").getMethod("getName");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }

    private static Method m1;
    private static Method m2;

    public $Proxy0(InvocationHandler var1) throws  {//3
        super(var1);
    }

    public final void setName(String name)  {//4
        try {
            super.h.invoke(this, m1, new Object[]{name});
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    @Override
    public String getName() {
        try {
            return (String) super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    } 
}
类图
1.png
动态代理使用场景

动态代理,适用于对所有代理方法做统一处理的场景;
动态代理可以没有实现,实现类由虚拟机生成;

总结

以上分析有不对的地方,请指出,互相学习,谢谢哦!

上一篇 下一篇

猜你喜欢

热点阅读