目录
Java代理模式(Proxy Pattern)是一种常见的设计模式,它允许在不改变原有代码的情况下,通过添加一个代理对象来控制对原始对象的访问。代理对象拥有与原始对象相同的接口,并且可以在原始对象的方法调用前后执行一些额外的操作。代理模式在Java中的应用非常广泛,例如AOP(面向切面编程)和RMI(远程方法调用)都是基于代理模式实现的。
Java中代理模式有两种实现方式:静态代理和动态代理。
1、静态代理
静态代理需要手动创建一个代理类,该代理类与原始类实现相同的接口,代理类中持有一个原始类的引用,并在代理类的方法中调用原始类的对应方法。在这个过程中,我们可以在原始类的方法调用前后添加一些额外的操作。以下是一个简单的静态代理示例:// 通过拿到原始的对象进行操作
public interface Image {
void display();
}
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk();
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk() {
System.out.println("Loading " + fileName);
}
}
public class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
public class Main {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
image.display();
}
}
在这个例子中,我们创建了一个Image接口和一个RealImage类,RealImage类实现了Image接口,并实现了display方法,该方法用于显示图片。我们还创建了一个ProxyImage类,该类也实现了Image接口,并持有一个RealImage对象的引用。在ProxyImage类的display方法中,我们首先判断RealImage对象是否已经被创建,如果没有,则创建一个RealImage对象,然后调用RealImage对象的display方法。这样,我们就可以通过ProxyImage对象控制对RealImage对象的访问,例如在图片显示前后添加一些日志信息或者进行权限检查等操作。
2、动态代理
动态代理是一种更加灵活的代理模式,它不需要手动创建代理类,而是在运行时动态地生成代理对象。Java中动态代理是通过反射机制实现的,它允许我们在运行时创建一个代理对象,并将方法调用转发到原始对象上。动态代理通常需要实现一个InvocationHandler接口,该接口中有一个invoke方法,用于处理方法调用。// 动态代理的核心在于动态生成代理类
以下是一个简单的使用Java动态代理的例子:
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 LogHandler implements InvocationHandler {
private Object target;
public LogHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After method " + method.getName());
return result;
}
}
public class Main {
public static void main(String[] args) {
Hello hello = new HelloImpl();
InvocationHandler handler = new LogHandler(hello);
Hello proxyHello = (Hello) Proxy.newProxyInstance(
hello.getClass().getClassLoader(),
hello.getClass().getInterfaces(),
handler
);
proxyHello.sayHello();
}
}
在这个例子中,我们定义了一个Hello接口和一个HelloImpl类作为被代理类,实现了InvocationHandler接口的LogHandler类作为代理类。在LogHandler类的invoke方法中,我们添加了一些日志信息,并通过反射调用了原始对象的对应方法。在Main类中,我们使用Proxy类的静态方法newProxyInstance来生成一个代理对象。这个方法接受三个参数:类加载器、被代理类实现的接口、和代理类的InvocationHandler实例。通过调用代理对象的sayHello方法,我们可以看到在调用被代理对象的sayHello方法前后输出了一些日志信息。
总的来说,动态代理是一种非常有用的代理方式,它可以帮助我们更加灵活地控制对原始对象的访问,并在其中添加一些额外的功能。在Java中,我们可以使用动态代理来实现这种功能,通过实现InvocationHandler接口来自定义代理类的行为,并通过Proxy类的静态方法newProxyInstance来生成代理对象。
3、Java动态代理的原理解析
// 仔细阅读,全文无废话
Java动态代理的实现原理是基于Java反射机制实现的,主要涉及到三个类:Proxy、InvocationHandler和Method。
首先,我们需要定义一个接口或者一个类,它是被代理的对象。然后,我们需要定义一个实现了InvocationHandler接口的代理类,它需要实现invoke方法来完成代理对象的方法调用。在invoke方法中,我们可以通过反射机制来调用被代理对象的方法,并在方法调用前后添加一些自己的逻辑。
在创建代理对象时,我们使用Proxy类的静态方法newProxyInstance来生成代理对象。这个方法接受三个参数:类加载器、被代理类实现的接口、和代理类的InvocationHandler实例。在生成代理对象时,Proxy类会动态生成一个新的类,这个类继承自被代理类实现的接口,并在其中实现了所有接口方法。这个新生成的类就是代理类,它会调用InvocationHandler实例的invoke方法来完成方法的调用,并在方法调用前后添加自己的逻辑。
当代理对象调用某个方法时,实际上是调用了代理类中实现的方法。代理类中实现的方法会通过Method类的invoke方法来调用InvocationHandler实例的invoke方法,从而完成被代理对象方法的调用,并在调用前后添加自己的逻辑。
总的来说,Java动态代理的原理就是通过生成一个新的代理类来完成对被代理对象的方法调用,并通过InvocationHandler实例来实现代理类的自定义逻辑。这种方式可以实现代理类的动态生成和自定义逻辑的灵活添加,非常适合对原始对象的访问进行控制和扩展。
3、代理模式的应用场景
代理模式作为一种常用的设计模式,它适用于以下几种场景:
-
远程代理:远程代理是指客户端通过代理访问远程对象,代理对象负责与远程对象通信,隐藏了远程对象的实现细节,使得客户端可以像访问本地对象一样访问远程对象。//RPC
-
虚拟代理:虚拟代理是指代理对象在创建时并不会立即加载真实对象,而是等到需要使用时才会去加载,这样可以节省系统资源,并提高系统响应速度。比如,图片加载时可以先使用一张占位图片,等到需要显示时再加载真实图片。
-
安全代理:安全代理是指代理对象在访问真实对象前进行权限检查,保证只有授权用户才能访问真实对象。比如,银行的ATM机只允许授权用户进行取款操作。
-
智能代理:智能代理是指代理对象在访问真实对象时添加一些额外的功能,比如缓存、日志记录、性能监测等。比如,Java中的动态代理可以在访问真实对象前后添加自己的逻辑。
-
延迟加载:延迟加载是指代理对象在访问真实对象时延迟加载某些资源,以避免一次性加载大量资源导致系统性能下降。比如,Java中的Hibernate框架使用代理对象来实现延迟加载,当客户端访问某个对象时,代理对象只加载该对象的部分属性,等到客户端需要访问其他属性时再加载。
总的来说,代理模式适用于那些需要对对象进行访问控制、性能优化、功能增强等场景,它能够提高系统的灵活性、可扩展性和可维护性。