JDK动态代理的底层实现解析

JDK动态代理的底层实现解析

2021-9-12·devcxl
devcxl

Java动态代理是一种在运行时创建代理和动态处理代理对象的机制。它能够在运行时生成代理类和对象,并将方法的调用转发到指定的处理器。

这种机制广泛应用于AOP(面向切面编程)等场景中,以实现对目标对象的增强和拓展。

实现原理

在Java中,动态代理的实现主要依赖于 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。

接口与实现类

首先,我们定义一个接口 UserService 和其实现类 UserServiceImpl,如下所示:

// 接口
interface UserService {
    void addUser(String name);

    void delUser(String name);
}

// 实现类
class UserServiceImpl implements UserService {
    @Override
    public void addUser(String name) {
        System.out.printf("添加用户:%s", name);
    }

    @Override
    public void delUser(String name) {
        System.out.printf("删除用户:%s", name);
    }
}

切面类

接着,我们创建一个切面类 UserLogger,用于在目标方法执行前后进行一些操作:

// 切面类
class UserLogger {
    public void before() {
        System.out.println("---------------操作前");
    }

    public void after() {
        System.out.println("---------------操作完成");
    }

    public void afterThrowing() {
        System.out.println("---------------操作异常");
    }

    public void afterReturning() {
        System.out.println("---------------操作结束");
    }
}

JDK动态代理实现

JDKProxy 类中,我们实现 InvocationHandler 接口,用于处理代理实例的方法调用。在 createProxyInstance 方法中,我们通过 Proxy.newProxyInstance 创建代理对象:

// JDK动态代理的实现
class JDKProxy implements InvocationHandler {
    private Object targetObject; //目标对象

    public Object createProxyInstance(Object targetObject) {
        this.targetObject = targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(),
                this);
    }

    public Object invoke(Object target, Method method, Object[] arg)
            throws Throwable {
        UserLogger userLogger = new UserLogger();//切面类
        try {
            //前置通知
            userLogger.before();
            // 调用目标方法
            Object obj = method.invoke(targetObject, arg);// 切入点
            userLogger.after();//后置通知
            return obj;
        } catch (RuntimeException e) {
            e.printStackTrace();
            userLogger.afterThrowing();//异常通知
        } finally {
            userLogger.afterReturning();//最终通知
        }
        return null;
    }
}

invoke 方法中,我们通过反射调用目标对象的方法,并在方法调用前后添加切面逻辑。

示例

最后,在 Main 类中,我们演示如何使用动态代理来增强 UserService 接口的实现类:

// 示例
public class Main {
    public static void main(String[] args) {
        JDKProxy proxy = new JDKProxy();
        UserService userService = (UserService) proxy.createProxyInstance(new UserServiceImpl());
        userService.addUser("a");
        userService.delUser("a");
    }
}

通过运行示例代码,我们可以看到在方法执行前后,切面逻辑会被正确地执行,从而实现对目标方法的增强和拓展。

以下是完整示例代码:


package com.example.demo;

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

// 接口
interface UserService {
    void addUser(String name);

    void delUser(String name);
}
// 实现类
class UserServiceImpl implements UserService {
    @Override
    public void addUser(String name) {
        System.out.printf("添加用户:%s", name);
    }

    @Override
    public void delUser(String name) {
        System.out.printf("删除用户:%s", name);
    }
}
// 切面类
class UserLogger {
    public void before() {
        System.out.println("---------------操作前");
    }

    public void after() {
        System.out.println("---------------操作完成");
    }

    public void afterThrowing() {
        System.out.println("---------------操作异常");
    }

    public void afterReturning() {
        System.out.println("---------------操作结束");
    }
}

// JDK动态代理的实现
class JDKProxy implements InvocationHandler {
    private Object targetObject; //目标对象

    public Object createProxyInstance(Object targetObject) {
        this.targetObject = targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(),
                this);
    }

    public Object invoke(Object target, Method method, Object[] arg)
            throws Throwable {
        UserLogger userLogger = new UserLogger();//切面类
        try {
            //前置通知
            userLogger.before();
            // 调用目标方法
            Object obj = method.invoke(targetObject, arg);// 切入点
            userLogger.after();//后置通知
            return obj;
        } catch (RuntimeException e) {
            e.printStackTrace();
            userLogger.afterThrowing();//异常通知
        } finally {
            userLogger.afterReturning();//最终通知
        }
        return null;
    }
}

// 示例
public class Main {
    public static void main(String[] args) {
        JDKProxy proxy = new JDKProxy();
        UserService userService = (UserService) proxy.createProxyInstance(new UserServiceImpl());
        userService.addUser("a");
        userService.delUser("a");
    }
}