0
点赞
收藏
分享

微信扫一扫

动态代理源码剖析深度个人理解

勇敢的趙迦禾 2022-02-02 阅读 30

恶心的东西就更要花时间让它变得更恶心🧎‍♀️ ----xmonster

文章目录

开篇

可以去看《设计模式之禅》(第2版)里对代理模式的理解,他利用的是“游戏打怪”的例子,我觉得非常的生动形象,理解起来非常通透!如果你对代理模式不是很通透,那么动态代理你就自然比较难理解了,不做无用功,先去补基础 (别忘了补完回来);如果你已经特别了解,那么就继续往下吧!
来一个图吧,没有任何意义,只是为了提个醒,这是上面那本书的流程图
💜💜
在这里插入图片描述
🧡🧡🧡🧡🧡
在这里插入图片描述
💛💛💛💛💛

走一遍百度百科

动态代理类

一般主要涉及到以下两个类:

一、Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method,Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

二、Proxy:该类即为动态代理类其中主要包含以下内容:
Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader,Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
重点看以下方法:

Static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

代理机制及特点(使用步骤)

通过实现 InvocationHandler 接口创建自己的调用处理器;
通过为 Proxy 类指定 ClassLoader 对象一组 interface来创建动态代理类;
通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

以下我们的代码就按照这个顺序来完成对应的动态代理实现

动态代理的工具类代码

下面的代码注解是我个人的一些理解,有点乱,但很nice

package com.xmonster.demo01;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//等会用这个类自动生成代理类!
public class ProxyInvocationHandler implements InvocationHandler {

//    Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
//            new Class<?>[] { Foo.class },
//            handler);

//    被代理的接口
//    1、代理一个接口  这个接口说白了是谁,就是真实对象;真实对象会实现那个接口,我们代理它就完了
    private Object target;
    public void setTarget(Object target) {
        this.target = target;
    }

    //生成得到代理类
    public Object getProxy(){
// getClassLoader()类加载器:它负责将字节码文件加载到内存,创建Class对象
//        target.getClass().getClassLoader()   通过target示例得到的Loader()信息
//         target.getClass().getInterfaces()   得到对应的interfaces信息(反射)
//      System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//      target.getClass().getClassLoader()
        /*    target.getClass()得到它的class对象
         *    getClassLoader():每个Class对象都会有一个方法,可以获取到它的ClassLoader
         * target.getClass().getClassLoader():获取类以及获取到这个类的类加载器
         *
         *
         *
         * */


      return  Proxy.newProxyInstance(target.getClass().getClassLoader(),
              target.getClass().getInterfaces(),
              this);
//   newProxyInstance:返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
// loader - 类加载器来定义代理类
//interfaces - 代理类实现的接口列表
//h - 调度方法调用的调用处理函数

    }


    //处理代理实例,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //代理的是一个接口
        //动态代理的本质,就是使用反射机制来实现
        setHost();
        Object invoke = method.invoke(target, args);
        return invoke;
    }


}

package com.xmonster.demo01;

public class Client {
    public static void main(String[] args) {
//        真实对象
        UserService userService = new UserServiceImpl();
//        代理对象
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
//        生成代理角色
        pih.setTarget(userService);   //设置要代理的对象
//        动态生成、获得代理类,获得代理类对象
//      注意这里的强制转换
        UserService proxy =(UserService)  pih.getProxy();
//        Object proxy = pih.getProxy();
//        调用响应的代理的方法即可
        proxy.query();
    }
}

回到上面我们讲的,代理类和被代理类都是实现了一个“接口”,只不过代理类传递了一个参数(传递被代理类),然后帮助被代理类干事情,所以重点就是“接口”

这也就是为什么

UserService proxy =(UserService)  pih.getProxy();

这里要强转的原因

分析

InvocationHandler只是一个只有一个函数的接口,这还意味着Proxy.newProxyInstance的第三个参数可以使用lambda表达式。

package java.lang.reflect;

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

来看看newProxyInstance的三个参数

private static Object newProxyInstance(Class<?> caller, // null if no SecurityManager
                                       Constructor<?> cons,
                                       InvocationHandler h)

注意看第三个参数,这也就是我们在用的时候会“动态”去调用使用了InvocationHandler 的对象,可以理解为当你在创建这个类的时候,他就已经去“拿”方法了

举报

相关推荐

0 条评论