使用Spring AOP配置Hibernate会话 - java

我有一个使用Hibernate 4.3.8作为JPA提供程序的Spring Framework 4应用程序。我想使用休眠过滤器,因此需要启用它们。我想在应用程序中全局进行此操作,而我正在尝试使用Spring AOP。我的想法是,我可以编写一个方面,以便每次创建/获取会话时都启用过滤器,例如this和this问题。

我已经将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)从未被调用;既不会打印文本,也不会启用我的过滤器。我已经通过将切入点更改为自己的类之一来验证是否可以检测到我的方面并且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)来验证我的建议是否与Hibernate兼容,但这也没有触发建议,因此这可能就是问题所在。我尝试了this post to enable Hibernate weaving中建议的内容,但无法做出任何改变。

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

因此,我不确定下一步要去哪里。如何从我的建议中保留Hibernate的Session对象,以便可以启用Hibernate过滤器?先感谢您!

编辑:
以防万一,我的配置中确实存在@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,它恰好是最终的public final class SessionFactoryImpl

根据documentation的proxyTargetClass = true配置

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

但是由于您要子类化的类是final,所以根据Java Language Specification有点问题

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

Spring MVC中的输入验证 - java

我知道Commons Validator框架是Struts项目在服务器端和客户端验证输入值的事实上的标准。Spring MVC项目是否也是如此?我得到的印象可能不是,大多数Struts书籍和论坛都谈论Commons Validator框架,但是只有少数Spring书籍和论坛可以。在Spring MVC项目中验证输入的最佳实践是什么?干杯! 参考方案 在引入S…

Hibernate:现实世界中的模式导出? - java

我很好奇我的下一个项目完全使用架构导出。我认为这是真正处理对象而非基础数据库的非常有用的方法。只需创建并注释模型,然后将其导出即可。但是从先创建表然后创建模型对象的习惯来看,我对完全使用模式导出有疑问。这主要是因为我真的很深入休眠。但是我仍然好奇使用模式导出时,该区域列表是否会成为问题。请分享您的经验..表之间的关系代理/复合主键支持当我只想从多个模型中导出…

Java:“自动装配”继承与依赖注入 - java

Improve this question 我通常以常见的简单形式使用Spring框架: 控制器服务存储库通常,我会在CommonService类中放一个通用服务,并使所有其他服务扩展到类中。一个开发人员告诉我,最好在每个服务中插入CommonClass而不是使用继承。我的问题是,有一个方法比另一个更好吗? JVM或性能是否会受到另一个影响?更新资料Comm…

在AbstractTransactionalTestNGSpringContextTests中的hibernate和JdbcTemplate之间共享Spring事务 - java

我正在AbstractTransactionalTestNGSpringContextTests的子类中运行测试,在此我通过部分Spring上下文执行测试。每个测试都在一个事务中运行,该事务在最后回滚以使数据库保持不变。一种测试通过Hibernate写入数据库,而另一种则使用JdbcTemplate从同一数据库读取数据,并且两者共享相同的数据源。我发现通过J…

Spring MVC Web应用程序检测暴力攻击的最佳方法? - java

Spring 3.0 MVC中是否有专门用于帮助检测Web应用程序的身份验证/登录页面上的蛮力攻击的功能? 参考方案 经过长期验证的实践是,如果身份验证失败,则会引入随机但相当大的延迟。这样,合法用户将立即登录,但攻击者每次尝试将花费500ms-1s,这使整个暴力概念不切实际(将永远存在)。合法用户偶尔失败的登录只会使他们稍有延迟,并且不会引起注意。如果需要…