Java 动态代理和静态代理 详解(结合代码实列)

📖Java 动态代理和静态代理的区别


动态代理和静态代理是两种不同的代理模式,它们在代理对象的创建和使用方式上有所不同。

  1. 静态代理:
    • 静态代理是在编译期间就已经确定的,需要为每个被代理的类编写一个代理类,代理类和被代理类实现相同的接口或继承相同的父类。
    • 静态代理的代理类在编译时就存在,所以在程序运行时只能代理特定的类,无法动态地决定代理哪些类。
    • 静态代理对原始对象的方法调用进行了包装,可以在调用前后添加额外的逻辑,但代理类需要提前编写,会增加代码的量。
    • 静态代理在代码中显式指定代理对象,使用起来相对直观,但增加新的代理类需要重新编译。
  2. 动态代理:
    • 动态代理是在运行时创建代理对象,无需提前编写代理类。使用Java的反射机制来动态生成代理类和代理对象。
    • 动态代理基于接口进行代理,通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。
    • 动态代理可以代理多个接口的类,并动态决定代理哪些类。在运行时,可以根据需要为不同的对象生成代理,更具灵活性。
    • 动态代理不需要为每个被代理类编写特定的代理类,更加灵活和节省代码量。
    • 动态代理在代理对象的方法调用前后可以添加自定义的逻辑,例如日志记录、事务管理等。
    • 动态代理的缺点是相对于静态代理而言,运行时生成代理对象需要一定的性能开销。

🔖下面是一个结合代码示例


展示了Java中动态代理和静态代理的区别:

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

// 接口定义
interface Subject {
    void doSomething();
}

// 静态代理类
class StaticProxy implements Subject {
    private Subject realSubject;

    public StaticProxy(Subject realSubject) {
        this.realSubject = realSubject;
    }

    public void doSomething() {
        System.out.println("静态代理 - 前置处理");
        realSubject.doSomething();
        System.out.println("静态代理 - 后置处理");
    }
}

// 动态代理处理器
class DynamicProxyHandler implements InvocationHandler {
    private Object realObject;

    public DynamicProxyHandler(Object realObject) {
        this.realObject = realObject;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理 - 前置处理");
        Object result = method.invoke(realObject, args);
        System.out.println("动态代理 - 后置处理");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建被代理对象
        Subject realSubject = new RealSubject();

        // 静态代理示例
        Subject staticProxy = new StaticProxy(realSubject);
        staticProxy.doSomething();

        System.out.println("------------------");

        // 动态代理示例
        Subject dynamicProxy = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                new DynamicProxyHandler(realSubject)
        );
        dynamicProxy.doSomething();
    }
}

// 实现类
class RealSubject implements Subject {
    public void doSomething() {
        System.out.println("执行业务操作");
    }
}
  • 上述代码中,首先定义了一个接口Subject,表示一个业务对象需要实现的功能。然后,创建了一个实现了Subject接口的具体类RealSubject
  • 接下来,我们实现了一个静态代理类StaticProxy,它在实际调用被代理对象前后进行额外的处理。然后,创建了一个静态代理对象staticProxy,并调用其doSomething()方法。
  • 然后,我们定义了一个动态代理处理器DynamicProxyHandler,它实现了InvocationHandler接口并在实际调用被代理对象前后进行额外的处理。最后,我们使用Proxy.newProxyInstance()方法创建了一个动态代理对象dynamicProxy,并调用其doSomething()方法。

🔖运行上述代码,输出如下


静态代理 - 前置处理
执行业务操作
静态代理 - 后置处理
------------------
动态代理 - 前置处理
执行业务操作
动态代理 - 后置处理

