Java设计模式——代理模式

静态代理:

Java静态代理是设计模式中的一种,它通过创建一个代理类来代替原始类,从而提供额外的功能或控制原始类的访问。

如何使用Java静态代理

要创建一个静态代理,你需要有一个接口,一个实现该接口的目标类,以及一个代理类,该代理类也实现了该接口。代理类持有一个对目标对象的引用,并在其方法调用中调用目标对象的相应方法。

// 定义一个接口
interface Calculator {
    int add(int a, int b);
}

// 目标类
class CalculatorImpl implements Calculator {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
}

// 代理类
class CalculatorProxy implements Calculator {
    private Calculator calculator;

    public CalculatorProxy(Calculator calculator) {
        this.calculator = calculator;
    }

    @Override
    public int add(int a, int b) {
        System.out.println("Before calculation");
        int result = calculator.add(a, b);
        System.out.println("After calculation");
        return result;
    }
}

// 测试类
public class ProxyExample {
    public static void main(String[] args) {
        Calculator target = new CalculatorImpl();
        Calculator proxy = new CalculatorProxy(target);

        int result = proxy.add(5, 3);
        System.out.println("Result: " + result);
    }
}

在这个例子中,Calculator是一个接口,CalculatorImpl是目标类,CalculatorProxy是代理类。当我们调用代理类的add方法时,它会首先打印"Before calculation",然后调用目标对象的add方法,最后打印"After calculation"。

为什么使用静态代理

  • 解耦:可以在不修改目标对象的情况下,通过代理对象添加额外的功能或控制访问。

  • 保持干净:代理类可以为目标对象提供一个干净的接口,隐藏了目标对象的实现细节。

  • 权限控制:可以在代理类中添加额外的权限检查,以控制对目标对象的访问。

缺点

  • 代码冗余:每次添加一个新的功能都需要创建一个新的代理类。

  • 静态:因为代理类是静态的,所以不能在运行时改变它们的行为。

总的来说,静态代理是一种简单且直接的方式来实现代理模式,它在很多情况下都是非常有用的,特别是当你需要对目标对象进行额外控制或添加额外功能时

动态代理:

Java动态代理 是Java语言提供的一个强大的特性,它允许你在运行时创建代理类和代理实例。这使得你可以在运行时为一个接口创建一个代理实例,而不需要手动编写实现该接口的类。动态代理通常在需要添加额外逻辑(例如日志记录、事务管理等)到现有代码中而不修改现有代码的情况下使用。

  • 是在内存中生成代理对象的一种技术
  • 无需手写代理类,也不会存在代码编译的过程。运用在内存中生产代理类的技术在JVM的运行区造一个代理对象,只需对需要修改的部分进行编辑。

编写流程:

  1. 准备一个目标类对象
  2. 使用jdk的API动态的生成代理对象
  3. 调用代理对象执行相应的方法

如何使用Java动态代理

要使用Java动态代理,你需要先创建一个接口,然后实现一个InvocationHandler接口,最后使用Proxy.newProxyInstance()方法创建代理实例

1.ClassLoader loader:

固定写法,指定目标类对象的类的加载器即可,用于加载目标类及其接口的字节码文件,通常使用目标类的字节码文件调用**getClassLoader()**方法可得到。

2.Class<?>[] interfaces:

固定写法,指定目标类的所以接口的字节码对象的数组,通常使用目标类的字节码文件调用**getinterfaces()**方法可得到。

3.InvocationHander h:

这个参数是一个接口,主要关注它里面的一个方法,它会在代理类调用方法时执行,也就是说,在代理类对象中调用的任何方法都会执行invoke()方法。所以在此方法中进行代码的扩展。

invoke()方法中参数的含义:

  1. proxy:就是代理类对象的一个引用也就是Proxy.newProxyInstance()方法的返回值;此引用几乎不会用到。
  2. method:对应的就是触发invoke执行的方法的Method对象。假如我们调用了Xxx方法,该方法触发了invoke执行,那么method就是Xxx方法对应的反射对象Method。
  3. args:代理对象调用方法时传入的实际参数
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public interface Hello {
    void sayHello();
}

public class HelloImpl implements Hello {
    @Override
    public void sayHello() {
        System.out.println("Hello World!");
    }
}

public class DynamicProxyExample {
    public static void main(String[] args) {
        Hello hello = new HelloImpl();
        Hello proxy = (Hello) Proxy.newProxyInstance(
                hello.getClass().getClassLoader(),
                hello.getClass().getInterfaces(),
                new MyInvocationHandler(hello)
        );

        proxy.sayHello();
    }
}

public class MyInvocationHandler implements InvocationHandler {
    private Object target;

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

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

在上面的例子中,我们首先定义了一个Hello接口和一个实现该接口的HelloImpl类。然后,我们创建了一个MyInvocationHandler类,实现了InvocationHandler接口,该类在方法调用前后打印日志。最后,在DynamicProxyExample类中,我们使用Proxy.newProxyInstance()方法创建了一个代理实例,并传入了一个MyInvocationHandler实例

为什么使用动态代理

  • 解耦:你可以将通用逻辑(如日志记录、事务管理等)与特定的业务逻辑分开。

  • 代码复用:可以为多个对象提供相同的额外功能,而无需在每个类中重复相同的代码。

  • 运行时改变行为:你可以在运行时改变对象的行为,而无需修改源代码。

注意事项

  • 接口代理:动态代理只能为接口创建代理,不能为类创建代理。

  • 性能开销:动态代理可能会带来一些性能开销,因为它涉及反射调用。

总的来说,Java动态代理是一个非常强大的特性,可以在很多场景中帮助你更加灵活地管理和组织你的

相关推荐
·云扬·13 分钟前
Lambda 表达式详解
java·开发语言·笔记·学习·1024程序员节
星叔1 小时前
ARXML汽车可扩展标记性语言规范讲解
java·前端·汽车
2401_857600951 小时前
SpringBoot框架:共享汽车管理的创新工具
java·spring boot·汽车
代码小鑫1 小时前
A15基于Spring Boot的宠物爱心组织管理系统的设计与实现
java·开发语言·spring boot·后端·毕业设计·宠物
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ2 小时前
mapper.xml 使用大于号、小于号示例
xml·java·数据库
一直学习永不止步2 小时前
LeetCode题练习与总结:迷你语法分析器--385
java·数据结构·算法·leetcode·字符串··深度优先搜索
Tech Synapse2 小时前
Java将Boolean转为Json对象的方法
java·开发语言·json
小冉在学习2 小时前
day55 图论章节刷题Part07([53.寻宝]prim算法、kruskal算法)
java·算法·图论
伴野星辰2 小时前
网站视频过大,加载缓慢解决方法【分段加载视频】
java·服务器·音视频
liang89992 小时前
设计模式之模版方法模式
设计模式