返回

面试官爱问的JDK动态代理的奥秘

见解分享

在面试中,关于Spring的代理方式的提问似乎是必不可少的。相信大家都会异口同声的回答:JDK动态代理和CGLIB动态代理。那么这两种代理方式究竟有何区别呢?

JDK动态代理是通过接口实现来创建代理对象,而CGLIB动态代理则是通过子类来实现的。接下来,我们将更深入地了解一下JDK动态代理。

一、JDK动态代理的原理

JDK动态代理是基于Java反射机制实现的。在运行时,JVM会动态创建一个实现指定接口的代理类,并生成该代理类的字节码。代理类中的方法会调用InvocationHandler接口的invoke()方法,而invoke()方法则可以调用目标对象的方法。

JDK动态代理的优点是侵入性较小,不需要修改目标对象。缺点是只能代理实现了接口的类,并且只能代理public方法。

二、JDK动态代理的应用场景

JDK动态代理可以应用于多种场景,例如:

  • 日志记录:可以通过JDK动态代理在目标方法执行前后记录日志。
  • 事务管理:可以通过JDK动态代理在目标方法执行前后开启和关闭事务。
  • 安全控制:可以通过JDK动态代理在目标方法执行前检查用户的权限。
  • 性能监控:可以通过JDK动态代理在目标方法执行前后记录性能数据。

三、JDK动态代理的注意事项

在使用JDK动态代理时,需要注意以下几点:

  • 目标类必须实现接口。
  • 代理类不能代理final方法。
  • 代理类不能代理静态方法。
  • 代理类不能代理私有方法。

四、JDK动态代理的示例代码

下面是一个JDK动态代理的示例代码:

public class JdkDynamicProxy {
    public static void main(String[] args) {
        // 目标对象
        Target target = new Target();

        // 代理对象
        Target proxy = (Target) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("代理对象调用了方法:" + method.getName());
                        return method.invoke(target, args);
                    }
                });

        // 调用代理对象的方法
        proxy.hello();
    }
}

interface Target {
    void hello();
}

class TargetImpl implements Target {
    @Override
    public void hello() {
        System.out.println("目标对象调用了hello方法");
    }
}

运行以上代码,输出结果如下:

代理对象调用了方法:hello
目标对象调用了hello方法

从输出结果可以看出,代理对象调用了目标对象的方法,并且在方法调用前后执行了代理逻辑。