1.什么是动态代理
动态代理是一种在程序运行时(而非编译时)动态生成代理对象的技术。代理对象可以拦截对目标对象的方法调用,并在调用前后执行一些自定义逻辑。
2.动态代理的作用和应用场景
- 面向切面编程(AOP):动态代理可以实现横切关注点,比如日志记录、权限检查、事务管理等,而不需要侵入到业务代码中。
- 权限控制:通过动态代理,可以在调用业务方法前后检查用户是否有权限执行某些操作。
- 事务管理:拦截业务方法,在其调用前后进行事务的开启和提交。
- 日志记录:在方法调用前后自动记录日志。
3.动态代理几种形式
3.1 JDK动态代理
- 简介: JDK 动态代理是 Java 内置的一种代理机制,它只适用于代理接口实现类,也就是说目标对象必须实现一个或多个接口。
- 实现方式: 使用
java.lang.reflect.Proxy
类和InvocationHandler
接口来实现动态代理。 - 优点: 简单易用,直接支持接口代理,适用于大多数场景。
- 缺点: 只能代理实现了接口的类,无法代理普通的类。
案例:
接口
public interface UserService {
void addUser(String username);
}
实现类
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("Adding user: " + username);
}
}
代理实现
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class UserServiceProxy {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
// 创建代理对象
UserService proxy = (UserService) 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("Before method: " + method.getName());
Object result = method.invoke(target, args); // 调用目标对象的方法
System.out.println("After method: " + method.getName());
return result;
}
}
);
// 使用代理对象调用方法
proxy.addUser("Tom");
}
}
运行结果
3.2 CGLIB 动态代理
- 简介: CGLIB (Code Generation Library) 是一个第三方库,可以动态生成字节码来创建代理对象。与 JDK 动态代理不同,CGLIB 可以代理普通类(非接口)。
- 实现方式: 通过继承目标类并重写方法实现代理,这也是为什么 CGLIB 不能代理
final
类或final
方法。 - 优点: 可以代理没有实现接口的类,性能通常比 JDK 代理快。
- 缺点: 需要额外的库(CGLIB),不能代理
final
类或方法。
案例:
引入maven坐标:
普通类
public class UserService {
public void addUser(String username) {
System.out.println("Adding user: " + username);
}
}
代理实现
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxyExample implements MethodInterceptor {
private Object target;
public Object getProxyInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method: " + method.getName());
return result;
}
public static void main(String[] args) {
UserService userService = new UserService();
UserService proxy = (UserService) new CglibProxyExample().getProxyInstance(userService);
proxy.addUser("Tom");
}
}
运行结果
3.3 Javassist 动态代理
- 简介: Javassist 是一个操作字节码的库,可以在运行时动态生成和修改 Java 字节码。相比 CGLIB 和 JDK 动态代理,Javassist 更灵活,可以直接操作类和方法。
- 实现方式: 通过
javassist.util.proxy
包或者直接操作字节码来创建代理类。 - 优点: 可以直接修改类的字节码,灵活性更高。
- 缺点: 使用复杂,需要熟悉字节码操作。
引入maven坐标
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;
public class JavassistProxyExample {
public static void main(String[] args) throws Exception {
// 创建代理工厂
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(UserService.class);
// 设置方法拦截器
MethodHandler handler = (self, thisMethod, proceed, args1) -> {
System.out.println("Before method: " + thisMethod.getName());
Object result = proceed.invoke(self, args1); // 调用原始方法
System.out.println("After method: " + thisMethod.getName());
return result;
};
// 生成代理对象
Class<?> proxyClass = factory.createClass();
UserService proxy = (UserService) proxyClass.getDeclaredConstructor().newInstance();
((ProxyObject) proxy).setHandler(handler);
// 使用代理对象
proxy.addUser("Tom");
}
}
class UserService {
public void addUser(String name) {
System.out.println("Adding user: " + name);
}
}
运行结果
3.4 ByteBuddy 动态代理
- 简介: ByteBuddy 是一个更现代的字节码操作库,设计上比 Javassist 更加友好和灵活,可以非常方便地创建和操作代理对象。
- 实现方式: 使用
ByteBuddy
类库,可以轻松创建和操作类。 - 优点: 语法友好,适合动态生成和操作复杂类,支持创建代理类。
- 缺点: 学习曲线较高,需要引入第三方库。
引入maven坐标
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;
public class JavassistProxyExample {
public static void main(String[] args) throws Exception {
// 创建代理工厂
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(UserService.class);
// 设置方法拦截器
MethodHandler handler = (self, thisMethod, proceed, args1) -> {
System.out.println("Before method: " + thisMethod.getName());
Object result = proceed.invoke(self, args1); // 调用原始方法
System.out.println("After method: " + thisMethod.getName());
return result;
};
// 生成代理对象
Class<?> proxyClass = factory.createClass();
UserService proxy = (UserService) proxyClass.getDeclaredConstructor().newInstance();
((ProxyObject) proxy).setHandler(handler);
// 使用代理对象
proxy.addUser("Tom");
}
}
class UserService {
public void addUser(String name) {
System.out.println("Adding user: " + name);
}
}
喜欢此文章就点个关注或收藏,常来看看就记住了