- 静态代理
- 概念:
- 静态代理是代理模式的一种简单实现。在这种模式中,代理类和被代理类在编译时期就已经确定了关系。代理类需要实现与被代理类相同的接口,并且在代理类中持有被代理类的一个实例,通过调用被代理类的方法来实现功能的扩展和控制。
- 示例代码:
- 首先定义一个接口,例如
Subject
接口:
public interface Subject { void doSomething(); }
- 然后实现一个被代理类
RealSubject
:
public class RealSubject implements Subject { @Override public void doSomething() { System.out.println("RealSubject is doing something."); } }
- 接着创建代理类
ProxySubject
:
public class ProxySubject implements Subject { private RealSubject realSubject; public ProxySubject() { this.realSubject = new RealSubject(); } @Override public void doSomething() { System.out.println("Before RealSubject do something."); realSubject.doSomething(); System.out.println("After RealSubject do something."); } }
- 在主程序中使用代理类:
public class Main { public static void main(String[] args) { Subject subject = new ProxySubject(); subject.doSomething(); } }
- 在这个例子中,
ProxySubject
是RealSubject
的代理。当调用ProxySubject
的doSomething
方法时,它会在真正调用RealSubject
的doSomething
方法前后添加额外的逻辑,如打印一些提示信息。 - 优缺点:
- 优点:
- 简单易懂,代码结构清晰。在代理类中可以方便地对被代理类的方法进行增强,比如添加日志记录、权限验证等功能。
- 缺点:
- 代理类和被代理类需要实现相同的接口,并且每一个被代理类都需要编写一个对应的代理类。如果接口和被代理类很多,会导致代码量急剧增加,维护成本变高。例如,如果有 10 个被代理类,就需要编写 10 个代理类。
- 动态代理
- 概念:
- 动态代理是在运行时动态地生成代理类。它不需要像静态代理那样在编译时期就为每个被代理类编写一个代理类。Java 提供了两种动态代理方式:基于 JDK 的动态代理和基于 CGLIB 的动态代理。JDK 动态代理是通过反射机制来实现的,它要求被代理对象必须实现一个或多个接口;CGLIB 动态代理是通过字节码生成技术来实现的,可以代理没有实现接口的类。
- JDK 动态代理示例代码:
- 还是使用上面的
Subject
接口和RealSubject
类。首先,创建一个动态代理类的处理器SubjectHandler
:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class SubjectHandler implements InvocationHandler { private Object target; public SubjectHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before RealSubject do something."); Object result = method.invoke(target, args); System.out.println("After RealSubject do something."); return result; } }
- 在主程序中使用动态代理:
public class Main { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); SubjectHandler handler = new SubjectHandler(realSubject); Subject subject = (Subject) Proxy.newProxyInstance( RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), handler); subject.doSomething(); } }
- 在这里,
SubjectHandler
是一个实现了InvocationHandler
接口的类,它的invoke
方法会在代理对象的方法被调用时执行。通过Proxy.newProxyInstance
方法动态地生成了一个代理对象,这个代理对象实现了RealSubject
的接口,并且在调用接口方法时会执行SubjectHandler
中的invoke
方法,从而实现了对RealSubject
方法的增强。 - CGLIB 动态代理示例代码(需要添加 CGLIB 库):
- 假设我们有一个没有实现接口的类
NonInterfaceClass
:
public class NonInterfaceClass { public void doSomething() { System.out.println("Non - Interface Class is doing something."); } }
- 创建 CGLIB 代理类的处理器
CglibSubjectHandler
:
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibSubjectHandler implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("Before Non - Interface Class do something."); Object result = methodProxy.invokeSuper(obj, args); System.out.println("After Non - Interface Class do something."); return result; } }
- 在主程序中使用 CGLIB 动态代理:
public class Main { public static void main(String[] args) { CglibSubjectHandler handler = new CglibSubjectHandler(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(NonInterfaceClass.class); enhancer.setCallback(handler); NonInterfaceClass nonInterfaceClass = (NonInterfaceClass) enhancer.create(); nonInterfaceClass.doSomething(); } }
- 在 CGLIB 动态代理中,
Enhancer
类用于创建代理对象。setSuperclass
方法指定了要代理的类,setCallback
方法设置了代理的处理器。当代理对象的方法被调用时,会执行CglibSubjectHandler
中的intercept
方法来实现方法的增强。 - 优缺点:
- 优点:
- 动态代理更加灵活。可以在运行时根据需要动态地生成代理类,不需要为每个被代理类编写一个代理类,减少了代码的冗余。特别是在处理大量相似的代理场景时,效率更高。
- 缺点:
- JDK 动态代理要求被代理对象必须实现接口,这在一定程度上限制了它的使用范围。CGLIB 动态代理虽然可以代理没有实现接口的类,但它是通过字节码生成技术实现的,可能会有一些性能损耗,并且在某些复杂的场景下可能会出现兼容性问题。不过,在大多数情况下,这些性能损耗是可以接受的。