目录
技术: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;
- }
-
- }
需要引入相关的依赖 或者导入相关的包。

-
- 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。

1、cglib底层是ASM字节码生成框架,但是字节码技术生成代理类,在JDL1.6之前比使用java反射的效率要高
2、在jdk6之后逐步对JDK动态代理进行了优化,在调用次数比较少时效率高于cglib代理效率
3、只有在大量调用的时候cglib的效率高,但是在1.8的时候JDK的效率已高于cglib