Java 中的动态代理是一种非常强大且灵活的机制,用于在运行时创建代理类并处理方法调用。动态代理主要有两种方式:JDK 动态代理和 CGLIB 动态代理。下面将详细介绍这两种动态代理的实现和使用场景。
JDK 动态代理
JDK 动态代理是基于接口的代理,这意味着它只能代理实现了接口的类。它主要依赖于 java.lang.reflect
包下的 InvocationHandler
接口和 Proxy
类。
基本步骤
定义接口和实现类:
public interface Hello { void sayHello(); } public class HelloImpl implements Hello { @Override public void sayHello() { System.out.println("Hello, World!"); } }
实现 InvocationHandler 接口:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class HelloInvocationHandler implements InvocationHandler { private Object target; public HelloInvocationHandler(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; } }
创建代理对象:
import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { Hello hello = new HelloImpl(); HelloInvocationHandler handler = new HelloInvocationHandler(hello); Hello proxy = (Hello) Proxy.newProxyInstance( hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), handler); proxy.sayHello(); } }
在以上代码中,
Proxy.newProxyInstance
方法用于创建代理对象,它需要三个参数:类加载器、被代理类实现的接口们、InvocationHandler
实例。
CGLIB 动态代理
CGLIB(Code Generation Library)是一种强大的字节码生成库,它可以在运行时生成代理类,并且不需要实现接口。这使得它可以代理那些没有实现接口的类。
基本步骤
添加 CGLIB 依赖:
如果使用 Maven,可以在pom.xml
中添加以下依赖:<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
定义目标类:
public class HelloService { public void sayHello() { System.out.println("Hello, World!"); } }
实现 MethodInterceptor 接口:
import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class HelloMethodInterceptor 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; } }
创建代理对象:
import net.sf.cglib.proxy.Enhancer; public class Main { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HelloService.class); enhancer.setCallback(new HelloMethodInterceptor()); HelloService proxy = (HelloService) enhancer.create(); proxy.sayHello(); } }
在以上代码中,
Enhancer
类用于创建代理类实例。setSuperclass
方法指定要代理的目标类,setCallback
方法设置方法拦截器。
选择哪种动态代理?
- JDK 动态代理:适用于目标对象已经实现一个或多个接口的情况。
- CGLIB 动态代理:适用于目标对象没有实现接口或者需要代理类的子类的情况。
动态代理的应用场景
动态代理在很多实际应用中非常有用,特别是在以下场景:
- AOP(面向切面编程):如 Spring AOP,通过动态代理实现横切关注点(如日志记录、事务管理等)。
- 远程方法调用(RPC):通过代理屏蔽底层通信细节,使得调用远程服务像调用本地方法一样简单。
- 权限控制:通过代理在方法调用前后进行权限检查。
- 缓存:在方法调用前检查缓存,如果存在则返回缓存结果,否则调用方法并将结果存入缓存。
总之,Java 的动态代理是一种强大且灵活的技术,能够有效解耦业务逻辑和横切关注点,提高代码的可维护性和可扩展性。