您的位置:首页 > 编程语言 > Java开发

Spring学习第二天Aop_invoke的代理对象生成解析

2018-03-02 20:04 281 查看
我还是事先声明我目前写的都是我的一些理解,仅仅作为我的笔记作为参考!
今天的主要内容就是解析动态代理中的newProxyInstance 和 invoke方法
第一部分:newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h):这个方法主要就是获取代理对象,其实就是委托类的实例,再进一步就是委托类拥有真实业务类的引用,从而这个代理类可以代替真实业务类处理业务逻辑;
    ClassLoader:类加载器的作用是什么呢?顾名思义,就是加载类文件,就是.class字节码文件(主要由8位字节码组成),这个部分可以详细的去学习JVM虚拟机;我的通俗理解就是使用这个类加载器对象可以去加载类对象;
    Class<?>[]:类,这个类是有一个private的私有构造方法,它是由JVM进行实例化的,大概所有的类都可以作为它的实例,比如User.class,可以是它的一个实例,这个Class的组成呢? 我们通过一些元或者初始化的东西来描述一个类:

        包名、类名或者接口、修饰符(类的修饰符、接口的修饰符、属性的修饰符、方法的修饰符)、

        方法以及方法参数、成员属性、

        注解等等;

    InvocationHandler:顾名思义: 调用处理器接口,只有一个invoke的方法;

第二部分:invoke(target,args)方法:
    target: 方法名

    args: 传入方法名中的参数

    综合上面的因素:我们推断: jvm的类加载器加载某一个类(真实业务类),因为加载了这个类所以我们就可以获得这个类的所有的信息(方法、属性啊),然后通过指定方法(这个类中的特定业务逻辑方法)以及参数就可以进行调用了;

其实还是没有理解到代理对象如何执行到业务方法的?然后我想理解的是invoke这个方法的底层:

Object newProxyInstance(ClassLoader loader,  
                      Class<?>[] interfaces,  
                      InvocationHandler h) 
首先我们看下这个方法的实现:在获得代理实例方法里面有下面这个方法:
     Class cl = getProxyClass(loader, interfaces);//这个方法主要就是获得代理的真实的类的对象,这个真实的类实现了至少一个接口,这个接口主要是我们自定义的(业务逻辑抽象接口),

/ 加载目标类实现的接口到内存中  
        interfaceClass = Class.forName(interfaceName, false, loader);  
加载相应的接口到内存中,其实也就是加载.class文件中的Class对象到内存中,

// 把目标类实现的接口名称作为缓存(Map)中的key  
    Object key = Arrays.asList(interfaceNames);  
这几个步骤是将第一次生成的Class类中的信息缓存起来,就是存到内存中,下次用的时候直接取,
Map cache;  
      
    synchronized (loaderToCache) {  
        // 从缓存中获取cache  
        cache = (Map) loaderToCache.get(loader);  
        if (cache == null) {  
        // 如果获取不到,则新建地个HashMap实例  
        cache = new HashMap();  
        // 把HashMap实例和当前加载器放到缓存中  
        loaderToCache.put(loader, cache);  
        }  
最关键的是这个一步:

try {  
        // 中间省略了一些代码 .......  
          
        // 这里就是动态生成代理对象的最关键的地方  
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(  
            proxyName, interfaces);  
        try {  
            // 根据代理类的字节码生成代理类的实例  
            proxyClass = defineClass0(loader, proxyName,  
            proxyClassFile, 0, proxyClassFile.length);  
        } catch (ClassFormatError e) {  
            throw new IllegalArgumentException(e.toString());  
        }  
        }  
        // add to set of all generated proxy classes, for isProxyClass  
        proxyClasses.put(proxyClass, null);  
  
    }   
我们是通过代理生成器来生成代理类的字节码,(注意代理类是含有真实业务的类的引用的),
又当我们获取到一个类的字节码的时候,有一个方法可以直接获取这个类的实例:
defineClass0(loader,proxyName,proxyClassFile,0,proxyClassFile.length);

    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: