JDK动态代理和CGLIB动态代理的区别
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
- JDK动态代理只提供接口的代理,不支持类的代理
(1)JDK会在运行时为目标类生成一个 动态代理类$proxy*.class .
(2)该代理类是实现了接目标类接口, 并且代理类会实现接口所有的方法增强代码。
(3)调用时 通过代理类先去调用处理类进行增强,再通过反射的方式进行调用目标方法。从而实现AOP - 如果代理类没有实现 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
(1)CGLIB的底层是通过ASM在运行时动态的生成目标类的一个子类。(还有其他相关类,主要是为增强调用时效率) 会生成多个 ,
(2)并且会重写父类所有的方法增强代码,
(3)调用时先通过代理类进行增强,再直接调用父类对应的方法进行调用目标方法。从而实现AOP。 - CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
- CGLIB 除了生成目标子类代理类,还有一个FastClass(路由类),可以(但不是必须)让本类方法调用进行增强,而不会像jdk代理那样本类方法调用增强会失效
- 很多人会对比 JDK和Cglib的性能,jdk动态代理生成类速度快,调用慢,cglib生成类速度慢,但后续调用
快,在老版本CGLIB的速度是JDK速度的10倍左右, 但是实际上JDK的速度在版本升级的时候每次都提高很多性能,而
CGLIB仍止步不前.
在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。
额外扩展
一、动态代理有什么用
- 他能创建对象
- 在原有代码不变不改动的情况下,对原有功能进行增强(有点像装饰者模式)
- 解耦合,让你的业务功能和日志,分离
二、两种实现方式
(1)、JDK动态代理:
- 通过这三个类 Proxy,method,invocationhandler来实现。
- 要求目标类必须实现接口
(2)、CGLIB 动态代理
- 原理是继承
- 通过创建子类,来重写父类的方法,来达到增强目标类方法。
三、JDK动态代理 代码演示
开发步骤:
- 创建目标类接口 SomeService
package com.mr.lee.service;
public interface SomeService {
public String doSome();
public String doOther();
}
- 创建目标类,SomeServiceImpl 目标类
package com.mr.lee.service;
public class SomeServiceImpl implements SomeService{
@Override
public String doSome() {
System.out.println("执行了doSome方法");
return "abc";
}
@Override
public String doOther() {
System.out.println("执行了doOther方法");
return "abc";
}
}
- 创建InvocationHandler 接口的实现类,在这个类实现给目标方法增强功能
package com.mr.lee.dao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 实现InvocationHandler接口,用来给目标方法增强功能
*/
public class MyInvocationHandler implements InvocationHandler {
//目标对象
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//通过代理对象执行方法时,会执行这个invoke方法
Object res = null;
//执行目标类的方法,通过method类实现
System.out.println("当前执行的方法是:" + method.getName());
if(method.getName().equals("doSome")){
System.out.println("当前执行时间:" + System.currentTimeMillis());
res = method.invoke(target,args);//相当于SomeServiceImpl.doSome()方法
System.out.println("执行结束时间:" + System.currentTimeMillis());
return res;
}
return method.invoke(target,args);//相当于SomeServiceImpl.doSome()方法
}
}
- 使用jdk中类proxy,创建代理对象,实现创建对象的能力
package com.mr.lee;
import com.mr.lee.dao.MyInvocationHandler;
import com.mr.lee.service.SomeService;
import com.mr.lee.service.SomeServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class AppTest
{
@Test
public void shouldAnswerWithTrue()
{
SomeService target = new SomeServiceImpl();
InvocationHandler handler = new MyInvocationHandler(target);
//使用Proxy创建代理对象
SomeService proxy = (SomeService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
//通过代理执行方法,会调用handler中的invoke方法
proxy.doSome();
proxy.doOther();
}
}
运行结果
当前执行的方法是:doSome
当前执行时间:1664091059671
执行了doSome方法
执行结束时间:1664091059671
当前执行的方法是:doOther
执行了doOther方法
Process finished with exit code 0
四、CGLIB 动态代理
- APO底层的实现就是动态代理,AOP就是对动态代理进行的一种规范化。
- 原理是继承来实现:创建子类, 子类就是代理对象,要求目标类和方法都不可以是final的,