Hibernate 4.0 新特性之 Service(Registry)

jopen 11年前發布 | 175K 次閱讀 Hibernate 持久層框架

已經遷移到 Hibernate Core 4.0 的用戶(非JPA)可能已經注意到,以前大家熟知的構造 SessionFactory 的方法已經不推薦使用了:

Configuration configuration = new Configuration();
SessionFactory sf = configuration.buildSessionFactory();

Hibernate ORM 4 里面推薦的方式是 org.hibernate.cfg.Configuration#buildSessionFactory(ServiceRegistry serviceRegistry), 需要先構造一個 ServiceRegistry 對象。

那么, 神馬是 ServiceRegistry?

顧名思義, ServiceRegistryService 的注冊表, 它為Service提供了一個統一的加載 / 初始化 / 存放 / 獲取機制.

首先來看看一個整體的類圖:

Hibernate 4.0 新特性之 Service(Registry)

整個 ServiceRegistry 結構和我們大家了解的 Classloader 的代理結構類似, 只不過和 Classloader 的首先代理給父節點,父節點找不到再從本級的 Classloader 中查找的策略不同,ServiceRegistry 是先從本級節點查找,找不到再去父親中查找。

Hibernate 4.0 新特性之 Service(Registry)

可以看到hibernate里面的 ServiceRegistry實際上是由三層(范圍)組成的:

  • BootstrapServiceRegistry

主要提供 Classloading 和 Service loading 服務, 供全局使用.

  • ServiceRegistry

標準的ServiceRegistry, 同樣服務于全局, 在初始化這個Registry中的服務的時候,可能需要使用到BootstrapServiceRegistry中的服務.

  • SessionFactoryServiceRegistry

SessionFactory相關聯(一對一的關系), 這里面的Services在初始化的時候需要訪問SessionFactory.

所以, BootstrapServiceRegistry 中主要包括全局都要使用的基礎服務, 而 ServiceRegistry 主要包括在 BootstrapServiceRegistry 之上的, 和Hibernate 相關的服務, 例如配置文件解析, JDBC, JNDI 等.

而, SessionFactoryServiceRegistry 則是和sessionfactory相關的了, 包括2LC的region factory, event listener等.

這里面的層級關系, 對于 service registry的client來說是完全透明的, 你可以直接調用getService 去獲取你需要的service, 而不用去關心你在哪個層級上, 如同 classloader.

Service

那么,什么是 Service ? 簡單的來說,Service 就是一個功能,它由一個接口(Service Role)和一個實現類組成.

Service 在Hibernate里面并不是一個新的概念,在以前的版本里面,我們已經有了這些東西,而這次,是通過把這些服務的提供者(類),給抽取成一個個的Service,從而可以用統一的方式進行訪問/加載/初始化等.

下圖列出了所有的Hibernate中內置的Services, 詳細介紹請參考:

Hibernate 4.0 新特性之 Service(Registry)

Building ServiceRegistry

在本文的開頭即說過, 現在標準的構造一個SessionFactory的做法是傳遞一個ServiceRegistry實例給Configuration#buildSessionFactory方法, 那么, 這里就需要我們首先創建一個 ServiceRegistry的實例.

最簡單的做法是:

StandardServiceRegistryBuilder serviceRegistryBuilder = new StandardServiceRegistryBuilder();
ServiceRegistry serviceRegistry = serviceRegistryBuilder.build();
SessionFactory sf = configuration.buildSessionFactory(serviceRegistry);

讓我們來繼續分析這里面究竟發生了什么.

如上文所介紹的, ServiceRegistry是一個代理結構, 那么, 實際上是需要分別創建 BootstrapServiceRegistry, ServiceRegistrySessionFactoryServiceRegistry.

BootstrapServiceRegistry

org.hibernate.service.ServiceRegistryBuilder 有兩個構造函數, 一個是接受一個 BootstrapServiceRegistry實例作為參數, 另外一個是無參的, 在內部自己構造一個 org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl的實例.

如同上面所講的, 事實上我們是先build了一個 BootstrapServiceRegistry 的.

而Hibernate也如你所愿的提供了 org.hibernate.boot.registry.BootstrapServiceRegistryBuilder.

通過這個builder類, 我們可以通過調用如下的方法來對一些基礎服務進行擴展:

  • with(Integrator integrator)
  • with(ClassLoader classLoader)
  • withStrategySelector

(關于這里的擴展的詳細解釋敬請期待下一篇)

現在我們有了 BootstrapServiceRegistryBuilderServiceRegistryBuilder , 那么很自然的, 會想到是不是也有一個 SessionFactoryServiceRegistryBuilder 呢?

很遺憾, 沒有!

是的, 不過我們提供了 org.hibernate.service.spi.SessionFactoryServiceRegistryFactory, 它是一個位于 ServiceRegistry 中的標準service.

這主要是因為它的全部工作就是創建一個沒啥意思的 org.hibernate.service.internal.SessionFactoryServiceRegistryImpl 實例, 也沒啥可擴展的地方, 所以自然也就不需要一個builder了.

那么, 如果你非得要替換到這個默認的實現, 或者, 更進一步, 例如你想要替換掉某一個Service的標準實現, 異或, 你想把自己寫的service也添加到service registry當中呢?

更進一步來看看Service

