核心思想:应用代理对象来代替原始对象实现对象拜访,这样就能够在不批改原始对象代码的前提下,拓展原始对象的额定性能。
1. 动态代理
动态代理实现步骤:
- 定义一个接口和实现类。
- 定义一个代理类也实现该接口。
- 将指标对象注入到代理类中,而后在代理类的办法中调用对应指标类中的办法。
例子:
-
定义发短信的接口及其实现类
public interface SmsService {String send(String message); } public class SmsServiceImpl implements SmsService { @Override public String send(String message) {System.out.println("send message:" + message); return message; } }
-
创立代理类
public class SmsProxy implements SmsService { private final SmsServiceImpl smsServiceImpl; public SmsProxy(SmsService smsService) {this.smsService = smsService;} @Override public String send(String message) { // 调用办法之前,咱们能够增加本人的操作 System.out.println("before method send()"); smsService.send(message); // 调用办法之后,咱们同样能够增加本人的操作 System.out.println("after method send()"); return null; } }
-
测试
public class Main {public static void main(String[] args) {SmsService smsService = new SmsServiceImpl(); SmsProxy smsProxy = new SmsProxy(smsService); smsProxy.send("java"); } } // 输入 // before method send() // send message:java // after method send()
毛病:
- 接口每新增一个接口,对应的指标类和代理类都须要批改。
- 须要对每个指标类都独自写一个代理类。
2. 动静代理
在运行时利用反射机制动静生成类字节码,并加载到 JVM 中的。
2.1 JDK 动静代理
外围: InvocationHandler 接口和 Proxy 类
JDK 动静代理实现步骤:
- 定义一个接口及其实现类。
- 自定义
InvocationHandler
并重写invoke
办法,在invoke
办法中会调用原生办法并进行拓展逻辑解决。 - 通过
Proxy.newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler h)
办法创立代理对象。
例子:
-
定义一个接口及其实现类。
public interface SmsService {String send(String message); } public class SmsServiceImpl implements SmsService { @Override public String send(String message) {System.out.println("send message:" + message); return message; } }
-
定义 JDK 动静代理类
public class DebugInvocationHandler implements InvocationHandler { /** * 代理类中的实在对象 */ private final Object target; public DebugInvocationHandler(Object target) {this.target = target;} // invoke() 办法: 当咱们的动静代理对象调用原生办法的时候,最终实际上调用到的是 invoke() 办法,而后 invoke() 办法代替咱们去调用了被代理对象的原生办法。@Override public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException { // 调用办法之前,咱们能够增加本人的操作 System.out.println("before method" + method.getName()); Object result = method.invoke(target, args); // 调用办法之后,咱们同样能够增加本人的操作 System.out.println("after method" + method.getName()); return result; } }
-
获取代理对象的工厂,应用 Proxy.newProxyInstance()办法创立代理对象
public class JdkProxyFactory {public static Object getProxy(Object target) { return Proxy.newProxyInstance(target.getClass().getClassLoader(), // 指标类的类加载 target.getClass().getInterfaces(), // 代理须要实现的接口,可指定多个 new DebugInvocationHandler(target) // 代理对象对应的自定义 InvocationHandler ); } }
-
应用 Proxy.newProxyInstance()办法创立代理对象
SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl()); smsService.send("java"); // 输入 // before method send // send message:java // after method send
毛病:
- 只能代理实现了接口的类。
2.2 cglib 动静代理
** 外围:通过继承的形式实现代理,MethodIntercept 接口和 Enhancer 类。
cglib 动静代理实现步骤:
- 定义一个类。
- 自定义
MethodIntercept
并重写intercept
办法,intercept
用于拦挡原生类的办法,相似于 JDK 动静代理中的invoke
。 - 通过
Enhancer
的create()
创立代理对象。
例子:
-
定义一个类
public class AliSmsService {public String send(String message) {System.out.println("send message:" + message); return message; } }
-
自定义 MethodIntercept 并重写 intercept 办法
public class DebugMethodInterceptor implements MethodInterceptor { /** * @param o 被代理的对象(须要加强的对象)* @param method 被拦挡的办法(须要加强的办法)* @param args 办法入参 * @param methodProxy 用于调用原始办法 */ @Override public 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; } }
-
通过 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();} }
-
理论应用
AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class); aliSmsService.send("java"); // 输入 // before method send // send message:java // after method send
2.3 JDK 动静代理和 cglib 动静代理区别
- JDK 动静代理只能代理实现了接口的类,而 cglib 能够代理未实现任何接口的类。cglib 通过生成原生类的子类来拦挡被代理类的的办法调用,因而 cglib 不能代理被 final 润饰的类和办法。
- jdk 效率更高。SpringAOP 中如果原生类实现了接口,默认应用 JDK 动静代理,否则应用 cglib。
参考文献:
https://snailclimb.gitee.io/j…