我正在使用Spring 5.1和Hibernate 5.3.9,包括hibernate-envers。 我不知道如何将春豆注入休眠 envers 自定义修订侦听器。
我试过了
(@Service or @Component)
public class ExtendedRevisionListener implements RevisionListener {
@Autowired
private MyService myService;
void newRevision(Object revisionEntity){
myService.doSomething(...)
}
}
当然,该类包含在@ComponentScan包分辨率中。 一个问题是 myService 没有注入到侦听器中。
在休眠-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 我在春季持久性JPA中设置了EntityMaganerFactoryBean。 配置 ->实体管理器 = 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:wildfly16standaloneconfigurationlogging.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 FilesJavajdk1.8.0_201jrebin, org.jboss.logmanager.nocolor=true, sun.java.command=org.jboss.modules.Main -mp C:wildfly16modules org.jboss.as.standalone -b localhost --server-config=standalone.xml -Djboss.server.base.dir=C:wildfly16standalone, java.specification.vendor=Oracle Corporation, java.naming.factory.url.pkgs=org.jboss.as.naming.interfaces, java.home=C:Program FilesJavajdk1.8.0_201jre, jboss.server.persist.config=true, file.separator=, jboss.server.data.dir=C:wildfly16standalonedata, line.separator=
, java.vm.specification.vendor=Oracle Corporation, java.specification.name=Java Platform API Specification, jboss.server.base.dir=C:wildfly16standalone, 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 FilesJavajdk1.8.0_201jrelibresources.jar;C:Program FilesJavajdk1.8.0_201jrelibrt.jar;C:Program FilesJavajdk1.8.0_201jrelibsunrsasign.jar;C:Program FilesJavajdk1.8.0_201jrelibjsse.jar;C:Program FilesJavajdk1.8.0_201jrelibjce.jar;C:Program FilesJavajdk1.8.0_201jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_201jrelibjfr.jar;C:Program FilesJavajdk1.8.0_201jreclasses, 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:UsersptaszekAppDataLocalTemp, org.jboss.boot.log.file=C:wildfly16standalonelogboot.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:wildfly16modules, java.library.path=C:Program FilesJavajdk1.8.0_201bin;C:WINDOWSSunJavabin;C:WINDOWSsystem32;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 FilesOracleJavajavapath;C:Program FilesMicrosoft MPIBin;C:Program Files (x86)InteliCLS Client;C:Program FilesInteliCLS Client;C:WINDOWSsystem32;C:WINDOWS;C:WINDOWSSystem32Wbem;C:WINDOWSSystem32WindowsPowerShellv1.0;C:Program FilesIntelIntel(R) Management Engine ComponentsDAL;C:Program FilesIntelIntel(R) Management Engine ComponentsIPT;C:Program Files (x86)IntelIntel(R) Management Engine ComponentsDAL;C:Program Files (x86)IntelIntel(R) Management Engine ComponentsIPT;C:WINDOWSSystem32OpenSSH;C:Program Files (x86)AOMEI Backupper;C:Program FilesTortoiseSVNbin;C:Program Files (x86)Microsoft SQL Server140ToolsBinn;C:Program FilesMicrosoft SQL Server140ToolsBinn;C:Program Files (x86)Microsoft SQL Server140DTSBinn;C:Program FilesMicrosoft SQL Server140DTSBinn;C:Program FilesMicrosoft SQL ServerClient SDKODBC130ToolsBinn;C:Program Files (x86)Microsoft SQL ServerClient SDKODBC130ToolsBinn;C:Program Files (x86)Microsoft SQL Server140ToolsBinnManagementStudio;C:Program FilesMySQLMySQL Shell 8.0bin;C:eclipse;;., jboss.server.name=1501-10, java.vendor=Oracle Corporation, jboss.modules.dir=C:wildfly16modules, sun.io.unicode.encoding=UnicodeLittle, jboss.server.temp.dir=C:wildfly16standalonetmp, 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:wildfly16jboss-modules.jar, jboss.server.deploy.dir=C:wildfly16standalonedatacontent, 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:wildfly16standaloneconfiguration, sun.cpu.endian=little, user.home=C:Usersptaszek, 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 FilesJavajdk1.8.0_201jrelibendorsed, 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:wildfly16standalonelog, java.vendor.url.bug=http://bugreport.sun.com/bugreport/, user.dir=C:wildfly16bin, 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 FilesJavajdk1.8.0_201jrelibext;C:WINDOWSSunJavalibext, jboss.node.name=1501-10, java.class.version=52.0}
在我的坚持JPAConfig中:
@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
未注入到修订侦听器中,则有以下几点需要检查:
- 验证你使用的是Spring Framework 5.1或更高版本。
虽然其他 Spring 组件可能使用不同的版本方案,但重要的是要确保底层 Spring Framework 版本确实是 5.1+。 RevisionListener
配置是否正确?
我通常通过添加一个带有@Entity
注释的@RevisionEntity
注释类来配置它,然后在@RevisionEntity
注释的值属性中指定侦听器。 如果您愿意,您应该能够使用org.hibernate.envers.revision_listener
来指定侦听器类的完全限定类名,否则。- 您的
MyService
可以注射到任何其他春豆中吗?
也许这里的问题是 Spring 一开始就没有构造你的MyService
bean,这会导致依赖注入在修订侦听器的 bean 注入期间不提供实现。
我在这里创建了一个小演示,您可以参考。 我将考虑在本月晚些时候在Hibernate博客上发表一篇关于此的博客文章。
更新
只是简单地看一下 Spring 框架源代码,我相信问题是你正在手动创建一个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
}
虽然LocalContainerEntityManagerFactoryBean
是BeanFactoryAware
,但它只是设置一个内部属性,仅此而已。 该属性实际上并未设置为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());
}
}
我正在使用带有 Hibernate 6.2 的 Spring Boot 3.1.1,但这两个答案都不适合我。相反,我可以通过以下方式解决它:
应用程序.yml
spring.jpa.properties:
hibernate:
# see https://github.com/hibernate/hibernate-orm/blob/6.2/migration-guide.adoc#cdi
cdi.extensions: false
修订侦听器
public class MyRevisionListener implements RevisionListenere {
private final MyService myService;
public MyRevisionListener (@org.springframework.context.annotation.Lazy MyService myService) {
this.myService = myService;
}
@Override
public void newRevision(Object revisionEntity) {
MyRevisionEntity revinfo = (MyRevisionEntity) revisionEntity;
// Use myService here to set something on MyRevisionEntity
}
}