首先, BootstrapServiceRegistry中所提供的service是固定的, 無法增減, 除非你提供一個自己的 org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl 實現類, 但是并不推薦.

org.hibernate.boot.registry.internal.BootstrapServiceRegistryImpl#locateServiceBinding 方法中我們可以看到BootStrapServiceRegistry所提供的標準服務.

public  ServiceBinding locateServiceBinding(Class serviceRole) {
    if ( ClassLoaderService.class.equals( serviceRole ) ) {
        return (ServiceBinding) classLoaderServiceBinding;
    }
    else if ( StrategySelector.class.equals( serviceRole) ) {
        return (ServiceBinding) strategySelectorBinding;
    }
    else if ( IntegratorService.class.equals( serviceRole ) ) {
        return (ServiceBinding) integratorServiceBinding;
    }

    return null;
}

推薦的擴展位置是 ServiceRegistry, 在這里, 你可以增加你自定義的service, 替換標準的service實現等等.

ServiceRegistry 中所提供的標準服務是定義在 org.hibernate.service.StandardServiceInitiators 當中:

public class StandardServiceInitiators {
    public static List LIST = buildStandardServiceInitiatorList();

    private static List buildStandardServiceInitiatorList() {
        final List serviceInitiators = new ArrayList();

        serviceInitiators.add( ConfigurationServiceInitiator.INSTANCE );
        serviceInitiators.add( ImportSqlCommandExtractorInitiator.INSTANCE );

        serviceInitiators.add( JndiServiceInitiator.INSTANCE );
        serviceInitiators.add( JmxServiceInitiator.INSTANCE );

        serviceInitiators.add( PersisterClassResolverInitiator.INSTANCE );
        serviceInitiators.add( PersisterFactoryInitiator.INSTANCE );

        serviceInitiators.add( ConnectionProviderInitiator.INSTANCE );
        serviceInitiators.add( MultiTenantConnectionProviderInitiator.INSTANCE );
        serviceInitiators.add( DialectResolverInitiator.INSTANCE );
        serviceInitiators.add( DialectFactoryInitiator.INSTANCE );
        serviceInitiators.add( BatchBuilderInitiator.INSTANCE );
        serviceInitiators.add( JdbcEnvironmentInitiator.INSTANCE );
        serviceInitiators.add( JdbcServicesInitiator.INSTANCE );
        serviceInitiators.add( RefCursorSupportInitiator.INSTANCE );

        serviceInitiators.add( SchemaManagementToolInitiator.INSTANCE );

        serviceInitiators.add( MutableIdentifierGeneratorFactoryInitiator.INSTANCE);

        serviceInitiators.add( JtaPlatformInitiator.INSTANCE );
        serviceInitiators.add( TransactionFactoryInitiator.INSTANCE );

        serviceInitiators.add( SessionFactoryServiceRegistryFactoryInitiator.INSTANCE );


        return Collections.unmodifiableList( serviceInitiators );
    }
}

可以看到, 每一個標準服務都被封裝成了 StandardServiceInitiator, 那么什么是 ServiceInitiator 呢?

ServiceInitiator

org.hibernate.service.spi.ServiceInitiator

定義了一個 Service 的加載器, 這個接口里面只有一個方法

/**
 * Obtains the service role initiated by this initiator.  Should be unique within a registry
 *
 * @return The service role.
 */
public Class getServiceInitiated();

org.hibernate.service.StandardServiceInitiator 繼承了 org.hibernate.service.spi.ServiceInitiator 并提供了另外一個方法:

/**
 * Initiates the managed service.
 *
 * @param configurationValues The configuration values in effect
 * @param registry The service registry.  Can be used to locate services needed to fulfill initiation.
 *
 * @return The initiated service.
 */
public R initiateService(Map configurationValues, ServiceRegistryImplementor registry);

認同下圖所示, ServiceInitiator定義了一個Service的接口 以及如何初始化這個service.

Hibernate 4.0 新特性之 Service(Registry)

所以, 當有了ServiceInitiator之后, 可以通過調用org.hibernate.boot.registry.StandardServiceRegistryBuilder 的方法添加到注冊表中:

  • addInitiator(StandardServiceInitiator initiator)
  • addService(final Class serviceRole, final Service service)

hibernate在初始化這些service的時候, 會先初始化內置的, 所以, 如果你想要替換以后的標準service的話, 只需要原樣調用上面兩個方法之一就行了.

Hibernate 還提供了一些接口來供Service的創建者來使用(具體如何使用請參考javadoc,在此就不重復了):

  • org.hibernate.service.spi.Configurable
  • org.hibernate.service.spi.Manageable
  • org.hibernate.service.spi.ServiceRegistryAwareService
  • org.hibernate.service.spi.InjectService
  • org.hibernate.service.spi.Startable
  • org.hibernate.service.spi.Stoppable
  • org.hibernate.service.spi.Wrapped

至此, 已經把ServiceRegistry中的大部分內容介紹完了, 希望大家對此有個感性的認識. 在以后的blog中, 我會按照從bootstrap, standard, sessionfactory的順序把各個service registry中提供的標準服務一一解釋, 我會盡量的從代碼級別來解釋為什么這樣設計, 和如何使用.

原文出處:http://in.relation.to/Bloggers/HibernateORMServiceRegistry

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!