Springboot интегрирует перехватчик Hibernate EmptyInterceptor

Java

Об изменении не всегда можно сказать, исполнение — это способность открывать дистанцию ​​между людьми.

1. Спрос2. Анализ проблемы3. Посмотрите исходный код, чтобы решить проблему, что перехватчик не работает4. Принцип пустого интерцептора5. Думая о фреймворке Hibernate и Mybatis6. Резюме:

1. Спрос

После того, как система наберет клиентов, она создаст лид, а теперь необходимо расширить создание лидов

2. Анализ проблемы

По причинам исторических разработчиков абстракция сделана плохо, а логики для создания подсказок в коде много, теперь нужно сделать расширение к созданным подсказкам. Если вы найдете все блоки кода, которые создают подсказки для модификации, это будет очень утомительно.

В системе используется: архитектура SpringBoot+Hibernate.

Первоначально я хотел решить эту проблему с помощью фасетов, но нашел это довольно громоздким.

Когда я был в замешательстве, у меня было прозрение, есть ли какой-нибудь перехватчик в Hibernate. У Baidu есть этоEmptyInterceptorперехватчик. Но судя по интернетуКонфигурация не вступает в силу.

3. Посмотрите исходный код, чтобы решить проблему, что перехватчик не работает

Вот как я решил эту проблему

Я пропускаюideaФункция find нашла несколько применений в исходном коде.EmptyInterceptorкодовый блок. Затем проверьте исходный код один за другим.

существуетSessionFactoryBuilderImplнашел подсказки в

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

Здесь в процессе сборки SessionFactory он будет установлен здесьinterceptorперехватчик. Вот простой режим стратегии.

Логика: если настроен пользовательский перехватчик, используйте пользовательский перехватчик. Если он не настроен, будет использоваться перехватчик по умолчанию.

configurationSettings.get( INTERCEPTOR )

Здесь берется конфигурационный ключ, соответствующий сконфигурированному перехватчику INTERCEPTOR.

String INTERCEPTOR = "hibernate.session_factory.interceptor";

То есть нам нужно использовать этот параметр ключа конфигурации при настройке пользовательского перехватчика.

    #配置
    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. Принцип пустого интерцептора

Сделав еще один шаг, я посмотрел, как работает перехватчик.

(1. Первый:LocalSessionFactoryBeanкакFactoryBeanсоздастSessionFactoryФабрика используется для созданияSession

Класс реализации SessionFactory: SessionFactoryImpl

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

(2. Второй
Метод SessionFactoryImpl.openSession вызовет построитель сеансов.SessionBuilderImplМетод openSession, создайте сеанс, затем перехватчик будет установлен на сеанс

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();
    }

Давайте посмотрим на этот процесс сохранения:

  • Оберните текущую сущность в событие SaveOrUpdateEvent.
  • сделать несколько проверок
  • перечислить同步监听器Метод onSaveOrUpdate, обрабатывающий событие сохранения.
  • вернуть идентификатор

Вызов перехватчика происходит в слушателе.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. Используйте фабрику для создания сеанса. В этом вопросе все примерно одинаковы.
  • Мибатис: пройтиExecutorисполнитель для обработки CRUD
  • Спящий режим использует同步监听器Чтобы обработать операцию, создайте событие перед операцией, а затем вызовите прослушиватель для его обработки.

6. Резюме:

Какой бы сложной ни была структура, она организована по разделам синхронного кода. Пока вы овладеваете навыками чтения исходного кода, вы обнаружите, что дизайн нескольких фреймворков похож по назначению. Чтение исходного кода помогает нам лучше решать проблемы