前三篇详细总结了Mybatis的基本特性、经常使用配置、映射器,相对于Hibernate,映射器的配置相对复杂,但有很好的灵活性和扩展性,能够应对各类业务场景。熟练掌握这些内容,能够流畅的使用MyBatis进行开发了。java
后面准备介绍MyBatis的解析和运行原理以及自定义插件,今天看了书籍的这部分,都会涉及到反射和动态代理这些基础,本篇文章总结下这些,便于理解原理。安全
文章索引:
微信
经过本篇的介绍,你会了解到:框架
首先看看官网对反射的定义:jvm
能够经过java代码,获取当前加载类的字段、方法、构造函数等信息,并在安全限制内,使用反射字段、方法、构造函数进行操做。函数
简单来讲,能够在运行时得到程序中每个类型的成员信息。程序中定义的对象,其类型都是在编译期肯定的,而反射能够动态地建立对象,并访问或调用其成员。post
所谓代理,是一我的或组织代替另外一我的或组织作事,主要有3个角色:访问者、代理人、被代理人,访问者经由代理人,与被代理人交互,中间会加入一些本身的处理。测试
所谓的动态代理,是说在编译时不须要定义代理类,而是在运行时建立,这个是关键:在运行时建立代理类。优化
Class类是一个实实在在的类,存在于java.lang包中,用来表示运行时类型信息。Class对象表示自定义类的类型信息,好比建立一个User类,JVM就会建立一个User对应的Class对象,保存User类相关的类型信息,该对象保存在jvm堆中,做为访问方法区中User类型信息的接口。this
在使用自定义类时,会首先检查这个类的Class对象是否已经加载,若是没有加载,默认的类加载器就会先根据类名查找.class文件,Class对象就会被加载到内存。
能够经过下面3种方法获取Class对象:
Class对象是反射的基础,提供了获取类信息的方法,后面会介绍。
java反射框架主要提供如下内容:
下面举例说明相关功能
建立实例:
//获取String所对应的Class对象
Class<?> c = User.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器建立实例
User user = (User)constructor.newInstance("calm");
复制代码
获取方法:
//返回类或接口声明的全部方法,包括私有的,但不包括继承的方法
public Method[] getDeclaredMethods() throws SecurityException
//全部public方法,包括继承的方法
public Method[] getMethods() throws SecurityException
//返回一个特定的方法,第一个参数为方法名称,后面的参数为方法参数对应Class的对象
public Method getMethod(String name, Class<?>... parameterTypes) 复制代码
调用方法:
Class<?> userClass=User.class;
Object obj = userClass.newInstance();
Method method =klass.getMethod("addRole",String.class);
method.invoke(obj,"超级管理员");
复制代码
JDK自己提供了动态代理的实现,要求被代理者必须实现接口。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) 复制代码
第一个参数为类加载器,第二个参数是被代理者实现的接口列表,第三个参数是实现了InvocationHandler接口的对象。
InvocationHandler是一个接口,用于规范执行被代理者的方法,可在执行方法先后,添加公共的处理代码。生成的动态代理类包含一个InvocationHandler属性,调用对应方法时,会触发invoke方法的调用。
public class JDKProxy implements InvocationHandler {
private Object targetObject;//被代理对象
public Object newProxy(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)//invoke方法 throws Throwable {
Object ret = null;
ret = method.invoke(targetObject, args);
return ret;
}
}
复制代码
测试代码:
JDKProxy jdkProxy=new JDKProxy();
UserService userService = (UserService)
jdkProxy.newProxy(new UserServiceImp());
userService.addRole("超级管理员");
复制代码
JDK动态代理的基本原理是根据定义好的规则,用传入的接口建立一个新类。
JDK动态代理要求必须有接口,CGLIB(Code Generate Library)动态代理没有这个要求,它是经过建立一个被代理类的子类,而后使用ASM字节码库修改代码来实现的。
public class CGLibProxy implements MethodInterceptor {
private Object targetObject; //被代理对象
public Object createProxyObject(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object obj = null;
obj = method.invoke(targetObject, args);
return obj;
}
}
复制代码
测试代码:
CGLibProxy cgLibProxy=new CGLibProxy();
UserService userService = (UserService)
cgLibProxy.newProxy(new UserServiceImp());
userService.addRole("超级管理员");
复制代码
ASM 是一个 Java 字节码操控框架。它可以以二进制形式修改已有类或者动态生成类。不过ASM在建立class字节码的过程当中,操纵的级别是底层JVM的汇编指令级别,这要求ASM使用者要对class组织结构和JVM汇编指令有必定的了解。另外可使用javassist框架操做字节码,它对开发者提供的接口比较优化。
了解了反射和动态代理,对后面介绍MyBatis的解析和运行原理有很大帮助,下一篇会重点介绍。
欢迎扫描下方二维码,关注个人我的微信公众号 ~