专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

Java 动态代理原理解析

什么是动态代理

可以在不修改原有类代码的情况下,对类功能接口进行拦截和增强,而且对于用户来说是透明的,好像没有发生任何变化。

比如说在 Spring 中我们给 UserService 的某个方法增加了 @Transactional 事务注解后,Spring 在进行 Bean 加载的时候,它检测到了这个注解,就会创建一个代理类来替换掉 UserService 对象,然后在调用对应的事务方法中,他就可以通过代理类去先开启事务,进行一系列操作,最后再提交或者回滚事务。

试想一下如果不通过动态代理我们是不是就要写很多代码,而且不易维护增加工作量。

如果一个类里面没有特殊的注解,Spring 加载的就是通过构造器创建的普通对象。

我们在使用上是没有察觉的什么差别的,在其它地方上我们还是通过 @Autowired 注入 UserService 然后调用 userService.xxx 方法

如果我们使用静态代理的话,我们就需要为每个类都写一遍代码

public class Test2 {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserService userServiceProxy = new UserServiceProxy(userService);
        userServiceProxy.add();
    }
}
class UserServiceProxy implements UserService {

    private UserService userService;

    public UserServiceProxy(UserService userService) {
        this.userService = userService;
    }

    @Override
    public void add() {
        System.out.println("add before");
        userService.add();
        System.out.println("add after");
    }
}
class ProjectServiceProxy implements ProjectService {

    private ProjectService projectService;

    public ProjectServiceProxy(ProjectService projectService) {
        this.projectService = projectService;
    }

    @Override
    public void add() {
        System.out.println("add before");
        projectService.add();
        System.out.println("add after");
    }
}

Java 动态代理

Java 动态代理,要求被代理的类必须实现一个接口,他会在运行时候动态生成代理类来替换掉原始的类

interface UserService {
    void add();
}

class UserServiceImpl implements UserService {

    @Override
    public void add() {
        System.out.println("add user");
    }
}

class TestInvocationHandler implements InvocationHandler {

    private Object object;

    public TestInvocationHandler(Object object) {
        this.object = object;
    }

    public Object getProxy() {
        return Proxy
            .newProxyInstance(Thread.currentThread()
                                    .getContextClassLoader(),
                              object.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("添加之前");
        Object obj = method.invoke(object, args);
        System.out.println("添加之后");
        return obj;
    }
}

public class Test {

    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        UserService userService = new UserServiceImpl();
        TestInvocationHandler invocationHandler = new TestInvocationHandler(userService);
        UserService userServiceProxy = (UserService) invocationHandler.getProxy();
        userServiceProxy.add();
    }
}

首先调用 Proxy.newProxyInstance()

57_1.png在其中会调用 getProxyClass0(loader, intfs) 来创建代理类

57_2.png然后从 proxyClassCache 中查找是否已经生成过了该代理类,生成了就直接返回

57_3.png否则执行加载过程最终会调用 generateProxyClass() 来生成代理类字节码文件,然后调用 defineClass0() 将字节码文件解析为 class 并且加载到内存中

57_4.png我们将生成的字节码文件下载到本地,通过 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 这个配置即可

public final class $Proxy0 extends Proxy implements UserService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void add() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("array.UserService").getMethod("add");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

最后在 newProxyInstance() 方法最后会调用通过构造器反射创建对象

57_5.png

在创建的时候就将我们自己实现的 InvocationHandler 设置进去了

57_6.png

当我们调用 userService.add() 的时候,实际上调用的是代理类的 add() 方法,然后调用我们自定义的 TestInvocationHandler 的 invoke 方法

57_7.png

57_8.png

用途

  • 各种框架中比如 AOP,过滤器,拦截器
  • 日志拦截、事务拦截、权限拦截
  • 类功能的增强与解耦

文章永久链接:https://tech.souyunku.com/26056

未经允许不得转载:搜云库技术团队 » Java 动态代理原理解析

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们