使用Spring AOP配置Hibernate会话

我有一个Spring Framework 4应用程序,它使用Hibernate 4.3.8作为JPA提供程序。 我想使用Hibernatefilter,因此我需要启用它们。 我想在应用程序中全局执行此操作,我正在尝试使用Spring AOP。 我的想法是,我可以编写一个方面,每次创建/获取会话时启用filter,就像在这个和这个问题中一样。

我已经将spring-aopaspectjweaver依赖项添加到我的项目中(使用Maven)。 我添加了以下方面。

 @Aspect @Component public class EnableHibernateFilters { @Pointcut("execution(* org.hibernate.SessionFactory.getCurrentSession(..))") protected void sessionBeingFetched() { } @AfterReturning(pointcut = "sessionBeingFetched()", returning = "object") public void enableFilters(JoinPoint joinPoint, Object object) { System.out.println("!!! Enabling filters !!!"); // Never printed Session session = (Session) object; session.enableFilter("myFilter"); } } 

我的问题是从不调用上面的建议( enableFilters ); 既没有打印文本,也没有启用我的filter。 我已经通过将切入点更改为我自己的一个类来validation我的方面已被检测到并且AOP在我的项目中有效。 我也尝试将切入点更改为execution(* org.hibernate.SessionFactory.openSession(..)) ,但没有结果。

我怀疑这是由我如何设置Hibernate引起的,因为我没有显式配置SessionFactory ; 相反,我设置了一个EntityManagerFactory 。 这是我的配置。

 @Configuration @EnableTransactionManagement public class PersistenceConfig { @Bean public DataSource dataSource() throws NamingException { Context ctx = new InitialContext(); return (DataSource) ctx.lookup("java:comp/env/jdbc/postgres"); // JNDI lookup } @Bean public EntityManagerFactory entityManagerFactory() throws SQLException, NamingException { HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); vendorAdapter.setGenerateDdl(false); vendorAdapter.setDatabase(Database.POSTGRESQL); vendorAdapter.setShowSql(true); LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); factory.setJpaVendorAdapter(vendorAdapter); factory.setPackagesToScan(...); factory.setDataSource(this.dataSource()); factory.afterPropertiesSet(); return factory.getObject(); } @Bean public JpaTransactionManager transactionManager() throws SQLException, NamingException { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(this.entityManagerFactory()); return transactionManager; } @Bean public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { return new PersistenceExceptionTranslationPostProcessor(); } } 

基本上我不确定使用上述配置的切入点。 我试图搞乱LocalContainerEntityManagerFactoryBean.setLoadTimeWeaver() ,但我无法弄明白。 我不知道我是否还需要配置它。

从本质上讲,我的AOP设置适用于我自己的自定义类。 我想问题是编织没有配置Hibernate或其他东西(我对这一部分非常不熟悉)或者由于我的设置而没有通过SessionFactory.getCurrentSession()方法获得会话。 我试图通过将我的切入点更改为execution(* org.hibernate.Hibernate.isInitialized(..))并在我的代码中手动调用Hibernate.isInitialized(null)来validation我的建议甚至可以使用Hibernate,但是这并没有触发建议,所以这可能是问题所在。 我尝试了这篇文章中的建议, 以启用Hibernate编织 ,但我无法让它有任何区别。

我还尝试将我的切入点设置为execution(* org.springframework.orm.hibernate4.SessionHolder.getSession(..))execution(* org.springframework.orm.jpa.vendor.HibernateJpaDialect.getSession(..)) ,但也没有任何运气。

所以,我不知道下一步该去哪里。 如何从我的建议中获取Hibernate的Session对象,以便我可以启用Hibernatefilter? 先感谢您!

编辑:以防万一,我的配置中有@EnableAspectJAutoProxy

 @Configuration @ComponentScan(basePackages = { ... }) @EnableAspectJAutoProxy(proxyTargetClass = true) public class AppConfig { // ... } 

也许只是你通过使用org.hibernate.SessionFactory接口作为执行参数来声明切入点这一事实……

@Pointcut("execution(* org.hibernate.SessionFactory.getCurrentSession(..))")

正确的方法是将切入点的执行定义为该接口的实现,并且其符号略有不同,请参阅+符号

@Pointcut("execution(* org.hibernate.SessionFactory+.getCurrentSession(..))")

另外一种表示法……

@Pointcut("within(org.hibernate.SessionFactory+) && execution(* getCurrentSession(..))")

你还应该看看aspectj-cheat-sheet

关于java.lang.IllegalArgumentException: Cannot subclass final class 。 目标类是org.hibernate.SessionFactory的具体实现,即org.hibernate.internal.SessionFactoryImpl ,恰好是final, public final class SessionFactoryImpl

根据文档, proxyTargetClass = true配置

指示是否要创建基于子类的(CGLIB)代理,而不是基于标准Java接口的代理。

但是,由于您尝试子类的类是final因此根据Java语言规范存在一些问题

如果最终类的名称出现在另一个类声明的extends子句(第8.1.4节)中,则是编译时错误; 这意味着最终的类不能有任何子类。

您的方面类似乎很好。

在您的实体上添加@Filter@FilterDef

  • @Filter:向实体或目标实体添加filter。
  • @FilterDef:定义filter定义名称和参数,以便在启用filter时设置值。

示例:

 @Entity @Table(name="myTable", schema="mySchema") @FilterDef(name="myFilter", parameters=@ParamDef(name="myAttribute", type="integer")) @Filter(name="myFilter", condition=":myAttribute <= attribute") public class MyEntity implements Serializable { ... @Column(name="attribute") private Integer attribute; ... } 

在您的配置中,filter已启用,但没有参数。

测试示例:

 session.enableFilter("myFilter").setParameter("myAttribute", Integer.valueOf(2)); 

当然,您可以在@FilterDef注释中根据需要设置任意数量的参数。

希望它能帮到你。 此致,安德烈。

面对确切的问题。 我能够通过使用EntityManager来解决它并使用其解包方法获取会话信息,而不是使用sessionFactory的getCurrentSession调用的切入点来获取会话信息。

 @PersistenceContext private EntityManager entityManager; @Around("myPointcut") public Object enableGlobalFilter(ProceedingJoinPoint pjp) throws Throwable { Session session = entityManager.unwrap(Session.class); Filter filter = session.enableFilter("Published_Entity"); filter.setParameter("is_publishedParam", true); Object obj = pjp.proceed(); session.disableFilter("Published_Entity"); return obj; } 

希望这可以帮助。