📈总结


  • 从输出结果可以看出,静态代理和动态代理都在原始对象的方法调用前后添加了额外的处理逻辑。但是,静态代理需要提前手动编写代理类,而动态代理则是在运行时生成代理对象。
  • 静态代理在编写和使用上更为直观,但是当需要代理多个类或接口时,需要为每个类或接口编写特定的代理类,有一定的重复工作。而动态代理可以更加灵活地决定代理哪些类或接口,并且减少了代码的重复性。
  • Java中的动态代理和静态代理都是代理模式的实现方式,适用于不同的场景。
    • 静态代理适合以下场景:
      • 当目标对象(被代理对象)数量有限且确定时,可以通过手动编写代理类来实现静态代理。静态代理在编译时就创建了代理类,因此在运行时性能较好。
      • 静态代理对目标对象进行了封装,在不修改原有代码的情况下增加了额外的功能。这使得静态代理常被用于日志记录、事务管理等横切关注点。
    • 动态代理适合以下场景:
      • 当目标对象数量不确定或者无法提前确定时,动态代理可以更方便地生成代理对象。它在运行时生成代理类和代理对象,避免了手动编写多个代理类的繁琐工作。
      • 动态代理可以灵活地在运行时为目标对象添加、删除或更改代理行为。这使得动态代理常被用于AOP(面向切面编程)、RPC(远程过程调用)等应用场景。
  • 需要注意的是,由于动态代理在运行时通过反射机制创建代理类和代理对象,因此相比静态代理,其性能可能略低。此外,动态代理只能代理实现了接口的目标对象,而静态代理没有这个限制。
  • 总结起来,静态代理适用于目标对象数量有限且确定、需要封装和增加额外功能的场景;而动态代理适用于目标对象数量不确定或无法提前确定、需要灵活添加、删除或更改代理行为的场景。根据具体需求和情况,选择合适的代理方式。
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Java动态代理是一种通过在运行时期间生成代理对象来实现对目标对象进行代理的技术。它可以在不修改目标对象的情况下,为目标对象提供额外的功能。 Java动态代理实现的核心是利用了Java的反射机制和动态生成类的技术。在动态代理中,我们需要定义一个代理类和一个实现了InvocationHandler接口的处理器类。 代理类是在运行时动态生成的类,它是目标对象的代理,它实现了与目标对象相同的接口,并且在方法调用时会通过InvocationHandler接口的实现类来处理方法的调用。InvocationHandler接口中只有一个方法invoke(Object proxy, Method method, Object[] args),这个方法就是用来处理方法调用的。 下面是一个简单的Java动态代理的示例代码: ``` import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxy implements InvocationHandler { private Object target; public DynamicProxy(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before method"); Object result = method.invoke(target, args); System.out.println("after method"); return result; } public static void main(String[] args) { RealObject realObject = new RealObject(); DynamicProxy dynamicProxy = new DynamicProxy(realObject); Interface proxyObject = (Interface) Proxy.newProxyInstance( Interface.class.getClassLoader(), new Class[] { Interface.class }, dynamicProxy); proxyObject.doSomething(); } } interface Interface { void doSomething(); } class RealObject implements Interface { public void doSomething() { System.out.println("RealObject doSomething"); } } ``` 在这个示例中,我们定义了一个DynamicProxy类作为代理处理器,它实现了InvocationHandler接口。在DynamicProxy类中,我们定义了一个Object类型的target属性,它表示目标对象。 在DynamicProxy类的invoke方法中,我们先输出了一句话“before method”,然后通过反射机制调用目标对象的方法,最后输出了一句话“after method”。 在DynamicProxy类的main方法中,我们首先创建了一个RealObject对象作为目标对象,然后创建了一个DynamicProxy对象,并将RealObject对象作为参数传递给DynamicProxy对象的构造方法。接着,我们通过Proxy.newProxyInstance方法动态生成了一个代理对象,并将DynamicProxy对象作为参数传递给它。最后,我们调用代理对象的doSomething方法。 当我们运行这个程序时,它会输出以下内容: ``` before method RealObject doSomething after method ``` 这表明,在代理对象调用doSomething方法时,它会先调用DynamicProxy类的invoke方法,在invoke方法中,我们将先输出一句话“before method”,然后调用目标对象的方法,最后输出一句话“after method”。 Java动态代理的优点是可以在运行时期间动态生成代理对象,不需要预先定义代理类,这样可以大大减少代码量。同时,Java动态代理也具有很好的灵活性,可以对不同的目标对象生成不同的代理对象,实现不同的处理逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值