jdk动态代理
作用:动态代理可以在不改变原类的情况下对该类的功能进行增强,在动态代理中我们不需要写代理类即可对该类进行增强。
例如:当导演要找演员演电影时,我们不会去自己找演员,而是找演员的经纪人,经纪人对演员能做什么进行规定。演员只负责演电影。
而在动态代理中我们可以通过InvocationHandler类生成代理。
要使用动态代理,该类必须实现一个接口
public interface SuperStarCan {
void play();
}
public class SuperStar implements SuperStarCan {
@Override
public void play() {
System.out.println("我决定出演这部戏");
}
}
写一个invocationH。。。的实现类,实现该接口的类必须重写invoke方法,
public class InvocationHandlerImpl implements InvocationHandler {
//要代理的真实对象
private Object target;
//构造方法,给我们要代理的真实对象赋初始值
public InvocationHandlerImpl(Object target){
this.target=target;
}
/**
*该方法集中处理动态代理类上的所有方法调用
* 调用 处理器根据这三个参数进行预处理或分派到委托实例上反射执行
* @param proxy 代理类实例
* @param method 被调用的方法对象
* @param args 调用方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//当代理对象调用真实对象的方法时,它会自动地跳转到代理对象关联地handler对象地invoke方法进行调用
Object invoke = method.invoke(target, args);
return invoke;
}
}
创建一个测试类
class InvocationHandlerImplTest {
@Test
void createDynamicProxyAbdInvoke(){
SuperStarCan superStar = new SuperStar();
InvocationHandler invocationHandler = new InvocationHandlerImpl(superStar);
SuperStarCan proxyInstance = (SuperStarCan) Proxy.newProxyInstance(superStar.getClass().getClassLoader(), superStar.getClass().getInterfaces(), invocationHandler);
proxyInstance.play();
}
}
CGLIB动态代理
与jdk动态代理相比,使用的类不用实现某个接口,不过得引入对应得包
CGLib 的原理是对指定目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对 final 修饰的类进行代理。
dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.2</version>
</dependency>
public class SuperStar {
public void play() {
System.out.println("我决定出演这部戏");
}
}
public class StarProxy implements MethodInterceptor {
private Object target;
public StarProxy(Object target) {
this.target = target;
}
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//调用父类的方法
Object result = proxy.invokeSuper(object, args);
return result;
}
}
class StarProxyTest {
@Test
void test(){
SuperStar superStar = new SuperStar();
StarProxy starProxy = new StarProxy(superStar);
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(superStar.getClass());
enhancer.setCallback(starProxy);
SuperStar superStarProxy = (SuperStar) enhancer.create();
superStarProxy.play();
}
}
JDK动态代理和CGLIB动态代理的区别
JDK 动态代理,JDK 动态代理的类必须实现一个接口,而且生成的代理类是其接口的实现类,也就是被代理的类的兄弟类,由JDK内部实现,无需引入Jar包
CGLIB代理的类,无需强制实现接口,其生成的代理类是被代理类的子类,并且重写被代理类的方法,而且需要额外的引入Jar
JDK动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象。
JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。
JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高。