java基础之代理
代理模式(Proxy Pattern)
简介
- 是一种结构型设计模式,主要用于为某对象提供一个代理对象,以控制对该对象的访问。
- 通过引入一个代理对象来控制对原对象的访问。代理对象在客户端和目标对象之间充当中介,负责将客户端的请求转发给目标对象,同时可以在转发请求前后进行额外的处理(如权限控制、延迟加载、日志记录等)而不修改目标对象的代码。
- 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
元素
- 抽象主题(Subject):定义了真实主题和代理主题的共同接口,这样在任何使用真实主题的地方都可以使用代理主题。
- 真实主题(Real Subject):实现了抽象主题接口,是代理对象所代表的真实对象。客户端直接访问真实主题,但在某些情况下,可以通过代理主题来间接访问。
- 代理(Proxy):实现了抽象主题接口,并持有对真实主题的引用。代理主题通常在真实主题的基础上提供一些额外的功能,例如延迟加载、权限控制、日志记录等。
- 客户端(Client):使用抽象主题接口来操作真实主题或代理主题,不需要知道具体是哪一个实现类。
类型
- 静态代理(Static Proxy):代理类在编译时就已经确定,代理类与目标类实现相同的接口。
- 动态代理(Dynamic Proxy):代理类在运行时动态生成,通常使用 Java 的 java.lang.reflect.Proxy 或 CGLIB 库来实现。
- 保护代理(Protection Proxy):控制对目标对象的访问权限。
- 虚拟代理(Virtual Proxy):通过代理对象来延迟对真实对象的创建或初始化。
- 缓存代理(Cache Proxy):通过代理对象在一定时间内缓存目标对象的结果,从而提升性能。
优点
- 职责分离:代理模式将访问控制与业务逻辑分离。
- 扩展性:可以灵活地添加额外的功能或控制。
- 智能化:可以智能地处理访问请求,如延迟加载、缓存等。
缺点
- 性能开销:增加了代理层可能会影响请求的处理速度。
- 实现复杂性:某些类型的代理模式实现起来可能较为复杂。
静态代理
静态代理是一种在编译期就确定的代理模式。代理类需要实现与目标类相同的接口,客户端通过代理类调用目标对象的方法。静态代理通常用于在方法调用前后添加额外操作,比如日志记录、安全检查等。
动态代理
动态代理是在运行时动态生成代理类,而不是在编译时生成。动态代理的优势是减少了重复的代理类代码,并且能够在运行时灵活地处理方法调用。
jdk动态代理和cglib动态代理
JDK动态代理 | CGLIB动态代理 | |
---|---|---|
代理对象 | 必须实现接口 | 不需要实现接口 |
代理方式 | 基于接口和反射 | 基于字节码生成子类 |
性能 | 创建代理开销小,方法调用开销较高 | 创建代理开销大,方法调用性能较好 |
限制 | 不能代理没有接口的类 | 不能代理final类和final方法 |
使用场景 | 适用于接口驱动的开发 | 适用于没有接口的类 |
spring AOP默认 | 接口时使用JDK动态代理 | 没有接口时使用CGLIB动态代理 |
代码示例
静态代理
interface Subject {
void doAction();
}
class RealSubject implements Subject {
@Override
public void doAction() {
System.out.println("doAction in RealSubject.");
}
}
class MyProxy implements Subject {
private RealSubject realSubject;
public MyProxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void doAction() {
System.out.println("Before doing action.");
realSubject.doAction();
System.out.println("After doing action.");
}
}
public class StaticProxyExample {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
MyProxy myProxy = new MyProxy(realSubject);
myProxy.doAction();
}
}
JDK动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Subject {
void doAction();
}
class RealSubject implements Subject {
@Override
public void doAction() {
System.out.println("doAction in RealSubject.");
}
}
class MyInvocationHandler implements InvocationHandler {
private final Object realSubject;
public MyInvocationHandler(Object realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before doing action.");
Object result = method.invoke(realSubject, args);
System.out.println("After doing action.");
return result;
}
}
public class DynamicProxyExample {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Subject subject = (Subject) Proxy.newProxyInstance(
RealSubject.class.getClassLoader(),
new Class[]{Subject.class},
new MyInvocationHandler(realSubject)
);
subject.doAction();
}
}
cglib动态代理
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
class RealSubject {
public void doAction() {
System.out.println("doAction in RealSubject.");
}
}
class MyProxy implements MethodInterceptor {
private Object target;
public MyProxy(Object target) {
this.target = target;
}
public Object getProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before doing action.");
Object result = proxy.invokeSuper(obj, args);
System.out.println("Before doing action.");
return result;
}
}
public class StaticProxyExample {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
MyProxy proxy = new MyProxy(realSubject);
RealSubject proxyService = (RealSubject) proxy.getProxyInstance();
proxyService.doAction();
}
}