美文网首页
Java基础->动态代理是什么东东

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

作者: 杨0612 | 来源:发表于2020-11-02 16:09 被阅读0次
什么是动态代呢

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

作用是什么

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

动态代理例子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)

参数解析:

  • ClassLoader :类加载器,传入被代理对象的类加载器即可,例子2中 被代理对象为Api,所以传入api.getClass().getClassLoader();
  • interfaces,代理对象需要实现接口,例子2中,代理对象需要实现Api接口,所以传入api.getClass().getInterfaces(),也可以传入new Class[]{Api.class};
  • InvocationHandler,拦截器,当调用方法时,会回调到InvocationHandler的invoke方法,这里可以丰富访问;
InvocationHandler.invoke 回调
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{}

参数解析:

  • proxy:动态代理对象,例子2中代理对象就是proxyApi ,如果在invoke内部调用了method.invoke(proxy,args),将会出现死循环,最后抛出异常;
  • method:被调用方法的Method对象,调用setName,则Method就是setName方法的封装;
  • args:被调用方法的参数,调用setName,则args就是new Object[]{name};
代理对象生成在哪呢

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

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:$Proxy0是代理对象的类型,它继承Proxy以及实现Api接口;
  • 注释2:静态代码块中,反射获取Api接口定义的方法Method;
  • 注释3:构建对象,需要传入InvocationHandler对象;
  • 注释4:setName方法的具体实现,会调用super.h.invoke(this, m1, new Object[]{name}),这个h就是在生成动态代理对象传入的InvocationHandler,所以当在外部通过代理对象调用相应方法时候,会回调到InvocationHandler.invoke;
类图
1.png
动态代理使用场景

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

总结
  • 动态代理可以丰富被代理对象的行为;
  • 动态代理对象是动态生成的;

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

相关文章

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

    什么是动态代呢 在运行期动态生成代理对象,控制被代理对象的访问,这有别于静态代理在编译期生成代理对象。 作用是什么...

  • Java基础:反射

    反射注解动态代理相关阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 ...

  • java基础巩固笔记(4)-代理

    标签: java Contents java基础巩固笔记(4)-代理概念动态代理创建动态类动态代理的工作原理面向切...

  • Spring 复盘 | AOP

    Spring AOP 基础 Java 动态代理实现,阅读文章之前,你最好有以下基础: java动态代理 1、什么是...

  • 安卓反射和动态代理的应用

    提纲 java反射基础 反射在Android中的应用 Java动态代理 动态代理在Android的应用 java反...

  • Java基础:注解

    系列阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 1. 概述 注解...

  • Java基础:动态代理

    系列阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 概述 在运行时,...

  • Java基础系列-静态代理和动态代理

    原创文章,转载请标注出处:《Java基础系列-静态代理和动态代理》 1、动态代理(Dynamic Proxy) 代...

  • Java基础:类加载器

    系列阅读 Java基础:类加载器 Java基础:反射 Java基础:注解 Java基础:动态代理 1. 什么是类加...

  • 初探java动态代理

    动态代理是什么 在Java API手册中原话是这样介绍动态代理的: Using Java Reflection t...

网友评论

      本文标题:Java基础->动态代理是什么东东

      本文链接:https://www.haomeiwen.com/subject/navwyktx.html