為了解決RMI無法解決的分布式事務(wù)控制,安全,并發(fā)等問題。
EJB解決訪問就是一種可以高校的開發(fā)分布式應(yīng)用的解決方案。
編寫EJB,其實(shí)只需要編寫2個接口和一個Bean類,和一個部屬描述就可以了。
服務(wù)接口:
import?javax.ejb.*;
import?java.rmi.*;
//business???remote

public?interface?Compute?extends?EJBObject
{
????public?double?add(double?a,double?b)?throws?RemoteException;
}

Home接口:
import?javax.ejb.*;
import?java.rmi.*;


public?interface?ComputeHome?extends?EJBHome
{
????public?Compute?create()?throws?RemoteException,CreateException;
}Bean,業(yè)務(wù)邏輯實(shí)現(xiàn)的地方
import?javax.ejb.*;

public?class?ComputeBean?implements?SessionBean


{
????public?void?setSessionContext(SessionContext?ctx)
???????????????????????throws?EJBException,

??????????????????????????????java.rmi.RemoteException
{
????}
????public?void?ejbRemove()
???????????????throws?EJBException,

??????????????????????java.rmi.RemoteException
{
????}
????public?void?ejbActivate()
?????????????????throws?EJBException,

????????????????????????java.rmi.RemoteException
{
????}
????public?void?ejbPassivate()
??????????????????throws?EJBException,

?????????????????????????java.rmi.RemoteException
{
????}

????public?void?ejbCreate()?throws?CreateException
{
????}

????public?double?add(double?a,double?b)
{
????????return?a*b;
????}
}

<?xml?version="1.0"?encoding="UTF-8"?>
<!DOCTYPE?ejb-jar?PUBLIC?"-//Sun?Microsystems,?Inc.//DTD?Enterprise?JavaBeans?2.0//EN"?"http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
????<enterprise-beans>
????????<session>
????????????<display-name>Compute</display-name>
????????????<ejb-name>abc</ejb-name>

????????????<home>ComputeHome</home>
????????????<remote>Compute</remote>
????????????<ejb-class>ComputeBean</ejb-class>

