目录
动态代理
JDK动态代理实现
技术:java反射
前提:代理的类实现了接口。
通过newProxyInstance()函数获得proxy对象,这个对象就代理了实现了这个接口所有的类,然后使用这个代理对象即可。 代理对象会自动调用相应的方法。比如
IRpcHelloService RpcHello = RpcProxy.create(IRpcHelloService.class);
System.out.println(RpcHello.hello("Tom老师"));
RpcHello
是 IRpcHelloService.class这个接口的代理类,IRpcHelloServiceImpl实现了这个接口,那么RpcHello.hello("Tom老师")就相当于调用了IRpcHelloServiceImpl中的hello方法。
newProxyInstance,方法有三个参数:
loader: 用哪个类加载器去加载代理对象
interfaces:动态代理类需要实现的接口
h:动态代理方法在执行时,会调用h里面的invoke方法去执行
public class ProxyHost implements InvocationHandler {
private Object target;
// 注入一个实现类
public void setTarget(Object target) {
this.target = target;
}
// 根据实现类 拿到其实现的方法
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
// 在使用时直接调用方法即可
// 调用时就会通过 invoke来实现
@Override
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
System.out.println("调用方法前的日志");// 在调用原对象的方法时 可以增强
Object result = method.invoke(target,args);
System.out.println("调用方法后的日志");
return result;
}
}
cglib动态代理
需要引入相关的依赖 或者导入相关的包。
public class ProxyFactory implements MethodInterceptor {
//维护一个目标对象
private Object target;
//构造器,传入一个被代理的对象
public ProxyFactory(Object target) {
this.target = target;
}
//返回一个代理对象: 是 target 对象的代理对象
public Object getProxyInstance() {
//1. 创建一个工具类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(target.getClass());
//3. 设置回调函数
enhancer.setCallback(this);
//4. 创建子类对象,即代理对象
return enhancer.create();
}
//重写 intercept 方法,会调用目标对象的方法
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
System.out.println("Cglib代理模式 ~~ 开始");
Object returnVal = method.invoke(target, args);
System.out.println("Cglib代理模式 ~~ 提交");
return returnVal;
}
}
测试
创建代理对象的性能测试
使用JMH进行测试
可以看到创建代理对象时 JDK速度远大于Cglib,这是由于cglib创建对象时需要操作字节码。
代表的是每秒中jdk可以执行下列方法 1926W 次, 也就是创建代理类 1926W 次。
@Benchmark
public void testJDK() {
ITeacherDao target = new TeacherDao();
ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
}
@Benchmark
public void testCGLIB() {
TeacherDaoCglib target2 = new TeacherDaoCglib();
TeacherDaoCglib proxyInstance2 = (TeacherDaoCglib)new ProxyFactoryCglib(target2).getProxyInstance();
}
调用代理对象方法的性能测试
先测的两组配置参数如下,测试结果两次不一致。
@BenchmarkMode({Mode.Throughput}) @Warmup(iterations = 3,time = 3,timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 3, time = 5,timeUnit = TimeUnit.SECONDS)
加大测试的组数和每组时间后,结果显示 JDK执行速度高于Cglib。
总结
Cglib执行速度比JDK快? 不同jdk版本不一样。
1、cglib底层是ASM字节码生成框架,但是字节码技术生成代理类,在JDL1.6之前比使用java反射的效率要高
2、在jdk6之后逐步对JDK动态代理进行了优化,在调用次数比较少时效率高于cglib代理效率
3、只有在大量调用的时候cglib的效率高,但是在1.8的时候JDK的效率已高于cglib
JDK 1.8 动态代理 JDK > Cglib
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/92789.html