為什么用腳本語言呢?是這樣的,如果我有完整的Java編程IDE,用Jython或是Groovy看起來就顯得有些落伍了。雖然可以用較少行來編碼 (雖然不是少很多),但是我希望輸入的編寫能夠自動化。我希望編譯器在編碼時告警,而且我需要分解。這需要Java IDE以外的插件。
但有時候沒有完整的IDE配置。想一下要自動敏捷的工作,或者想一下服務器管理員。這些人沒有任何像Eclipse之類的東西,而且他們的工作不可能事先完成。不可能為系統(tǒng)管理而編碼。這就是像WLST這類工具產(chǎn)生的來由,它們使得世界更美好。
WebLogic 腳本工具(WLST,WebLogic Scripting Tool)是一個幫助編寫遠程管理和修改服務器安裝腳本的Jython模塊。它有兩個版本:離線,它可以配置尚不存在的服務器實例,以及在線,它需要連接 到一個WebLogic服務器。這兩個版本都是Beta版而且文檔很少,但是它們保證會改進并在將來的某個WebLogic版本中包含。
這里我們將專注于在線版本,因為它的功能比離線版本更為完整。
使服務器配置自動化:
讓我們從難以對付的WebLogic服務器配置開始吧!典型的開發(fā)團隊在幾臺主機上復制同樣的配置,僅僅改變少量參數(shù),如IP、主機名和TCP端口。在相對典型的項目中,必須對每個開發(fā)人員的PC、集成測試主機和生產(chǎn)主機,都要執(zhí)行一遍這個過程。Ant任務對這個問題有很大幫助,但是它還沒有準備好處理像定制JMX bean這類的事務。
我們將創(chuàng)建并裝載服務器,配置它,然后關機,混合使用Ant和WLST。首先,讓我們創(chuàng)建清單1中的服務器。為了簡化,我們將在這里使用Ant任務,因為結合使用WLST離線和在線會使事情復雜化。
清單1
build.properties:
server=weblogic
weblogic.server.name=myserver
weblogic.domain.name=mydomain
weblogic.admin.username=weblogic
weblogic.admin.password=weblogic
weblogic.home=C:/bea
weblogic.lib.dir=/weblogic81/server/lib
weblogic.mbeantypes.dir=/mbeantypes
server.project.root.dir=/user_projects/domains/
server.deploy.dir=/applications
我檢查了屬性,因為在多于一個品牌的應用服務器上部署時,很容易使用錯誤的build.properties文件(參見清單2)。
清單 2
build.xml:
[...]
<path id="weblogic.classpath">
<fileset dir="">
<include name="weblogic.jar"/>
</fileset>
</path>
<target name="check-properties">
<condition property="wlproperties.ok">
<and>
<isset property="weblogic.server.name"/>
<isset property="weblogic.domain.name"/>
<isset property="weblogic.admin.username"/>
<isset property="weblogic.admin.password"/>
</and>
</condition>
<fail unless="wlproperties.ok">
Weblogic properties are missing. Double check build.properties.
</fail>
<fail>
<condition>
<not><available file="/weblogic.jar"/></ not>
</condition>
Missing file /weblogic.jar
</fail>
</target>
<target name="create-server" depends="check-properties">
<taskdef name="wlserver" classname="weblogic.ant.taskdefs. management.WLServer"
classpathref="weblogic.classpath"/>
<echo>Creating server at </echo>
<delete dir="" includeemptydirs="true" quiet="true"/>
<mkdir dir="" />
<wlserver
dir=""
domainName=""
serverName=""
host=""
port=""
generateConfig="true"
productionModeEnabled="false"
weblogicHome="/weblogic81"
username=""
password=""
action="start"
>
<classpath refid="weblogic.classpath"/>
</wlserver>
我們剛剛刪除了整個域目錄,創(chuàng)建了一個新的、干凈的目錄,并讓服務器運行,這樣,在清單3中,我們可連接并配置它。
清單3
<java classname="weblogic.WLST" fork="true" failOnError="true" dir="scripts/wlst">
<classpath refid="weblogic.classpath"/>
<classpath>
<fileset dir="lib/wlst">
<include name="*.jar"/>
</fileset>
</classpath>
<arg line="createAll.py" />
</java>
<wlserver
host=""
port=""
username=""
password=""
action="shutdown"
/>
</target>
停止服務器是必要的,因為有些設置改變了,如安全驗證者,需要正常關機以保存到磁盤。省略這一步將會在Ant腳本結束處突然中止服務器。
注意:WLST任務有分叉,因此,如果WLST在腳本中發(fā)現(xiàn)了錯誤,Ant仍將會顯示“成功編譯”,從而會使得裝載該腳本的人迷惑。
讓我們將WLST腳本分成兩個部份,這樣在以后的管理任務中能盡可能多的重用它。我已經(jīng)使用了包含在WLST包中的很棒的例子,并且將 saveDomain()命令的輸出作為起點。saveDomain()生成的腳本不是很完美,但是它能指出工具的可能性(參見清單4)。
清單 4
createAll.py:
execfile("AdminTool.py")
admin.configureServer()
admin.createXaPool()
AdminTool.py:
from javax.management import InstanceNotFoundException
# Python 2.4 will include booleans, but until then this is required
true = 1
false = 0
class AdminTool:
def __init__(self):
loadProperties("administration.properties")
# Connects with a weblogic instance
def connect(self):
connect(username, password, "t3://" + host + ":" + port)
self.myServer = getTarget("/Server/" + serverName)
# Server attributes that cannot be generated via ant
def configureServer(self):
# Activates console DEBUG mode - I really like that
self.myServer.setStdoutSeverityLevel(64)
print "Configured server " + self.myServer.getName()
# Creates a JDBC pool:
def createPool(self, poolName, driverName):
pool = create(poolName, "JDBCConnectionPool")
pool.setDriverName(driverName)
pool.setURL(dbURL)
pool.setPassword(dbPassword)
pool.setProperties(makePropertiesObject("user=" + dbUsername))
pool.setRemoveInfectedConnectionsEnabled(false)
pool.setTestConnectionsOnCreate(true)
pool.setTestTableName("SQL SELECT 1 FROM DUAL")
# setTestFrecuencySeconds is not soported by WLST objects
# so here is a workaround
cd(′/JDBCConnectionPool/′ + poolName)
set(′TestFrequencySeconds′, 300)
cd(′/′)
pool.addTarget(self.myServer)
def createXaPool(self):
self.createPool(MY_POOL_NAME, ′oracle.jdbc.xa.client.? OracleXADataSource′)
# Removes an element if it exists
def removeIfExists(self, name, type):
try:
mbean = home.getAdminMBean(name, type)
home.deleteMBean(mbean)
print ′Removed the ′ + type + ′: ′ + name
except InstanceNotFoundException, e:
print "Cannot remove " + name + ",type=" + type + " because ? it does not exist"
def removeXaPool(self):
self.removeIfExists(MY_POOL_NAME, "JDBCConnectionPool")
# The JDBC Connection Pool name
MY_POOL_NAME=′MyPool′
# the instance we are going to use
admin = AdminTool()
admin.connect()
administration.properties
host=127.0.0.1
port=7001
username=weblogic
password=weblogic
dbURL=jdbc:oracle:thin::1521:DATABASE
dbUsername=foo
dbPassword=bar
LoadProperties任務將administration.properties文件中的所有項轉換成Jython變量。我們已經(jīng)使用了 Jython類的第一個方法來管理WebLogic服務器實例。還可以輕易將它擴展到創(chuàng)建和刪除DataSources,這是一個JMS環(huán)境,甚至還可以 擴展到安全領域。
MBean方法
前面我們已經(jīng)看到的是創(chuàng)建和配置MBeans的一個方法(下一節(jié)會解釋另一種方法)。不利的一面是必須知道支持的屬性和方法,而WLST沒有這些文檔。我怎么去猜哪個方法可用呢?
噢,我想到的第一個方法是到config.xml文件或是Web控制臺去找,并假設屬性名稱未改變。如果有一個不錯的IDE,我們還可以打開Mbean 接口類看看那里有些什么(它和Mbean的名稱一樣,以“Mbean”結束)。這不會顯示代碼,但是可以查到哪個方法可用。
我喜歡連接到http://e-docs.bea.com/wls/docs81/javadocs/index.html, 查看weblogic.management.configuration包的內容。比如,如果我們找到ServerMBean類,就可以看到兩個有趣的 但是不太為人們所熟悉的方法isJDBCLoggingEnabled()和setJDBCLoggingEnabled()。我們可通過打開wlst交 互shell來查看它們,如下所示:
wls:/mydomain/config> server=home.getAdminMBean(′myserver′, ′Server′)
wls:/mydomain/config> server.setJDBCLoggingEnabled(1)
wls:/mydomain/config> server.isJDBCLoggingEnabled()
1
?。ā癶ome”是一個AdminMbeanHomeImpl類型的變量,可以像對任何其他Mbean一樣研究;唯一的問題是因為它是一個內部類,所以沒有javadoc可用。)
如果最后三個命令不好理解,不要擔心。我們會在下一節(jié)介紹Shell。
命令行系統(tǒng)管理
系統(tǒng)管理員也可以通過使用交互式shell來手工管理WebLogic服務器實例。其優(yōu)點是在試圖修改系統(tǒng)配置時,不用事先知道Mbean接口。對這 一部分,需要在classpath包含webLogic.jar、jython.jar以及wlst.jar,并啟動主類weblogic.WLST,它 是交互式控制臺。
要記住這是Jython。引號和雙引號用于字符串聲明;實例化不需要新的運算符(事實上,這是一個語法錯誤);不需要分號,因為每行用回車結束;而且不必聲明變量(la Unix shell腳本)。如果這還不夠,請參考Python和WLST的文檔。
我們需要開始連接到WebLogic服務器的實例。我們可以選擇使用之前編寫的AdminTool腳本,或者手工連接:
execfile(′AdminTool.py′)
admin.connect()
或
connect(′weblogic′, ′weblogic′, "t3://localhost:7001)
Connecting to weblogic server instance running at t3://127.0.0.1:7001 as
username weblogic ...
成功連接到屬于“mydomain”域的Admin服務器“myserver”是系統(tǒng)輸出,而且應采用編碼的格式。
現(xiàn)在,我們可以開始好好玩一下了。對于WLST,JMX樹可像UNIX文件系統(tǒng)一樣進行遍歷,在這里JMX Mbeans是目錄而其屬性是文件。在所有這些過程中要記住Python語法,并要記得WLST仍然不能分辨通配符。這就是為什么我們要省略大多數(shù) ls()輸出的原因(參見清單5)。
清單5
wls:/mydomain/config> ls()
[...]
drw-JDBCConnectionPools
drw-JDBCDataSourceFactories
drw-JDBCDataSources
drw-JDBCMultiPools
drw-JDBCTxDataSources
[...]
wls:/mydomain/config> cd(′JDBCConnectionPools′)
wls:/mydomain/config/JDBCConnectionPools> ls()
drw-MyPool
wls:/mydomain/config/JDBCConnectionPools> cd(′MyPool′)
wls:/mydomain/config/JDBCConnectionPools/MyPool> ls()
[...]
-rw-TestConnectionsOnCreatetrue
-rw-TestConnectionsOnReleasefalse
-rw-TestConnectionsOnReservefalse
-rw-TestFrequencySeconds300
-rw-TestStatementTimeout-1
-rw-TestTableNameSQL SELECT 1 FROM DUAL
-r--TypeJDBCConnectionPool
-rw-URLjdbc:oracle:thin::1521:DATABASE
[...]
我們還可以對于單個cd(′/JDBCConnectionPools/MyPool′)命令深入到這個地步。WLST永遠記得cmo(當前管理對 象,Current Managed Object),即與我們正在瀏覽的當前“文件夾”相關的Mbean。因此,從實際角度來看這些命令是相當?shù)模?/p>
wls:/mydomain/config/JDBCConnectionPools/MyPool> cmo
[Caching Stub]Proxy for mydomain:Name=MyPool,Type=JDBCConnectionPool
wls:/mydomain/config/JDBCConnectionPools/MyPool> pwd()
′/JDBCConnectionPools/MyPool′
現(xiàn)在,讓我們改變一些隨機屬性(參見清單6)。記住Python沒有布爾屬性。服務器可返回真或假(既然它運行Java),但是不能賦這些值。然而,不用擔心;如果通過WebLogic控制臺查看它,布爾值1得到了服務器的正確解釋。
清單 6
wls:/mydomain/config/JDBCConnectionPools/MyPool> set?(′TestFrequencySeconds′, 500)
wls:/mydomain/config/JDBCConnectionPools/MyPool> set(′TestConnectionsOnRelease′, 1)
wls:/mydomain/config/JDBCConnectionPools/MyPool> ls()
-rw-TestConnectionsOnCreatetrue
-rw-TestConnectionsOnRelease1
-rw-TestConnectionsOnReservefalse
-rw-TestFrequencySeconds500
-rw-TestStatementTimeout-1
-rw-TestTableNameSQL SELECT 1 FROM DUAL
-r-- TypeJDBCConnectionPool
-rw-URLjdbc:oracle:?thin::1521:DATABASE
[...]
wls:/mydomain/config/JDBCConnectionPools/MyPool> get(′TestConnectionsOn?Release′)
1
使用前一節(jié)關于“使服務器配置自動化”中介紹的相當技術,也可能得到了同樣的結果。我發(fā)現(xiàn)這個方法對于系統(tǒng)管理員更簡單,而第一個方法對于開發(fā)人員準備 腳本則更簡單。這只是適應不同類型的工具集:系統(tǒng)管理員更習慣于Unix Shell,而開發(fā)人員對于的Java的“味道”則感覺更為舒服。
管理服務器配置的例子:一個真實例子
需要了解那些煩人的JDBC調用內部是一種常見現(xiàn)象。有時人們真的希望能夠看見WebLogic服務器和數(shù)據(jù)庫之間對話,為什么它會見鬼地返回0行,或者輪廓性能,OK。用熱插拔功能記錄JDBC調用(而不僅是SQL,拜托了,還要記錄參數(shù))應該不錯。想試一下嗎?
首先,讓我們下載p6spy JDBC驅動程序。它是一個JDBC包,可以記錄任何經(jīng)過它的東西。要配置它,將p6spy.jar和包含p6spy.properties的目錄放到服 務器classpath目錄下(不要忘了這個目錄,否則WebLogic會報告JAR文件不存在)。按照需要調整p6spy.properties。
我們想要到達的目的是創(chuàng)建兩個Connection Pool(連接池),一個直接用Oracle JDBC驅動程序而另一個通過p6spy。然后,我們將修改數(shù)據(jù)源指向p6spy數(shù)據(jù)源而不重啟服務器(如果我們相信Web控制臺接口,這個修改無需重啟)。
我們將通過執(zhí)行之前開發(fā)出的管理腳本來開始:
wls:/(offline)> execfile(′AdminTool.py′)
Connecting to weblogic server instance running at t3://127.0.0.1:7001 as
username weblogic ...
成功連接到屬于“mydomain”域的Admin服務器“myserver”,它也是系統(tǒng)輸出并且應正確格式化。
我們現(xiàn)在可以創(chuàng)建連接池了。
wls:/mydomain/config> admin.createPool("P6SPY Connection Pool",
"com.p6spy.engine.spy.P6SpyDriver")
JDBCConnectionPool with name ′P6SPY Connection Pool′
has been created successfully.
在WebLogic控制臺我們可看到以下顯示(WebLogic日志行將只在將“debug to console”選項啟用時才會顯示):
<28-feb-2005 20H18′ GMT> <Info> <JDBC> <BEA-001132>
<Initialized statement cache of size "10"
for connection in pool "P6SPY Connection Pool".>
1109621928226|0|1|statement|SELECT 1 FROM DUAL|SELECT 1 FROM DUAL
1109621928242|0|1|statement|SELECT 1 FROM DUAL|SELECT 1 FROM DUAL
這顯示連接池初始化以及新連接測試。我們將假設數(shù)據(jù)源還不存在。如果我們還清楚,應該已經(jīng)預見到這一點并在AdminTool類創(chuàng)建了方法,但是,我們還是可通過清單7中所列的交互式shell來這么做。
清單 7
wls:/mydomain/config> datasource=create(′MyDS′, ′JDBCTxDataSource′)
JDBCTxDataSource with name ′MyDS′ has been created successfully.
wls:/mydomain/config> datasource.setJNDIName("MyDS")
wls:/mydomain/config> datasource.setPoolName("P6SPY Connection Pool")
wls:/mydomain/config> datasource.setEnableTwoPhaseCommit(true)
wls:/mydomain/config> datasource.addTarget(admin.myServer)
1
我們已經(jīng)開始將數(shù)據(jù)源指向P6SPY連接池,因此,可以檢查應用程序看看它真的記錄了JDBC語句;用測試案例來嘗試。現(xiàn)在,有兩個方法可以禁止記錄。既然在Jython變量中有數(shù)據(jù)源,我們就可以用“Java”的方式來做。
datasource.setPoolName(MY_POOL_NAME)
或者,采用如清單8所示的“system administrator”方法:
清單8
wls:/mydomain/config> cd (′JDBCTxDataSources′)
wls:/mydomain/config/JDBCTxDataSources> ls()
drw-MyDS
wls:/mydomain/config/JDBCTxDataSources> cd(′MyDS′)
wls:/mydomain/config/JDBCTxDataSources/MyDS> ls()
[...]
-rw-PoolNameMyPool
[...]
wls:/mydomain/config/JDBCTxDataSources/MyDS> set(′PoolName′, MY_POOL_?NAME)
結束語
WLST是一個能夠推進應用程序服務器配置和遠程維護的杰出工具。它還不支持用通配符查找/定位選項(對于一些并非不常見的情況,如有人需要查找某個配置選項但是想不起它的位置)。但是,當最后與WebLogic 9綁定后,它肯定會非常有用。