2015-10-04 22 views
6

JPAプロバイダとしてHibernate 4.3.8を使用するSpring Framework 4アプリケーションがあります。私はハイバネートフィルタを使用したいので、それらを有効にする必要があります。私はアプリケーションでこれを全世界的にやりたいと思っています。これはSpring AOPでやろうとしています。私は、セッションが作成/フェッチされるたびに、thisthisの質問のようなフィルタを有効にするという側面を書くことができます。Spring AOPでHibernateセッションを設定する

Mavenを使用して私のプロジェクトにspring-aopaspectjweaverの依存関係を追加しました。私は次の点を追加しました。

@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(..))にポイントカットを変更しようとしましたが、結果はありません。

これは、明示的にSessionFactoryを設定しないため、私はHibernateの設定方法が原因であると思われます。むしろ、私は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フィルタを有効にすることができますか?前もって感謝します!

EDIT: 念のために、私は私の構成で@EnableAspectJAutoProxy存在を持っています:

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

'@ComponentScan(" org.hibernate ")'は役に立ちますか? – Ruben

+0

@Rubenいいえ、違いはありません。 – Andy0708

+0

あなたは 'SessioNFactory'をインターセプトしていますが、単純なJPAを使用しています(実装者としてhibernateを使用しています)。明らかに決して進まないでしょう。あなたの設定には 'SessionFactory'がありません。したがって、あなたのアスペクトは何も一致しません。代わりに 'EntityManagerFactory.getEntityManager'のポイントカットを書きます。 –

答えて

1

は、多分それはあなたが実行引数としてorg.hibernate.SessionFactoryインタフェースを使用してポイントカットを宣言していることだけ事実です...

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

適切な方法は、implementatioとしてポイントカットの実行を定義することですそのインターフェイスのNS及びそのための表記法は、少しだけ異なっている、また別の表記を+符号

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

を見ます

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

またjava.lang.IllegalArgumentException: Cannot subclass final classについてaspectj-cheat-sheet

を見ている必要があります。 対象となるクラスは、org.hibernate.SessionFactoryの具体的な実装です。つまり、org.hibernate.internal.SessionFactoryImplは最終的にpublic final class SessionFactoryImplとなります。 documentation

に従って

proxyTargetClass = true構成は、標準のJavaインターフェースベースのプロキシとは対照的に、サブクラスベース(CGLIB)プロキシを作成するかどうかを示します。

しかし、最終的なクラスの名前が表示された場合、あなたはサブクラスにしようとしているクラスはfinal問題のビットがJava Language Specification

に応じてありますこれは、コンパイル時エラーとされているので別のクラス宣言のextends節(8.1.4)。これは、最終クラスにはサブクラスを持たないことを意味します。

+0

ありがとうございました!残念ながら、あなたが言及したポイントカットを試しましたが、私のために働かなかったのです。 – Andy0708

+0

'LocalContainerEntityManagerFactoryBean'の代わりに' LocalEntityManagerFactoryBean'を使ってみましたか?私はこの分野の専門家ではありませんが、アプリケーション管理のEntityManagerFactoryを生成する最初のものであり、後者によって生成されるコンテナ管理のEntityManagerFactoryではないことがわかります...そして、私たちはSpringがこれを管理して、作品:) – Filip

+0

今私はaopがクールであることを理解していますが、セッション管理に関する次の可能な解決策を実際に見てください。 docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/hibernate4/support/OpenSessionInterceptor.html)または[org.hibernate.SessionEventListener](https://docs.jboss.org/hibernate)を参照してください。 /more/4.3/javadocs/org/hibernate/SessionEventListener.html) – Filip

1

あなたのアスペクトクラスは良いと思われます。

はあなたのエンティティに @FilterDefと@Filter を追加します。

  • @Filter:をエンティティまたはターゲット・エンティティにフィルタを追加します。
  • @FilterDef:フィルターを有効にしているときに値を設定するフィルター定義名とパラメーターを定義します。

例:お使いの設定で

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

、フィルタが有効になってますが、パラメータはありませんされています。テストへ

例:もちろん

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

あなたは@FilterDef注釈に必要として、あなたは、多くのパラメータを設定することができます。

あなたのお役に立てれば幸いです。よろしく、アンドレ。

+0

私は既に自分のエンティティ内でフィルタを宣言していますが、セッションでフィルタが有効にならないという問題があります。これは私の中で起こるはずですが、そのコードは実行されないのでフィルタは決して有効になりません。私のフィルタはパラメータを必要としないので、私は何も追加していません。 – Andy0708

0

正確な問題に直面していました。 私は、SessionFactoryのgetCurrentSession呼び出しの周りにpointcutを使用してセッション情報を取得するのではなく、EntityManagerを使用してunwrapメソッドを使用してセッション情報を取得することで解決できました。

@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; 
} 

これが役立ちます。

関連する問題