Springboot整合Hibernate拦截器EmptyInterceptor

简介: Springboot整合Hibernate拦截器EmptyInterceptor

1.需求


系统获客后,会创建一条线索,现在要对创建线索进行扩展


2.问题分析


由于历史开发者的原因,没有做好抽象,代码里有大量创建线索的逻辑,现在要对创建的线索做一个扩展。如果找到所有的创建线索的代码块去修改,会非常的疲惫。

系统使用的是:SpringBoot+Hibernate 架构。

原本我想用切面解决这个问题,但是发现挺繁琐。

正在我一筹莫展时,灵光一现,Hibernate里有没有拦截器。百度一下果然有EmptyInterceptor拦截器。但是根据网上的配置不生效


3.看源码解决拦截器不生效问题


下面讲讲我是如何解决这个问题的

我通过idea 的find功能找到了源码中几处使用EmptyInterceptor的代码块。 然后挨个源码查看。

SessionFactoryBuilderImpl中找到了了端倪

this.interceptor = strategySelector.resolveDefaultableStrategy(
                    Interceptor.class,
                    configurationSettings.get( INTERCEPTOR ),//自定义的拦截器
                    EmptyInterceptor.INSTANCE//默认的拦截器
            );

此处在构建SessionFactory过程中,会在此处设置interceptor 拦截器。这里算是用了一个简单策略模式模式吧。

逻辑:如果配置了自定义拦截器则使用自定义的拦截器。没有配置则适用默认的拦截器。

configurationSettings.get( INTERCEPTOR )

此处取的就是配置的拦截器INTERCEPTOR 对应的配置key为

String INTERCEPTOR = "hibernate.session_factory.interceptor";

也就说我们在配置自定义拦截器需要使用此配置key设置。

#配置
    hibernate.session_factory.interceptor=com.wsjia.ms.doApplication.util.SerialIntercpter
    @Value("${hibernate.session_factory.interceptor}")
    private String INTERCEPTOR;
    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource());
        sessionFactoryBean.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);
        Properties hibernateProperties = new Properties();
        hibernateProperties.put("hibernate.dialect", HIBERNATE_DIALECT);
        hibernateProperties.put("hibernate.show_sql", HIBERNATE_SHOW_SQL);
        hibernateProperties.put("hibernate.hbm2ddl.auto", HIBERNATE_HBM2DDL_AUTO);
        hibernateProperties.put("hibernate.session_factory.interceptor",INTERCEPTOR);
        sessionFactoryBean.setHibernateProperties(hibernateProperties);
        return sessionFactoryBean;
    }


4.EmptyInterceptor原理


更进一步我又看了拦截器是如何生效的。

