本文的研究基於jboss-eap-4.3,一開始解決一個問題,接下來實驗jboss-eap-4.3的一些簡單屬性。
1. 解決一個簡單問題
問題如上一篇博客描述:jboss-eap-4.3啓動時停滯在Configuring from URL: resource:jboss-log4j.xml ,詳細描述可以參見鏈接http://kylinsoong.iteye.com/blog/793215;
問題解決:
先區別兩個不同版本的JBOSS:jboss-4.2.2.GA和jboss-eap-4.3:
jboss-4.2.2.GA | jboss-eap-4.3 |
普通JBOSS,完全開源,相比較簡單,用於簡單個人的實驗與測試,啓動時顯示啓動完全過程,即啓動時間。 | eap(Enterprise Application)指JBOSS企業版,與jboss-4.2.2.GA相比企業版的JBOSS加入安全性,穩定性等方面的考慮,沒有完全開源,用於企業部署與應用。 |
所以綜上兩個版本在功能上沒有區別。
對於經常使用普通版JBOSS的人第一次使用企業版JBOSS,啓動企業版JBOSS,啓動完成後不顯示啓動時間及啓動詳細過程,當啓動停滯在Configuring from URL: resource:jboss-log4j.xml 時啓動已經完成,完成界面如下:
當出現上述界面說明JBOSS企業版已經啓動完成,這時可以點擊http://localhost:8080/查看,爲什麼Jboss企業版不在Console口輸出大量日誌呢?個人認爲出於兩方面原因:一是是出去JBoss性能考慮,日誌輸出實際是大量的IO操作,消耗大量資源;另一方面,日誌信息是供開發人員測試使用,Jboss企業版,注重的是企業應用,所以,不需要向Console臺輸出大量日誌,當然爲了我們調試方便,我們可以修改相關日誌配置文件,輸出相關日誌信息,供我們開發,調試,相關日誌控制文件位置jboss-eap-4.3\jboss-as\server\<configure version>\conf\jboss-log4j.xml;
至此http://kylinsoong.iteye.com/blog/793215提出的問題得以解決,由此可見這個問題絕對是一個新手錯誤,犯錯的主要原因是犯錯者習慣使用普通版JBOSS。
2. JBoss eap Quick starting
關於JBoss企業版下載,參見http://kylinsoong.iteye.com/blog/784231;
JBoss目錄結構:
解壓jboss-eap-4.3後目錄結構如下圖:
jboss-as | 最高層目錄,包含Jboss啓動的腳步文件、jar文件、配置文件、工作目錄等,系統設置JBOSS_HOME就是到這層目錄,即(%\jboss-eap-4.3\jboss-as) |
seam | 包含JBoss seam Framework和Hibernate相關文件 |
jboss-as\bin | 包含系統啓動,關閉及一些系統特定腳步 |
jboss-as\client | 存儲Java Client Application或外部Web 容器可能使用到的配置文件和jar文件,jbossall-client.jar(上篇博客中JNDI客戶端代碼用到的jar)就存儲於此 |
jboss-as\docs | 存儲了一些例子配置文件,比如要使用Entity Bean管理Oracle,可以在此位置找到Oracle JCA相關配置文件樣本 |
jboss-as\server |
包含Jboss服務的配置種類,jboss提供四種配置設置:minimal,default, production, 和 all, 啓動時不指定,默認啓動的是production設置,這四種設置分別對應jboss-as\server下四個子文件夾: minimal:啓動logging service、JNDI server、URL deployment Scanner default:包含J2EE1.4所必須的一些service和部署J2EE所常用的一些Service,不包括JAXR service、IIOP Service和任何集羣的Service all:基本包括所有常見service,如JAXR service、IIOP Service和任何集羣的Service等 production:基於all配置,加入了日誌冗長處理(減少),每隔60秒掃描一次部署組建功能,和內存按需分配等,也是默認的啓動選項 |
jboss-as\server\production\conf | 包含Jboss啓動的引導文件jboss-service.xml,該文件包含jboss要啓動的核心服務的描述 |
jboss-as\server\production\deploy | 包括熱部署服務,你部署的服務(jar、war、ear) |
jboss-as\server\production\conf\props | 包含一些安全設置的配置文件,例如解壓完修改此文件下jmx-console-users.properties文件,你纔可以訪問jmx-console,否則你沒有權限 |
jboss啓動實例 | run.bat -c production -b 0.0.0.0 |
啓動完成後可以通過http://localhost:8080/jmx-console/來訪問JMX Console,如果沒有權限訪問,修改jboss-as\server\production\conf\props下jmx-console-users.properties配置文件;
3. Jboss服務器構架
分析一個關於Jboss服務器構架的圖片
Jboss模塊的構架是建立在底層JMX之上;
JMX作爲底層總線,基於可插入式的服務器設計理念(EJB容器,Web服務等);
容器的設計採用反射機制;
JBOSS主要模塊:
EJB Container | JBoss服務器的核心實現,它有兩個特性,第一是在運行期產生EJB 對象的Stub和Skeleton類,第二是支持熱部署 |
Web Server | 支持Web容器和Servlet引擎 |
JBossTx | JBossTX架構被設計成爲可以使用任何的實現了JTA接口的交易管理 |
JBossCx | JBossCX實現了部分JCA的功能。JCA制訂了J2EE應用組件如何訪問基於連接的資源(數據庫) |
Deployment | 支持EJB(jar)、Web應用文檔(war)和企業級應用文檔(ears)的部署。它會時刻關心J2EE應用的URL情況,一旦它們被改變或出現的時候將自動部署。 |
JBossSx | 安全相關的實現 |
JBossNS | JBossNS是JBoss命名服務用來定位對象和資源。它實現了JNDI J2EE規範 |
JBossMQ | JBossMQ使Java 消息規範(JMS)的實現 |
關於JMX
JMX(Java Management Extensions)是一個爲應用程序植入管理功能的框架,JMX致力於解決分佈式系統管理的問題。JMX可以看做分爲三層:表現層(實現層)、代理層、分佈式服務層,如下圖所示,最下面屬於表現層,中間代理層,最上面屬於分佈式服務層:
表現層:JMX可管理資源所在的層,這些已管理的資源可以編寫或封裝爲MBean,MBean分爲四種類型: 標準、動態、開放、模型;
代理層:代理層相當於一個MBean服務器,用來管理MBean如何和分佈式層的服務連接,連接這些分佈式服務一般用的是相關的Adapter或連接器;
分佈式服務層:如RMI管理應用、基於瀏覽器的管理控制等
詳細可以參考:http://www.blogjava.net/mlh123caoer/archive/2007/09/03/142456.html
4. EJB 容器 on JBoss
重申兩個名詞:
EJB:可部署的組件,能夠被裝配成完整的解決方案
EJB容器:提供一組標準服務:分佈式對象、事務、持久性、安全性和併發性
客戶端與JBOSS EJB組件系統的交互
由圖可見EJB客戶端與EJB組件的交互主要是與EJB各類bean之間的交互;
企業Bean的組成部分:
Enterprise Bean類 |
業務邏輯核心,不包含與網絡有關的邏輯功能; 依照明確定義的接口並且遵守某些規則,能運行於任何EJB容器中; 實現javax.ejb.SessionBean/EntityBean/MessageDrivenBean接口 客戶端不直接對實際的Enterprise Bean類的實例進行調用 |
遠程接口 |
複製Bean類公開的所有商務邏輯方法,具有網絡功能; EJB Object是EJB容器的一部分; 客戶端調用EJB Object中的方法; |
Home接口:EJB工廠 |
EJB Object的生成庫:生成EJB Object,查找現存的EJB Object,刪除EJB Object,負載均衡等; EJB Home Object是EJB容器的一部分; 客戶端從Home接口獲得對EJB Object的引用; |
本地接口 |
如果調用的Enterprise Bean在同一進程中,不必經過Stub、Skeleton、網絡調用以及參數的編組和解組; 擴展javax.ejb.EJBLocalObject接口; 通過引用而不是值來對參數進行編組; |
本地Home接口 |
通過本地調用創建或查找EJB,與本地接口對應 |
部署描述文件:ejb-jar.xml | 描述文件名:ejb-jar.xml 確定要運行的是哪一種EJB、Home接口、遠程接口和Bean類的名字等信息; |
向JBoss EJB容器中部署一個EJB2.0的HelloWorld應用:
Step 1:定義企業bean HelloWorldBean
public class HelloWorldBean implements SessionBean {
private SessionContext mySessionCtx;
public SessionContext getMySessionCtx() {
return mySessionCtx;
}
public void setMySessionCtx(SessionContext mySessionCtx) {
this.mySessionCtx = mySessionCtx;
}
public void ejbCreate() throws EJBException, RemoteException{
System.out.println("EJB Created");
}
public void ejbActivate() throws EJBException, RemoteException {}
public void ejbPassivate() throws EJBException, RemoteException {}
public void ejbRemove() throws EJBException, RemoteException {}
public void setSessionContext(SessionContext arg0) throws EJBException,
RemoteException {}
public String helloWorld() throws EJBException, RemoteException{
return "Hello World. Welcome to EJB!";
}
}
Step 2:定義遠程接口HelloWorld
public interface HelloWorld extends EJBObject {
public String helloWorld() throws RemoteException;
}
Step 3:定義Home接口HelloWorldHome
public interface HelloWorldHome extends EJBHome {
public HelloWorld create() throws CreateException, RemoteException;
}
Step 4: 定義部署描述文件ejb-jar.xml
<?xml version="1.0"?> <!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> <ejb-name>HelloWorld</ejb-name> <home>com.home.ejb.home.HelloWorldHome</home> <remote>com.home.ejb.remote.HelloWorld</remote> <ejb-class>com.home.ejb.bean.HelloWorldBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Bean</transaction-type> </session> </enterprise-beans> </ejb-jar>
Step 5:定義JNDI描述文件jboss.xml
<?xml version="1.0" encoding="gb2312"?> <jboss> <enterprise-beans> <session> <ejb-name>HelloWorld</ejb-name> <jndi-name>ejb/HelloWorld</jndi-name> </session> </enterprise-beans> </jboss>
Step 6:定義打包部署文件build.xml
<?xml version="1.0"?> <project name="com.home.ejb" default="deploy" basedir=".."> <property environment="env" /> <property name="app.dir" value="${basedir}\com.home.ejb" /> <property name="src.dir" value="${app.dir}\src" /> <property name="jboss.home" value="${env.JBOSS_HOME}" /> <property name="jboss.server.config" value="production" /> <property name="build.dir" value="${app.dir}\build" /> <property name="build.classes.dir" value="${build.dir}\classes" /> <path id="build.classpath"> <fileset dir="${jboss.home}\client"> <include name="*.jar" /> </fileset> <pathelement location="${build.classes.dir}" /> </path> <target name="prepare" depends="clean"> <mkdir dir="${build.dir}" /> <mkdir dir="${build.classes.dir}" /> </target> <target name="clean"> <delete dir="${build.dir}" /> <delete file="${jboss.home}\server\${jboss.server.config}\deploy\helloworld.jar" /> </target> <target name="compile" depends="prepare" > <javac srcdir="${src.dir}" destdir="${build.classes.dir}" debug="on" deprecation="on" optimize="off" includes="com/**"> <classpath refid="build.classpath" /> </javac> </target> <target name="ejbjar" depends="compile" > <jar jarfile="${app.dir}\helloworld.jar"> <fileset dir="${build.classes.dir}"> <include name="com/**/*.class" /> </fileset> <metainf dir="${app.dir}/META-INF"> <include name="ejb-jar.xml" /> <include name="jboss.xml" /> </metainf> </jar> </target> <target name="deploy" depends="ejbjar"> <copy file="${app.dir}\helloworld.jar" todir="${jboss.home}\server\${jboss.server.config}\deploy" /> </target> </project>
Step 7:ant運行build.xml,將組件部署到Jboss,部署成功Jboss console口會出現如下信息:
http://localhost:8080/jmx-console/HtmlAdaptor下Global JNDI Namespace會出現如下JNDI綁定信息:
Step 8:編寫客戶端調運代碼:
public class HelloWorldClient {
public static void main(String[] args) {
Properties properties = new Properties();
properties.setProperty(Context.INITIAL_CONTEXT_FACTORY , "org.jnp.interfaces.NamingContextFactory");
properties.setProperty(Context.PROVIDER_URL, "jnp://localhost");
try {
Context ctx = new InitialContext(properties);
Object objRef = ctx.lookup("ejb/HelloWorld");
HelloWorldHome home = (HelloWorldHome)PortableRemoteObject.narrow(objRef, HelloWorldHome.class);
HelloWorld helloworld = home.create();
System.out.println(helloworld.helloWorld());
} catch (NamingException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}
}
}
Step 9:運行客戶端代碼:
如上客戶端代碼功能可分爲三步如下:
1. 執行JNDI檢索,找出Home對象
2. 使用Home接口,創建一個EJB實例
3. 利用EJB實例,調用業務方法
Hello World. Welcome to EJB!
Step 10:Eclipse下文件詳細描述:
Step 11: 運行流程分析:
整個客戶端調運企業bean總helloworld方法可以分爲以用如下圖描述:
1.檢索Home對象引用
2.返回Home對象引用/Stub
3.創建新的EJB對象
4.生成EJB對象
5.返回EJB對象引用/Stub
6.調用業務方法
7.將請求委託給Bean