在Java中写代理主要有两种方式,一种是静态代理,另一种是动态代理。静态代理主要是通过在代码中显式定义一个代理类来实现代理,而动态代理则是通过在运行时动态生成代理类来实现。
在Java中使用静态代理是一种较为简单的实现方式,我们只需要定义一个接口和该接口的实现类,然后再定义一个代理类,使其实现同样的接口,并在代理类中添加我们需要的控制代码即可。而在使用动态代理时,我们不需要显式地定义代理类,而是通过Java的反射机制,在运行时动态生成代理类,从而实现对目标对象的代理。动态代理的主要优点是可以使我们的代码更加灵活和通用,但同时也需要对Java的反射机制有一定的理解。
下面我们将逐一详细介绍这两种代理的实现方式。
一、静态代理
静态代理是一种在编译阶段就确定代理关系的代理方式。在静态代理中,代理类和被代理类在编译前就已经确定,编译完成后代理类的.class文件也会产生。
-
创建接口及其实现类
在Java中,我们首先需要定义一个接口,然后创建该接口的实现类。例如,我们可以定义一个接口叫做"Workable",该接口有一个方法叫做"work"。然后,我们创建一个类叫做"Employee",该类实现了"Workable"接口。
public interface Workable {
void work();
}
public class Employee implements Workable {
@Override
public void work() {
System.out.println("Employee is working.");
}
}
-
创建代理类
创建代理类,同样实现"Workable"接口,并在代理类的"work"方法中调用被代理对象的"work"方法。
public class WorkProxy implements Workable {
private Workable workable;
public WorkProxy(Workable workable) {
this.workable = workable;
}
@Override
public void work() {
System.out.println("WorkProxy start.");
workable.work();
System.out.println("WorkProxy end.");
}
}
-
使用代理类
在主程序中,我们可以使用"WorkProxy"类来代替"Employee"类,以此实现对"Employee"的代理。
public class Main {
public static void main(String[] args) {
Workable employee = new Employee();
Workable proxy = new WorkProxy(employee);
proxy.work();
}
}
二、动态代理
动态代理是一种在运行时动态生成代理类的代理方式。在动态代理中,代理类并不是在.java文件中定义的,而是在运行时通过Java的反射机制动态生成的。
-
创建接口及其实现类
创建接口及其实现类的步骤与静态代理相同,这里不再赘述。
-
创建代理类
在动态代理中,我们并不需要显式地创建代理类,而是通过Java的
Proxy
类和InvocationHandler
接口来实现。public class WorkInvocationHandler implements InvocationHandler {
private Object target;
public WorkInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("WorkInvocationHandler start.");
Object result = method.invoke(target, args);
System.out.println("WorkInvocationHandler end.");
return result;
}
}
-
使用代理类
使用动态代理类的方式与静态代理稍有不同。我们需要通过
Proxy
类的newProxyInstance
方法来动态创建代理对象。public class Main {
public static void main(String[] args) {
Workable employee = new Employee();
InvocationHandler handler = new WorkInvocationHandler(employee);
Workable proxy = (Workable) Proxy.newProxyInstance(employee.getClass().getClassLoader(),
employee.getClass().getInterfaces(), handler);
proxy.work();
}
}
总结起来,静态代理和动态代理各有其优缺点。静态代理的优点是结构简单,易于理解和实现,但缺点是代理类和被代理类在编译阶段就已经绑定,灵活性不足。而动态代理则是在运行时动态生成代理类,灵活性较高,但实现相对复杂,需要理解反射原理。
相关问答FAQs:
1. 代理模式在Java中的应用场景有哪些?
代理模式在Java中有很多应用场景,例如:
- 当需要控制对一个对象的访问时,可以使用代理模式。代理对象可以作为真实对象的门卫,只允许特定的客户端访问真实对象。
- 当需要在访问一个对象之前或之后执行额外的操作时,可以使用代理模式。代理对象可以在调用真实对象的方法之前或之后执行一些附加的逻辑,如记录日志、缓存数据等。
- 当需要将远程调用转换为本地调用时,可以使用代理模式。代理对象可以隐藏远程调用的复杂性,使客户端感觉像调用本地对象一样。
2. 代理模式和装饰器模式有什么区别?
代理模式和装饰器模式都是结构型设计模式,它们都通过引入一个中间层来控制对真实对象的访问。但是它们有一些区别:
- 代理模式主要关注对真实对象的访问控制,即代理对象在访问真实对象之前或之后可以执行一些额外的操作。而装饰器模式主要关注对真实对象的功能扩展,即装饰器对象在调用真实对象的方法前后可以执行一些额外的逻辑。
- 代理模式通常在编译时确定代理对象和真实对象的关系,而装饰器模式可以在运行时动态地添加装饰器对象。
3. Java中常用的代理模式有哪些?
在Java中,常用的代理模式有以下几种:
- 静态代理:通过手动编写代理类来实现代理功能,需要为每个被代理的类编写一个代理类。
- 动态代理:通过Java的反射机制,在运行时动态生成代理对象,不需要手动编写代理类。Java提供了两种实现动态代理的方式:基于接口的动态代理和基于类的动态代理(使用字节码生成库,如CGLIB)。
- 远程代理:用于在不同的JVM之间进行通信,将远程对象的方法调用转发给远程对象执行,并将结果返回给客户端。
- 虚拟代理:用于延迟加载对象的创建,当真实对象的创建和销毁成本较高时,可以通过虚拟代理来优化性能。
- 保护代理:用于控制对真实对象的访问权限,只允许特定的客户端访问真实对象。
原创文章,作者:Edit2,如若转载,请注明出处:https://docs.pingcode.com/baike/358557