2

Glassfish v3 サーバーを使用しています。

通常、EJB3 + JPA (Eclipselink) との DB 接続は、@PersistenceUnit または @Persistencecontext を使用したインジェクションによって行われます。

ただし、私のアプリには3つのレイヤーがあります:

  • コア (ビジネス ロジック、エンティティ、例外処理などを含む)

  • その上に EJB を配置し、適切なコア オブジェクトとメソッドを呼び出してジョブを実行します。この EJB は、ERP の他の内部モジュールによって呼び出されます。

  • フロントエンド Web サイトで使用するための REST レイヤー。

EJB で entityManager も EMF (EM ファクトリ) も取得したくありません。これは、中間層がその下で使用される DB があることを認識しないようにするためです。結局、後で、コアの実装を DB を使用しない実装に変更することを決定できます。

私は2つの悪い解決策しか見ていません:

  • 1) DB 接続が必要なコア層のメソッドを呼び出すたびに EM パラメータを追加します。非常に醜く、私が上で言ったことに反します。

  • 2) DB 接続を必要とするコアのすべてのメソッドで、ファクトリ、EM を作成し、それらを使用してから、両方を閉じます。

Core レベルのクラスごとに 1 つのファクトリを持ち、すべてのメソッドで EM が作成され、閉じられます。しかし、私はまだこのようなメモリリークがあります:

javax.servlet.ServletException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.0.v20091127-r5931): org.eclipse.persistence.exceptions.DatabaseException

Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: In-use connections equal max-pool-size and expired max-wait-time. Cannot allocate more connections.

私の EJB メソッドの 1 つが 10 個の異なるオブジェクトを使用すると、10 個の EM ファクトリが作成され、どれも閉じられていないためだと思います。

Core オブジェクトでの一般的な使用例:

 EntityManager em = emf.createEntityManager();
 em.getTransaction().begin();
 // do some stuff with em; for example persist, etc
 em.flush();
 em.close();

解決策 2 を使用する必要がありますか? このコア レベルで単一の EM ファクトリを使用する方法はありますか? JPA 仕様では、EJB レベルでのみエンティティを使用することを想定しているようですが、これは多層アプリでは不適切です。

編集: @Inject を試した後の現在のステータスは次のとおりです。

  • CORE jar の /META-INF ディレクトリに空の beans.xml ファイルを追加しました。

  • 親DAOクラスは次のようになりました:

    public class ExampleBZL {

     public EntityManagerFactory emf;
     @Inject public Emf emfobject;
    
     public ExampleBZL()
     {
        this.emf = emfobject.emf;
     }
    
  • Emf クラスは非常に単純で、ステートレスです。

    @Stateless public class Emf は EmfAbstract を実装します {

    @PersistenceUnit(unitName = Setup.persistenceUnitName)
    public EntityManagerFactory emf;
    
    public Emf()
    {
    }
    

    }

私は何か間違ったことをしているに違いありませんが、グラスフィッシュではエンジンリストに「[ejb、weld、web]」が表示されているため、CDIがロードされていますが、インジェクションは機能しません。

Servlet.service() for servlet Jersey Web Application threw exception
java.lang.NullPointerException
    at com.blablabla.core.bizlogic.ExampleBZL.<init>(ExampleBZL.java:40)

他の注釈がありませんか?? これら 2 つの小さな注釈 (一方はステートレス、もう一方は注入) を使用して JAR で inect を実行することは本当に機能していますか?

4

4 に答える 4

1

JavaEE 6 では、コア レベルのクラスを Bean として定義し、そこにリソースを注入できます。JavaEE 6 で Context and Dependency Injection (CDI) を確認してください。

于 2010-08-19T12:32:03.723 に答える
0

2つのセッションBeanがある場合はどうなりますか?1つはJTAを活用できるEntityManagerが注入されたもので、もう1つは現在のセッションBeanです。

現在、EclipseLinkとGlass Fish v3を使用したRESTサービスとしてセッションBeanを使用して、ブログにシリーズをまとめています。

以下は、RESTサービスとして機能しているセッションBeanにEntityManagerを注入する方法です。

package org.example.customer;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.ws.rs.Path;

import org.eclipse.persistence.rest.JPASingleKeyResource;

@Stateless
@LocalBean
@Path("/customers")
public class CustomerService  {

    @PersistenceContext(unitName="CustomerService", type=PersistenceContextType.TRANSACTION)
    EntityManager entityManager;

}

@EJBアノテーションを使用してセッションBeanをリンクできます。

package org.example;

import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.naming.Context;
import javax.naming.InitialContext;

@Stateless
@LocalBean
@EJB(name = "someName", beanInterface = CustomerService.class)
public class OtherSessionBean {

    public Customer read(long id) {
        try {
            Context ctx = new InitialContext();
            CustomerService customerService = (CustomerService) ctx.lookup("java:comp/env/someName");
            return customerService.read(id);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

}
于 2010-08-19T17:52:12.563 に答える
0

それが良い答えかどうかはわかりませんが、これを見つけました: フォーラムのリンク

JPA と CDI の間の相互作用が考慮されたようですが、何らかの理由で仕様の一部にはなりませんでした。理由がわかったら、このスレッドを更新します。その間、それは適切な人々にフィードバックとして送信されました. したがって、これは間違いなく GlassFish のバグではありません。

では、Java クラスの (エンティティ マネージャを含むクラスの) @Inject が機能しない理由を説明できますか?

于 2010-08-24T08:49:00.573 に答える
0

Blaise のおかげで、最終的な作業コードは次のとおりです。

  • 接続を「受け取る」親クラス

    com.wiztivi.apps.wsp.billing.interfaces.bin.db.NewInterface をインポートします。import javax.ejb.LocalBean; import javax.ejb.Stateless; javax.naming.Context をインポートします。import javax.naming.InitialContext; import javax.persistence.EntityManager;

    @Stateless
    @LocalBean
    public class FatherService {
    
     public EntityManager em;
    
     public FatherService()
     {
     }
    
    
    
     public EntityManager getGoodEm()
     {
        try {
            Context ctx = new InitialContext();
            NewInterface dp = (NewInterface) ctx.lookup("java:global/billing-ear/billing-connection/DataProvider");
            em = dp.getEm();
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
         return em;
     }
    
    }
    
  • 接続を「提供」するクラス (別の接続 JAR で、エンティティを使用)

    import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.persistence.EntityManager; javax.persistence.PersistenceContext をインポートします。import javax.persistence.PersistenceContextType;

    @Stateless @LocalBean public class DataProvider は NewInterface {

    @PersistenceContext(unitName=Setup.persistenceUnitName, type=PersistenceContextType.TRANSACTION)
    public EntityManager entityManager;
    
    public DataProvider() {
    }
    
    @Override
    public EntityManager getEm()
    {
        return entityManager;
    }
    

    }

何か重要なこと:FatherService EJB(私の場合はRESTクラス)を呼び出す「上位レベル」レイヤーのクラスに@Statelessを配置する必要があります。コアレイヤーはEJBとしてパッケージ化する必要があり、接続もEAR 内の両方

于 2010-09-06T16:28:37.060 に答える