引言
衡量我们是否掌握一种知识,标准是我们对它核心技术和原理的掌握程度。
概述
mybatis核心技术包括:反射和动态代理;mybatis运行原理分为俩部分,第一部分是读取配置文件缓存到Configuration对象,用以创建SqlSessionFactory,第二部分是SqlSession的执行过程。
内容
一 核心技术
1 反射技术
(1)好处:配置性大大提高,可以给很多配置设置参数,使得java应用程序能够顺利运行起来,大大提高了Java的灵活性和可配置性,降低模块之间的耦合。
(2)实例:通过反射技术去创建ReflectService对象,获取服务方法后通过反射调用
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectService{
/**
* 服务方法
* @param name -- 姓名
*/
public void sayHello(String name){
System.err.println("hello" + name);
}
/**
* 测试
* @param args
*/
public static void main(String[] args) throw ClassNotFoundException,
NoSuchMethodException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException{
//通过反射创建ReflectService对象
Object service = Class.forName(ReflectService.class.getName()).newInstance();
//获取服务方法——sayHello
Method method = service.getClass().getMethod("sayHello", String.class);
//反射调用方法
method.invoke(service, "liming");
}
}
2 动态代理
(1)代理是什么?
在原有的服务上多加一个占位,通过这个占位控制服务的访问。简单理解就是大厨和前台服务员的关系,我们去吃饭,直接和前台服务员沟通要吃什么,不用考虑是哪个大厨做饭,做什么饭,怎么做的。在服务的层面上,这个服务员就是大厨的代理了,也就是代理服务。
(2)为什么使用代理模式
1)控制如何访问真正的服务对象,提供额外服务。
2)通过重写一些类来满足特定的需要。
(3)分类
1)JDK动态代理:由JDK的java.lang.reflect.*包支持,必须提供接口
步骤:编写服务类和接口,这个是真正的服务提供者,在JDK代理中接口是必须的
编写代理类,提供绑定和代理方法
示例:第一步,编写服务接口
public interface HelloService{
public void sayHello(String name);
}
第二步,编写服务接口实现类
public class HelloServiceImpl implements HelloService{
@Override
public void sayHello(String name){
System.err.println("hello" + name);
}
}
第三步,编写一个代理类,提供真实对象的绑定和代理方法。代理类的要求是实现InvocationHandler接口的代理方法,当一个对象被绑定后,执行其方法的时候就会进入到代理方法
public class HelloServiceProxy implements InvocationHandler{
//定义真实对象
private Object target;
/**
* 真实对象绑定委托代理对象并返回一个代理类
* @param target
* @return
*/
public Object bind(Object target){
//获取真实对象
this.target = target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader,
target.getClass().getInterfaces(),this); //jdk代理需要提供接口
}
@Override
/**
* 通过代理对象调用真实对象方法会进入代理方法
* @param proxy --代理对象
* @param method --被调用方法
* @param args --方法的参数
*/
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
System.err.println("####我是JDK冬天代理####");
Object result = null;
//反射方法前调用
System.err.println("我准备说hello。");
//执行方法,相当于调用HelloServiceImpl类的sayHello方法
result = method.invoke(target,args);
//反射方法后调用
System.err.println("我说过hello了");
return result;
}
}
第四步:测试客户端代码
public class client{
public static void main(String[] args){
HelloServiceProxy HelloHandler = new HelloServiceProxy();
HelloServiceProxy proxy = (HelloService)HelloHandler.bind(new HelloServiceImpl());
proxy.sayHello("李明");
}
}
2)CGLIB代理:HelloService.java和HelloServiceImpl.java都不需要改变,实现CGLIB的代理类(MethodInterceptor)
代码示例:
public class HelloServiceCgLib implements MethodInterceptor{
private Object target;
/**
*创建代理对象
*
*@param target
*@return
*/
public Object getInstance(Object target){
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
//回调方法
enhancer.setCallback(this);
//创建代理对象
return enhancer.create();
}
@Override
//回调方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable{
System.err.println("#####我是CGLIB的动态代理#####");
//反射方法前调用
System.err.println("我准备说hello");
Object returnObj = proxy.invokeSuper(obj, args);
//反射方法后调用
System.err.println("我说过hello了");
return returnObj;
}
}
二 mybatis运行原理
1 构建SqlSessionFactory过程
(1)客户端调用SqlSesisonFactoryBuilder.build,传入对象为SqlMapConfig文件流
(2)根据sqlMapCconfig文件流--> 创建XMLConfigBuilder对象
(3)直接创建XMLMapperEntityResolver,该对象是SqlMapConfig文件的DTD本地实例 作用:将远程DTD文件转化为本地文件
(4)根据sqlMapConfig文件流,确定校验,XMLMapperEntityResolver实例对象 -->创建XPathParser . XPathParser作用:根据Xpath表达式获取基本的DOM节点Node信息的操作
(5)根据传入的SqlMapConfig配置文件流--> 创建Document实例
(6)返回XMLConfigBuilder实例.实例变量中有一个属性parsed,parserd=false. 代表并没有进行解析
(7)调用XMLConfigBuilder实例实例的parse方法
(8)在parse方法中,调用该实例属性的XPathParser,让它去处理SqlMapConfig配置文件的的<configuration>节点对应的Node对象,然后依次解析此Node节点的子Node:properties, settings, typeAliases,typeHandlers,objectFactory, objectWrapperFactory, plugins, environments,databaseIdProvider, mappers
(9)将XML配置文件内的信息解析成Java对象Configuration
(10)将上一步创建的Cofiguration对象作为参数,来创建DefaultSqlSessionFactory对象
(11)返回一个DefaultSqlSessionFactory对象
2 SqlSession运行过程
(1)运行图
(2)说明:SqlSession是通过Executor(执行器)创建StatementHandler来运行的,StatementHandler要经过下面三步:1)prepared预编译SQL , 2)parameterize设置参数, 3)query/update执行SQL
其中parameterize调用parameterHandler的方法设置参数,参数根据类型处理器typeHandler去处理。query/update方法是通过resultHandler继续处理结果的封装,如果是update的语句,返回整数;否则通过typeHandler处理结果类型,然后用ObjectFactory提供的规则组装对象,返回给调用者。
总结
mybatis是目前流行的持久层框架,反射技术与动态代理是其核心的内幕技术,同时SqlSessionFactory的创建以及SqlSession运行原理是mybatis核心内容之一,另外一个核心内容就是配置文件与映射。mybatis从构建mapper配置文件再到核心文件配置,再到方法引入配置文件通过SqlSessionFactoryBuilder创建SqlSessionFactory,然后通过SqlSessionFactory打开SqlSession执行数据库的访问操作,完成数据持久化的操作。