代理模式就是用代理对象代替真实对象去完成相应的操作,并且能够在操作执行的前后对操作进行增强处理。
静态代理
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() { //调用处理器
@Override
public 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 方法代理对象