Mybatis底层原理的简单实现

Mybatis底层原理的简单实现,第1张

Mybatis底层原理的简单实现 Mybatis自定义接口底层实现的方式 1. 创建Dao层的自定义接口

首先创建Dao层数据库的接口,为了理解Mybatis动态代理机制,简单的以下述方法为例进行 *** 作

package mymybatis;

import com.cqupt.entity.User;

import java.util.List;

public interface UserMapper {
    public User findById(Integer id);
    public List findAll();
}

2. 在对应的XML 中定义接口方法对应的 SQL 语句

第二步,创建与之对应的xml,注意 接口通过接口的全类名+方法名如 mymybatis.UserMapper+findById ,Mybatis首先会查到到对应的命名空间,然后在其命名空间下通过接口中方法名与





    
        select * from user
    


mybatis配置文件中配置数据源,与注册接口对应的Mapper.xml文件,Mapper.xml文件中的命名空间需要设置为其对应接口的全类名,使得生成代理对象的时候,能过通过接口的全类名找到对应的xml文件。





    
    
        
            
            
                
                
                
                
            
        
    

    
    
        
    


3. 根据 XML,通过 JDK 动态代理(反射)完成自定义接口的具体实现

JDK提供的实现动态代理相关的是一个接口InvocationHandler与动态代理类Proxy,实现的主要分为以下几个步骤
1、继承并实现一个InvocationHandler的实现类,该实现类的作用就是实现需要增强的业务逻辑
2、创建一个该接口的动态代理类,传入InvocationHandler实现类对象。
3、使用生成的动态代理实例调用接口的方法实现

package mymybatis;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.dom4j.document;
import org.dom4j.documentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.lang.reflect.*;
import java.sql.*;
import java.util.*;
//实现InvocationHandler的对象
public class MyInvocationHandler implements InvocationHandler {

    //为目标对象创建动态代理对象
    public Object getInstance(Class cls){
        Object newProxyInstance = Proxy.newProxyInstance(
                cls.getClassLoader(),//第一个参数为类参加载器
                new Class[]{cls},//第二个参数为需要代理的接口
                this//第三个参数为InvocationHandler实例,调用代理对象的时候,会调用传递的InvocationHandler实例中的invoke方法。
        );
        return newProxyInstance;//返回生成的代理对象
    }

    @Override  //调用接口执行的部分参数分别为 代理对象,执行的方法,参数
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //1、读取xml文件中数据源的信息
        Map dataSourceProperty = getDataSourceProperty();
        
        //2、创建数据库连接对象
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass(dataSourceProperty.get("driver"));
        dataSource.setJdbcUrl(dataSourceProperty.get("url"));
        dataSource.setUser(dataSourceProperty.get("username"));
        dataSource.setPassword(dataSourceProperty.get("password"));
        Connection connection = dataSource.getConnection();
        
        //3、执行 SQL,获取结果集
        //获取方法对应的statement 解析获取到需要执行SQL语句的相关信息
        Map sqlMap = parseSatement(method.getName());
        String sql = sqlMap.get("sql");
        String resultType = sqlMap.get("resultType");
        String parameterType = sqlMap.get("parameterType");
        //4、根据实体类解析结果集 结果集-Java对象
        return createObj(connection,sql, resultType,parameterType,args);
    }
4. 自动解析结果集,映射成 XML 中配置的 JavaBean

读取xml文件中数据源的信息,结果以Map的形式返回

    
    public Map getDataSourceProperty(){
        Map maps = new HashMap<>();
        //通过dom4j读取config.xml
        try {
            SAXReader reader = new SAXReader();
            //这里为数据源文件的地址
            document document = reader.read("src/main/resources/config.xml");
            //获取配置文件中的数据
            Element rootElement = document.getRootElement();
            Iterator iterator = rootElement.elementIterator();
            while (iterator.hasNext()) {
                Element next = iterator.next();
                if("environments".equals(next.getName())){
                    Iterator iterator1 = next.elementIterator();
                    while (iterator1.hasNext()) {
                        Element next1 = iterator1.next();
                        Iterator iterator2 = next1.elementIterator();
                        while (iterator2.hasNext()) {
                            Element next2 = iterator2.next();
                            if("dataSource".equals(next2.getName())) {
                                Iterator iterator3 = next2.elementIterator();
                                while (iterator3.hasNext()) {
                                    Element next3 = iterator3.next();
                                    String name = next3.attributevalue("name");
                                    String value = next3.attributevalue("value");
                                    maps.put(name, value);
                                }
                            }
                        }
                    }
                }
            }
        } catch (documentException e) {
            e.printStackTrace();
        }
        return maps;
    }

