什么是代理模式?
代理模式(Proxy Pattern)是一种经典的设计模式,它提供了一个代理对象来控制对另一个对象的访问。
代理模式主要解决的是对象直接的业务关系,即将行为请求和行为实现分离出来,以达到增强类的功能的目的。
Java代理模式的分类
Java代理模式可以分为三类:静态代理、动态代理和CGLIB代理。
静态代理
静态代理是指在程序运行前已经确定需要代理的类或接口,因此在Java的编译期间可以动态地生成代理类。
下面是一个静态代理的示例:
// 接口
public interface ISubject {
void doSomething();
}
// 实现类
public class RealSubject implements ISubject {
@Override
public void doSomething() {
System.out.println("Real subject do something.");
}
}
// 代理类
public class StaticProxy implements ISubject {
private ISubject realSubject;
public StaticProxy(ISubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void doSomething() {
System.out.println("Before real subject do something.");
realSubject.doSomething();
System.out.println("After real subject do something.");
}
}
在上面的示例中,ISubject
是一个接口,定义了需要被代理的类的行为。
RealSubject
是实现了ISubject
接口的具体类,StaticProxy
是ISubject
接口的代理类,它通过构造函数接收一个ISubject
类型的对象,并在代理中透明地调用了该对象。
代理类在方法调用前后执行了一些逻辑,可以用来添加额外的功能,如日志记录、安全检查等。
动态代理
动态代理是指在程序运行时,通过反射机制对需要代理的类或接口进行代理,因此不需要事先知道需要代理的类或接口,也不需要声明与它匹配的代理类。
动态代理在Java中主要通过java.lang.reflect.Proxy
类实现。
下面是一个动态代理的示例:
// 接口
public interface ISubject {
void doSomething();
}
// 实现类
public class RealSubject implements ISubject {
@Override
public void doSomething() {
System.out.println("Real subject do something.");
}
}
// InvocationHandler实现类
public class DynamicProxy implements InvocationHandler {
private Object realObject;
public DynamicProxy(Object realObject) {
this.realObject = realObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before real subject do something.");
Object result = method.invoke(realObject, args);
System.out.println("After real subject do something.");
return result;
}
}
同上,ISubject
是一个接口,定义了需要被代理的类的行为。
RealSubject
是实现了ISubject
接口的具体类。
DynamicProxy
是动态代理类的实现类,它实现了InvocationHandler
接口,并在代理中透明地调用了被代理对象。代理类可以在方法调用前后执行一些逻辑。
由于动态代理在运行时通过反射机制生成代理对象,因此需要保证被代理的类或接口具有一些特定的条件:必须是一个接口或者是继承了至少一个接口的类,同时这些接口必须是public访问权限的。
CGLIB代理
CGLIB代理是指使用CGLIB库动态生成子类代理的过程,它可以直接对类进行代理,因此被代理的类无需实现任何接口。
下面是一个使用CGLIB代理的示例:
// 实现类
public class RealSubject {
public void doSomething() {
System.out.println("Real subject do something.");
}
}
// MethodInterceptor实现类
public class CGLIBProxy implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before real subject do something.");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After real subject do something.");
return result;
}
}
// 测试类
public class TestCGLIBProxy {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new CGLIBProxy());
RealSubject proxy = (RealSubject) enhancer.create();
proxy.doSomething();
}
}
在上面的示例中,RealSubject
是一个具体的实现类,没有实现任何接口。
CGLIBProxy
是基于CGLIB库实现的代理类,它实现了MethodInterceptor
接口,并在代理中透明地调用了被代理对象。CGLIB代理需要使用Enhancer
类来创建代理对象。
Java代理模式的应用场景
Java代理模式比较适合在以下情况下使用:
- 远程代理:将网络中的一个对象作为本地对象使用,通过网络的方式实现远程方法调用。
- 虚拟代理:缓存对象的创建和销毁等开销较大的操作,将这些操作延迟到真正需要的时候再执行。
- 安全代理:控制对象的访问权限,保证只有授权的用户才能使用对象。
- 智能代理:在访问对象的时候,加入一些额外的逻辑,如调用对象前后执行一些操作、记录日志等。
- 延迟加载:当需要的时候再去创建对象,从而优化系统性能或者节约资源。
结论
Java代理模式是一种经典的设计模式,可以帮助我们将行为请求和行为实现分离出来,以达到增强类的功能的目的。根据Java代理模式的不同实现方式,我们可以将代理分为静态代理、动态代理和CGLIB代理三种不同的类型。在实际开发中,我们可以根据具体业务场景的不同来选择使用不同的代理类型。