會話bean(session bean),可以分爲無狀態會話bean和有狀態會話bean
負責與客戶端交互,是編寫業務邏輯的地方,在會話bean中可以通過jdbc直接操作數據庫,但大多數情況下都是通過實體bean來完成對數據庫的操作.
平常,我們使用最多的是無狀態bean,因爲它的bean實例可供多個用戶使用,所以它的性能比有狀態bean高.正因爲一個bean實例被多個用戶使用.那麼,前一個用戶設置的值有可能被後一個用戶所修改,所以它無法正確保存某個用戶設置的值,因此是無狀態的.
有狀態bean平常使用的並不多,因爲它的一個bean實例只供一個用戶使用,所以性能開銷比較大,正因爲它的實例只被一個用戶使用,用戶爲它設置的值是不會被其他用戶修改,所以可以正確保存用戶設置的值,因此是有狀態的.
如何開發一個無狀態會話bean?1.可以在jboss安裝路徑的client目錄下找到,通常會把client目錄下的所有jar文件添加到項目的類路徑下.
2.開發接口和實現類:
public String sayHello(String name);
}
@Remote(HelloWorld.class)
public class HelloWorldBean implements HelloWorld {
@Override
public String sayHello(String name) {
return name+"說:你好啊!";
}
}
public class EJBClient {
public static void main(String[] args) {
try {
InitialContext ctx = new InitialContext();
HelloWorld helloworld = (HelloWorld) ctx
.lookup("HelloWorldBean/remote");//參數裏面的是JNDI名稱
System.out.println(helloworld.sayHello("張三"));
} catch (NamingException e) {
System.out.println(e.getMessage());
}
}
}
重要的幾點:
1.在進行JNDI查找前,我們必須設置應用服務器的上下文信息,主要是設置JNDI驅動的類名(java.naming.factory.initial)和命名服務提供者的URL (java.naming.provider.url) 。
如同數據庫一樣,根據訪問命名服務器的不同,爲上下文設置的驅動類和URL也是不同的
創建InitialContext對象時如果沒有指定Properties參數,InitialContext還會在classpath下尋找jndi.properties文件,並從該文件中加載應用服務器的上下文信息。這樣避免了硬編碼爲InitialContext設置Properties參數。
jndi.properties的配置如下:(這個是用作爲jboss應用服務器的上下文信息)
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost:1099
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
2.當EJB發佈到Jboss 時,如果我們沒有爲它指定全局JNDI名稱或修改過其默認EJB名稱,Jboss就會按照默認的命名規則爲EJB生成全局JNDI名稱,默認的命名規則如下:
如果把EJB作爲模塊打包進後綴爲*.ear的JAVA EE企業應用文件,默認的全局JNDI名稱是
EAR-FILE-BASE-NAME爲ear文件的名稱,EJB-CLASS-NAME爲EJB的非限定類名。
例:把HelloWorld應用作爲EJB模塊打包進名爲HelloWorld.ear的企業應用文件,它的遠程接口的JNDI 名稱是:HelloWorld/HelloWorldBean/remote
如果把EJB應用打包成後綴爲*.jar的模塊文件,默認的全局JNDI名稱是
例:把HelloWorld應用打包成HelloWorld.jar文件,它的遠程接口的JNDI名稱是:HelloWorldBean/remote
可以使用註釋改變會話Bean的JNDI 名稱
如果我們沒有指定EJB的JNDI名稱,當EJB發佈到應用服務器時,應用服務器會按默認規則爲EJB生成全局JNDI名稱。當我們需要自定義JNDI名稱時,可以這樣做
如果EJB在Jboss中使用,可以使用Jboss提供的 @LocalBinding 和 @RemoteBinding 註釋,@LocalBinding註釋指定Session Bean的Local接口的JNDI名稱,@RemoteBinding註釋指定Session Bean的Remote接口的JNDI名稱,如下:
@Stateless
@Remote ({Operation.class})
@RemoteBinding (jndiBinding="foshanshop/RemoteOperation")
@Local ({LocalOperation.class})
@LocalBinding (jndiBinding="foshanshop/LocalOperation")
public class OperationBean implements Operation, LocalOperation {
}
也可以使用xml部署描述文件改變SessionBean的JNDI 名稱由於JNDI名稱與廠商有關,如果使用註釋定義JNDI名稱會帶來移植問題,因此建議使用ejb-jar.xml部署描述文件進行定義,該文件必須放置在jar的META-INF目錄下
<?xml version="1.0"encoding="UTF-8"?>
<ejb-jar xmlns=http://java.sun.com/xml/ns/javaee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd" version="3.0">
<enterprise-beans>
<session>
<ejb-name>HelloWorldBean</ejb-name>
<mapped-name>HelloWorldBean</mapped-name>
</session>
</enterprise-beans>
</ejb-jar>
ejb-name爲EJB名稱,mapped-name爲bean的JNDI名稱。目前jboss不支持在ejb-jar.xml通過mapped-name指定JNDI名稱,但我們可以使用他專屬的部署描述文件jboss.xml進行定義,如下:
<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE jboss PUBLIC "-//JBoss//DTDJBOSS 4.2//EN“ "http://www.jboss.org/j2ee/dtd/jboss_4_2.dtd">
<jboss><enterprise-beans> <session>
<ejb-name>HelloWorldBean</ejb-name>
<jndi-name>hello/remote</jndi-name>
</session></enterprise-beans></jboss>
具有Local接口的Session bean首先了解一下通過遠程接口調用ejb的過程,首先客戶端需要與ejb建立起socket通信,在通信管道上他們之間需要來回發送IIOP協議消息,因爲數據要在網絡進行傳輸,存放數據的java對象必須要進行序列化。
在這個過程中我們看到,有網絡通信的開銷、協議解析的開銷、對象序列化的開銷。因爲ejb是分佈式技術,它允許客戶端與ejb應用在不同一機器上面,所以這些性能開銷也是必然的。但是在實際生產中,不可避免存在這種情況:客戶端與EJB應用運行在同一個jboss中。這時候客戶端訪問ejb是否有必要走上面的網絡通信呢?據我們所知,這時候客戶端與ejb是在同一個jvm內,他們之間完全可以通過內存進行交互,這樣就可以避免網絡通信的性能開銷。既然我們都想到了這一點,EJB專家組也想到了這一點,所以引入了本地接口。通過本地接口調用ejb,直接在內存中交互,這樣就能避免因網絡通信所造成的各種性能開銷。但是有一點,大家必須注意,只有客戶端與EJB應用在同一個JVM內運行的時候,我們才能調用本地接口,否則只能調用遠程接口。談到這裏,有同學會問什麼情況下客戶端與EJB應用是在同一個JVM?簡單地說只要客戶端與ejb發佈在同一個jboss內,我們就認爲他們是在同一個JVM
@Stateless
@Local ({HelloWorldLocal.class})
public class HelloWorldBean implements HelloWorldLocal {
public String say (String name) {
return name +"說:你好!世界,這是我的第一個EJB3哦.";
}
}
如何訪問具有本地接口的會話bean呢?新建一個web項目,在jsp裏面進行訪問 ,然後打好war包,把打好的war包放到jboss的default/deploy目錄下面,這樣確保客戶端與EJB應用運行在同一個jboss中
<%@ page import="cn.itcast.ejb3.HelloWorldLocal, javax.naming.*, java.util.Properties"%>
<%
try {
InitialContext ctx = new InitialContext();
HelloWorldLocal helloworld = (HelloWorldLocal) ctx.lookup("HelloWorldBean/local");
out.println(helloworld.sayHello("佛山人"));
} catch (NamingException e) {
out.println(e.getMessage());
}
%>
然後訪問這個jsp頁面即可
一般做應用的時候是既做一個本地接口,也做一個遠程接口如果客戶端應用與ejb部署在同一個jboss內的話,會優先應用本地接口,否則用遠程接口.