根据接口调用的方法获取对应的statement,并解析获取到需要执行SQL语句的相关信息,以Map形式返回结果,主要解析sql语句,返回值类型,参数类型

 
    public Map parseSatement(String methodName){
        Map maps = new HashMap<>();
        //通过dom4j读取config.xml
        try {
            SAXReader reader = new SAXReader();
            document document = reader.read("src/main/java/mymybatis/UserMapper.xml");
            //获取配置文件中的数据
            Element rootElement = document.getRootElement();
            Iterator iterator = rootElement.elementIterator();
            while (iterator.hasNext()) {
                Element next = iterator.next();
                String id = next.attributevalue("id");
                if(id.equals(methodName)){
                    String sql = next.getText();
                    maps.put("sql", sql);
                    String parameterType = next.attributevalue("parameterType");
                    String resultType = next.attributevalue("resultType");
                    maps.put("resultType",resultType);
                    maps.put("parameterType",parameterType);
                }
            }
        } catch (documentException e) {
            e.printStackTrace();
        }
        return maps;
    }

根据实体类解析结果集 结果集-Java对象

 
    public Object createObj(Connection connection,String sql,String resultType,String parameterType,Object[] args){
        Object result = null;
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            //实现传入参数的替换SQL中的占位符
            if(parameterType!=null){
                switch (parameterType){
                    case "java.lang.Integer":
                        preparedStatement.setInt(1,(Integer) args[0]);
                        break;
                    case "java.lang.String":
//                    preparedStatement.setString();
                        break;
                }
            }
            ResultSet resultSet = preparedStatement.executeQuery();
            //将结果集映射成 Java 对象
            try {
                Class aClass = Class.forName(resultType);
                result = parseObject(resultSet, aClass);
            } catch (Exception e) {
                e.printStackTrace();
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return result;
    }
	//根据查询到的ResultSet完成Javabean的映射
    public Object parseObject(ResultSet resultSet,Class aClass) throws SQLException {
        //多行数据,映射成集合
        List list = new ArrayList();
        ResultSetmetaData metaData = resultSet.getmetaData();
        try {
            while (resultSet.next()) {
                String columnName = null;
                String columnTypeName = null;
                Object object = aClass.getConstructor(null).newInstance(null);
                Object value = null;
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    columnName = metaData.getColumnName(i);
                    columnTypeName = metaData.getColumnTypeName(i);
                    switch (columnTypeName){
                        case "INT":
                            value = resultSet.getInt(columnName);
                            break;
                        case "VARCHAR":
                            value = resultSet.getString(columnName);
                            break;
                    }
                    //给object赋值
                    //获取方法
                    String methodName = "set"+columnName.substring(0,1).toUpperCase()+columnName.substring(1);
                    //获取实体类属性
                    Field declaredField = aClass.getDeclaredField(columnName);
                    Method method = aClass.getMethod(methodName, declaredField.getType());
                    method.invoke(object,value);
                }
                list.add(object);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(list.size()==0)  return null;
        if(list.size() == 1) return list.get(0);

        return list;
    }
5.动态代理的测试
package mymybatis;

import com.cqupt.entity.User;

import java.util.List;

public class Test {
    public static void main(String[] args) {
        //创建handler对象
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        //传入需要代理的接口,生成其动态代理对象
        UserMapper userMapper = (UserMapper) myInvocationHandler.getInstance(UserMapper.class);
        //调用代理对象的方法
        List all = userMapper.findAll();
        for (User user : all) {
            System.out.println(user);
        }
        System.out.println("******************");
        User byId = userMapper.findById(1);
        System.out.println(byId);
    }
}

执行后的查询结果:通过接口代理的方式可以成功的从数据库中查询到结果,并完成对象的封装

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5681729.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存