posts - 48,  comments - 14,  trackbacks - 0
脚本语言近来受到一些关注。随着Groovy和 Jython的到来,编写与Java合并的脚本比Ant更简单自然。一直以来使用XML来调用Java方法都是被迫的,这主要是因为在标记语言中解释流、条件表达式和自定义代码比较困难(虽然自Ant 1.5之后这一点有了较大的改进)。

  为什么用脚本语言呢?是这样的,如果我有完整的Java编程IDE,用Jython或是Groovy看起来就显得有些落伍了。虽然可以用较少行来编码(虽然不是少很多),但是我希望输入的编写能够自动化。我希望编译器在编码时告警,而且我需要分解。这需要Java IDE以外的插件。

  但有时候没有完整的IDE配置。想一下要自动敏捷的工作,或者想一下服务器管理员。这些人没有任何像Eclipse之类的东西,而且他们的工作不可能事先完成。不可能为系统管理而编码。这就是像WLST这类工具产生的来由,它们使得世界更美好。

  WebLogic 脚本工具(WLST,WebLogic Scripting Tool)是一个帮助编写远程管理和修改服务器安装脚本的Jython模块。它有两个版本:离线,它可以配置尚不存在的服务器实例,以及在线,它需要连接到一个WebLogic服务器。这两个版本都是Beta版而且文档很少,但是它们保证会改进并在将来的某个WebLogic版本中包含。

  这里我们将专注于在线版本,因为它的功能比离线版本更为完整。

使服务器配置自动化:

  让我们从难以对付的WebLogic服务器配置开始吧!典型的开发团队在几台主机上复制同样的配置,仅仅改变少量参数,如IP、主机名和TCP端口。在相对典型的项目中,必须对每个开发人员的PC、集成测试主机和生产主机,都要执行一遍这个过程。Ant任务对这个问题有很大帮助,但是它还没有准备好处理像定制JMX bean这类的事务。

  我们将创建并装载服务器,配置它,然后关机,混合使用Ant和WLST。首先,让我们创建清单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>

  我们刚刚删除了整个域目录,创建了一个新的、干净的目录,并让服务器运行,这样,在清单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在脚本中发现了错误,Ant仍将会显示“成功编译”,从而会使得装载该脚本的人迷惑。

  让我们将WLST脚本分成两个部份,这样在以后的管理任务中能尽可能多的重用它。我已经使用了包含在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变量。我们已经使用了Jython类的第一个方法来管理WebLogic服务器实例。还可以轻易将它扩展到创建和删除DataSources,这是一个JMS环境,甚至还可以扩展到安全领域。

MBean方法

  前面我们已经看到的是创建和配置MBeans的一个方法(下一节会解释另一种方法)。不利的一面是必须知道支持的属性和方法,而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

  (“home”是一个AdminMbeanHomeImpl类型的变量,可以像对任何其他Mbean一样研究;唯一的问题是因为它是一个内部类,所以没有javadoc可用。)

  如果最后三个命令不好理解,不要担心。我们会在下一节介绍Shell。

命令行系统管理

  系统管理员也可以通过使用交互式shell来手工管理WebLogic服务器实例。其优点是在试图修改系统配置时,不用事先知道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”是系统输出,而且应采用编码的格式。

  现在,我们可以开始好好玩一下了。对于WLST,JMX树可像UNIX文件系统一样进行遍历,在这里JMX Mbeans是目录而其属性是文件。在所有这些过程中要记住Python语法,并要记得WLST仍然不能分辨通配符。这就是为什么我们要省略大多数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。因此,从实际角度来看这些命令是相当的:

wls:/mydomain/config/JDBCConnectionPools/MyPool> cmo
[Caching Stub]Proxy for mydomain:Name=MyPool,Type=JDBCConnectionPool
wls:/mydomain/config/JDBCConnectionPools/MyPool> pwd()
´/JDBCConnectionPools/MyPool´

  现在,让我们改变一些随机属性(参见清单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

  使用前一节关于“使服务器配置自动化”中介绍的相当技术,也可能得到了同样的结果。我发现这个方法对于系统管理员更简单,而第一个方法对于开发人员准备脚本则更简单。这只是适应不同类型的工具集:系统管理员更习惯于Unix Shell,而开发人员对于的Java的“味道”则感觉更为舒服。

管理服务器配置的例子:一个真实例子

  需要了解那些烦人的JDBC调用内部是一种常见现象。有时人们真的希望能够看见WebLogic服务器和数据库之间对话,为什么它会见鬼地返回0行,或者轮廓性能,OK。用热插拔功能记录JDBC调用(而不仅是SQL,拜托了,还要记录参数)应该不错。想试一下吗?

  首先,让我们下载p6spy JDBC驱动程序。它是一个JDBC包,可以记录任何经过它的东西。要配置它,将p6spy.jar和包含p6spy.properties的目录放到服务器classpath目录下(不要忘了这个目录,否则WebLogic会报告JAR文件不存在)。按照需要调整p6spy.properties。

  我们想要到达的目的是创建两个Connection Pool(连接池),一个直接用Oracle JDBC驱动程序而另一个通过p6spy。然后,我们将修改数据源指向p6spy数据源而不重启服务器(如果我们相信Web控制台接口,这个修改无需重启)。

  我们将通过执行之前开发出的管理脚本来开始:

wls:/(offline)> execfile(´AdminTool.py´)

Connecting to weblogic server instance running at t3://127.0.0.1:7001 as
username weblogic ...

  成功连接到属于“mydomain”域的Admin服务器“myserver”,它也是系统输出并且应正确格式化。

  我们现在可以创建连接池了。

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

  这显示连接池初始化以及新连接测试。我们将假设数据源还不存在。如果我们还清楚,应该已经预见到这一点并在AdminTool类创建了方法,但是,我们还是可通过清单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

  我们已经开始将数据源指向P6SPY连接池,因此,可以检查应用程序看看它真的记录了JDBC语句;用测试案例来尝试。现在,有两个方法可以禁止记录。既然在Jython变量中有数据源,我们就可以用“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绑定后,它肯定会非常有用。

参考资料

原文出处

http://wldj.sys-con.com/read/48932.htm

 作者简介
Ignacio Coloma 是InfoInnova的J2EE架构师。过去6年以来,他已经为电子银行、航空运输、电子政府以及消息处理系统开发了许多应用程序。目前,他正在用脚本语言扩展J2EE应用程序。
posted on 2005-09-28 18:49 逍遥草 阅读(4154) 评论(0)  编辑 收藏 引用 所属分类: weblogic+structs
只有注册用户登录后才能发表评论。