文章目录
- 静态代理
- 动态代理
- jdk动态代理
- JDK生成的动态代理类大概源码
- cglib动态代理
代理模式就是用代理对象代替真实对象去完成相应的操作,并且能够在操作执行的前后对操作进行增强处理。
静态代理
mybatis使用的就是静态代理,相比动态代理,静态代理在编译期间就确定了代理类,因此在运行时的性能通常会比动态代理更好。
步骤:定义接口,真实类实现接口,代理类也实现接口
真实场景,我们现在有一个歌手,歌手只想唱歌,不想管其他的事情,这时歌手就需要一个代理人,歌手代理人完成除唱歌之外的所有琐事,等完成了一系列工作后,再让歌手来唱歌。
定义业务接口
public interface Service {void sing();
}
真实类实现业务接口
public class Singer implements Service{public void sing() {System.out.println("歌手演唱");}
}
代理人实现业务接口
public class SingerProxy implements Service{public void sing() {System.out.println("歌手经纪人预定唱歌时间");System.out.println("歌手经纪人预定唱歌场地");System.out.println("歌手经纪人通知歌手唱歌");Singer singer = new Singer();singer.sing();System.out.println("歌手经纪人清理场地");}
}
调用代理人去让歌手完成唱歌
public class Main {public static void main(String[] args) {SingerProxy singerProxy = new SingerProxy();singerProxy.sing();}}
运行结果:
动态代理
静态代理的缺陷显而易见,每有一个真实类,我们就需要手动创建他的代理类,代码量巨大,这时我们的需求就是能不能动态生成。
动态代理是在程序运行时动态生成代理对象,而不是在编译时就确定代理对象。这意味着可以根据需要在运行时创建不同的代理对象,以满足不同的需求。
jdk动态代理
java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:
业务接口
public interface Service {void sing();void dance();
}
真实类实现业务接口
public class Singer implements Service{public void sing() {System.out.println("歌手演唱");}public void dance() {System.out.println("歌手跳舞");}}
生成代理类
public class Main {public static void main(String[] args) {//创建真实对象Singer singer = new Singer();//动态创建真实对象的被代理对象Service proxy = createProxy(singer);proxy.sing();}//生成代理类public static Service createProxy(Singer singer){Service proxy = (Service)Proxy.newProxyInstance(Singer.class.getClassLoader(), //类的加载器new Class[]{Service.class}, //接口数组new InvocationHandler() { //调用处理器@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //proxy 代理对象,method正在执行的方法,agrs方法参数//先获取正在执行的方法名String name = method.getName();Object result = null;//if ("sing".equals(name)) {System.out.println("歌手经纪人预定唱歌时间");System.out.println("歌手经纪人预定唱歌场地");System.out.println("歌手经纪人通知歌手唱歌");result = method.invoke(singer, args);System.out.println("歌手经纪人清理场地");}if ("dance".equals(name)) {System.out.println("歌手经纪人预定跳舞时间");System.out.println("歌手经纪人预定跳舞场地");System.out.println("歌手经纪人通知歌手唱跳");result = method.invoke(singer, args);System.out.println("歌手经纪人清理场地");}return result;}});return proxy;}}
JDK生成的动态代理类大概源码
动态生成的代理类其方法与实现的接口有关,接口有什么方法,他就实现什么方法。
当我们代理类对象.sing()时,代理类内部会有sing方法,sing方法中会super.h.invoke(代理对象本身,正在执行的方法,方法参数)。super是其父类Proxy,h是父类的属性InvocationHandler h,这个调用处理器是我们传给父类对象的。
当我们代理类对象.dance()时,代理类内部会有dance方法,dance方法同样有super.h.invoke(代理对象本身,正在执行的方法,方法参数)。super是其父类Proxy,h是父类的属性InvocationHandler h,这个调用处理器是我们传给父类对象的。
public final class $Proxy0 extends Proxy implements Service {private static Method m0;private static Method m1;private static Method m2;private static Method m3;private static Method m4;public $Proxy0(InvocationHandler var1) throws {super(var1);}public final boolean equals(Object var1) throws {try {return (Boolean)super.h.invoke(this, m0, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final String toString() throws {try {return (String)super.h.invoke(this, m1, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final int hashCode() throws {try {return (Integer)super.h.invoke(this, m2, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}//Method m3中有sing方法的信息,调用父类Proxy的protected InvocationHandler h 的invoke方法public final void sing() throws {try {super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}//Method m4中有dance方法的信息public final void dance() throws {try {super.h.invoke(this, m4, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}static {try {m0 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m1 = Class.forName("java.lang.Object").getMethod("toString");m2 = Class.forName("java.lang.Object").getMethod("hashCode");m3 = Class.forName("Service").getMethod("sing");m4 = Class.forName("Service").getMethod("dance");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}
cglib动态代理
jdk动态代理需要接口,许多场景是没有接口的,这个时候就需要cglib动态代理了,CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。
cglib代理最重要的是实现MethodInterceptor接口,实现他的intercept方法
jdk代理最重要的是实现 InvocationHandler接口,实现他的invoke方法
当我们代理类对象.sing() --> MethodInterceptor. intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) -->根据类名通过反射调用对应的方法
intercept方法的四个参数
Object o, 被代理对象
Method method, 正在执行的方法
Object[] objects, 方法参数
MethodProxy methodProxy 方法代理对象