Java静态代理和动态代理详解

Java中的代理模式是一种非常重要的设计模式,它允许在不修改被代理对象的基础上,通过代理对象来控制对实际对象的访问,从而扩展对象的功能。Java代理模式主要分为静态代理和动态代理两种实现方式。

前言

原理读完后是不是还是不明白,那就举个例子 for example:

我们可以用 房东出租房子 的场景来类比 Java 代理模式,帮助理解代理模式的核心思想。

类比关系

  1. 定义“出租行为”接口(规范)
public interface RentHouse {
    void rent(); // 出租方法
}
  1. 房东(真实对象)实现接口
public class Landlord implements RentHouse {
    @Override
    public void rent() {
        System.out.println("房东直接出租房子");
    }
}
  1. 中介(代理对象)实现接口
public class Agency implements RentHouse {
    private RentHouse landlord; // 持有真实对象的引用

    public Agency(RentHouse landlord) {
        this.landlord = landlord;
    }

    @Override
    public void rent() {
        beforeRent();   // 代理添加的额外操作
        landlord.rent(); // 调用真实对象的出租方法
        afterRent();    // 代理添加的额外操作
    }

    private void beforeRent() {
        System.out.println("中介发布租房广告");
    }

    private void afterRent() {
        System.out.println("中介协助签订合同");
    }
}
  1. 租客(客户端)通过中介租房
public class Client {
    public static void main(String[] args) {
        // 房东直接出租
        RentHouse landlord = new Landlord();
        landlord.rent();
        // 输出:房东直接出租房子

        // 通过中介代理出租
        RentHouse agency = new Agency(landlord);
        agency.rent();
        // 输出:
        // 中介发布租房广告
        // 房东直接出租房子
        // 中介协助签订合同
    }
}

一、 静态代理

1.定义‌

静态代理是一种设计模式,通过创建一个代理类来实现对目标对象的代理。代理类和目标类实现相同的接口,通过代理类来间接调用目标类的方法,从而实现功能的扩展。

2.特点

1)代理类在编译时就已经确定,不需要在运行时动态生成代理类。
2)代理类需要实现与目标对象相同的接口,并持有目标对象的引用,通过代理对象调用目标对象的方法。

3.实现步骤‌

1)定义接口
2)实现目标类(实现接口的具体业务类)
3) 创建代理类(实现接口,并在内部持有目标类的实例,通过调用目标类的方法来实现代理功能)。
4) 使用代理类。

4.优缺点
优点:结构简单,容易理解;代理类可以扩展目标类的功能(如添加日志、权限校验等)。
缺点:每增加一个接口,都需要单独编写代理类,扩展性差;代理类的维护工作量较大。

5.代码示例
首先,我们定义一个接口Service,然后创建一个实现该接口的RealService类,最后创建一个代理类ServiceProxy来代理RealService。

// 定义接口
interface Service {
    void execute();
}

// 实现接口的实际类
class RealService implements Service {
    @Override
    public void execute() {
        System.out.println("Executing RealService");
    }
}

// 代理类
class ServiceProxy implements Service {
    private RealService realService;

    public ServiceProxy(RealService realService) {
        this.realService = realService;
    }

    @Override
    public void execute() {
        System.out.println("Executing ServiceProxy before RealService");
        realService.execute();
        System.out.println("Executing ServiceProxy after RealService");
    }
}

// 使用代理
public class StaticProxyDemo {
    public static void main(String[] args) {
        RealService realService = new RealService();
        ServiceProxy proxy = new ServiceProxy(realService);
        proxy.execute();
    }
}

在上面的代码中,ServiceProxy类代理了RealService类,并在调用RealService的execute方法之前和之后添加了额外的逻辑。

二、动态代理

1.定义

动态代理是指在运行时动态生成代理类,该代理类实现一个或多个接口,并且可以在代理类的各个方法中实现对非代理对象的操作。

2.特点

1)代理类在运行时动态生成,不需要在编译时定义代理类的实现。
2)动态代理依赖于Java的反射机制。

3.实现步骤

1)定义接口。
2)创建InvocationHandler接口的实现类,用来处理方法调用。
3)使用Proxy.newProxyInstance()方法生成动态代理对象。

4.优缺点
优点:灵活性更强,适用于需要动态扩展功能或减少重复代码的场景;将代理逻辑与具体实现解耦,使代码更加灵活、可维护,同时提供了更高的复用性。
缺点:性能上不如静态代理,因为动态代理依赖于反射机制。

5.实现方式
1)JDK动态代理‌:适用于实现了接口的类,通过接口类型来代理对象。它使用Java标准库中的java.lang.reflect包来创建代理对象。
2)CGLIB动态代理‌:适用于没有实现接口的类。它允许在运行时创建子类,通过继承被代理类来创建代理对象。

6.代码示例
我们使用JDK的动态代理来创建一个代理对象。动态代理不需要预先定义代理类,而是在运行时动态生成。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义接口
interface Service {
    void execute();
}

// 实现接口的实际类
class RealService implements Service {
    @Override
    public void execute() {
        System.out.println("Executing RealService");
    }
}

// 动态代理处理器
class ServiceInvocationHandler implements InvocationHandler {
    private Object target;

    public ServiceInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Executing ServiceInvocationHandler before method");
        Object result = method.invoke(target, args);
        System.out.println("Executing ServiceInvocationHandler after method");
        return result;
    }
}

// 使用动态代理
public class DynamicProxyDemo {
    public static void main(String[] args) {
        RealService realService = new RealService();
        Service proxyInstance = (Service) Proxy.newProxyInstance(
                realService.getClass().getClassLoader(),
                realService.getClass().getInterfaces(),
                new ServiceInvocationHandler(realService)
        );
        proxyInstance.execute();
    }
}

在上面的代码中,ServiceInvocationHandler类实现了InvocationHandler接口,并在invoke方法中添加了额外的逻辑。然后,我们使用Proxy.newProxyInstance方法创建了一个代理对象,该对象将方法调用委托给ServiceInvocationHandler。

静态代理与动态代理的区别
  • 生成时机‌:静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件;动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中。
  • 灵活性‌:静态代理的目标角色固定,代理对象会增强目标对象的行为;动态代理的目标对象不固定,代理对象在应用程序执行时动态创建。
  • 应用场景‌:静态代理适用于小型项目或代理类相对固定的场景;动态代理适用于需要动态扩展功能或减少重复代码的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值