在 Java 编程中,动态代理是一种常用的设计模式。它允许我们在运行时动态地创建一个对象的代理,并通过代理对象来访问目标对象。这样,我们就可以在不修改目标对象代码的情况下,为目标对象添加额外的功能。
目前,Java 中常用的动态代理方式有两种:JDK 动态代理和 CGLIB 动态代理。这两种动态代理方式有一些区别,本文将对它们进行简要介绍,并给出一些简单的代码演示案例。
JDK 动态代理
JDK 动态代理是 Java 自带的一种动态代理方式。它通过实现 java.lang.reflect.InvocationHandler
接口来创建自定义的调用处理器,并通过 java.lang.reflect.Proxy
类来创建动态代理对象。
JDK 动态代理的一个重要特点是,它只能对实现了接口的类生成代理。也就是说,如果一个类没有实现任何接口,那么我们就无法使用 JDK 动态代理来为它创建代理对象。
下面是一个简单的 JDK 动态代理示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
interface Hello { void sayHello(); }
class HelloImpl implements Hello { @Override public void sayHello() { System.out.println("Hello, World!"); } }
class MyInvocationHandler implements InvocationHandler { private Object target;
public MyInvocationHandler(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before method call"); Object result = method.invoke(target, args); System.out.println("After method call"); return result; } }
public class JdkProxyDemo { public static void main(String[] args) { Hello hello = new HelloImpl(); MyInvocationHandler handler = new MyInvocationHandler(hello); Hello proxy = (Hello) Proxy.newProxyInstance( hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler); proxy.sayHello(); } }
|
上面的代码中,我们定义了一个 Hello
接口和它的实现类 HelloImpl
。然后我们创建了一个自定义的调用处理器 MyInvocationHandler
,并在其中实现了 invoke
方法。最后,我们使用 Proxy.newProxyInstance
方法创建了一个 Hello
接口的动态代理对象,并通过该代理对象调用了 sayHello
方法。
运行上面的代码,你会看到如下输出:
1 2 3
| Before method call Hello, World! After method call
|
可以看到,在调用 sayHello
方法时,我们成功地在方法调用前后添加了额外的逻辑。
CGLIB 动态代理
CGLIB(Code Generation Library)是一个第三方的动态代理库,它通过继承目标类并生成子类的方式来实现动态代理。
与 JDK 动态代理不同,CGLIB 可以对任意类(无论是否实现了接口)生成代理。但是,由于 CGLIB 是通过继承来实现动态代理的,所以它无法对 final 类或方法进行代理。
下面是一个简单的 CGLIB 动态代理示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
class Hello { public void sayHello() { System.out.println("Hello, World!"); } }
class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before method call"); Object result = proxy.invokeSuper(obj, args); System.out.println("After method call"); return result; } }
public class CglibProxyDemo { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Hello.class); enhancer.setCallback(new MyMethodInterceptor()); Hello proxy = (Hello) enhancer.create(); proxy.sayHello(); } }
|
上面的代码中,我们定义了一个普通类 Hello
,并在其中实现了 sayHello
方法。然后我们创建了一个自定义的方法拦截器 MyMethodInterceptor
,并在其中实现了 intercept
方法。最后,我们使用 Enhancer
类创建了一个 Hello
类的动态代理对象,并通过该代理对象调用了 sayHello
方法。
运行上面的代码,你会看到如下输出:
1 2 3
| Before method call Hello, World! After method call
|
可以看到,在调用 sayHello
方法时,我们成功地在方法调用前后添加了额外的逻辑。
总结
希望本文能够帮助读者更好地了解JDK和CGLIB动态代理的区别。