JDK动态代理和Cglib动态代理原理与区别
2.2动态代理实现
2.2.1JDK动态代理实现
只能针对接口进行代理
public class JDKProxy {public static void main(String[] args) {//目标对象Targer targer = new Targer();//当前类的类加载器ClassLoader loader = JDKProxy.class.getClassLoader();//Proxy.newProxyInstance : 创建一个新的代理实例,运行期间生成代理类的字节码/*参数说明:loader 加载代理类在运行期间动态生成的字节码new Class[]可以代理多个Foo接口对行为进行封装*/Foo proxy = (Foo)Proxy.newProxyInstance(loader, new Class[]{Foo.class}, new InvocationHandler() {//参数说明:代理对象自己、正在执行的方法对象、方法传来的实际参数@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before...");//目标 方法(参数)//方法反射调用目标对象//目标对象 和 参数Object result = method.invoke(targer, args);//让代理也返回目标方法执行的结果System.out.println("after...");return result;}});//调用代理的父方法proxy.foo();}interface Foo{void foo();}static class Targer implements Foo{@Overridepublic void foo() {System.out.println("target foo");}}
}
- 代理类和目标类是兄弟关系,所以目标类可以被final修饰
原理:
以下是一个半成品的proxy,可以看到实现的方式很巧妙
- 调用类
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;/* @author 我见青山多妩媚* @date 2023/4/15 0015 16:06* @Description TODO*/
public class Proxy$0 {interface Foo{int foo();void bar();}static class Target implements Foo {@Overridepublic int foo() {System.out.println("target foo");return 1;}@Overridepublic void bar() {System.out.println("bar foo");}}public static void main(String[] args) {Foo proxy = new $Proxy0(new InvocationHandler() {@Overridepublic Object invoke(Object proxy,Method method,Object[] args) throws InvocationTargetException, IllegalAccessException {//1.实现功能增强System.out.println("before...");//2.调用目标
// new Target().foo();//反射调用return method.invoke(new Target(),args);}});proxy.foo();proxy.bar();}//抽象成一个代理接口,所有代理的方法就不用写在代理内内部,具体实现具体做,不会写死,成为动态代理interface InvocationHandler{public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;}}
- 代理类
import com.example.springreaddemo.SpringRead.Demo02_SpringAop.proxy.JDK.Proxy$0.Foo;
import com.example.springreaddemo.SpringRead.Demo02_SpringAop.proxy.JDK.Proxy$0.InvocationHandler;import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;/* @author 我见青山多妩媚* @date 2023/4/15 0015 15:59* @Description TODO*/
//JDK 代理类
public class $Proxy0 implements Foo {private InvocationHandler invocationHandler;public $Proxy0(InvocationHandler invocationHandler){this.invocationHandler = invocationHandler;}@Overridepublic int foo() {try {//将foo的方法 以及 方法参数传过去,调用foo方法Object invoke = invocationHandler.invoke(this,foo, new Object[0]);return (int)invoke;} catch (RuntimeException | Error e) { //运行时异常直接抛出throw e;} catch (Throwable e){throw new UndeclaredThrowableException(e); //检查异常转化为运行异常抛出}}@Overridepublic void bar() {try {//将foo的方法 以及 方法参数传过去,调用bar方法invocationHandler.invoke(this,bar,new Object[0]);} catch (Throwable e) {e.printStackTrace();}}static Method foo;static Method bar;static {try {foo = Foo.class.getMethod("foo");bar = Foo.class.getMethod("bar");} catch (NoSuchMethodException e) {throw new NoSuchMethodError(e.getMessage()); //比较严重的问题}}}
JDK生成的代理类,不会有源码阶段,直接到字节码,这个动态生成代理类并且直接到字节码的方式叫ASM
2.2.2cglib代理实现
与JDK不同,可以针对很对进行代理
public class CglibProxy {static class Target{public void foo(){System.out.println("target foo...");}}public static void main(String[] args) {Target target = new Target();Target proxy = (Target)Enhancer.create(Target.class, new MethodInterceptor() {@Override/*参数:1.o 代理类自己2.method 代理类内执行的方法3.objects 参数4.方法对象,和method参数有些区别*/public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("before...");
// method.invoke(target,objects); //方法反射调用目标//methodProxy 可以避免反射调用 内部没有用反射
// Object result = methodProxy.invoke(target, objects); //需要目标才能调用自己 spring使用的是这个Object result = methodProxy.invokeSuper(o, objects); //内部没有用反射,需要代理System.out.println("after...");return result;}});proxy.foo();}
}
-
代理类是目标类的子类,所以目标类不能被final修饰,
-
因为是代理,相当于是对目标类的方法重写,所以方法也不能被final修饰
内部实现:
我们知道cglib是根据继承实现的,我们这有个父类
- Target
public class Target {public void save(){System.out.println("save");}public void save(int i){System.out.println(i+"save");}public void save(long i){System.out.println("save long");}
}
- Proxy
public class Proxy extends Target {private MethodInterceptor methodInterceptor;public void setMethodInterceptor(MethodInterceptor methodInterceptor){this.methodInterceptor = methodInterceptor;}static Method save0;static Method save1;static Method save2;static MethodProxy save0Proxy;static MethodProxy save1Proxy;static MethodProxy save2Proxy;static {try {save0 = Target.class.getMethod("save");save1 = Target.class.getMethod("save", int.class);save2 = Target.class.getMethod("save", long.class);//参数://目标对象//代理对象//方法参数描述符//带增强功能的方法//带原始功能的方法save0Proxy = MethodProxy.create(Target.class,Proxy.class,"()V","save","saveSuper");//参数类型为整型save1Proxy = MethodProxy.create(Target.class,Proxy.class,"(I)V","save","saveSuper");//长整型为大写Jsave2Proxy = MethodProxy.create(Target.class,Proxy.class,"(J)V","save","saveSuper");} catch (NoSuchMethodException e) {throw new NoSuchMethodError(e.getMessage());}}//代理原始功能的方法public void saveSuper(){super.save();}public void saveSuper(int i){super.save(i);}public void saveSuper(long i){super.save(i);}//属于待增强功能的方法@Overridepublic void save() {try {methodInterceptor.intercept(this,save0,new Object[0],save0Proxy);} catch (Throwable e) {throw new UndeclaredThrowableException(e);}}@Overridepublic void save(int i) {try {methodInterceptor.intercept(this,save1,new Object[]{i},save1Proxy);} catch (Throwable e) {throw new UndeclaredThrowableException(e);}}@Overridepublic void save(long i) {try {methodInterceptor.intercept(this,save2,new Object[]{i},save2Proxy);} catch (Throwable e) {throw new UndeclaredThrowableException(e);}}
}
- Main
public class Main {public static void main(String[] args) {Proxy proxy = new Proxy();Target target = new Target();proxy.setMethodInterceptor(new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects,MethodProxy methodProxy) throws Throwable {System.out.println("before...");//内部有反射
// return method.invoke(target,objects);//内部无反射调用 结合目标使用
// return methodProxy.invoke(target,objects);//内部无反射return methodProxy.invokeSuper(o,objects);}});proxy.save();proxy.save(1);proxy.save(2L);}
}
内部实现,和jdk的区别,他可以做到不使用反射进行动态的代理
不使用反射调用的原理:
package com.example.springreaddemo.SpringRead.Demo02_SpringAop.proxy.Cglib;import org.springframework.cglib.core.Signature;/* @author 我见青山多妩媚* @date 2023/4/16 0016 20:21* @Description TODO*/
//desc 不用反射实现代理的原理
public class TargetFastClass {//将目标对象的方法对应为三个签名static Signature s0 = new Signature("save","()V");static Signature s1 = new Signature("save","(I)V");static Signature s2 = new Signature("save","(J)V");/* 根据方法的前面信息,获取目标方法的编号 save 0* save(int i) 1* save(long i) 2* @param signature 签名 包括方法的名字、参数、返回值等等* @return 编号*/public int getIndex(Signature signature){if(s0.equals(signature)){return 0;}else if (s1.equals(signature)){return 1;}else if(s2.equals(signature)){return 2;}else {return -1;}}/* 根据获取到的方法编号,调用目标对象中的方法* @param index 编号* @param target 目标对象* @param args 参数列表* @return 返回目标对象*/public Object invoke(int index,Object target,Object[] args){if(index == 0){((Target) target).save();return null;}else if(index == 1){((Target) target).save((int) args[0]);return null;}else if(index == 2){((Target) target).save((long) args[0]);return null;}else{throw new RuntimeException("无此方法");}}
}
MethodProxy内部不使用反射的原理:
public class ProxyFastClass {//将目标对象的方法对应为三个签名static Signature s0 = new Signature("saveSuper","()V");static Signature s1 = new Signature("saveSuper","(I)V");static Signature s2 = new Signature("saveSuper","(J)V");/* 根据方法的前面信息,获取目标方法的编号 save 0* save(int i) 1* save(long i) 2* @param signature 签名 包括方法的名字、参数、返回值等等* @return 编号*/public int getIndex(Signature signature){if(s0.equals(signature)){return 0;}else if (s1.equals(signature)){return 1;}else if(s2.equals(signature)){return 2;}else {return -1;}}/* 根据获取到的方法编号,调用目标对象中的方法* @param index 编号* @param proxy 代理对象* @param args 参数列表* @return 返回目标对象*/public Object invoke(int index,Object proxy,Object[] args){if(index == 0){((Proxy) proxy).saveSuper();return null;}else if(index == 1){((Proxy) proxy).saveSuper((int) args[0]);return null;}else if(index == 2){((Proxy) proxy).saveSuper((long) args[0]);return null;}else{throw new RuntimeException("无此方法");}}public static void main(String[] args) {ProxyFastClass proxyFastClass = new ProxyFastClass();int index = proxyFastClass.getIndex(new Signature("saveSuper", "()V"));System.out.println(index);proxyFastClass.invoke(index,new Proxy(),new Object[0]);}
}
实际上就是调用了代理类
区别
jdk在调用第17次时一个方法生成一个代理类,而cglib会给生成一个代理类,对应两个fastClass,一个对应目标代理,一个对代理类代理,生成的代理类数目比jdk少