簡體   English   中英

如何將 spring bean 注入休眠環境 RevisionListener

[英]How to inject spring beans into the hibernate envers RevisionListener

我正在使用 Spring 5.1 和 Hibernate 5.3.9,包括 hibernate-envers。 我不知道如何將 spring beans 注入 hibernate envers 自定義 RevisionListener。

我試過了

  (@Service or @Component)
  public class ExtendedRevisionListener implements RevisionListener {

  @Autowired
  private MyService myService;

  void newRevision(Object revisionEntity){
    myService.doSomething(...)
  }
}

當然,該類包含在@ComponentScan 包解析中。 一個問題是 myService 沒有注入監聽器。

在 hibernate-envers 文檔中:

https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#envers-basics

從 Hibernate Envers 5.3 開始,RevisionListener 現在支持依賴注入。 此功能取決於各種依賴框架,例如 CDI 和 Spring,在 Hibernate ORM 引導期間提供必要的實現以支持注入。 如果未提供符合條件的實現,則將在不注入的情況下構造 RevisionListener。

不幸的是,我還沒有找到任何有效的例子。

@Naros 我在 spring 持久性 JPA 配置中設置了 EntityMaganerFactoryBean -> entityManager = new org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean()

10:49| DEBUG | SessionFactoryImpl.java 252 | Session factory constructed with filter configurations : {}
10:49| DEBUG | SessionFactoryImpl.java 253 | Instantiating session factory with properties: {hibernate.format_sql=true, awt.toolkit=sun.awt.windows.WToolkit, hibernate.id.new_generator_mappings=false, java.specification.version=1.8, logging.configuration=file:C:\wildfly16\standalone\configuration\logging.properties, sun.cpu.isalist=amd64, sun.jnu.encoding=Cp1250, sun.arch.data.model=64, org.jboss.resolver.warning=true, java.vendor.url=http://java.oracle.com/, javax.persistence.validation.mode=AUTO, sun.boot.library.path=C:\Program Files\Java\jdk1.8.0_201\jre\bin, org.jboss.logmanager.nocolor=true, sun.java.command=org.jboss.modules.Main -mp C:\wildfly16\modules org.jboss.as.standalone -b localhost --server-config=standalone.xml -Djboss.server.base.dir=C:\wildfly16\standalone, java.specification.vendor=Oracle Corporation, java.naming.factory.url.pkgs=org.jboss.as.naming.interfaces, java.home=C:\Program Files\Java\jdk1.8.0_201\jre, jboss.server.persist.config=true, file.separator=\, jboss.server.data.dir=C:\wildfly16\standalone\data, line.separator=
, java.vm.specification.vendor=Oracle Corporation, java.specification.name=Java Platform API Specification, jboss.server.base.dir=C:\wildfly16\standalone, hibernate.transaction.coordinator_class=class org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl, wicket.configuration=development, jboss.bind.address.management=localhost, sun.boot.class.path=C:\Program Files\Java\jdk1.8.0_201\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\rt.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\sunrsasign.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_201\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_201\jre\classes, hibernate.hbm2ddl.auto=update, user.script=, java.protocol.handler.pkgs=org.jboss.net.protocol|org.jboss.vfs.protocol, sun.management.compiler=HotSpot 64-Bit Tiered Compilers, java.runtime.version=1.8.0_201-b09, user.name=ptaszek, hibernate.enable_lazy_load_no_trans=true, file.encoding=Cp1250, sun.rmi.dgc.client.gcInterval=3600000, java.io.tmpdir=C:\Users\ptaszek\AppData\Local\Temp\, org.jboss.boot.log.file=C:\wildfly16\standalone\log\boot.log, jboss.modules.system.pkgs=org.jboss.byteman, java.version=1.8.0_201, java.vm.specification.name=Java Virtual Machine Specification, jboss.bind.address=localhost, java.awt.printerjob=sun.awt.windows.WPrinterJob, jboss.host.name=1501-10, org.jboss.security.context.ThreadLocal=true, sun.os.patch.level=, module.path=C:\wildfly16\modules, java.library.path=C:\Program Files\Java\jdk1.8.0_201\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;native;C:/Program Files/Java/jre1.8.0_211/bin/server;C:/Program Files/Java/jre1.8.0_211/bin;C:/Program Files/Java/jre1.8.0_211/lib/amd64;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files\Microsoft MPI\Bin\;C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\WINDOWS\System32\OpenSSH\;C:\Program Files (x86)\AOMEI Backupper;C:\Program Files\TortoiseSVN\bin;C:\Program Files (x86)\Microsoft SQL Server\140\Tools\Binn\;C:\Program Files\Microsoft SQL Server\140\Tools\Binn\;C:\Program Files (x86)\Microsoft SQL Server\140\DTS\Binn\;C:\Program Files\Microsoft SQL Server\140\DTS\Binn\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\130\Tools\Binn\;C:\Program Files (x86)\Microsoft SQL Server\Client SDK\ODBC\130\Tools\Binn\;C:\Program Files (x86)\Microsoft SQL Server\140\Tools\Binn\ManagementStudio\;C:\Program Files\MySQL\MySQL Shell 8.0\bin\;C:\eclipse;;., jboss.server.name=1501-10, java.vendor=Oracle Corporation, jboss.modules.dir=C:\wildfly16\modules, sun.io.unicode.encoding=UnicodeLittle, jboss.server.temp.dir=C:\wildfly16\standalone\tmp, sun.desktop=windows, file.encoding.pkg=sun.io, hibernate.connection.handling_mode=DELAYED_ACQUISITION_AND_HOLD, hibernate.dialect=org.hibernate.dialect.MySQL8Dialect, java.class.path=C:\wildfly16\jboss-modules.jar, jboss.server.deploy.dir=C:\wildfly16\standalone\data\content, java.vm.vendor=Oracle Corporation, user.variant=, user.timezone=Europe/Belgrade, os.name=Windows 10, java.vm.specification.version=1.8, program.name=JBossTools: WildFly 16 at localhost, hibernate.generate_statistics=false, sun.java.launcher=SUN_STANDARD, user.country=PL, hibernate.use_sql_comments=false, javax.persistence.sharedCache.mode=UNSPECIFIED, jboss.server.config.dir=C:\wildfly16\standalone\configuration, sun.cpu.endian=little, user.home=C:\Users\ptaszek, user.language=pl, jboss.qualified.host.name=1501-10, java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment, java.awt.headless=true, org.apache.xml.security.ignoreLineBreaks=true, sun.rmi.dgc.server.gcInterval=3600000, java.net.preferIPv4Stack=true, jboss.home.dir=C:\wildfly16, path.separator=;, os.version=10.0, java.endorsed.dirs=C:\Program Files\Java\jdk1.8.0_201\jre\lib\endorsed, java.runtime.name=Java(TM) SE Runtime Environment, hibernate.ejb.persistenceUnitName=default, sun.nio.ch.bugLevel=, java.vm.name=Java HotSpot(TM) 64-Bit Server VM, hibernate.show_sql=false, java.security.auth.login.config=jar:file:/C:/wildfly16/modules/system/layers/base/org/picketbox/main/picketbox-5.0.3.Final.jar!/auth.conf, jboss.server.log.dir=C:\wildfly16\standalone\log, java.vendor.url.bug=http://bugreport.sun.com/bugreport/, user.dir=C:\wildfly16\bin, os.arch=amd64, org.hibernate.envers.audit_strategy=org.hibernate.envers.strategy.ValidityAuditStrategy, javax.management.builder.initial=org.jboss.as.jmx.PluggableMBeanServerBuilder, hibernate.boot.CfgXmlAccessService.key=org.hibernate.boot.cfgxml.spi.LoadedConfig@35a3f1ae, java.util.logging.manager=org.jboss.logmanager.LogManager, java.vm.info=mixed mode, java.vm.version=25.201-b09, hibernate.bytecode.use_reflection_optimizer=false, hibernate.connection.datasource=HikariDataSource (HikariCpConnectionPool), java.ext.dirs=C:\Program Files\Java\jdk1.8.0_201\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext, jboss.node.name=1501-10, java.class.version=52.0}

在我的 PersistenceJPAConfig 中:

@EnableJpaRepositories(basePackages = "pl.atmoterm", entityManagerFactoryRef = "localContainerEntityManagerFactoryBean")

  @Bean
  @DependsOn({"dataSource"})
  public LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean() {
     LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
     em.setDataSource(dataSource());
     em.setPackagesToScan(new String[]{
        "pl.atmoterm.**.*"
     });

     em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
     em.setJpaProperties(additionalProperties());
     return em;
  }

使用 Spring Framework 5.1 和 Envers 設置 bean 注入確實沒有太多涉及。 偵聽器實現不需要由@Service@Component進行注釋,因為這些類實際上是由 Hibernate 構造的,然后ManagedBeanRegistry負責與用於注入/連接依賴項的任何 DI 框架進行協調。

如果您的MyService沒有被注入修訂偵聽器,則需要檢查的內容很少:

  1. 驗證您使用的是Spring Framework 5.1或更高版本。
    雖然其他 spring 組件可能使用不同的版本方案,但確保底層 Spring Framework 版本確實是 5.1+ 很重要。
  2. RevisionListener配置是否正確?
    我通常通過添加帶有@Entity注釋的@RevisionEntity注釋類來配置它,然后在@RevisionEntity注釋的 value 屬性中指定偵聽器。 如果您願意,您應該能夠使用org.hibernate.envers.revision_listener來指定偵聽器類的完全限定類名。
  3. 您的MyService是否可以在任何其他 spring bean 中注入?
    也許這里的問題是 Spring 根本沒有首先構建您的MyService bean,這將導致依賴注入在修訂偵聽器的 bean 注入期間不提供實現。

我在這里創建了一個小演示,您可以參考。 我將考慮在本月晚些時候在 Hibernate 博客上發布一篇關於此的博客文章。


更新

簡單地看一下 Spring Framework 源代碼,我相信問題在於您手動創建了一個LocalContainerEntityManagerFactoryBean ,當注入 bean 工廠時,它實際上並沒有創建必要的 Hibernate 配置來進行依賴注入。

我認為您可能需要做的是自己手動設置:

@Bean
@DependsOn({"dataSource"})
public LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean(ConfigurableListableBeanFactory beanFactory) {
   // Create the LocalContainerEntityManagerBean like you were

   // Pass beanFactory here so right configuration gets applied
   em.setJpaProperties(additionalProperties(beanFactory));
   return em;
}

private Properties additionalProperties(ConfigurableListableBeanFactory beanFactory) {
  // add your properties here like you were before
  Properties properties = new Properties();

  // THIS HERE IS THE CRITICAL SETTING
  properties.put(
    "hibernate.resource.beans.container", 
     new SpringBeanContainer(beanFactory));

  return properties
}

雖然LocalContainerEntityManagerFactoryBeanBeanFactoryAware ,但它只是設置了一個內部屬性,僅此而已。 該屬性實際上並未設置為 Hibernate 檢測它的必要配置屬性,因此 Hibernate 最終默認為 CDI 注入,因為您處於 CDI 環境中。

在上面,當 EntityManagerFactory bean 正在構建時,我們在BeanFactory實例中有配置傳遞。 我們將該工廠傳遞到additionalProperties ,在那里我們手動將其應用到正確的 Hibernate 配置,然后傳遞給 Hibernate 引導程序。

如果使用 Spring Boot,最好使用 ApplicationContextAware:

public class MyRevisionListener implements RevisionListener, ApplicationContextAware {

    private MyService myService;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.myService = applicationContext.getBean(MyService.class);
    }

    @Override
    public void newRevision(Object revisionEntity) {
        MyRevisionEntity revinfo = (MyRevisionEntity) revisionEntity;

        // Use myService here to set something on MyRevisionEntity
    }

}

這是使用 Spring Boot 2.3.9 測試的。

有其他方式...您可以使用 spring 中的靜態類....

查看....

import org.hibernate.envers.RevisionListener;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;


public class EnverRevisionListener implements RevisionListener{

    @Override
    public void newRevision(Object revisionEntity) {
        EnverRevisionEntity revEntity = (EnverRevisionEntity) revisionEntity;
        SecurityContext context = SecurityContextHolder.getContext();
        Authentication auth = context.getAuthentication();
        revEntity.setUserName(auth.getName());
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM