| WebLogic Scripting Tool (WLST) 是一种用于编写 BEA WebLogic 域配置脚本的 BEA 工具。本文包含一些提示和技巧,使用 WLST 准备具有生产质量 WebLogic 域时将派上用场。它还提出了编写更加简洁的 WLST 脚本的技术,并且描述了如何根据简明规范创建 JMS 分布式队列。此外,还提供了示例源代码。
WebLogic Scripting Tool 是一种用于编写 BEA WebLogic 域配置脚本的 BEA 工具。目前,在 BEA dev2dev Web 站点上,WLST 可以作为 WebLogic 8.1 的开发人员发行版使用。 BEA 计划在 WebLogic Server 的下一个主要发行版中包含 WLST 。请注意, BEA Support 既不包括 WLST 的 dev2dev 发行版,也不包括本文包含的代码。
经过几年的努力,我已经帮助构建了多个自定义配置系统。尽管 WLST 还处于开发人员预发行状态,但是它比目前可用的其他选项更适用于 WebLogic 配置。在 WLST 之前, WebLogic 用户通常综合应用 Apache Ant 、 shell 脚本、 XSLT 、 WebLogic Configuration Wizard 和 Paco Gomez 的 wlshell(一种与 WLST 非常 类似的工具) 。我现在向客户推荐 WLST 作为工具的一种选择。
与 wlshell 相比,为什么说 WLST 较好一些呢 ? 脚本语言 Jython 是形成这一事实的奥妙所在,这种脚本语言可以在 Java 中实现 流行的 Python 语言。
WLST 具有以下两个版本:
- WSLT Online : 可用于查询和修改正在运行的 WebLogic Server 域。
- WLST Offline : 可用于在不具备正在运行的 WebLogic Server 域的情况下构建 WebLogic 域。
本文重点介绍 WLST Offline 的使用方法。与源程序控制系统一起使用时,WLST Offline 脚本是对配置进行记录和管理的主要方式。对于将 WLST Online 用作多刀工具对活动 WebLogic 域进行切分,需要介绍的内容也很多。自然有人堪当此任。我要说的是以后将作为 WLST 应用的 WLST Offline,这些建议多半同样也适用于 WLST Online 。
不难想像,WLST 的预发行版可能还不够完善,需要进一步调试。本文包含一些提示和技巧,可用于解决这些问题,以及如何应用 Jython 和 WLST 建立高生产质量的 WebLogic 域。本文不尝试教读者如何使用 Jython 或 WLST 。对于 Java 或 shell 脚本的编程人员来说,学习 Jython 是相当容易的事(尽管他们可能使用它的样式千差万别)。同样地,本文也不是供新手学习 WLST 使用的教程。要从本材料中最大限度获益,您必须在熟悉 Jython 和 WLST 的基础上阅读。
示例源代码
本文附带的示例源代码对下面讨论的技术进行了演示。此代码已经在 WLST Offline 的预发行版和 WebLogic Server 8.1 上做过测试。我预期再将其少量更新即可与最终版本的 WLST 一起使用。
如果您要运行此示例代码,则确保您已从 dev2dev 得到最新版本的 WLST Offline 。如果遇到诸如 Error: cd() failed之类的错误,则说明您使用的是较旧的版本。
提示:从其他模块访问 WLST
WLST 脚本可以通过多个函数和变量 (例如 assign() 、 cmo 和 readTemplate() ) 与 WLST 引擎进行交互。在通过 WLST 调用脚本时,这些函数和变量可以隐式使用,就是说,它们会自动出现在该脚本的全局命名空间中。这对于脚本来说,方便之处在于,它们无需将这些对象显式导入。
不足之处是,WLST 不允许子模块导入这些对象。这一点妨碍了将脚本包括在适当的模块中的能力。简单粗陋的解决方案将这些对象作为参数传递给每一个需要它们的函数。
这里介绍一种较好的解决方案。在 wlstutility 程序包中定义一个方法,让它从字典读取所需的对象,并将其存储在 wlstutility 全局命名空间中。我们的每一个顶级脚本开头都是:
import wlstutility
wlstutility.initialize(globals())
初始化方法的定义位于 wlstutility 包的 __init__.py 文件中。
# __all__ defines the public names that the package
# exports.
__all__ = []
def initialize(topLevelNamespace):
for f in ("assign", "cd", "create", "ls",
"readTemplate", "set", "writeDomain"):
globals()[f] = topLevelNamespace[f]
__all__.append(f)
global _topLevelNamespace
_topLevelNamespace = topLevelNamespace
def getCMO():
return _topLevelNamespace["cmo"]
然后,在任何其他模块中,从 wlstutility 导入所需的对象 :
from wlstutility import assign, cd, ls, set, getCMO
注意,对 WLST cmo 变量的访问已由 getCMO() 函数取代,后者是一种较好的形式。 在 WLST 的未来发行版中,将增加从其他模块使用 WLST 的能力。 writeIniFile() 方法也将被添加上去,该方法用于创建包含 WLST 已 定义的函数和变量的 Python 模块。
Python的功能:Mbean构造函数
标准的 WLST 样式包括对 Mbean 的重新调用 :
cd("/")
jmsTemplate = create("myTemplate", "JMSTemplate")
jmsTemplate.redeliveryDelayOverride = 100
jmsTemplate.redeliveryLimit = 3
# ...
我们还必须确保在要创建的参数中使用正确的类型名称。如果我们拥有每种类型的 Mbean 的构造函数,是不是更好 ? 该构造函数类似于 :
from wlstutility.constructors import JMSTemplate
cd("/")
jmsTemplate = JMSTemplate("myTemplate",
redeliveryDelayOverride = 100,
redeliveryLimit = 3)
这对我来说已经够用了。您可能需要进行更复杂的配置(如 JDBCConnectionPool )才能最大限度受益。 Mbean 构造函数的额外好处是,允许对参数进行设置以使用字典来传递:
myRedeliveryPolicy = { "redeliveryDelayOverride" : 100,
"redeliveryLimit" : 3 }
cd("/")
jmsTemplate = JMSTemplate("myTemplate",
bytesMaximum = 1000000,
**myRedeliveryPolicy)
下面是创建这些 Mbean 构造函数时要使用的代码 :
# wlstutility/constructors.py
import wlstutility
__all__ = []
for mbeanType in (
"Application", "Cluster", "Domain", "DomainLogFilter",
"EJBComponent", "EmbeddedLDAP", "ExecuteQueue",
"JDBCConnectionPool", "JDBCDataSource",
"JDBCTxDataSource", "JMSConnectionFactory",
"JMSDistributedQueue", "JMSDistributedQueueMember",
"JMSDistributedTopic", "JMSDistributedTopicMember",
"JMSFileStore", "JMSQueue", "JMSServer", "JMSTemplate",
"JMSTopic", "JTA", "Log", "Machine", "MailSession",
"SecurityConfiguration", "Server", "StartupClass",
"SSL", "UnixMachine", "User", "WebAppComponent",
"WebServer", ):
def mbeanFactory(name, _type=mbeanType,
existingMBean = None, **kwds):
logMBeanCreation(name, _type, kwds)
if existingMBean:
mbean = existingMBean
existingMBean.name = name
else:
mbean = wlstutility.create(name, _type)
for key, value in kwds.items():
setattr(mbean, key, value)
return mbean
globals()[mbeanType] = mbeanFactory
__all__.append(mbeanType)
该代码通过许多已知的 Mbean 类型进行迭代。它为每种类型创建一个新函数 mbeanFactory ,该函数执行创建正确类型的实例,并通过调用适当的设置方法应用所有关键字参数。然后,将该函数插入到模板的全局命名空间,同时附加到模板导出的 ( __all__ ) 名称列表中。如上例所示,要得到新函数,从其他模板导入也是一种方法。
参数 existingMBean 的作用是什么 ? 它允许您将 “ 构造函数 ” 用于现有的 Mbean 。例如 :
from wlstutility import getCMO from wlstutility.constructors import ExecuteQueue # ... cd("/") cd("Servers/%s/ExecuteQueue/weblogic.kernel.Default" % myServerName) defaultQueue = ExecuteQueue("weblogic.kernel.Default", existingMBean = getCMO(), threadCount = 15)
WLST特色:模板必须至少包含一台服务器
使用 WLST Offline 时,您需要通过 Configuration Wizard Domain Template 来启动。 WLST Offline 期望域模板至少包含一个服务器项。它将第一台服务器视为域的管理服务器。我们希望根据自己的意愿定义或多或少的服务器的灵活性,我们不希望从模板继承附加服务器后就结束。
要以变通的方法解决此问题,我们在域模板中只定义一台服务器。它将成为管理服务器。然后,使用实用工具构造函数中的 existingMBean 支持适当地更改其名称。
from wlstutility import getCMO
from wlstutility.constructors import Server
# ...
# Our domain template has a blank server called "admin"
cd("/")
cd("Servers/admin")
# The following statement uses the existingMBean argument to alter the
# existing MBean, rather than defining a new one.
administrationServer = Server(
domainName,
"MyAdministrationServer", # Rename
existingMBean = getCMO(),
administrationPort = 7001,
# ...
)
提示:您已经得到了一个对象模型——使用它!
WLST 的运行依赖于 JMX 对象模型。您很少有机会保持自己的配置模型 ; 您只要传递 Mbean 就行了。下面是配置 JDBC ConnectionPool 和 DataSource 的示例。
# (server MBean created above).
cd("/")
pool = JDBCConnectionPool("Pool_%s" % server.name,
URL = url,
**nonXAPoolOptions)
dataSource = JDBCDataSource("DataSource_%s" % server.name,
poolName = pool.name,
# ...
)
)
注意构造函数调用中其他 Mbean 的 name 属性的引用方式。
WLST特色:没有脚本参数
可以将命令行参数传递到脚本是一种有用功能。在 WLST 中,这一点是不可能实现的,因为它将多个参数视为多个脚本。如果只将第一个参数视为脚本并在 sys.argv 中传递其余参数,情况会好一些。此外,如果顶级模板的 __name__ 是 __main__ ,则更好。
遗憾的是,这些问题不存在干净的解决方法。为了定制脚本的行为,我使用了在脚本中硬编码名称的属性文件。该示例代码提供一个 loadProperties 方法,该方法可包装这些属性的负载到 Python 字典中。
该问题将在 WLST 的未来发行版中得到解决。第一个命令行参数将被视为脚本名称,其余参数将被传递到该脚本。
WLST特色:writeDomain重命名域
调用 writeDomain() 时,Domain 、 JTA 、 SecurityConfiguration 和 EmbeddedLDAP Mbean 将被忽略,而使用输出目录的名称来代替。
我通常需要让这些 Mbean 的名称与域名称相匹配,所以我将域名称作为目录参数传递到 writeDomain() ,并在以后需要的时候重命名该目录。
该问题将在 WLST 的未来 dev2dev 发行版中得到解决。域名称和域目录名称可以分开设置。
Python的功能:处理JMS分布式目的地
现在我们来考虑复杂一点的问题。假定我们有许多应用程序 JMS 队列,需要作为 WebLogic 分布式目的地被部署到集群中。这需要为每个应用队列配置多个 Mbean 类型:
- 针对集群中每个服务器的 JMSQueue
- 针对集群的 JMSDistributedQueue
- 将 JMSQueue 关联到 JMSDistributedQueue 的 JMSDistributedDestinationMember
我们还需要为分布式主题创建相似的 Mbean,并将引用连接到错误目的地。
在下面的代码中,独立队列或主题的配置被包装在 DestinationFactory 中。 DestinationFactory 知道如何为应用程序代码创建适当的 Mbean 。 QueueFactory 和 TopicFactory这两个附加类都是DestinationFactory 的子类,用于相应地对其行为进行限定。这就是 DestinationFactories 的使用方法:
destinationFactories = (
QueueFactory("AlphaQueue",)
QueueFactory("ErrorQueue", distributed = 0),
QueueFactory("BetaQueue", errorDestination = "ErrorQueue"),
TopicFactory("MyTopic"))
for destinationFactory in destinationFactories:
destinationFactory.createDistributedDestination(cluster)
for server in managedServers:
cd("/")
fileStore = JMSFileStore("JMSFileStore_%s" % server.name,
directory = "jmsfilestore")
jmsServer = JMSServer("JMSServer_%s" % server.name,
store = fileStore)
assign("JMSServer", jmsServer.name, "Target", server.name)
for destinationFactory in destinationFactories:
destinationFactory.createDestinationForServer(
server, jmsServer)
我在此无暇讨论 DestinationFactory 的实现,但是您应该明白它们在此例中的作用。
提示:后处理输出
WLST 只能识别模板文件中的特定标记,如 @BEAHOME 。它基于模板中的 stringsubs.xml 描述符文件使用环境特定的值替换这些标记。您的脚本模板很可能具有不属于 WLST 所做设置的附加参数。我采取后处理生成文件的方式来适当地设置这些参数。
此外,执行后处理时,特殊情况下可能发生 MBean/WLST 故障。以下是我遇到的两个问题:
设置ApplicationMBean twoPhase属性
WLST 包括一个缺陷 ,它认为 ApplicationMBean 的默认值 twoPhase 为 true 。该默认值实际上为 false 。因为 WLST 只为非默认值生成配置,所以它不可能将 twoPhase 设置为 true 。
要使用变通的方法解决此问题,将 twoPhase 设置为 false ,以便 写出一种属性,然后,后处理 config.xml 以将 TwoPhase='false' 的所有实例更改为 TwoPhase='true' 。
支持完整的Oracle JDBC URL语法
WLST 不接受以下形式的 Oracle URL : jdbc:oracle:thin:@//host:1234/SERVICE.myco.com,即指定 Oracle 服务名称 ( 而非 SID ) 的地方。
要使用变通的方法解决此问题,请生成一个占位符 URL,并后处理 config.xml 以插入真正的 URL 。
结束语
本文涵盖 WLST 的多个方面。它介绍了 WLST 的许多特色,向读者提供高效使用 WLST 的一些提示并说明如何利用 Python 的基础。 Jython 可用于很多其他目的,例如,将产生的域打包到独立的 tar 文件中,这样即可方便地将每个服务器复制到目标环境中。幸运的是,Jython 将 Java 和 Python 库放在了触手可及的位置,所以实现这一点非常方便。
总之,我希望阅读本文,对于您提高用于配置 WebLogic 域的自动化脚本编写的水平有所帮助。
鸣谢
非常感谢 Matthew Slingsby 、 Larry Du 和 WLST 团队的投入。 |