EJB無狀態Bean


無狀態對談bean是一種企業bean,通常是用於執行獨立操作。正如它的名字一樣,無狀態對談bean不具有任何關聯的用戶端的狀態,但它可能會保持其範例的狀態。 EJB容器通常建立一個容器池和幾無狀態的bean的物件,並使用這些物件來處理用戶端的請求。由於有容器池,範例變數的值不能保證跨查詢/方法呼叫同一個。

下面是建立一個無狀態的EJB所需的步驟。

  • 建立一個遠端/本地介面暴露的業務方法。

  • 此介面將用於EJB用戶端應用程式。

  • 使用@ Local註釋如果EJB用戶端是在相同的環境中部署EJB對談Bean。

  • 使用@ Remote批註如果EJB用戶端是在不同的環境中部署EJB對談Bean。

  • 建立一個無狀態對談bean實現上述介面。

  • 使用@ Stateless註釋,以表示它一個無狀態的bean。 EJB容器會自動建立通過讀取這個註解,在部署過程中的相關組態或介面。

Remote Interface

import javax.ejb.Remote;
 
@Remote
public interface LibrarySessionBeanRemote {
   //add business method declarations
}

Stateless EJB

@Stateless
public class LibrarySessionBean implements LibrarySessionBeanRemote {
   //implement business method 
}

範例應用程式

讓我們建立一個測試測試無狀態EJB的EJB應用程式。

步驟 描述
1 Create a project with a name EjbComponent under a package com.tutorialspoint.stateless as explained in the EJB - Create Application chapter. You can also use the project created in EJB - Create Application chapter as such for this chapter to understand stateless ejb concepts.
2 Create LibrarySessionBean.java and LibrarySessionBeanRemote as explained in the EJB - Create Application chapter. Keep rest of the files unchanged.
3 Clean and Build the application to make sure business logic is working as per the requirements.
4 Finally, deploy the application in the form of jar file on JBoss Application Server. JBoss Application server will get started automatically if it is not started yet.
5 Now create the ejb client, a console based application in the same way as explained in theEJB - Create Application chapter under topic Create Client to access EJB.

EJBComponent (EJB Module)

LibrarySessionBeanRemote.java

package com.tutorialspoint.stateless;
 
import java.util.List;
import javax.ejb.Remote;
 
@Remote
public interface LibrarySessionBeanRemote {
   void addBook(String bookName);
   List getBooks();
}

LibrarySessionBean.java

 
package com.tutorialspoint.stateless;
 
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
 
@Stateless
public class LibrarySessionBean implements LibrarySessionBeanRemote {
    
   List<String> bookShelf;    
 
   public LibrarySessionBean(){
      bookShelf = new ArrayList<String>();
   }
 
   public void addBook(String bookName) {
      bookShelf.add(bookName);
   }    
 
   public List<String> getBooks() {
      return bookShelf;
   }
}
  • As soon as you deploy the EjbComponent project on JBOSS, notice the jboss log.

  • JBoss has automatically created a JNDI entry for our session bean -LibrarySessionBean/remote.

  • We'll using this lookup string to get remote business object of type -com.tutorialspoint.stateless.LibrarySessionBeanRemote

JBoss應用伺服器的紀錄檔輸出

