目录
代理
是通过代理对象访问目标对象,可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。
静态代理
运行前就定义好了静态代理类和被代理类之间的关系,并且静态代理类和被代理类应该共同实现同一个接口。
静态代理实现了目标对象的所有方法,一旦目标接口增加方法,代理对象和目标对象都要进行相应的修改,增加维护成本。
动态代理
通过代理对象将被代理对象的方法和参数传递给InvocationHandler的invoke方法统一执行。
其中涉及三个重要的内容:反射、Proxy(代理类)、InvocationHandler(代理事件处理器)
反射
在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息及动态调用类对象方法的功能称为java的反射机制
也就是说,在运行时,通过Class.forName("类的全限定名") or "类的全限定名".class or 类的实例.getClass()获取一个类的类型,通过这个类型调用 getDeclaredFields()、getDeclaredMethods() 、getDeclaredConstructors() 等能够知道这个类的所有属性(Fileds)和方法(Methods)和构造器( Constructors)等。通过invoke(类的实例对象或代理对象,参数args)执行方法的机制称为反射
动态代理的实现就是利用了反射机制获取代理类的类型和方法
Proxy
为解决静态代理对象必须实现接口的所有方法的问题,Java给出了java.lang.reflect.Proxy实现动态代理,不需要预先implement接口(因此也不需要显式地实现所有的接口方法),统一通过Proxy代理类的invoke方法执行接口方法。
java.lang.reflect.Proxy提供静态方法newProxyInstance创建一个指定类型和代理事件执行器的接口代理对象
参数说明:
ClassLoader loader: 指定类加载器
Class<?>[] interfaces: 需要代理的接口类型
InvocationHandler h: 代理事件执行器,implement InvocationHandler接口的实现类的实例(实现InvocationHandler的invoke方法,通过代理对象传入的被代理类方法和参数来执行)
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
Objects.requireNonNull(h);
final Class<?> caller = System.getSecurityManager() == null
? null
: Reflection.getCallerClass();
/*
* Look up or generate the designated proxy class and its constructor.
*/
Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
return newProxyInstance(caller, cons, h);
}
InvocationHandler
InvocationHandler 接口只有一个invoke方法,负责处理被代理对象的操作。
package MyConfig;
import org.apache.ibatis.annotations.Select;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
/**
* 动态代理获取接口方法,解析执行
* @param proxy 接口代理对象
* @param method 代理对象传入的方法
* @param args 代理对象传入的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 对方法解析和执行
// 返回结果
return null;
}
}
mybatis的接口映射方法的执行就是通过动态代理实现的,通过org.apache.ibatis.binding.MapperProxy实现的InvocationHandler接口的invoke方法,将dao方法委托为org.apache.ibatis.binding.MapperMethod执行(execute)
【Mybatis源码分析 8】mybatis的mapper接口中dao方法并没有具体实现类,是怎么通过mapper动态代理运行的