????????????<session-type>Stateless</session-type>
????????????<transaction-type>Container</transaction-type>?????
????????</session>
????</enterprise-beans>
????<assembly-descriptor>
????????<container-transaction>
????????????<method>
????????????????<ejb-name>abc</ejb-name>
????????????????<method-name>*</method-name>
????????????</method>
????????????<trans-attribute>Required</trans-attribute>
????????</container-transaction>
????????
????</assembly-descriptor>
</ejb-jar>JNDI的實(shí)現(xiàn)各個服務(wù)器的實(shí)現(xiàn)不同,所以需要依賴于服務(wù)器的一個xml。
JNDI也是一種面向接口編程,工廠模式的典范。
<?xml?version="1.0"?encoding="UTF-8"?>
<!DOCTYPE?weblogic-ejb-jar?PUBLIC?'-//BEA?Systems,?Inc.//DTD?WebLogic?8.1.0?EJB//EN'?'http://www.bea.com/servers/wls810/dtd/weblogic-ejb-jar.dtd'>
<weblogic-ejb-jar>
????<weblogic-enterprise-bean>
????????<ejb-name>abc</ejb-name>????????
????????<jndi-name>efg</jndi-name>
????</weblogic-enterprise-bean>
</weblogic-ejb-jar>
想編譯EJB,需要j2ee jar,那就用\bea\weblogic81\server\lib\weblogic.jar
做一個META-INF放置兩個xml文件
jar -cvf Compute.jar *.class META-INF/*.xml
c創(chuàng)建,v看到它創(chuàng)建的過程,f文件名
部屬EJB,看看Weblogic幫助吧。
=============================
那么會發(fā)現(xiàn)jar文件中并沒有出現(xiàn)_stub或者_(dá)skeleton文件阿,那是因?yàn)橛扇萜髟谶\(yùn)行EJB時動態(tài)創(chuàng)建在容器內(nèi)部了。
那么怎么才能看到呢?我們要分析阿。
java weblogic.appc ejb.jar
如果抱錯,在classpath中添加\jdk142_04\lib\tools.jar
如果想看原文件的話,就是-keepgenerated

===============================
開始分析EJB工作原理
看下面一張圖,就清楚了,實(shí)際就是兩次RMI 調(diào)用。

要細(xì)致來說。
基本是這樣的。
定義Home接口,主要是為讓客戶端有可能在創(chuàng)建EJB Bean對象時,給予初始化。
import?javax.ejb.*;
import?java.rmi.*;


public?interface?ComputeHome?extends?EJBHome
{
????public?Compute?create()?throws?RemoteException,CreateException;
}
這只是一個接口,weblogic.appc會生成一個HomeImpl,并生成Stub和Skeleton對象。在客戶端JNDI查找時,返回就是這個HomeImpl的Stub對象,注意類文件也會動態(tài)下載的。
create()與ejbcreate()方法是對應(yīng)的。
可有參數(shù)。
//Bean


???public?void?ejbCreate(String?param)?throws?CreateException?
{
????????//?TODO?Auto-generated?method?stub
????????this.userName?=?param;
????}


//Home

public?com.infogo.interfaces.Shopping?create(java.lang.String?param)
??????throws?javax.ejb.CreateException,java.rmi.RemoteException;===========
那么客戶端實(shí)際調(diào)用的是HomeImpl的Stub對象的方法,通過網(wǎng)絡(luò)傳送到服務(wù)器上的Skeleton,Skeleton再調(diào)用真正的HomeImpl對象的方法,創(chuàng)建一個創(chuàng)建Bean對象放入實(shí)例池,Impl調(diào)用Bean的ejbcreate方法,初始化參數(shù)。
并且HomeImpl,還要創(chuàng)建一個業(yè)務(wù)業(yè)務(wù)接口的實(shí)現(xiàn)類,并把業(yè)務(wù)接口實(shí)現(xiàn)類(EOImpl)對象的Stub返回給客戶端。
客戶端拿到Stub,調(diào)用響應(yīng)服務(wù)方法(別忘了,真正的服務(wù)方法實(shí)現(xiàn)可是在Bean類里),所以調(diào)用Stub方法,通過網(wǎng)絡(luò)傳遞EOImpl的Skeleton對象,然后調(diào)用EOImpl的響應(yīng)方法。
這是注意,EOImpl被稱為請求攔截器,因?yàn)樗鼤谶@時察看ejb-jar.xml,看一看方法聲明的事務(wù)類型,并調(diào)用容器提供的API(安全、事務(wù)等)。所以這種服務(wù)器或者容器叫做隱式容器,它有工具生成的類來調(diào)用容器相關(guān)API。而不是用戶直接調(diào)用。
在EOImpl調(diào)用完容器API之后,就會調(diào)用Bean的業(yè)務(wù)方法。
最后將接口-Skeleton-Stub-客戶端。
所以是兩次RMI調(diào)用。
這就是EJB工作原理。
import?javax.naming.*;
import?java.util.*;
import?javax.rmi.*;


public?class?Client


{
????public?static?void?main(String[]?args)?throws?Exception

????
{
????????Hashtable?hash?=?new?Hashtable();
????????hash.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
????????hash.put(Context.PROVIDER_URL,"t3://localhost:7001");
????????InitialContext?ic?=?new?InitialContext(hash);
????????
????????ComputeHome?home?=?(ComputeHome)ic.lookup("efg");
????????
????????//(ComputeHome)ProtableRemoteObject.narrow(ic.lookup("efg"),ComputeHome.class);

???????/**//*
????????*?客戶端從服務(wù)器獲得HomeImpl_stub?.class文件,并獲得HomeImpl_stub的對象
????????*?
????????*?home.create()-->HomeImpl_stub.create()-->網(wǎng)絡(luò)發(fā)送-->HomeImpl_skel.create()-->HomeImpl創(chuàng)建ComputeBean對象-->ComputeBean.ejbcreate()&&HomeImpl還要創(chuàng)建EOImpl_stub對象,返回HomeImpl_skel--->[網(wǎng)絡(luò)往回傳輸]--->HomeImpl_stub--->客戶端拿到EOImpl_stub對象。
????????*
????????*?這時完成了第一次rmi
????????*
????????*?c獲得了EOImpl_Stub對象,
????????*?
????????*?c.add(32,32)---->?EOImpl_Stub.add()--->網(wǎng)絡(luò)發(fā)送--->EOImpl_Skel.add()--->EOImpl--->[根據(jù)xml描述的事務(wù),進(jìn)行事務(wù)描述]--->判斷add方法是否開始事務(wù)--->調(diào)用創(chuàng)建好Bean對象的add方法---->方法結(jié)果給EOImpl_Skel---->網(wǎng)絡(luò)往回傳輸---->EOImpl_Stub----客戶端拿到結(jié)果。
????????*
????????*?第二次rmi完成。
????????*/
????????
????????
????????
????????Compute?c?=?home.create();
????????System.out.println(c.add(32,32));
????????
????}???
}