...
16:30:01,401 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.tutorialspoint.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface
16:30:02,723 INFO  [SessionSpecContainer] Starting jboss.j2ee:jar=EjbComponent.jar,name=LibrarySessionBean,service=EJB3
16:30:02,723 INFO  [EJBContainer] STARTED EJB: com.tutorialspoint.stateless.LibrarySessionBeanRemote ejbName: LibrarySessionBean
16:30:02,731 INFO  [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI:
 
   LibrarySessionBean/remote - EJB3.x Default Remote Business Interface
   LibrarySessionBean/remote-com.tutorialspoint.stateless.LibrarySessionBeanRemote - EJB3.x Remote Business Interface
...   

EJBTester (EJB Client)

jndi.properties

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
  • These properties are used to initialize the InitialContext object of java naming service

  • InitialContext object will be used to lookup stateless session bean

EJBTester.java

package com.tutorialspoint.test;
   
import com.tutorialspoint.stateful.LibrarySessionBeanRemote;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
 
public class EJBTester {
 
   BufferedReader brConsoleReader = null; 
   Properties props;
   InitialContext ctx;
   {
      props = new Properties();
      try {
         props.load(new FileInputStream("jndi.properties"));
      } catch (IOException ex) {
         ex.printStackTrace();
      }
      try {
         ctx = new InitialContext(props);            
      } catch (NamingException ex) {
         ex.printStackTrace();
      }
      brConsoleReader = 
      new BufferedReader(new InputStreamReader(System.in));
   }
   
   public static void main(String[] args) {
 
      EJBTester ejbTester = new EJBTester();
 
      ejbTester.testStatelessEjb();
   }
   
   private void showGUI(){
      System.out.println("**********************");
      System.out.println("Welcome to Book Store");
      System.out.println("**********************");
      System.out.print("Options 
1. Add Book
2. Exit 
Enter Choice: ");
   }
   
   private void testStatelessEjb(){
 
      try {
         int choice = 1; 
 
         LibrarySessionBeanRemote libraryBean =
         LibrarySessionBeanRemote)ctx.lookup("LibrarySessionBean/remote");
 
         while (choice != 2) {
            String bookName;
            showGUI();
            String strChoice = brConsoleReader.readLine();
            choice = Integer.parseInt(strChoice);
            if (choice == 1) {
               System.out.print("Enter book name: ");
               bookName = brConsoleReader.readLine();
               Book book = new Book();
               book.setName(bookName);
               libraryBean.addBook(book);          
            } else if (choice == 2) {
               break;
            }
         }
 
         List<Book> booksList = libraryBean.getBooks();
 
         System.out.println("Book(s) entered so far: " + booksList.size());
         int i = 0;
         for (Book book:booksList) {
            System.out.println((i+1)+". " + book.getName());
            i++;
         }       
         LibrarySessionBeanRemote libraryBean1 = 
            (LibrarySessionBeanRemote)ctx.lookup("LibrarySessionBean/remote");
         List<String> booksList1 = libraryBean1.getBooks();
         System.out.println(
            "***Using second lookup to get library stateless object***");
         System.out.println(
            "Book(s) entered so far: " + booksList1.size());
         for (int i = 0; i < booksList1.size(); ++i) {
            System.out.println((i+1)+". " + booksList1.get(i));
         }		 
      } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
      }finally {
         try {
            if(brConsoleReader !=null){
               brConsoleReader.close();
            }
         } catch (IOException ex) {
            System.out.println(ex.getMessage());
         }
      }
   }
}

EJBTester在執行以下任務。

  • Load properties from jndi.properties and initialize the InitialContext object.

  • In testStatelessEjb() method, jndi lookup is done with name - "LibrarySessionBean/remote" to obtain the remote business object (stateless ejb).

  • Then user is shown a library store User Interface and he/she is asked to enter choice.

  • If user enters 1, system asks for book name and saves the book using stateless session bean addBook() method. Session Bean is storing the book in its instance variable.

  • If user enters 2, system retrieves books using stateless session bean getBooks() method and exits.

  • Then another jndi lookup is done with name - "LibrarySessionBean/remote" to obtain the remote business object (stateless ejb) again and listing of books is done.

執行用戶端存取EJB

Locate EJBTester.java in project explorer. Right click on EJBTester class and select run file.

Verify the following output in Netbeans console.

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 1
Enter book name: Learn Java
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 1
1. Learn Java
***Using second lookup to get library stateless object***
Book(s) entered so far: 0
BUILD SUCCESSFUL (total time: 13 seconds)

再次執行用戶端存取EJB

在專案資源管理器中找到EJBTester.java。右鍵點選上EJBTester類,並選擇run file.

在Netbeans控制台驗證以下輸出。

run:
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 0
***Using second lookup to get library stateless object***
Book(s) entered so far: 1
1. Learn Java
BUILD SUCCESSFUL (total time: 12 seconds)
  • 如上圖所示的輸出可能會有所不同,這取決於許多無狀態JBoss的EJB物件保持。

  • 萬一單一的無狀態EJB物件得以維持,每次查詢後,你可能會看到相同書籍列表。

  • EJB容器可以為每個查詢返回相同的無狀態EJB物件。

無狀態EJB的bean範例變數的值是直到重新啟動伺服器才失效的。