# 简介
代理模式可以创造代理对象,替代对真实对象的访问。目的是在不修改原对象的前提下,扩展目标对象并提供额外的功能操作。
代理模式主要分为动态代理和静态代理两种实现方式。
# 动态代理
动态代理是在 JVM 运行时动态生成字节码,并加载到 JVM 中的。
| JDK 动态代理
在 Java 动态代理机制中,InvocationHandler 和 Proxy 类是核心。
* 过程
- 定义接口和接口实现类;
- 通过 Proxy.newProxyInstance() 方法创建代理对象;
重写 InvocationHandler 中的 invoke() 方法,自定义一些处理逻辑;
* 实例
以发送短信为例:
定义发送短信的接口
public interface SmsService {String send(String message);}
实现发送短信的接口
public class SmsServiceImpl implements SmsService {@Overridepublic String send(String message) {System.out.println("send " + message);return message;}}
定义生成代理对象的工厂类 ```java import java.lang.reflect.*;
public static class ProxyFactory { // 代理接口的实现类 public static Object getProxy(Object target) { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { /*
* @param proxy: 生成的动态代理类* @param method: 和代理类对象调用的方法对应;* @param args:当前method方法的参数*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("proxy send " + args[0]);return method.invoke(target, args);}});}// 代理接口public static Object getInterfaceProxy(Class<?> inter) {ClassLoader classLoader = inter.getClassLoader();Class<?>[] interfaces = new Class[]{inter};return Proxy.newProxyInstance(classLoader,interfaces,new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(method.getName());return "None";}});}
}
我们使用动态代理对象调用原对象的原生方法时,实际上是通过 invoke() 方法去调用被代理对象的原生方法。4. 使用动态代理类```javaSmsService smsServiceimpl = (SmsService) ProxyFactory.getProxy(new SmsServiceImpl());smsServiceimpl.send("new value");// out:// proxy send new value// send new valueSmsService smsServiceimpl = (SmsService) ProxyFactory.getInterfaceProxy(SmsService.class);// out:// send
| CGLIB 动态代理
CGLIB 通过生成一个被代理类的子类来拦截被代理类的方法调用。核心是 MethodInterceptor 接口和Enhancer 类。
* 过程
- 定义一个类;
- 定义 MethodInterceptor 方法并重写 intercept(),intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke() 类似;
通过 Enhancer 类的 create() 创建代理类;
* 实例
同样的发短信为例:
实现类
public class AliSmsService {public String send(String message) {System.out.println("send message:" + message);return message;}}
自定义 MethodInterceptor ```java import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
- 自定义MethodInterceptor */ public class DebugMethodInterceptor implements MethodInterceptor {
/*** @param o 代理对象(增强的对象)* @param method 被拦截的方法(需要增强的方法)* @param args 方法入参* @param methodProxy 用于调用原始方法*/@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//调用方法之前,我们可以添加自己的操作System.out.println("before method " + method.getName());Object object = methodProxy.invokeSuper(o, args);//调用方法之后,我们同样可以添加自己的操作System.out.println("after method " + method.getName());return object;}
}
3. 获取代理类```javaimport net.sf.cglib.proxy.Enhancer;public class CglibProxyFactory {public static Object getProxy(Class<?> clazz) {// 创建动态代理增强类Enhancer enhancer = new Enhancer();// 设置类加载器enhancer.setClassLoader(clazz.getClassLoader());// 设置被代理类enhancer.setSuperclass(clazz);// 设置方法拦截器enhancer.setCallback(new DebugMethodInterceptor());// 创建代理类return enhancer.create();}}
- 使用 ```java AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class); aliSmsService.send(“java”);
// out // before method send // send message:java // after method send
<a name="ASbnl"></a>## | JDK 动态代理和 CGLIB 动态代理比较1. JDK 动态代理只能代理接口实现类或者接口。1. CGLIB 可以代理未实现任何接口的类,但是该类不能声明为 final。1. JDK 的动态代理效率更高,优势明显。<a name="HanXp"></a># # 静态代理静态代理实际应用的场景很少,日常几乎不使用静态代理。<a name="MEx6d"></a>## * 过程1. 定义一个接口及其实现类;1. 创建一个代理类同样实现接口;1. 将目标对象注入进代理类,在代理类中调用目标类的对应方法。<a name="x2tbe"></a>## * 实例```javapublic static class SmsServiceProxy implements SmsService {public SmsServiceImpl smsServiceimpl;public SmsServiceProxy(SmsServiceImpl smsServiceimpl) {this.smsServiceimpl = smsServiceimpl;}@Overridepublic String send(String message) {System.out.println("proxy send " + message);smsServiceimpl.send(message);return message;}}public static class SmsServiceImpl implements SmsService {@Overridepublic String send(String message) {System.out.println("send " + message);return message;}}public interface SmsService {String send(String message);}public static void main(String[] args) {SmsServiceImpl smsServiceimpl = new SmsServiceImpl();SmsService smsServiceProxy = new SmsServiceProxy(smsServiceimpl);smsServiceProxy.send("new message");}// out:// proxy send new message// send new message
