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
  3. Add Book
  4. Exit Enter Choice: 2 Book(s) entered so far: 1
  5. 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
  3. Learn Java BUILD SUCCESSFUL (total time: 12 seconds)
  • 如上圖所示的輸出可能會有所不同,這取決於許多無狀態JBoss的EJB對象保持。

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

  • EJB容器可以爲每個查詢返回相同的無狀態EJB對象。

無狀態EJB的bean實例變量的值是直到重新啓動服務器才失效的。