(1.首先LocalSessionFactoryBean 做为一个FactoryBean会创建一个SessionFactory工厂用于创建Session

SessionFactory的实现类:SessionFactoryImpl

public SessionFactory build() {
        metadata.validate();
        return new SessionFactoryImpl( metadata, buildSessionFactoryOptions() );
    }

(2.其次

SessionFactoryImpl.openSession方法会调用session构建器SessionBuilderImpl的openSession方法,构建一个session出来,此时就会把拦截器设置给session

public Session openSession() {
            log.tracef( "Opening Hibernate Session.  tenant=%s, owner=%s", tenantIdentifier, sessionOwner );
            final SessionImpl session = new SessionImpl(
                    connection,
                    sessionFactory,
                    sessionOwner,
                    getTransactionCoordinator(),
                    getJdbcCoordinator(),
                    getTransaction(),
                    getTransactionCompletionProcesses(),
                    autoJoinTransactions,
                    sessionFactory.settings.getRegionFactory().nextTimestamp(),
                    interceptor,
                    statementInspector,
                    flushBeforeCompletion,
                    autoClose,
                    connectionReleaseMode,
                    tenantIdentifier
            );
            for ( SessionEventListener listener : listeners ) {
                session.getEventListenerManager().addListener( listener );
            }
            return session;
        }

(3.session

来看看SessionImpl.save方法

@Override
    public Serializable save(Object obj) throws HibernateException {
        return save( null, obj );
    }
    @Override
    public Serializable save(String entityName, Object object) throws HibernateException {
        return fireSave( new SaveOrUpdateEvent( entityName, object, this ) );
    }
    private Serializable fireSave(SaveOrUpdateEvent event) {
        errorIfClosed();
        checkTransactionSynchStatus();
        checkNoUnresolvedActionsBeforeOperation();
        for ( SaveOrUpdateEventListener listener : listeners( EventType.SAVE ) ) {
            listener.onSaveOrUpdate( event );
        }
        checkNoUnresolvedActionsAfterOperation();
        return event.getResultId();
    }

来看看这个save过程:

  • 将当前entity 包装成一个SaveOrUpdateEvent事件
  • 做一些check校验
  • 调用同步监听器的onSaveOrUpdate方法,处理save事件
  • 返回id

拦截器的调用是在监听器中发生的.AbstractSaveEventListener

protected boolean substituteValuesIfNecessary(
            Object entity,
            Serializable id,
            Object[] values,
            EntityPersister persister,
            SessionImplementor source) {
        //拦截器的调用
        boolean substitute = source.getInterceptor().onSave(
                entity,
                id,
                values,
                persister.getPropertyNames(),
                persister.getPropertyTypes()
        );
}

此时就会调用我们自定义的拦截器了


5.Hibernate与Mybatis 框架的思考


更进一步思考:Hibernate与Mybatis

读过Mybatis 源码和 少许Hibernate后,我产生了如下总结

  • Mybatis 与 Hibernate 设计方式:配置化个性SessionFactory工厂的创建。使用工厂创建 Session。在这一点上大家是差不多的。
  • Mybatis: 通过Executor执行器来处理增删改查
  • Hibernate 使用同步监听器来处理操作,操作前先创建一个事件,然后调用监听器处理。


6.总结:


再复杂的框架也是一段段同步代码组织起来的。只要掌握了阅读源码的技巧,会发现多个框架的设计上有异曲同工之妙。阅读源码有助于帮助我们更好的解决问题


相关文章
|
6月前
|
XML Java 数据库连接
Spring Boot的数据访问之Spring Data JPA以及Hibernate的实战(超详细 附源码)
Spring Boot的数据访问之Spring Data JPA以及Hibernate的实战(超详细 附源码)
114 0
|
1月前
|
SQL Java 数据库连接
springBoot+Jpa(hibernate)数据库基本操作
springBoot+Jpa(hibernate)数据库基本操作
42 0
|
3月前
|
Java 关系型数据库 MySQL
|
4月前
|
Java 数据库连接 数据库
如何在Spring Boot中集成Hibernate
如何在Spring Boot中集成Hibernate
|
6月前
|
Java 关系型数据库 MySQL
【极光系列】springBoot集成Hibernate
【极光系列】springBoot集成Hibernate
41 2
|
SQL 缓存 Oracle
一文教会你如何在SpringBoot项目里集成Hibernate
一文教会你如何在SpringBoot项目里集成Hibernate
828 0
|
6月前
|
存储 Java 数据库连接
Spring Boot 嵌入式服务器、Hibernate 关系和 Spring Data 全解析
Spring Boot 的嵌入式服务器功能是一项方便而强大的功能,它允许你在应用程序中直接运行 Web 服务器,无需将其部署到单独的独立 Web 服务器中。这使得开发、测试和部署 Web 应用程序变得容易,而且它还是轻量级的、易于启动和停止的,易于配置。
110 0
|
Java 关系型数据库 数据库连接
Spring Boot 学习研究笔记(八) - Spring Data JPA与Hibernate区别及配置(2)
Spring Boot 学习研究笔记(八) - Spring Data JPA与Hibernate区别及配置
277 0
|
SQL Java 数据库连接
Spring Boot 学习研究笔记(八) - Spring Data JPA与Hibernate区别及配置(1)
Spring Boot 学习研究笔记(八) - Spring Data JPA与Hibernate区别及配置
353 0
|
Java 关系型数据库 MySQL
IDEA版SpringBoot全教程 06 SpringBoot整合hibernate
IDEA版SpringBoot全教程 06 SpringBoot整合hibernate
224 0