动态代理
- Spring动态代理主要是通过cglib和jdk的动态代理实现.
- Aspectj是一个单独的AOP框架,在编译或运行时生成代理类,可以实现前置增强、环绕增强、后置增强等功能。平时开发可以引入Aspetcj依赖实现一系列代理操作
cglib动态代理
注意:jdk8以上版本对反射进行了限制,需要手动打开。VM参数添加:–add-opens java.base/java.lang=ALL-UNNAMED
实现原理:
创建一个被代理类
新建一个Interceptor实现MethodInterCeptor,重写内部的intercept方法
使用Enhancer获取代理对象
- 创建被代理类:
1 2 3 4 5 6 7 8 9
| package com.haomiao.proxy.dynamic.cglib;
public class SmsService {
public void sendMessage() { System.out.println("send message success"); } }
|
- 实现Interceptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.haomiao.proxy.dynamic.cglib;
import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class DebugInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("proxy start..."); Object object = methodProxy.invokeSuper(o, objects); System.out.println("proxy end..."); return object; } }
|
- 获取代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.haomiao.proxy.dynamic.cglib;
import net.sf.cglib.proxy.Enhancer;
public class CglibFactory {
public static Object getProxy(Class<?> clazz) { Enhancer enhancer = new Enhancer(); enhancer.setClassLoader(clazz.getClassLoader()); enhancer.setSuperclass(clazz); enhancer.setCallback(new DebugInterceptor()); return enhancer.create(); }
}
|
- 测试
1 2 3 4 5 6 7 8 9
| package com.haomiao.proxy.dynamic.cglib;
public class CglibTest {
public static void main(String[] args) { SmsService proxy = (SmsService) CglibFactory.getProxy(SmsService.class); proxy.sendMessage(); } }
|
jdk动态代理
主要流程:
- 创建被代理的接口,实现被代理接口
- 创建一个代理类实现InvocationHandler ,重写invoke方法
- 使用Proxy.newProxyInstance获取代理对象
- 创建被代理的接口
1 2 3 4 5 6 7
| package com.haomiao.proxy.dynamic.jdk;
public interface SmsService {
void sendMessage(); }
|
- 实现被代理的接口
1 2 3 4 5 6 7 8 9
| package com.haomiao.proxy.dynamic.jdk;
public class SmsServiceImpl implements SmsService { @Override public void sendMessage() { System.out.println("send message"); } }
|
- 实现InvocationHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.haomiao.proxy.dynamic.jdk;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;
public class DebugInvocationHandler implements InvocationHandler {
private final Object target;
public DebugInvocationHandler(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("proxy start..."); Object invoke = method.invoke(target, args); System.out.println("proxy end..."); return invoke; } }
|
- 通过Proxy获取代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.haomiao.proxy.dynamic.jdk;
import java.lang.reflect.Proxy;
public class JdkProxyFactory {
public static Object getProxy(Object target) { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new DebugInvocationHandler(target)); }
}
|
- 测试
1 2 3 4 5 6 7 8 9 10
| package com.haomiao.proxy.dynamic.jdk;
public class JdkProxyTest {
public static void main(String[] args) { SmsService proxy = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl()); proxy.sendMessage(); } }
|
cglib和jdk区别
JDK 动态代理是官方的,它要求被代理的类必须实现接口。它的原理是动态生成一个接口的实现类来作为代理。
CGLIB 是第三方的,它不需要接口。它的原理是动态生成一个被代理类的子类来作为代理。但也正因为是继承,所以它不能代理 final 的类,被代理的方法也不能是 final 或 private 。
就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。