weblogic有一個很貼心的功能,允許把多個war應用共同依賴的jar包,打包一個單獨的war,以libary方式部署,然后各應用在weblogic.xml里聲明引用該libary即可,這樣可大大減少打包后的war文件尺寸,可以加快部署的上傳進度,對web server而言,這類共用jar包只加載一次,也節省資源。
但是jboss下想達到類似的功能就要復雜很多了,先來一個簡單的示例:
一、基礎篇
1.1 假如我們先開發了一個工具庫,打包后生成的mylib.jar ,為了減少各種依賴項的干擾,這個工程不依賴任何其它第三方庫,只有一個測試方法:
package yjmyzz.test; public class TestUtils { public String sayHello(String msg) { return "Hello ," + msg + " !"; } }
1.2 再建一個spring mvc的web項目,為了簡單起見,也只有一個空頁面,啥功能也沒有,pom.xml里引用剛才的mylib工程
1 <dependency> 2 <groupId>yjmyzz</groupId> 3 <artifactId>mylib</artifactId> 4 <version>1.0</version> 5 <scope>compile</scope> 6 </dependency>
Controller里,調用mylib中的sayHello方法
@RequestMapping("/index") public String index() { TestUtils utils = new TestUtils(); System.out.println(utils.sayHello("hello")); return "index"; }
然后打包,默認情況下mylib.jar會打進myweb項目的WEB-INF/lib下
前面這些都是准備工作而已,不用太在意具體細節,下面才是正經開始.
現在我們要把這個mylib-1.0.jar給弄到jboss里,讓它成為jboss的默認模塊,最終目的是myweb.war的WEB-INF/lib目錄下,不再需要這個jar。
1.3 折騰 jboss EAP
a. $JBOSS_HOME/modules 目錄下,創建 mylib/main 目錄,即要保證$JBOSS_HOME/modules/mylib/main目錄存在
b. 把mylib-1.0.jar復制到$JBOSS_HOME/modules/mylib/main中
c. 在$JBOSS_HOME/modules/mylib/main中創建一個名為module.xml的文件,內容如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <module xmlns="urn:jboss:module:1.1" name="mylib"> 3 <resources> 4 <resource-root path="mylib-1.0.jar" /> 5 </resources> 6 </module>
注意:第2行中的name="xxx"這里的name一定要跟/modules/下的子目錄名一致,如果子目錄是多層結構,比如 /modules/mycompany/mylib/main,則這里的name應該是"mycompany.mylib"
1.4 應用新增加的module
module加好以后,myweb在啟動時並不知道jboss新增了這個module,有3種方法可以處理:
a) 修改myweb.war中META-INF/MANIFEST.MF清單文件
Manifest-Version: 1.0 Dependencies: mylib Built-By: jimmy Build-Jdk: 1.7.0_79 Created-By: Apache Maven 3.3.3 Archiver-Version: Plexus Archiver
注意第2行, Dependencies: mylib 把這行加上后,就表示myweb.war在啟動時,要依賴mylib這個module,如果我們自己開發的module不止一個,多個module之間要英文逗號隔開,比如:module1,module2
當然,這一行如果要人工手動添加,未免太不講究,有maven-plugin可以幫我們搞定:
1 <plugin> 2 <groupId>org.apache.maven.plugins</groupId> 3 <artifactId>maven-war-plugin</artifactId> 4 <configuration> 5 <archive> 6 <manifestEntries> 7 <Dependencies>mylib</Dependencies> 8 </manifestEntries> 9 </archive> 10 </configuration> 11 </plugin>
b) 還有第2種方式,在WEB-INF下添加文件jboss-deployment-structure.xml,內容如下:
1 <jboss-deployment-structure> 2 <deployment> 3 <dependencies> 4 <module name="mylib"/> 5 </dependencies> 6 </deployment> 7 </jboss-deployment-structure>
c) 上面二種方式,都是由應用本身來控制加載哪些模塊,也是我個人推薦的方式,還有一種一勞永逸的暴力方法,直接修改$JBOSS_HOME/standalone/configuration/standalone.xml文件(注:如果是domain模式,則相應修改domain.xml文件),內容如下:
1 <subsystem xmlns="urn:jboss:domain:ee:1.1"> 2 <global-modules> 3 <module name="mylib" slot="main"/> 4 </global-modules> 5 <spec-descriptor-property-replacement>false</spec-descriptor-property-replacement> 6 <jboss-descriptor-property-replacement>true</jboss-descriptor-property-replacement> 7 </subsystem>
根據關鍵字":ee:1.1"找到這段, 添加第2-4行即可,這樣jboss在啟動時,會把這個當成全局module,默認加載。
注:這種方式雖然簡單,但是不推薦,原因是如果jboss部署了多個應用,其它應用不知道有這個全局module,在自己的項目中再重復打包這些jar包,極容易在啟動時造成沖突,最終啟動失敗,各種報錯。
只有一種情況,比較適合這種方式:數據庫驅動jar,比如:ojdbc6.jar這類,不過對於數據庫驅動jar包而言,有一種更簡單的方式,直接將驅動jar包當成普通應用來部署就行了,所以這種改standalone.xml的方式,仍然體現不出優越性。
1.5 修改pom.xml ,不打包公用jar包
既然mylib這個公用jar已經移動jboss中了,那么myweb這個項目打包里就不必再打包它了,修改pom.xml中的相關部分:
1 <dependency> 2 <groupId>yjmyzz</groupId> 3 <artifactId>mylib</artifactId> 4 <version>1.0</version> 5 <scope>provided</scope> 6 </dependency>
注意:第5行,改成provided表示該依賴項,運行時由jboss容器提供,因此打包時該項被忽略。
二、進階篇
根據前面的步驟,好象並不難弄,但是實際應用中,如果想把一些知名的開源jar包,比如:spring, mybatis, hibernate , jackson這些全都以module的形式弄到jboss里,卻並不容易,原因在於:這些開源項目本身又依賴其它開源項目,而其它開源項目,還有依賴,一層一層分析下來,關系十分復雜。更要命的的jboss本身也默認集成了一些知名的開源項目,比如:commons-logging之類,所以相互之間極容易沖突。就拿spring來說,最低層的是spring-core,它是依賴項最少的,如果要放到jboss的module中,module.xml內容為:
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <module xmlns="urn:jboss:module:1.1" name="mylib.spring-core"> 4 5 <resources> 6 <resource-root path="spring-core-4.1.1.RELEASE.jar" /> 7 </resources> 8 9 <dependencies> 10 <module name="org.apache.commons.logging"/> 11 <module name="javax.api" export="true"/> 12 <module name="org.jboss.vfs"/> 13 </dependencies> 14 15 </module>
注意:9-13行,這里表示spring-core依賴了哪些更底層次的module,一個也都不能少,否則啟動時就會有一堆其名其妙的錯誤。所以,分析眾多開源項目和jboss內置module的依賴關系,將是一個極大的挑戰。
spring 4.1.1-RELEASE整套jar包,全部以module方式融合進jboss的話,步驟如下:
a) modules目錄下先創建子目錄org/springframework/spring/main
b) 將spring的一堆jar包復制進來,文件列表如下:
spring-aop-4.1.1.RELEASE.jar
spring-aspects-4.1.1.RELEASE.jar
spring-beans-4.1.1.RELEASE.jar
spring-context-4.1.1.RELEASE.jar
spring-context-support-4.1.1.RELEASE.jar
spring-core-4.1.1.RELEASE.jar
spring-expression-4.1.1.RELEASE.jar
spring-instrument-4.1.1.RELEASE.jar
spring-instrument-tomcat-4.1.1.RELEASE.jar
spring-jdbc-4.1.1.RELEASE.jar
spring-jms-4.1.1.RELEASE.jar
spring-messaging-4.1.1.RELEASE.jar
spring-orm-4.1.1.RELEASE.jar
spring-oxm-4.1.1.RELEASE.jar
spring-test-4.1.1.RELEASE.jar
spring-tx-4.1.1.RELEASE.jar
spring-web-4.1.1.RELEASE.jar
spring-webmvc-4.1.1.RELEASE.jar
spring-webmvc-portlet-4.1.1.RELEASE.jar
spring-websocket-4.1.1.RELEASE.jar
c) module.xml內容如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <module xmlns="urn:jboss:module:1.1" name="org.springframework.spring"> 3 <resources> 4 <resource-root path="spring-aop-4.1.1.RELEASE.jar"/> 5 <resource-root path="spring-aspects-4.1.1.RELEASE.jar"/> 6 <resource-root path="spring-beans-4.1.1.RELEASE.jar"/> 7 <resource-root path="spring-context-4.1.1.RELEASE.jar"/> 8 <resource-root path="spring-context-support-4.1.1.RELEASE.jar"/> 9 <resource-root path="spring-core-4.1.1.RELEASE.jar"/> 10 <resource-root path="spring-expression-4.1.1.RELEASE.jar"/> 11 <resource-root path="spring-instrument-4.1.1.RELEASE.jar"/> 12 <resource-root path="spring-instrument-tomcat-4.1.1.RELEASE.jar"/> 13 <resource-root path="spring-jdbc-4.1.1.RELEASE.jar"/> 14 <resource-root path="spring-jms-4.1.1.RELEASE.jar"/> 15 <resource-root path="spring-messaging-4.1.1.RELEASE.jar"/> 16 <resource-root path="spring-orm-4.1.1.RELEASE.jar"/> 17 <resource-root path="spring-oxm-4.1.1.RELEASE.jar"/> 18 <resource-root path="spring-test-4.1.1.RELEASE.jar"/> 19 <resource-root path="spring-tx-4.1.1.RELEASE.jar"/> 20 <resource-root path="spring-web-4.1.1.RELEASE.jar"/> 21 <resource-root path="spring-webmvc-4.1.1.RELEASE.jar"/> 22 <resource-root path="spring-webmvc-portlet-4.1.1.RELEASE.jar"/> 23 <resource-root path="spring-websocket-4.1.1.RELEASE.jar"/> 24 </resources> 25 <dependencies> 26 <module name="org.apache.commons.logging"/> 27 <module name="javax.api" export="true"/> 28 <module name="javaee.api" export="true"/> 29 <module name="org.jboss.vfs"/> 30 </dependencies> 31 </module>%
d) 應用中jboss-deployment-structure.xml的內容如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <jboss-deployment-structure> 3 <deployment> 4 <dependencies> 5 <module name="org.springframework.spring" export="true" meta-inf="export"/> 6 </dependencies> 7 </deployment> 8 </jboss-deployment-structure>
三、實戰篇
下面就以一個Spring MVC 4.1.1 RELEASE + mybatis 3.2.8 + mysql + druid 的實例來說明,如何定制共享jar包:
這是打包后WEB-INF/lib下的所有依賴jar包:
aopalliance-1.0.jar
commons-dbcp-1.4.jar
commons-logging-1.1.3.jar
commons-pool-1.5.4.jar
mybatis-3.2.8.jar
mybatis-spring-1.2.2.jar
mysql-connector-java-5.1.25.jar
spring-aop-4.1.1.RELEASE.jar
spring-beans-4.1.1.RELEASE.jar
spring-context-4.1.1.RELEASE.jar
spring-core-4.1.1.RELEASE.jar
spring-expression-4.1.1.RELEASE.jar
spring-jdbc-4.1.1.RELEASE.jar
spring-tx-4.1.1.RELEASE.jar
spring-web-4.1.1.RELEASE.jar
spring-webmvc-4.1.1.RELEASE.jar
整個應用打包后,war包的尺寸約為6.7M(注:druid數據源是用在jboss創建jndi datasource的,所以不需要打包在war中)。根據前面的介紹,一步一步來精減發布包:
1. %JBOSS_HOME/modules/mylib/main 先創建該目錄,把lib下的這些jar文件,全復制進去
2. 然后創建module.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <module xmlns="urn:jboss:module:1.1" name="mylib"> 3 <resources> 4 <resource-root path="standard-1.1.2.jar"/> 5 <resource-root path="jstl-1.2.jar"/> 6 <resource-root path="aopalliance-1.0.jar"/> 7 <resource-root path="mybatis-3.2.8.jar"/> 8 <resource-root path="mybatis-spring-1.2.2.jar"/> 9 <resource-root path="mysql-connector-java-5.1.25.jar"/> 10 <resource-root path="spring-aop-4.1.1.RELEASE.jar"/> 11 <resource-root path="spring-beans-4.1.1.RELEASE.jar"/> 12 <resource-root path="spring-context-4.1.1.RELEASE.jar"/> 13 <resource-root path="spring-core-4.1.1.RELEASE.jar"/> 14 <resource-root path="spring-expression-4.1.1.RELEASE.jar"/> 15 <resource-root path="spring-jdbc-4.1.1.RELEASE.jar"/> 16 <resource-root path="spring-tx-4.1.1.RELEASE.jar"/> 17 <resource-root path="spring-web-4.1.1.RELEASE.jar"/> 18 <resource-root path="spring-webmvc-4.1.1.RELEASE.jar"/> 19 <resource-root path="druid-1.0.15.jar"/> 20 </resources> 21 <dependencies> 22 <module name="org.apache.commons.logging"/> 23 <module name="javax.api" export="true"/> 24 <module name="javaee.api" export="true"/> 25 <module name="javax.transaction.api" export="true"/> 26 <module name="javax.servlet.api" optional="true"/> 27 <module name="org.jboss.vfs"/> 28 </dependencies> 29 </module>
3. 應用中的jboss-deployment-structure.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <jboss-deployment-structure> 3 <deployment> 4 <exclusions> 5 6 </exclusions> 7 <dependencies> 8 <module name="mylib"/> 9 </dependencies> 10 </deployment> 11 </jboss-deployment-structure>
4. META-INF的特殊處理
因為spring的相關jar全放到jboss中了,這樣會給應用本身運行帶來問題,spring程序在啟動時,會解析bean.xml配置文件,這個過程會加載spring.handers等文件,原來spring打包在應用本身中時,這些文件內嵌在sping的jar中,所以不會有問題,現在這些文件沒有了,解析過程就會報錯,因此需要手動把這些文件放到META-INF下,如圖:
圖中的這些文件,在spring里都可以找到,如果你的應用還使用了struts2,jstl,standard這些jar包,這些jar包里META-INF下的tld等文件也要復制到自己項目的META-INF下,根據我實際測試的結果,如果出現問題
spring-webmvc-xxx.jar
struts2-core-xxx.jar
這二個jar最好還是打包到應用中
最后別忘記了修改pom.xml文件,把所有依賴項的scope改成provided。
這樣處理后,war包的尺寸從6.7M直接降到19K。