我想根据 OP 的要求添加 Aviad 的答案以使其完整。
内部情况:
为了获得 MetadataImplementor 的实例,解决方法是通过 Java 的ServiceLoader工具注册SessionFactoryBuilderFactory的实例。这个注册的服务的getSessionFactoryBuilder方法然后由MetadataImplementor用它自己的一个实例调用,当 hibernate 被引导时。代码参考如下:
- 服务加载
- 调用 getSessionFactoryBuilder
因此,最终要获得 MetadataImplementor 的实例,您必须实现 SessionFactoryBuilderFactory 并注册,以便 ServiceLoader 可以识别此服务:
SessionFactoryBuilderFactory 的一个实现:
public class MetadataProvider implements SessionFactoryBuilderFactory {
private static MetadataImplementor metadata;
@Override
public SessionFactoryBuilder getSessionFactoryBuilder(MetadataImplementor metadata, SessionFactoryBuilderImplementor defaultBuilder) {
this.metadata = metadata;
return defaultBuilder; //Just return the one provided in the argument itself. All we care about is the metadata :)
}
public static MetadataImplementor getMetadata() {
return metadata;
}
}
为了注册上述内容,在以下路径中创建简单的文本文件(假设它是一个 maven 项目,最终我们需要在类路径中提供“META-INF”文件夹):
src/main/resources/META-INF/services/org.hibernate.boot.spi.SessionFactoryBuilderFactory
并且文本文件的内容应该是单行(如果您需要注册多个实例,甚至可以是多行),说明您的 SessionFactoryBuilderFactory 实现的完全限定类路径。例如,对于上面的类,如果你的包名是 'com.yourcompany.prj',那么下面应该是文件的内容。
com.yourcompany.prj.MetadataProvider
就是这样,如果您运行您的应用程序、spring 应用程序或独立休眠,一旦休眠被引导,您将通过静态方法获得一个 MetadataImplementor 实例。
更新1:
无法通过 Spring 注入它。我深入研究了 Hibernate 的源代码,元数据对象没有存储在 SessionFactory 的任何地方(这是我们从 Spring 中得到的)。因此,无法注入它。但是,如果您希望以 Spring 的方式使用,有两种选择:
- 扩展现有的类并从
LocalSessionFactoryBean -> MetadataSources -> MetadataBuilder
LocalSessionFactoryBean 是你在 Spring 中配置的,它有一个 MetadataSources 对象。MetadataSources 创建 MetadataBuilder,后者又创建 MetadataImplementor。以上所有操作都不存储任何内容,它们只是动态创建对象并返回。如果你想要一个 MetaData 的实例,你应该扩展和修改上面的类,以便它们在返回之前存储相应对象的本地副本。这样您就可以参考 MetadataImplementor。但除非真的需要,否则我不会真的推荐这个,因为 API 可能会随着时间而改变。
另一方面,如果您不介意从 SessionFactory 构建 MetaDataImplemetor,以下代码将为您提供帮助:
EntityManagerFactoryImpl emf=(EntityManagerFactoryImpl)lcemfb.getNativeEntityManagerFactory();
SessionFactoryImpl sf=emf.getSessionFactory();
StandardServiceRegistry serviceRegistry = sf.getSessionFactoryOptions().getServiceRegistry();
MetadataSources metadataSources = new MetadataSources(new BootstrapServiceRegistryBuilder().build());
Metadata metadata = metadataSources.buildMetadata(serviceRegistry);
SchemaUpdate update=new SchemaUpdate(serviceRegistry,metadata); //To create SchemaUpdate
// You can either create SchemaExport from the above details, or you can get the existing one as follows:
try {
Field field = SessionFactoryImpl.class.getDeclaredField("schemaExport");
field.setAccessible(true);
SchemaExport schemaExport = (SchemaExport) field.get(serviceRegistry);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}