Geronimo tomcat: 在 Apache Geronimo 插件体系中将 Apache Tomcat 这个优秀的 Web 容器整合至其中...
Apache Geronimo 靈活的插件體系將 Tomcat, OpenJPA, OpenEJB, ActiveMQ 等第三方組件集成至其中。本文從多角度介紹了在 Apache Geronimo 中,如何通過其微內核的設計和靈活的插件體系將 Apache Tomcat, 這個優秀的 Web 容器整合至其中, 內容涉及到集成環境下 Tomcat Web 容器的配置和啟動, Geronimo 基礎服務的使用, 以及 Web 應用程序的部署。 同時, 對于部分新舊版本之間實現的差異也進行了優劣比較。
Geronimo 整合機制概述
Apache Geronimo 是一款優秀的開源 Java EE 應用服務器平臺。 其本身只是一個應用程序框架,但依賴其獨特的微內核架構和靈活的插件機制, 整合了大量的開源產品, 例如 Tomcat, ActiveMQ, OpenEJB 等, 極大地豐富了其功能。
圖片 1所示為 Geronimo 架構圖, 可以看到, 處于最底層的是 Geronimo 內核, 它可以說是 Geronimo 的心臟, 處于其上的所有基礎服務和各種插件都以 GBean 的形式運行于其中。 Geronimo 提供的基礎服務包括日志服務, 線程池服務, 生命周期管理服務, 插件支持等, 其他插件和用戶的應用程序都可以使用這些基礎服務, 以提高程序開發效率。 前文提到, Geronimo 本身不提供 Java EE 的相關服務, 但通過插件集成其他組件達到對相關標準的支持。 例如, 通過 OpenEJB 插件, 提供了對 EJB 標準的支持。 通過 Tomcat 插件, 提供了對 Web 標準的支持, 本文即介紹 Tomcat 插件實現。
圖 1. Geronimo 架構圖
一般來說, Geronimo 插件由三部分內容組成, 分別是 :
從插件的組成可以看到, 其關鍵作用的便是 GBean, 它可謂 Geronimo 插件的基石。 那么, GBean 在插件體系中, 究竟扮演了什么角色呢 ?
圖 2. GBean 的角色之一 : 適配器 ( Adapter )
如?圖片 2所示, GBean 的第一個角色是適配器。 在第三方組件中, 往往在運行時需要初始化一些實例, 例如 Tomcat 在運行時需要初始化多種 Connector 來接受用戶的請求, 而 OpenEJB 在運行時需要初始化 EJB 容器, 以用于部署用戶的 EJB 組件。 由此, 結合 Geronimo 提供的生命周期的基礎服務, 可以為那些運行時需要創建的第三方應用組件定義對應的 GBean, 在這些 GBean 中封裝第三方組件的創建和啟動邏輯。 同時, 還可以通過 GBean 靈活的 XML 配置方式, 將參數設置傳遞到所封裝的第三方組件中去。
圖 3. GBean 的角色之二 : 代理器 ( Broker )
GBean 的另外一個角色是代理器, 從?圖片 3可得知, 插件之間的交互, 是通過 GBean 來實現。 同樣, 如果用戶希望修改一些組件的運行時參數時, 也可以通過調用 GBean 開放的接口。 例如, Geronimo 為所有的 Web 容器插件定義了添加 Web Service 的接口, 那對于 Axis2 插件而言, 無需知道該服務是由 Tomcat 插件還是 Jetty 插件提供, 它只需要到內核中檢索實現該接口的 GBean, 并調用對應的方法即可。 換句話說, GBean 屏蔽了任何第三方實現相關的內容, 并依托 Geronimo 內核, 對外發布服務, 服務消費者只需要在 Geronimo 內核中檢索提供所需服務的 GBean 實例, 并調用對應的方法, 而消費者自身無需了解服務提供者的任何信息, 實現了服務提供和消費的完全透明性。
以上概述了 GBean 在 Geronimo 插件體系中最常見的兩種作用, 以此我們也可以得知, 在開發一個插件時, 通常需要定義兩種類型的 GBean, 一種便是適配器類型, 由此實現第三方組件的生命周期管理和配置管理。 另外一種便是代理器類型, 如果我們希望對外發布一些服務接口供其他組件使用, 則需要定義對應的 GBean, 并實現公共接口。
Geronimo 與 Tomcat 整合
Apache Tomcat 是一個優秀的開源 Web 服務器, 提供了對 Servlet, JSP 等 Web 標準的實現。 Geronimo 的發行版本之一便是以 Tomcat 為 Web 容器的 Java EE 應用服務器版本。 早在 Geronimo 1.* 時代, Tomcat 就被通過插件的形式整合到 Geronimo 當中, 到目前的 Geronimo 2.2, 整合的實現發生了許多變化。 下文將分別介紹其實現, 并對不同實現進行比較。
Tomcat 容器配置和啟動
在整合 Tomcat 的步驟中, 最重要的就是使 Tomcat Web 容器在 Geronimo 集成環境中啟動起來。 首先來介紹一下 Tomcat Web 容器的組成, 如?圖片 4所示 :
圖 4. Tomcat Web 容器結構圖
Tomcat Web 容器構成是高度結構化的, 并且每個組件都提供了可擴展結構以用于添加其子組件。 關于各個組件的含義和作用, 請參照?Tomcat 官方網站。
根據前文介紹 的 GBean 作為適配器, 集成這些組件的方式之一便是為其每個組件定義對應的 GBean, 再通過 GBean 之間的引用, 將其組裝起來。 在 Geronimo 1.* 和 Geronimo 2.1.* 中, 就是通過這種方式實現 Tomcat Web 容器的配置與啟動。
以 Connector 組件為例, Connector 的作用是接受用戶的 Web 請求, 比如說, 如果期望用戶可以通過 http://localhost:8080 訪問部署在 Tomcat 之中的應用程序, 則需要定義一個支持 HTTP 協議, 并綁定到 8080 端口的 Connector。
如?圖片 5所示, Geronimo-Tomcat 插件為 Tomcat 支持的每種 Connector 都定義了一個 Connector GBean。 例如 Http11ConnectorGBean 為支持 HTTP 1.1 協議的連接器, Https11ConnectorGBean 為支持 HTTPS 1.1 協議的連接器等。
Geronimo 1.* 和 2.1.* 中的 Tomcat 整合實現
圖 5. Geronimo 1.* 和 2.1.* 中定義的 Connector GBean 結構圖
如?清單 1所示, 在所有類型的 Connector GBean 的父類 ConnectorGBean 中, 定義了 Tomcat 私有的 Connector 類型的成員變量, 并在構造函數中, 創建了該 connector 的實例。 而在 doStart 方法中, 首先將 connector 對象通過 container 引用添加到 Tomcat Web 容器中, 并調用 Tomcat Connector 對象自身的 start 方法。 而在?清單 2所示的 BaseHttp11ConnectorGBean 的代碼片段中, 封裝了 Tomcat Connector 特定的參數設置邏輯。 對于其他組件而言, 其只需從 Geronimo 內核中檢索到 Connector GBean 對象, 并調用其 setAcceptCount 方法, 即可實現對 acceptCount 屬性修改。
清單 1. ConnectorGBean 代碼片段
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public abstract class ConnectorGBean extends BaseGBean implements CommonProtocol, ????GBeanLifecycle, ObjectRetriever, TomcatWebConnector { ??????…… ??????protected final Connector connector; ??????private final TomcatContainer container; ??????…… ??????public ConnectorGBean(String name, Map initParams, String tomcatProtocol, ???????????????TomcatContainer container, ServerInfo serverInfo) throws Exception { ???????????…… ??????????// Create the Connector object ?????????connector = new Connector(tomcatProtocol); ?????????setParameters(connector, initParams); ? } ? public void doStart() throws LifecycleException { container.addConnector(connector); ??????connector.start(); ??????…… container.addConnector(connector); } ? public void doStop() { try { ???????????connector.stop(); ??????} catch (LifecycleException e) { ???????????Log.error(e); ??????} ??????container.removeConnector(connector); ???…… ??} } |
清單 2. BaseHttp11ConnectorGBean 代碼片段
| 1 2 3 4 5 6 7 8 9 10 11 12 | public abstract class BaseHttp11ConnectorGBean extends ConnectorGBean implements ????????????????????BaseHttp11Protocol, StatisticsProvider { ???…… ???public void setAcceptCount(int acceptCount) { ????????????connector.setAttribute("acceptCount", new Integer(acceptCount)); ???} ???? ??public void setAddress(String address) { ????????????connector.setAttribute("address", address); ???} ???…… } |
和上文介紹的 ConnectorGBean 類似, Geronimo-Tomcat 插件針對其他 Tomcat 組件而定義的 GBean 實現也是如此。 概而言之, 通過這些類似適配器的 GBean, 實現了 :
- 對 Tomcat 私有對象創建和配置的邏輯的封裝
- 實現了各個組件之間的組裝。伴隨 GBean 的生命周期,最終在 Geronimo 環境中構建并啟動了一個完整的 Tomcat Web 容器。
Geronimo 2.2 中的 Tomcat 整合實現
但是,在 Geronimo 2.2 中, 對 Tomcat 的整合方式進行了徹底修改。我們首先介紹新的 Tomcat 整合方式, 之后再與之前的方式做對比。
Tomcat 自身是通過 server.xml 來描述 Web 容器的構成和參數設置, 如?清單 3所示 :
清單 3. server.xml 片段
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <Server port="8005" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on"/> ...... ? <Service name="Catalina">??????? <Connector name="TomcatWebConnector" ??????????????????port="${HTTPPort + PortOffset}" ??????????????????host="${ServerHostname}" ??????????????????protocol="HTTP/1.1" ??????????????????connectionTimeout="20000" ??????????????????redirectPort="${HTTPSPort + PortOffset}" ??????????????????executor="DefaultThreadPool"/> ????????????...... ????????????<Engine name="Catalina" defaultHost="${ServerHostname}"> ???????????<Host name="${ServerHostname}" appBase="" ?????????????????unpackWARs="true" autoDeploy="true" ?????????????????xmlValidation="false" xmlNamespaceAware="false"> ???????????????<Valve className="org.apache.catalina.valves.AccessLogValve" ??????????????????directory="logs" prefix="${ServerHostname}_access_log." ??????????????????suffix=".txt" pattern="common" resolveHosts="false"/> ???????????...... ???????</Engine>??????? </Service> </Server> |
那么, 在 Geronimo 中是否也能通過 server.xml 來定義 Web 容器的結構呢 ? 如此對于原來的 Tomcat 用戶而言, 沒有任何學習的曲線。 甚而, 用戶可以將之前修改過 Tomcat 配置文件拷貝到指定目錄, 則立即獲取之前的環境。
基于以上的期望, 在 Geronimo 2.2 中, 通過如下步驟實現了 Tomcat Web 容器的整合。
- 依據 server.xml 的樣式 (schema) 文件, 利用 Java Architecture for XML Binding(JAXB),生成了對應的 Java 類, 由此實現 server.xml 文件與 Java 對象之間的轉換。
- 在每個組件對應的 JAXB 生成類中, 封裝了 Tomcat 私有組件的創建和初始化邏輯, 同時組件之間的拼裝邏輯也包含于此。 依舊以 Connector 為例, 如?清單 4所示, 在 getConnector 方法中, 包含了對 Tomcat 私有的 Connector 對象創建和初始化。 而組裝 Connector 組件的邏輯位于其父組件 Service 之中。 在清?單 5所示的 ServiceType 的 getService 方法, 其所包含的 ConnectorType 對象的 getConnector 方法依次被調用, 并添加到 Service 組件中。
- 定義 TomcatServerGBean, 如?清單 7所示, 配置一個 TomcatServerGBean 實例,serverConfigLocaiton 屬性指定 server.xml 配置文件的相對路徑。 如清單 6 所示,在 TomcatServerGBean 的構造函數中, 對 server.xml 執行解析, 并調用頂層組件 serverType 的 build 方法, 完成 Tomcat 各個組件的創建, 初始化和組裝, 最終在 doStart 方法中啟動容器, 開始接受用戶請求。
清單 4. ConnectorType 代碼片段
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class ConnectorType { ?…… ?@XmlAttribute ?protected String className = Connector.class.getName(); ?…… ?public Connector getConnector(ClassLoader cl, Service service) throws Exception { ?…… ???ObjectRecipe recipe = new ObjectRecipe(className, properties); ?????recipe.allow(Option.IGNORE_MISSING_PROPERTIES); ?????recipe.setConstructorArgTypes(new Class[] { String.class }); ?????recipe.setConstructorArgNames(new String[] { "protocol" }); ?????Connector connector = (Connector) recipe.create(cl); ?????…… ?????return connector; ???} } |
清單 5. ServiceType 代碼片段
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | public class ServiceType { ? ?@XmlElement(name = "Connector") ?protected List<ConnectorType> connector; ?public Service getService(ClassLoader cl, Kernel kernel) throws Exception { ???…… ???for (ConnectorType connectorType: getConnector()) { ?????Connector connector = connectorType.getConnector(cl, service); ?????service.addConnector(connector); ???} ???…… ?} } |
清單 6. TomcatServerGBean 代碼片段
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class TomcatServerGBean implements GBeanLifecycle { ?public TomcatServerGBean( …… ) throws Exception { ???…… ???Reader in = new StringReader(serverConfig); ???try { ?????ServerType serverType = loadServerType(in);??????????? ?????server = serverType.build(classLoader, kernel); ???} finally { ?????in.close(); ???} ?} ?public void doStart() throws Exception { ???server.initialize(); ???((Lifecycle)server).start(); ?} ?…… } |
清單 7. TomcatServerGBean 配置文件片段
| 1 2 3 4 5 6 7 8 9 10 11 12 | <gbean name="TomcatServer" class="org.apache.geronimo.tomcat.TomcatServerGBean"> <attribute name="serverConfigLocation">var/catalina/server.xml</attribute> <reference name="ServerInfo"> <name>ServerInfo</name> </reference> <reference name="AttributeManager"> ?????????<name>AttributeManager</name> </reference> <reference name="MBeanServerReference"> ?????????<name>MBeanServerReference</name> </reference> </gbean> |
Tomcat 整合實現的對比
應該說, Geronimo 1.*/2.1.* 和 Geronimo 2.* 中整合 Tomcat 的整體思路并沒有發生變化, 都是通過 GBean 封裝第三方組件, 并伴隨 GBean 的生命周期管理啟動和停止第三方組件, 同時通過 GBean 提供對其訪問的窗口。 主要區別在一些實現策略以及用戶可用性方面, 下文從以下幾個角度對兩者進行比較 :
- 其他組件和應用獲取 Tomcat 狀態信息的便捷性 :
- 在 Geronimo 1.*/2.1.* 的環境中, 為每個 Tomcat 組件都定義了對應的 GBean,例如 Connector 對應了 ConnectorGBean, Valve 對應了 ValveGBean 等, 而每個組件都通過提供公開的方法以便于其他組件和應用訪問, 應該說是相當方便。
- 在 Geronimo 2.2 的環境中, 所有的組件的創建和初始化均封裝在 JAXB 類中, 而這些類并沒有通過 GBean 的形式運行于內核中, 其他組件和應用訪問的唯一接口只有 TomcatServerGBean, 略顯單薄。 事實上, 在 Geronimo 2.2 的開發過程中, 已充分考慮到這一點, 對于舊版本中的 ConnectorGBean, ValveGBean 等絕大部分 GBean 都進行修改并予以保留, 即提供對已創建 Tomcat 組件的訪問和設置。 默認情況下或者通過配置后, 這些 GBean 實例仍然會被 Geronimo 內核載入并啟動。
綜上而述, 就 Tomcat 狀態訪問的便捷性上, 考慮到 Geronimo 2.2 對之前絕大部分 GBean 予以保留, 將由于整合策略的修改而造成對訪問便捷性的影響降到最低, 兩者相差并不大。
- Geronimo 客戶的用戶體驗
- 在 Geronimo 1.*/2.1.* 的環境中, 由于每個 Tomcat 組件都是由對應 GBean 創建和組裝, 所以當用戶修改 Tomcat Web 容器配置時, 需要在 var/config/config.xml 文件中, 添加或者修改對應組件的 GBean 定義。 對于原來 Tomcat 用戶而言, 需要學習 GBean 的相關概念, 稍顯不便。 當然, 熟悉了 GBean 的配置規則之后, 仍然是比較方便的。
- 在 Geronimo 2.2 的環境中, 所有的 Tomcat Web 容器的配置都存在于 var/config/server.xml 中, 并且與 Tomcat 自身的配置文件保持了大部分的兼容。 毫無疑問, 對于原來 Tomcat 用戶來說, 幾乎可以立馬上手, 根本不需要去了解 GBean 的相關概念。 有一點需要強調的是, Geronimo 對部分 server.xml 中的設置不提供支持, 比如說數據源, 安全域, 全局目錄等, 原因在于, 這些配置, 均屬于 Tomcat 的自定義擴展, 而 Geronimo 對此提供了更強大和完善的配置方式, 具體可參照 Geronimo 的官方文檔。 而對于 Geronimo 1.*/2.1.* 的用戶來說, server.xml 也顯得更加簡潔。 前文也提到, 考慮到兼容性的原因, 之前的 GBean 配置均予以保留, 用戶依舊可以使用之前的方式配置 Tomcat Web 容器, 但 Geronimo 社區并不推薦這樣做, 而且在今后的版本中有可能會移除這些 GBean 的配置方式, 以保持整體配置的唯一性。
Geronimo 基礎服務整合
從?圖片 1所示 Geronimo 架構圖可知, Geronimo 對外提供了很多基礎服務, 包含線程池服務, 安全訪問控制服務等, 以下將介紹 Tomcat 整合中如何使用其中的線程池服務以提高應用程序的運行效率。
線程池服務是應用服務器的一個重要關注點, Geronimo 自產生之始, 便通過 GBean 的形式提供了線程池的支持, 其他組件或者應用可以通過該 GBean 獲取線程池支持。 但在 Geronimo 1.*/2.1.* 中, Tomcat 插件并沒有使用 Geronimo 平臺提供的線程池服務, 而是由各個 Connector 維護了其自身的線程池。 顯而易見, 資源不能得到最大化利用, 而且也不利于 Geronimo 監控當前 Web 請求的相關狀態。 在 Geronimo 2.2 中, 這點做了改善, 默認情況下, 所有支持外部線程池的 Tomcat Connector 組件均會使用 Geronimo 的線程池服務。 下文將介紹在 Geronimo 2.2 中是如何配置外部線程池和其內部的一些實現。
如?清單 8所示, 如果需要在 Tomcat 中定義一個公共線程池, 需要添加 Executor 元素, 而 Executor 元素的 executor-ref 屬性設定了在 Geronimo Kernel 中檢索線程池服務的查詢條件, 當前配置的含義是查詢名稱為 DefaultThreadPool 并且實現了 java.util.concurrent.Executor 接口的 GBean 對象。 由默認的查詢條件可知, Geronimo 提供的線程池實現是通過名為 DefaultThreadPool 的 GBean 供其他組件和應用使用的。 顯然, 用戶如果配置了自定義的線程池, 可以很方便的修改 executor-ref 屬性而達到目的。 Executor 元素只是線程池的定義, 需要某個在 Connector 中使用, 需要設置其 executor 屬性, 值為期望使用的 Executor 元素的名稱。
需要注意的兩點是, executor-ref 為 Geronimo 自定義屬性, 僅在 Geronimo 環境中有效。 另外一點是, 不是所有的 Tomcat Connector 類型都支持外部連接池, 具體可參照 Tomcat 官方文檔。
如?清單 9所示的代碼片段, 在 ExecutorType 中, 通過 executor-ref 屬性指定的查詢條件, 在 Geronimo 內核中執行查詢, 并使用結果列表中第一個線程池 GBean 的實例。 而在 ConnectorType 中, 依據 exector 屬性指定的 Executor 的名稱, 從 Service 組件中獲取其引用并通過反射的方式調用 Connector 所持有 ProtocolHandler 對象的 setExecutor 方法, 如此之后, 該 Connector 將使用設定的 Geronimo 線程池來處理用戶請求。
清單 8. Tomcat Connector 線程池配置
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | <Service name="Catalina"> ?<Executor className="org.apache.geronimo.tomcat.TomcatExecutorWrapper" ?????????????????name="DefaultThreadPool" ?????????????????executor-ref="?name=DefaultThreadPool#java.util.concurrent.Executor"/> ????????????<Connector name="TomcatWebConnector" ??????????????????port="${HTTPPort + PortOffset}" ??????????????????host="${ServerHostname}" ??????????????????protocol="HTTP/1.1" ??????????????????connectionTimeout="20000" ??????????????????redirectPort="${HTTPSPort + PortOffset}" ??????????????????executor="DefaultThreadPool"/> ???…… </Service> |
清單 9. Tomcat Connector 引用 Geronimo 線程池實現片段
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | ????????????????ConnectorType.java ? public Connector getConnector(ClassLoader cl, Service service) throws Exception { for (Map.Entry<QName, String> entry : otherAttributes.entrySet()) { ??????????????String name = entry.getKey().getLocalPart(); ??????????????if (executorSupported && "executor".equals(name)) { ????????????????????Executor executor = service.getExecutor(entry.getValue()); ????????????????????…… ????????????????????IntrospectionUtils.callMethod1(connector.getProtocolHandler(), ????????????????????????????"setExecutor", ????????????????????????????executor, ????????????????????????????java.util.concurrent.Executor.class.getName(), ????????????????????????????cl); ? ??????????????} …… ????????} } ? ? ExecutorType.java ? public Executor getExecutor(ClassLoader cl, Kernel kernel) throws Exception { ??????????Map<String, Object> properties = new HashMap<String, Object>(); ??????????for (Map.Entry<QName, String> entry: otherAttributes.entrySet()) { String name = entry.getKey().getLocalPart(); ??????????????if (name.endsWith("-ref")) { ????????????????????AbstractNameQuery query = ????????????????????????????????new AbstractNameQuery(URI.create(entry.getValue())); ????????????????????Set<AbstractName> names = kernel.listGBeans(query); ????????????????????…… ????????????????????Object ref = kernel.getGBean(names.iterator().next()); ????????????????????properties.put(name.substring(0, name.length() - 4), ref); ? ??????????????} ????????} ????????…… ????????return executor; } |
部署 Web 應用程序到 Tomcat 容器
Tomcat 插件除了實現 Tomcat 容器配置和啟動以及 Geronimo 基礎服務整合等功能外, 另外的一個重要功能就是如何將用戶的應用程序部署到集成后的 Tomcat Web 容器中去。
在 Geronimo 整合機制概述章節中, 我們提到 GBean 的另外一個角色 : 代理器。 當用戶通過控制臺 GUI 界面或者命令行下執行 deploy 命令時, 需要一個負責解析用戶部署應用的 GBean 服務。 在 Geronimo-Tomat 插件中, TomcatModuleBuilder GBean 便是應此目的而定義。
在介紹 TomcatModuleBuilder GBean 之前, 我們首先列出當用戶部署一個應用程序至 Java EE 運行環境中, 需要分析的主要內容包括 :
- 應用程序依賴關系, 即當前應用依賴于哪些第三方服務, 在應用的類載入路徑中需要添加哪些第三方的組件包等。
- 應用程序的配置信息, 例如上下文路徑, 顯示名稱等。
- 應用程序是否包含其他 Java EE 組件, 例如是否包含 JPA 應用, 是否對外發布 Web Service 應用等。
下面, 我們將結合 TomcatModuleBuilder GBean 依次介紹以上步驟在 Geronimo-Tomcat 插件中的實現。
Geronimo 會為每個用戶部署的應用程序建立一個多父類載入器, 對于一個 Web 應用程序而言, 以下內容需要添加到應用程序環境中
- 在 geronimo-web.xml 中定義的依賴關系, 如果該依賴是一個 JAR 文件, 則添加到應用程序的類載入器路徑中, 如果該依賴是其他應用或者插件, 則將其對應的類載入器設為該應用類載入器的父親。
- 掃描 WEB-INF/lib 目錄下所有的 JAR 文件, 將其加入至當前應用的類載入器路徑中。
- 如果存在 WEB-INF/classes 目錄, 同樣將該目錄添至當前應用的類載入器路徑中。
- 將 Tomcat 插件對應的類載入器設置為該應用類載入器的父親。
在一個 WAR 包中, web.xml 和 geronimo-web.xml 中設置大量應用相關的信息, 這些也是 TomatModuleBuilder 處理的主要內容之一。 如?清單 10所示代碼片段中, 用戶在 web.xml 中設置的 displayName 值會被讀出, 并設置到 TomcatWebAppContextGBean 中去。
清單 10. TomcatModuleBuilder 代碼片段
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public void addGBeans(EARContext earContext, Module module, ClassLoader cl, ?????????????????????????Collection repository) throws DeploymentException { ??GBeanData webModuleData = new GBeanData(moduleName, ???????????????????????????????????????????????TomcatWebAppContext.GBEAN_INFO); ???…… ?????????try { ?????????????…… ?????????????if (webApp.getDisplayNameArray().length > 0) { ???????????????????webModuleData.setAttribute("displayName", ???????????????????????????????webApp.getDisplayNameArray()[0].getStringValue()); ?????????????} ???…… ?} ?} catch (DeploymentException de) { ???????????throw de; ?????????} catch (Exception e) { ???????????throw new DeploymentException( ?????????????????"Unable to initialize GBean for web app " + module.getName(), e); } |
由?清單 11所示的 TomcatModuleBuilder 配置文件而知, 在運行時, 其他 Java EE 模塊對應的分析器 GBean 引用會被注入至 TomcatModuleBuilder 中。 如此, Tomcat 插件即可使用其他分析器對當前應用程序進行解析, 例如 WebServiceBuilder 會檢測當前應用中是否包含 Web Service 應用, PersistenceUnitBuilder 會檢測當前應用中是否包含 JPA 應用等。
清單 11. TomcatModuleBuilder 配置片段
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <gbean name="TomcatWebBuilder" ??????class="org.apache.geronimo.tomcat.deployment.TomcatModuleBuilder"> …… ?<references name="WebServiceBuilder"> ?<pattern> ????????????????<name>CXFBuilder</name> ?????????</pattern> ?????????…… ?</references> ?<reference name="NamingBuilders"> ?????????<name>NamingBuilders</name> ?</reference> ?<reference name="ClusteringBuilders"> ?????????<name>TomcatClusteringBuilder</name> ?</reference> ?<references name="ModuleBuilderExtensions"> ?<pattern> ????????????????<name>PersistenceUnitBuilder</name> ?????????</pattern> ???????<pattern> ????????????????<name>MyFacesModuleBuilderExtension</name> ?????????</pattern> ?????????<pattern> ????????????????<name>JspModuleBuilderExtension</name> ?????????</pattern> ???????<pattern> ????????????????<name>SecurityBuilder</name> ???????</pattern> ?</references> …… ?</gbean> |
在 TomcatModuleBuilder 執行完所有分析步驟之后, 最終得到的就是?清單 10中提及地 TomcatWebAppContext GBean, 它包含了所有對當前應用分析的結果。 同樣, 將應用添加到 Tomcat Web 容器中的邏輯也在該 GBean 中。 如?清單 12 所示代碼片段, 當 TomcatWebAppContext GBean 啟動時, 會調用 TomcatContainer 的 addContext 方法, 而在 addContext 方法中, 首先創建了 Tomcat 的 Context 對象, 然后通過 Host 的 addChild 方法, 將用戶的應用程序部署至 Tomcat Web 容器之中。
清單 12. TomcatWebAppContext/TomcatContainer 代碼片段
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ????????????????TomcatWebAppContext.java public class TomcatWebAppContext implements …… { ??…… ??public void doStart() throws Exception { ????…… ????container.addContext(this); ????…… ??} ??…… } ? TomcatContainer.java public class TomcatContainer implements …… { ??public void addContext(TomcatContext contextInfo) throws Exception { ????Context context = createContext(contextInfo.getContextPath(), ????????????????????????????contextInfo.getDocBase(), contextInfo.getClassLoader()); ????…… ????host.addChild(context); ????…… ??} ??…… } |
總結
Geronimo 集成眾多開源應用, 并最終成為通過 Java EE 5 認證的應用服務平臺, GBean 在其中起了至關重要的作用, 本文以 Tomcat 插件為例, 介紹了集成過程中涉及到的內容, 以及不同版本中部分實現的差異。 對于 Geronimo 用戶而言, 可以更加深入了解一些內部實現機理。 而對 Geronimo 插件開發人員和系統架構設計師, 也具備一定的借鑒意義。
?相關主題
- 訪問?ApacheGeronimo 項目的官方網站,該網站詳盡的用戶手冊和開發文檔, 并有一個活躍社區。
- 訪問?Apache Tomcat 項目的官方網站。
- 發揮 Tomcat 在 Geronimo 中強大功能,介紹了 Geronimo 1.* 中, Tomcat 集成的相關內容。
- 訪問 developerWorks?Open source 專區?獲得豐富的 how-to 信息、工具和項目更新以及?最受歡迎的文章和教程,幫助您用開放源碼技術進行開發,并將它們與 IBM 產品結合使用。
轉載于:https://www.cnblogs.com/dengyungao/p/7492950.html
總結
以上是生活随笔為你收集整理的Geronimo tomcat: 在 Apache Geronimo 插件体系中将 Apache Tomcat 这个优秀的 Web 容器整合至其中...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机ip如何设置,win7电脑ip地址
- 下一篇: 睡觉姿势看性格