Java 代理模式

September 28, 2024 作者: southern 分类: 浏览: 2 评论: 0

代理模式是一种结构型设计模式,它为对象提供了一个代理,以控制对这个对象的访问。在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中有两种动态代理方式:

  1. JDK 动态代理(基于接口)

  2. CGLIB 动态代理(基于子类继承)

2.1 JDK 动态代理(基于接口)

JDK动态代理是Java提供的原生动态代理机制,使用 java.lang.reflect.ProxyInvocationHandler 动态生成代理类,在运行时创建代理对象。

//定义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动态代理高(因为直接调用父类方法,不使用反射)。

#2024(13)

评论