Java 代理模式
代理模式是一种结构型设计模式,它为对象提供了一个代理,以控制对这个对象的访问。在Java中,代理模式主要用于增强原始对象的功能。
1. 静态代理
静态代理是在编译阶段就已经确定代理类,它要求代理类和目标对象实现相同的接口。代理类内部持有目标对象的引用,并在代理方法中调用目标对象的方法,同时可以在方法执行前后增加额外逻辑,如日志、权限校验等。
//定义接口
public interface UserService {
void register(String username);
}
//真实对象(被代理类)
public class UserServiceImpl implements UserService {
@Override
public void register(String username) {
System.out.println(username + " 注册成功!");
}
}
//代理类
public class UserServiceProxy implements UserService {
private final UserService target; // 目标对象
public UserServiceProxy(UserService target) {
this.target = target;
}
@Override
public void register(String username) {
System.out.println("【日志】用户开始注册...");
target.register(username);
System.out.println("【日志】用户注册完成!");
}
}
public class StaticProxyTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserService proxy = new UserServiceProxy(userService); // 代理对象
proxy.register("张三");
}
}
执行结果
复制编辑【日志】用户开始注册...
张三 注册成功!
【日志】用户注册完成!
特点:
代理类在编译期间生成,类结构固定。
代理对象和目标对象实现相同的接口。
适用于固定的业务场景,但每个目标对象都需要编写代理类,导致代码量较大,不够灵活。
2. 动态代理
动态代理是在运行时动态生成代理类,而不是在编译期确定,避免了静态代理的代码重复问题。Java中有两种动态代理方式:
JDK 动态代理(基于接口)
CGLIB 动态代理(基于子类继承)
2.1 JDK 动态代理(基于接口)
JDK动态代理是Java提供的原生动态代理机制,使用 java.lang.reflect.Proxy
和 InvocationHandler
动态生成代理类,在运行时创建代理对象。
//定义InvocationHandler代理处理逻辑
public class JdkProxyHandler implements InvocationHandler {
private final Object target; // 目标对象
public JdkProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("【日志】方法 " + method.getName() + " 开始执行...");
Object result = method.invoke(target, args); // 调用目标对象方法
System.out.println("【日志】方法 " + method.getName() + " 执行完成!");
return result;
}
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 类加载器
target.getClass().getInterfaces(), // 目标对象实现的接口
new JdkProxyHandler(target) // 代理执行逻辑
);
}
}
public class JdkProxyTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserService proxy = (UserService) JdkProxyHandler.getProxy(userService);
proxy.register("李四");
}
}
执行结果
【日志】方法 register 开始执行...
李四 注册成功!
【日志】方法 register 执行完成!
特点:
代理类是在运行时动态生成的,不需要手写代理类,避免代码重复。
目标对象必须实现接口,代理对象也是基于接口进行代理。
代理方法的调用使用反射(
Method.invoke()
),相比静态代理略有性能损耗。
2.2 CGLIB 动态代理(基于子类)
CGLIB 采用子类继承的方式生成代理类,适用于没有实现接口的类。它使用 net.sf.cglib.proxy.Enhancer
来生成代理对象。
<!--引入CGLIB 依赖-->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
创建 CGLIB 代理
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
//真实对象
public class OrderService {
public void createOrder() {
System.out.println("订单创建成功!");
}
}
public class CglibProxyHandler implements MethodInterceptor {
public Object getProxy(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz); // 设置父类
enhancer.setCallback(this); // 设置回调
return enhancer.create(); // 创建代理对象
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("【日志】执行 " + method.getName() + " 方法...");
Object result = proxy.invokeSuper(obj, args); // 调用父类方法
System.out.println("【日志】方法 " + method.getName() + " 执行完成!");
return result;
}
}
public class CglibProxyTest {
public static void main(String[] args) {
CglibProxyHandler proxyHandler = new CglibProxyHandler();
OrderService proxy = (OrderService) proxyHandler.getProxy(OrderService.class);
proxy.createOrder();
}
}
执行结果
复制编辑【日志】执行 createOrder 方法...
订单创建成功!
【日志】方法 createOrder 执行完成!
特点:
代理类是目标类的子类(继承目标类),通过方法拦截增强功能。
不需要目标类实现接口,比JDK动态代理适用范围更广。
运行效率比JDK动态代理高(因为直接调用父类方法,不使用反射)。
评论