查看动态代理生成的代理类字节码

动态代理的知识介绍

一、动态代理和Class字节码的关系

动态代理有什么作用及应用场景?
  1.日志集中打印
  2.事务
  3.权限管理
  4.AOP

在Spring Aop当中可以哪些方式实现,及区别?
  l.java Proxy(动态构建字节码)(动态构建全新字节码bean初始化的时候)
  2.cglib(动态构建字节码)(动态构建全新字节码bean初始化的时候)
  3.Aspecti(修改目标类的字节,织入代理的字节,在程序编译(编译的时候插入动态代理的字节码,不会生成全新的Class)
  4.instrumentation(修改目标类的字节码、类装载的时候动态拦截去修改,基于iavaagent)-javaagent:spring-instrument-4.3.8.RELEASE.jar(类装载的时候插入动态代理的字节码,不会生成全新的Class)

关于实现动态代理的技术

1.动态代理可以由java proxy、cglib、instrumentation(javaagent)、Aspectj、等多种方式实现
  2.动态代理本质是对class字节码进行动态构建或修改。
  3.修改的工具有ASM、javavssist
  4.多种实现方式的区别在于对字节码切入方式不一样。可选方式的有:

java proxy、Cglib是基于动态构建接口实现类字节

AspectJ是借助Eclipse工具在编译时织入代理字节

instrumentation是基于javaagent在类装载时修改Class织入代理字节

使用字定义ClassLoader在装载时织入代理字节JAVA Proxy实现过程
动态代理技术栈图:
在这里插入图片描述

用java proxy实现动态代理

一个简单实现的例子:

public interface User {
    
    
    String getName(String name);
}

```java
public class Userimpl implements User{
    
    
    @Override
    public String getName(String name) {
    
    
        System.out.println("实现类");
        return name;
    }
}


```java
public class UserProxy {
    public static void main(String[] args) {
        final Userimpl userimpl = new Userimpl();
        User targetproxy = (User) Proxy.newProxyInstance(UserProxy.class.getClassLoader(), new Class[]{User.class}, new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] myargs) throws Throwable {
                System.out.println("q我是前置");
                try {
                    return method.invoke(userimpl,myargs);
                } finally {
                    System.out.println("后置");
                }

            }
        });
targetproxy.getName("hzy");
    }
}

在这里插入图片描述

在这里插入图片描述

查看生成的class代理类字节码

    public static void buildProxy() throws IOException {
    
    
        byte[] bytes = ProxyGenerator.generateProxyClass("User$proxy",new Class[]{
    
    User.class});
        String fileName = System.getProperty("user.dir")+"\\target\\UserService$proxy.class";
     
        File file = new File(fileName);

        FileOutputStream fileOutputStream = new FileOutputStream(file);
        fileOutputStream.write(bytes);
        fileOutputStream.flush();
        fileOutputStream.close();
    }

在上面的main函数中加上 buildProxy()方法,执行后查看文件目录:
在这里插入图片描述
可以看到生成的class文件
把文件拖到idea里面,可以看到反编译后的文件:
在这里插入图片描述

创建代理的源码

首先是newProxyInstance方法:
在这里插入图片描述
可以看到进入了这句 Class<?> cl = getProxyClass0(loader, intfs);//寻找或者生成目标代理类
在这里插入图片描述

    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
    
    
        if (interfaces.length > 65535) {
    
    
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

这个注释的意思:如果由实现给定接口的给定加载器定义的代理类存在,这将简单地返回缓存副本;否则,它将通过 ProxyClassFactory 创建代理类,即判断这个接口是不是已经装载class,如果有则直接返回

之后还有apply方法、proxyfactory中的方法等等,比较复杂,以后再仔细学。

猜你喜欢

转载自blog.csdn.net/qq_41358574/article/details/121800405