网站首页 > java教程 正文
代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过代理对象控制对原始对象的访问。代理模式创建一个代理对象,使代理对象可以在不改变原始对象的情况下,控制客户端的访问。代理对象通常是原始对象的包装器,它提供了与原始对象相同的接口,并且在调用原始对象的方法之前或之后可以执行一些附加操作。
代理模式有多种变体,其中最常见的有以下几种:
- 静态代理:在编译时确定代理对象,并在代理对象中显式实现原始对象的接口。
- 动态代理:在运行时使用反射机制动态创建代理对象,并代理对象的方法调用将被转发到原始对象。
- 远程代理:在不同的进程或计算机上,使用网络通信来访问远程对象。
- 虚拟代理:在需要时才实例化原始对象,以避免在创建时进行大量初始化工作。
- 智能代理:在代理对象中添加一些额外的功能,如缓存、事务处理、权限检查等。
代理模式的优点包括:
- 代理对象可以在不修改原始对象的情况下,增强原始对象的功能。
- 代理对象可以控制对原始对象的访问,以实现访问控制、缓存等功能。
- 代理对象可以隐藏原始对象的实现细节,保护原始对象的安全性。
- 代理对象可以在原始对象不可用时,提供一个占位符对象。
代理模式的缺点包括:
- 代理模式会增加系统的复杂性,因为需要额外的代理对象来管理原始对象。
- 代理模式可能会降低系统的性能,因为在代理对象中添加了额外的逻辑和处理。
- 代理模式可能会增加代码的维护难度,因为需要维护原始对象和代理对象之间的一致性。
手写静态代理
静态代理是在编译时就已经确定了代理类和委托类的关系,并生成了代理类的字节码文件,代理类和委托类的关系在程序运行之前就已经确定了。
以下是一个简单的Java静态代理示例,演示如何创建一个代理类:
- 定义接口
public interface Calculator {
int add(int a, int b);
}
- 实现接口
public class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) {
return a + b;
}
}
- 创建代理类
public 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;
}
}
在上面的代码中,CalculatorProxy是代理类,实现了Calculator接口,并包含了一个Calculator类型的成员变量calculator。代理类的构造函数接受一个Calculator类型的参数,该参数是委托类的实例。
代理类的add()方法调用了委托类的add()方法,并在方法调用前后添加了一些额外的逻辑。
- 使用代理类
public static void main(String[] args) {
Calculator calculator = new CalculatorImpl();
Calculator proxy = new CalculatorProxy(calculator);
int result = proxy.add(1, 2);
System.out.println("Result: " + result);
}
在上面的代码中,首先创建一个CalculatorImpl的实例,然后通过该实例创建一个CalculatorProxy的实例,代理类的构造函数接受委托类的实例作为参数。
最后,使用代理对象调用add()方法,代理类的add()方法中会先输出一条“Before calculation...”的日志,然后调用委托类的add()方法,最后输出一条“After calculation...”的日志。
这就是一个简单的Java静态代理示例。通过代理对象,我们可以在不修改委托类的情况下,为委托类的方法添加额外的逻辑。静态代理虽然简单易用,但缺点是需要手动编写代理类,当委托类的方法发生变化时,代理类也需要相应地进行修改。
手写动态代理
Java动态代理是在运行时动态地生成代理类的字节码,并在内存中创建代理类的实例。与静态代理不同的是,动态代理可以代理任意实现了接口的委托类,而不需要为每个委托类手动编写代理类。
下面是一个简单的Java动态代理示例,演示如何创建一个代理类:
- 定义接口
public interface Calculator {
int add(int a, int b);
}
- 实现接口
public class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) {
return a + b;
}
}
- 创建代理类
public class CalculatorProxy implements InvocationHandler {
private Object target;
public CalculatorProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before calculation...");
Object result = method.invoke(target, args);
System.out.println("After calculation...");
return result;
}
}
在上面的代码中,CalculatorProxy实现了Java标准库中的InvocationHandler接口,它的invoke()方法会在代理对象调用方法时被调用,方法参数中包含了委托类的实例、委托方法的信息以及方法参数。在该方法中,可以添加额外的逻辑,并调用委托类的方法。
- 使用代理类
public static void main(String[] args) {
Calculator calculator = new CalculatorImpl();
Calculator proxy = (Calculator) Proxy.newProxyInstance(
calculator.getClass().getClassLoader(),
calculator.getClass().getInterfaces(),
new CalculatorProxy(calculator));
int result = proxy.add(1, 2);
System.out.println("Result: " + result);
}
在上面的代码中,首先创建一个CalculatorImpl的实例,然后通过Java标准库中的Proxy.newProxyInstance()方法创建一个代理类的实例。该方法接受三个参数,分别是类加载器、接口列表和InvocationHandler实例。通过该方法返回的代理对象,可以调用委托类的方法,并在方法调用前后添加额外的逻辑。
这就是一个简单的Java动态代理示例。通过动态代理,我们可以代理任意实现了接口的委托类,并为委托类的方法添加额外的逻辑。相比静态代理,动态代理的缺点是性能较低,因为需要在运行时动态生成代理类的字节码。但是,由于动态代理的灵活性和通用性,它在很多场景下都是非常有用的。
cglib实现动态代理
除了使用Java标准库中的Proxy类实现动态代理外,还可以使用第三方库CGLIB实现动态代理。CGLIB是一个高效的字节码生成库,它可以在运行时动态生成代理类的字节码,从而实现动态代理。与Java标准库中的动态代理不同,CGLIB可以代理非接口类型的类。
下面是一个使用CGLIB实现动态代理的简单示例:
- 引入依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
- 定义目标类
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}
- 创建代理类
public class CalculatorProxy implements MethodInterceptor {
private Object target;
public CalculatorProxy(Object target) {
this.target = target;
}
public Object getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("Before calculation...");
Object result = method.invoke(target, args);
System.out.println("After calculation...");
return result;
}
}
在上面的代码中,CalculatorProxy实现了CGLIB的MethodInterceptor接口,它的intercept()方法会在代理对象调用方法时被调用,方法参数中包含了委托方法的信息以及方法参数。在该方法中,可以添加额外的逻辑,并调用委托类的方法。
- 使用代理类
public static void main(String[] args) {
Calculator calculator = new Calculator();
Calculator proxy = (Calculator) new CalculatorProxy(calculator).getProxy();
int result = proxy.add(1, 2);
System.out.println("Result: " + result);
}
在上面的代码中,首先创建一个Calculator的实例,然后通过调用CalculatorProxy的getProxy()方法创建一个代理类的实例。在该方法中,使用CGLIB的Enhancer类动态生成代理类的字节码,并设置代理类的父类和回调方法。通过该方法返回的代理对象,可以调用委托类的方法,并在方法调用前后添加额外的逻辑。
这就是一个简单的使用CGLIB实现动态代理的示例。与Java标准库中的动态代理相比,CGLIB可以代理非接口类型的类,并且性能较高,但它也有一些缺点,例如不能代理final方法和类等。在实际开发中,可以根据实际情况选择使用Java标准库中的动态代理或CGLIB。
- 上一篇: Java的动态代理机制详解(附示例代码)
- 下一篇: Java 17中的动态代理:实现灵活的代理模式
猜你喜欢
- 2024-10-24 Java动态代理与静态代理以及它能为我们做什么
- 2024-10-24 Java 设计模式 之 代理模式 (1)(java设计模式之代理模式)
- 2024-10-24 Java设计模式:代理模式 vs. 装饰模式
- 2024-10-24 设计模式篇——代理模式详解(面试再问你代理模式,这么回答他)
- 2024-10-24 动态代理大揭秘,带你彻底弄清楚动态代理
- 2024-10-24 面试:Java的代理模式动态代理和静态代理区别,aop用的什么代理
- 2024-10-24 Java设计模式之代理模式(java代理类是什么)
- 2024-10-24 JAVA设计模式——代理模式(java编写代理服务)
- 2024-10-24 23种java设计模式之:门面模式、享元模式、代理模式
- 2024-10-24 Java 17中的动态代理:实现灵活的代理模式
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)