内容纲要
动态代理在Java中是一个常用的设计模式,它允许在运行时创建代理对象并指定代理行为。动态代理有几种实现方式,常见的有以下几种:
1. JDK 动态代理(基于接口)
- 原理:JDK动态代理利用
java.lang.reflect.Proxy
类和InvocationHandler
接口,要求目标对象实现一个接口,代理对象通过Proxy.newProxyInstance
方法动态生成。 - 使用场景:适用于接口驱动的代理,不需要显式编写代理类。
示例代码
public interface MyService {
void sayHello();
}
public class MyServiceImpl implements MyService {
public void sayHello() {
System.out.println("Hello, world!");
}
}
public class MyServiceProxy implements InvocationHandler {
private Object target;
public MyServiceProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before invoking " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After invoking " + method.getName());
return result;
}
}
public class Main {
public static void main(String[] args) {
MyService target = new MyServiceImpl();
MyService proxy = (MyService) Proxy.newProxyInstance(
MyService.class.getClassLoader(),
new Class[]{MyService.class},
new MyServiceProxy(target)
);
proxy.sayHello();
}
}
```
**输出**:
```
Before invoking sayHello
Hello, world!
After invoking sayHello
2. CGLIB 动态代理(基于继承)
- 原理:CGLIB(Code Generation Library)通过继承目标类,生成目标类的子类来进行代理。它不要求目标对象实现接口。CGLIB 通过字节码技术生成目标类的子类,并重写方法实现代理。
- 使用场景:适用于目标对象没有接口时,或者你需要对类的非接口方法进行代理。
示例代码
public class MyService {
public void sayHello() {
System.out.println("Hello, world!");
}
}
public class MyServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before invoking " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("After invoking " + method.getName());
return result;
}
}
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyService.class);
enhancer.setCallback(new MyServiceInterceptor());
MyService proxy = (MyService) enhancer.create();
proxy.sayHello();
}
}
```
**输出**:
```
Before invoking sayHello
Hello, world!
After invoking sayHello
3. Spring AOP 动态代理(基于 JDK 或 CGLIB)
- 原理:Spring框架提供了AOP(面向切面编程)功能,支持基于JDK动态代理和CGLIB动态代理。Spring会根据目标对象是否实现接口来决定使用JDK代理还是CGLIB代理。
- 使用场景:广泛应用于事务管理、日志记录、权限控制等场景,适用于开发者在应用层做切面编程。
示例代码(JDK动态代理示例)
public class MyServiceImpl implements MyService {
public void sayHello() {
System.out.println("Hello, Spring AOP!");
}
}
@Component
public class MyServiceAspect {
@Before("execution(* MyService.sayHello(..))")
public void beforeAdvice() {
System.out.println("Before method execution.");
}
}
配置Spring容器后,AOP会自动为MyServiceImpl
创建代理对象,并在调用sayHello
方法前触发beforeAdvice
。
4. ASM 动态代理(字节码操作)
- 原理:ASM是一个字节码操作框架,它能够直接操作字节码来动态生成代理类。ASM提供了比CGLIB更底层的字节码生成控制,适合在性能要求特别高的场景下使用。
- 使用场景:主要用于性能敏感型的应用,或需要更复杂字节码操作的场景。
总结
- JDK动态代理:适用于接口驱动的代理。
- CGLIB动态代理:适用于没有接口的类的代理。
- Spring AOP:基于JDK或CGLIB,根据目标对象的情况自动选择代理方式。
- ASM:适用于字节码级的操作,性能要求较高时使用。
不同的动态代理方式适用于不同的场景,根据需求选择合适的方式。