Java jdk动态代理 源码 debug

本文详细介绍了Java动态代理的工作流程,从newProxyInstance方法开始,探讨getProxyClass0和newInstance方法,以及如何通过debug进行源码跟踪。在代理对象生成后,执行的方法会调用InvocationHandler的invoke方法,实现对目标方法的调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大体流程:

1. 在public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)方法中
  1.1 通过getProxyClass0()方法生成并获得.class文件,加载至内存
  1.2 通过newInstance()方法生成代理对象
2. 调用需要执行的方法,途中会调用InvocationHandler的invoke()方法(这里的invoke()方法会调用UserDaoImpl的query()方法)

基本配置:

UserDao.java

public interface UserDao {
    public void query();
}

UserDaoImpl.java

@Component("dao")
public class UserDaoImpl implements UserDao {
    @Override
    public void query() {
        System.out.println("I want to ask you a question!");
    }
}

InvocationHandler接口的实现类

public class MyInvocationHandler implements InvocationHandler {

    private UserDao userDao;

    public MyInvocationHandler(UserDao userDao) {
        this.userDao = userDao;
    }

    public UserDao getProxy() {
        return (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
                userDao.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        Object invoke = method.invoke(userDao, args);
        System.out.println("after");
        return invoke;
    }
}

main方法

@RunWith(SpringRunner.class)
@SpringBootTest
@ComponentScan("com.example.demo")
public class DemoApplicationTests {


    @Test
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(DemoApplicationTests.class);
//        UserDao dao = (UserDaoImpl) annotationConfigApplicationContext.getBean("dao");
//        dao.query();
        UserDao userDao = new UserDaoImpl();
        MyInvocationHandler handler = new MyInvocationHandler(userDao);
        UserDao proxy = handler.getProxy();
        proxy.query();
    }

}

实现效果
在这里插入图片描述

Debug过程

1. main方法打断点,进入
在这里插入图片描述
2. 在newProxyInstance方法内部打断点,并“F9”(跳到下一个断点)进入
在这里插入图片描述
**3.newProxyInstance()方法 **
重点就是getProxyClass0()方法和newInstance()方法
在这里插入图片描述4. 进入getProxyClass0()方法
在这里插入图片描述
5. 进入proxyClassCache.get()方法

如果缓存中没有目标对象,则创建,并第二次循环时返回在这里插入图片描述6. 进入supplier.get()方法
由返回值可知进入valueFactory.apply()方法
private final BiFunction<K, P, V> valueFactory;
在这里插入图片描述7. 进入valueFactory.apply()方法
这就是重点方法了
大概的意思就是生成代理类的字节码文件,加载至内存。

public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

    Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
    for (Class<?> intf : interfaces) {
        /*
         * Verify that the class loader resolves the name of this
         * interface to the same Class object.
         */
        Class<?> interfaceClass = null;
        try {
            interfaceClass = Class.forName(intf.getName(), false, loader);
        } catch (ClassNotFoundException e) {
        }
        if (interfaceClass != intf) {
            throw new IllegalArgumentException(
                intf + " is not visible from class loader");
        }
        /*
         * Verify that the Class object actually represents an
         * interface.
         */
        if (!interfaceClass.isInterface()) {
            throw new IllegalArgumentException(
                interfaceClass.getName() + " is not an interface");
        }
        /*
         * Verify that this interface is not a duplicate.
         */
        if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
            throw new IllegalArgumentException(
                "repeated interface: " + interfaceClass.getName());
        }
    }

    String proxyPkg = null;     // package to define proxy class in
    int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

    /*
     * Record the package of a non-public proxy interface so that the
     * proxy class will be defined in the same package.  Verify that
     * all non-public proxy interfaces are in the same package.
     */
    for (Class<?> intf : interfaces) {
        int flags = intf.getModifiers();
        if (!Modifier.isPublic(flags)) {
            accessFlags = Modifier.FINAL;
            String name = intf.getName();
            int n = name.lastIndexOf('.');
            String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
            if (proxyPkg == null) {
                proxyPkg = pkg;
            } else if (!pkg.equals(proxyPkg)) {
                throw new IllegalArgumentException(
                    "non-public interfaces from different packages");
            }
        }
    }

    if (proxyPkg == null) {
        // if no non-public proxy interfaces, use com.sun.proxy package
        proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
    }

    /*
     * Choose a name for the proxy class to generate.
     */
    long num = nextUniqueNumber.getAndIncrement();
    String proxyName = proxyPkg + proxyClassNamePrefix + num;

    /*
     * Generate the specified proxy class.
     */
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
        proxyName, interfaces, accessFlags);
    try {
        return defineClass0(loader, proxyName,
                            proxyClassFile, 0, proxyClassFile.length);
    } catch (ClassFormatError e) {
        /*
         * A ClassFormatError here means that (barring bugs in the
         * proxy class generation code) there was some other
         * invalid aspect of the arguments supplied to the proxy
         * class creation (such as virtual machine limitations
         * exceeded).
         */
        throw new IllegalArgumentException(e.toString());
    }
}

8. 得到.class文件后,获得构造方法,执行newInstance()方法,生成代理对象,再返回

在这里插入图片描述
在这里插入图片描述
9. 执行代理对象的方法,途中会调用InvocationHandler的invoke()方法(即这里的UserDaoImpl的query()方法)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
讲述完毕

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值