Mybatis实现过程小结

经验总结

今天跟着视频写了一个简单版的Mybatis,特此记录细节以及感悟。

实现步骤

一、.首先看main方法,实现一个Mybatis框架到底需要哪些对象。

 public static void main(String[] args)throws Exception {
    
    
       // 1.读取配置文件
       InputStream in = Resources.getResourcesAsStream("SqlMapConfig.xml");
       // 2.创建SQLSessionFaction工厂
       SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
       SqlSessionFactory factory = builder.build(in);
       // 3.用SQLSession工厂生产SQLSession对象0
       SqlSession session = factory.openSession();
       // 4.使用SQLSession创建Dao接口的代理对象
       IAccountDao accountDao = (IAccountDao) session.getMapper(IAccountDao.class);
       // 5.使用代理对象执行方法
       List<Account> accounts = accountDao.findAllAccount();
       for (Account account : accounts) {
    
    
           System.out.println(account);
       }
       // 6.释放资源
       session.close();
       in.close();
   }

分析:
第一行代码,需要一个Resource对象,并且在这个类中,需要一个名为getResourcesAsStream,返回值类型为InputStream的方法。
第二行代码,明显需要一个SqlSessionFactoryBuilder对象。
第三行代码,分析出需要一个SqlSessionFactory 对象,且这个对象是通过SqlSessionFactoryBuilder对象的build方法和一个InputStream参数创建出来的。
第四行代码,用到一个SqlSession对象,且这个对象是通过S qlSessionFactory的openSession方法创建出来的。
第五行代码,通过SqlSession的getMapper方法和一个对象的字节码文件,可以看出这里是使用了泛型,以此才能支持通过同一个方法,返回不同的mapper。

小结:Mybatis至少需要用到的对象:1.Resource、2.SqlSessionFactoryBuilder、3.SqlSessionFactory 、4.SqlSession。
除此之外,还需要xml文件的解析类(XMLConfigBuilder),SQL语句的执行类(Executor),数据库连接属性类(Configuration),
注册驱动获取连接类(DataSourceUtil),动态代理接口InvocationHandler接口实现类(MapperProxy),Sql语句对象封装映射类(Mapper),但是其中的Executor和XMLConfigBuilder类我还需要花点时间消化,这里相关的工具类和配置类就先不展出,择日更新。
至少用到的方法:

  1. Resources对象 的 public static InputStream getResourcesAsStream(String filePath){}
  2. SqlSessionFactoryBuilder 的 public SqlSessionFactory build(InputStream config){}
  3. Sqlsesson 的 SqlSession openSession();
  4. SqlSession 的 < T > T getMapper(Class< T > daoIntegerClass);
    大致流程:Resource类读取配置文件,把配置文件内容转换为字节输入流,再使用创建者模式,利用字节流创建出一个SqlSessionFactory(工厂模式),接着使用工厂生产出SqlSession,最后通过Session获得Mapper对象。
    二、实现具体类和接口
    1.Resource类
public class Resources {
    
    
    //getResourcesAsStream方法,返回一个字节输入流
    public static InputStream getResourcesAsStream(String filePath){
    
    
        //反射机制,类加载器获取方法
        return Resources.class.getClassLoader().getResourceAsStream(filePath);
    }
}

2.SqlSessionFactoryBuilder类

public class SqlSessionFactoryBuilder {
    
    
    //创建SqlSessionFactory对象的方法
    public SqlSessionFactory build(InputStream config){
    
    
        //解析xml文件获取连接信息,并封装进Configuration对象中
        Configuration cfg = XMLConfigBuilder.loadConfiguration(config);
        //返回一个SqlSessionFactory的实现类对象
        return new DefaultSqlSessionFactoryImpl(cfg);
    }
}

3.SqlSessionFactory 接口及其实现类

public interface SqlSessionFactory {
    
    
    SqlSession openSession();
}
public class DefaultSqlSessionFactoryImpl implements SqlSessionFactory{
    
    
    private Configuration cfg;

    public DefaultSqlSessionFactoryImpl(Configuration cfg) {
    
    
        this.cfg = cfg;
    }

    @Override
    public SqlSession openSession() {
    
    
    	//SqlSession的实现类
        return new DefaultSqlSessionImpl(cfg);
    }
}

4.SqlSession接口及其实现类以及动态代理接口实现类

public interface SqlSession {
    
    

    <T> T getMapper(Class<T> daoIntegerClass);

    void close();
}
public class DefaultSqlSessionImpl implements SqlSession {
    
    

    private Configuration cfg;
    private Connection connection;

    public DefaultSqlSessionImpl(Configuration cfg) {
    
    
        this.cfg = cfg;
        connection = DataSourceUtil.getConnection(cfg);
    }

    @Override
    public <T> T getMapper(Class<T> daoIntegerClass) {
    
    
		//Proxy是动态代理技术的实现,MapperProxy类实现了InvocationHandler接口,做到了方法增强
        return (T) Proxy.newProxyInstance(daoIntegerClass.getClassLoader(),new Class[]{
    
    daoIntegerClass},
                new MapperProxy(cfg.getMappers(),connection));
    }

    @Override
    public void close() {
    
    
        if (connection != null){
    
    
            try {
    
    
                connection.close();
            } catch (SQLException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}
public class MapperProxy implements InvocationHandler{
    
    
    private Map<String,Mapper> mappers;
    private Connection conn;

    public MapperProxy(Map<String, Mapper> mappers, Connection conn) {
    
    
        this.mappers = mappers;
        this.conn = conn;
    }

    public MapperProxy(Map<String, Mapper> mappers) {
    
    
        this.mappers = mappers;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        //获取方法名
        String methodName = method.getName();
        //获取方法所在的类名
        String className = method.getDeclaringClass().getName();
        String key = className+"."+methodName;
        Mapper mapper = mappers.get(key);
        if (mapper == null){
    
    
            throw new IllegalArgumentException("传入参数有误");
        }
        return new Executor().selectList(mapper,conn);
    }
}

猜你喜欢

转载自blog.csdn.net/TreeCode/article/details/108037796
今日推荐