Mybatis是一款ORM(Object Relational Mapping)对象关系映射框架,其底层封装了jdbc并使用了jdk动态代理,需要一个interface、一个invocationHandler实现类、还有一个SqlSession
一、先准备一个接口与实现类
public interface MoveAble {
public void move();
}
public class Car implements MoveAble{
public Car(){}
@Override
public void move() {
System.out.println("汽车开始运动");
}
}
二、准备一个invocationHandler
/**
*
* JDK动态代理类
*
*
*/
public class JdkProxyHandler implements InvocationHandler {
private Object target;//动态代理对象
public Object bindProxy(Object target){//传入目标代理对象
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); //返回代理对象
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk动态代理开始-------");
Object object=method.invoke(target,args);
System.out.println("jdk动态代理结束-------");
return object;
}
}
三、调用jdk动态代理过程
public class Test {
public static void main(String[] args) {
MoveAble subject=new Car();
JdkProxyHandler handler = new JdkProxyHandler();
MoveAble subjectProxy=(MoveAble) handler.bindProxy(subject);
subjectProxy.move();
}
}
实现原理是创建一个被代理类的子类,从而实现方法的增强。
一、先实现一个业务类,注意这个类并没有实现接口
public class HelloService {
public HelloService() {
System.out.println("HelloService构造");
}
/**
* 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
*/
final public String sayOthers(String name) {
System.out.println("HelloService:sayOthers>>"+name);
return null;
}
public void sayHello() {
System.out.println("HelloService:sayHello");
}
}
二、实现一个MethodInterceptor
/**
* 自定义MethodInterceptor
*/
public class MyMethodInterceptor implements MethodInterceptor{
//被代理对象
private Object target;
public Object bindProxy(Object target){//传入目标代理对象
this.target = target;
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(target.getClass());
// 设置enhancer的回调对象
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
/**
* sub:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
*/
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后者通知======");
return object;
}
}
三、cglib测试类
public class Test{
public static void main(String[] args){
HelloService service = new HelloService();
MyMethodInterceptor methodInterceptor = new MyMethodInterceptor();
HelloService proxy=(HelloService )methodInterceptor.bindProxy(sevice);
proxy.sayHello();
}
}
jdk动态代理这便是Mybatis自动映射器Mapper的底层实现原理。
一、引入maven依赖
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- MySQL连接对象 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
二、配置application.yml
#数据库连接配置
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://10.212.130.05:3306/xxxDbNm?useUnicode=true&characterEncoding=utf8
spring.datasource.username=xxx
spring.datasource.password=xxx
#pojo扫描包路径
mybatis.type-aliases-package=com.bdcloud.bean
#mybaits配置文件目录
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
三、定义用户bean与Mapper接口
public class User {
private Integer id;
private String user_id;
private String user_name;
}
----------------------------------------------
import com.bdcloud.bean.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper {
public List<User> getAllUsers();
}
四、定义UserMapper.xml
<mapper namespace="com.bdcloud.mapper.UserMapper">
<select id="getAllUsers" resultType="User">
select * from login_user
select>
mapper>
五、调用测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootMybatisApplicationTests {
@Autowired
UserMapper userMapper;
@Test
public void contextLoads() {
List<User> allUsers = userMapper.getAllUsers();
System.out.println(allUsers.toString());
}
}
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import org.apache.ibatis.reflection.ExceptionUtil;
import org.apache.ibatis.session.SqlSession;
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
} else {
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
}
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
this.methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
}
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.ibatis.session.SqlSession;
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return this.mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return this.methodCache;
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
}
1.读取配置文件sqlMapperConfig.xml生成SqlSessionFactory
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
mappers>
configuration>
创建sqlSessionFactory的代码如下:
String resource = "mybatis/sqlMapperConfig.xml";//或者路径字符串修改为"classpath:/mybatis/sqlMapperConfig.xml"
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
2.根据SqlSessionFactory对象获取SqlSession,通过调用session.getMapper()方法已经涉及到了上述jdk代理,获取到代理Mapper对象后,执行相应的sql语句并返回
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
} finally {
session.close();
}
3.构建数据返回结果集使用到了ObjectFactory封装返回结果