首页 > Java框架应用 > Hibernate 入门教程 > 自定义类 Hibernate 框架的基本过程

自定义类 Hibernate 框架的基本过程

1. 前言

不要一味地迷信,要善于质疑,善于打破。这应该是我们在学习框架时应该保持的心态。

Hibernate 是所有 JDBC 框架中封装最高的、使用起来最便利的框架之一。对于初学者而言,要么在感叹它的神奇,要么敬畏它的存在。

但是,作为一个真正的开发者,应该有破有立的想法。

本节课程试图通过一个简易的 JDBC 框架的实现流程描述,让大家更清晰地了解 Hibernate 框架的设计过程。

TIps: 框架的编写是一个比较复杂的过程,并不是一言两语能说清楚的,本文中的代码介于伪代码和真实代码之间 ,仅仅用来帮助大家理解 Hibernate 的框架基础原理。

2. 读取配置信息

简易框架主要模拟 3 个组件,分别对应 Hibernate 中的 Configuration、SessionFactory、Session 组件。

Configuration 组件的作用:解析配置文件中的信息。

Tips: 简易框架中,保持配置文件格式及内容和 Hiberante 的主配置文件一致。

查看一下 Configuration 类的结构:

public class Configuration {
    //保存配置文件中的 property 元素信息
    private Map<String,String> pros;
    //保存配置文件中的映射类
    private List<String> mappings;

    public Configuration() {
        this.pros=new HashMap<String, String>();
        this.mappings=new ArrayList<String>();
    }

    /**
     * 读取配置文件
     */
    public void configure() throws DocumentException {
        configure("/hibernate.cfg.xml");
    }

    private void configure(String resource) throws DocumentException {
        InputStream stream =Configuration.class.getResourceAsStream(resource);
        doConfigure( stream);
    }

    /**
     * 使用 DOM4j XML 解析器解决配置文件中的信息
     */
    private void doConfigure(InputStream stream) throws DocumentException {
        SAXReader saxReader=new SAXReader();
        Document doc= saxReader.read(stream);
        Element rootEle= doc.getRootElement();
        Element sfEle= rootEle.addElement("session-factory");       
        List<Element> propertys= sfEle.elements("property");
        for (Element ele : propertys) {
            this.pros.put(ele.attributeValue("name"), ele.getText());
        }
        List<Element> mappings= sfEle.elements("mapping");
        for (Element m : mappings) {
            this.mappings.add(m.attributeValue("class"));
        }   
    }
    /**
    *创建会话工厂
    *
    */
    public SessionFactory buildSessionFactory()  {
        return new SessionFactory(this.pros,this.mappings);
    }
}

Hibernate 的主配置文件中有很多配置项,因受限于文章篇幅和本文初设目标,这里只解析 2 类信息:

  • 数据库连接信息;
  • 实体类路径信息。

基础好的学习者可以查阅 Hibernate 的源代码。

3. 会话工厂

会话工厂的核心作用:建立和数据库系统的连接,创建会话对象。

创建时需要依赖 Configuration 组件解析出来的信息。Hiberante 的会话工厂的源代码实现比较复杂,代码具有良好的结构性,会衍生出很多辅助性组件。

因为只是说明问题,本文中的工厂仅仅用来创建会话对象,不考虑性能、缓存、事务等各方面问题,也不刻意讲究代码的结构性。

简易框架中的会话工厂的代码简单但具有说明力:

public class SessionFactory {
    private Map<String, String> pros;
    private List<String> mappings;
    private ThreadLocal<Session> threadLocal;
    public SessionFactory(Map<String, String> pros, List<String> mappings) {
        this.pros = pros;
        this.mappings = mappings;
        this.threadLocal = new ThreadLocal<Session>();
    }
    public Connection getConn() {
        String driverClass = this.pros.get("connection.driver_class");
        String url = this.pros.get("connection.url");
        String userName = this.pros.get("connection.username");
        String password = this.pros.get("connection.password");
        try {
            Class.forName(driverClass);
            return DriverManager.getConnection(url, userName, password);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    public Session openSession() {
        return new Session(this.getConn(), this.mappings);
    }
    public Session getCurrentSession() {
        Session session = this.threadLocal.get();
        if (session == null) {
            session = this.openSession();
            this.threadLocal.set(session);
        }
        return session;
    }
}

会话工厂类中有 2 个创建 Session 的方法,一个是普通的创建方法,另一个是从线程上下文中检查是否已经存在 Session 对象。

4. 会话对象

Session 对象提供具体的方法用来对数据库中的数据进行相关操作。

public class Session<T> {
private Connection conn;
private List<String> mappings;

public Session(Connection conn, List<String> mappings) {
    this.conn=conn;
    this.mappings=mappings;
}

public T get(Class<T> clz,Serializable ser) {
    //构建 SQL        
    //得到结果集
    //封装数据
    return null;
}

public Object load(Class<T> clz,Serializable ser) {
    return null;
}
public int save() {
    return 0;
}

//其它方法
}

在前面的《Hibernate 自动生成 SQL 语句》和《 Hibernate 自动进行数据封装 》章节中已经讲解了如何通过反射构建 SQL 和数据封装。请查阅相关内容。

因为延迟加载是 Hibernate 中一个比较重要的特性,所以,这里讲解一下 load 方法的实现原理。load()方法调用时并没有直接访问数据库,而是返回给用户一个代理对象,只有当使用者调用代理对象的 getXXX()方法时,才会进入数据库。

做到这一点并不难,使用代理设计模式便可。

代理设计模式中创建代理对象的方案有 2 种:

  • 静态代理对象;
  • 动态代理对象。

一般都会使用动态方式创建代理对象,动态代理对象的常用创建方案有 2 种:

  • 使用 JDK 中提供的 Proxy 类创建;
  • 第三方实现,如 cglib 库。

使用 Proxy 创建时有一个前提条件,需要被代理的对象提供接口规范,使用 cglib 就不需要,因是第三方实现,则需要在项目中导入依赖包。

通过代理设计模式的回调机制,load()方法就能实现当需要时再触发对应的数据库操作。

5. 小结

本节课以简易代码的方式描述了 Configuration、SessionFactory、Session 3 个组件的功能实现,以及其相互之间的依赖关系。

但并没有更深入的接轨 Hibennate 的源代码,Hiberanate 源代码中有很多商业性的解决方案,值得大家深究参考。

希望通过本次课程,能让大家更进一步的认识 Hibernate 。

本文来自互联网用户投稿,不拥有所有权,该文观点仅代表作者本人,不代表本站立场。
访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。
本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,邮箱:80764001@qq.com,予以删除。
© 2023 PV138 · 站点地图 · 免责声明 · 联系我们 · 问题反馈