Apache Axis2 常用 CLI 命令与工具详解

解析 Axis2 2.0.1 自带脚本:axis2server.sh 启动与堆参数、axis2.sh 启动器机制、wsdl2java 生成 stub、java2wsdl 反向生成 WSDL,附真实 help 回显与 -cp 失效根因。

Apache Axis2Axis22026/10/13

Apache Axis2 常用 CLI 命令与工具详解

目标:把 Axis2 官方 bin 发行包里 4 个核心脚本一次讲透——axis2server.sh(standalone 服务端启动)、axis2.sh(通用 Java 启动器)、wsdl2java.sh(WSDL 转 Java)、java2wsdl.sh(Java 转 WSDL)——每个脚本给出真实 help 回显与实跑结果,并解释脚本内部的类路径组装机制(这是排查"类找不到"问题的关键),已在 Ubuntu 22.04.5(OpenJDK 17.0.20.1、Axis2 2.0.1)实测通过。

一、环境信息

本篇全部命令与回显均在以下环境中实测采集:

  • 操作系统:Ubuntu 22.04.5 LTS,x86_64
  • JDK:OpenJDK 17.0.20.1(JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64)
  • 组件版本:Apache Axis2 2.0.1(官方 bin 发行包)
  • 安装目录:/opt/axis2
  • 服务端口:HTTP 8080(standalone 形态)
  • 执行用户:root

发行包 bin/ 目录实测清单(4 个 .sh 脚本即本篇主角,.bat 为 Windows 等价物):

ls /opt/axis2/bin/

回显(实测):

axis2.bat  axis2.sh  axis2server.bat  axis2server.sh  java2wsdl.bat  java2wsdl.sh  setenv.sh  wsdl2java.bat  wsdl2java.sh

⚠️ 注意:所有脚本启动前必须设置 JAVA_HOME 环境变量,否则直接退出(真实报错见第九节 Q1);PATH 里的 java 与脚本实际使用的 JVM 无关,脚本一律用 $JAVA_HOME/bin/java 启动。

二、工具概览

Axis2 的命令行能力全部由发行包自带脚本提供,分工如下:

脚本作用最终执行的 Java 主类
axis2server.sh启动 standalone 服务端(HTTP 8080 + 可选 TCP)org.apache.axis2.kernel.SimpleAxis2Server
axis2.sh通用启动器:加载 setenv.sh 后运行任意主类由参数指定
wsdl2java.sh从 WSDL 生成 Java 客户端 stub 或服务端骨架org.apache.axis2.wsdl.WSDL2Java
java2wsdl.sh从 Java 类反向生成 WSDLorg.apache.ws.java2wsdl.Java2WSDL
setenv.sh被 axis2.sh 加载:校验 JAVA_HOME、组装 AXIS2_CLASSPATH无(仅设置环境)

解读:三个工具脚本最终都会经过 setenv.sh → axis2.sh 这条链路——java2wsdl.sh 的全部内容就一行转发命令(第七节展示),wsdl2java.sh 与之同构。因此 setenv.sh 组装的 AXIS2_CLASSPATH 决定了所有脚本的类路径行为,理解它才能解释第七节的 -cp 失效问题。

三、前置条件

本篇命令相互独立,只需已按《Ubuntu 22.04 安装 Apache Axis2 指南》或《CentOS 8 安装 Apache Axis2 指南》完成安装的 Axis2 2.0.1 环境。开始前确认服务基线与脚本可执行性:

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export AXIS2_HOME=/opt/axis2
curl -s "http://localhost:8080/axis2/services/Version/getVersion"

回显(实测):

<ns:getVersionResponse xmlns:ns="http://axisversion.sample"><ns:return>Hi - the Axis2 version is 2.0.1</ns:return></ns:getVersionResponse>

版本回显为 2.0.1 即环境就绪。以下各节中,第六、七节的代码生成示例依赖一个已发布的 HelloService 服务(发布方法见《Apache Axis2 快速入门与集成示例》),其余示例不依赖任何自建服务。

四、axis2server.sh:standalone 服务端启动器

4.1 帮助信息

/opt/axis2/bin/axis2server.sh -h

回显(实测,前两行环境提示为脚本正常输出):

 Using AXIS2_HOME: /opt/axis2
 Using JAVA_HOME:  /usr/lib/jvm/java-17-openjdk-amd64
Usage: axis2server.sh
commands:
  -xdebug    Start Axis2 Server under JPDA debugger
  -security  Enable Java 2 security
  -h         help

三个选项的行为可以对照脚本源码确认(以下为 axis2server.sh 第 36-44 行原文):

sed -n '36,44p' /opt/axis2/bin/axis2server.sh

回显(实测):

while [ $# -ge 1 ]; do
    case $1 in
        -xdebug)
            JAVA_OPTS="$JAVA_OPTS -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,address=8000"
            shift
        ;;
        -security)
            JAVA_OPTS="$JAVA_OPTS -Djava.security.manager -Djava.security.policy=$AXIS2_HOME/conf/axis2.policy -Daxis2.home=$AXIS2_HOME"

解读:-xdebug 在堆参数后追加 JPDA 调试参数并监听 8000 端口;-security 启用 Java 2 安全管理器并加载发行包自带的 conf/axis2.policy 策略文件。两者都只是拼接 JVM 参数,不含任何额外启动逻辑。

4.2 启动、观察与停止

前台启动用于首次部署观察日志(占住终端,Ctrl+C 停止):

/opt/axis2/bin/axis2server.sh

回显(实测关键行):

 Using AXIS2_HOME: /opt/axis2
 Using JAVA_HOME:  /usr/lib/jvm/java-17-openjdk-amd64
10:00:15.964 [main] INFO  org.apache.axis2.deployment.DeploymentEngine - Deploying Web service: HelloService.aar - file:/opt/axis2/repository/services/HelloService.aar
10:00:16.016 [HttpListener-8080-1] INFO  org.apache.axis2.transport.http.server.DefaultConnectionListener - Listening on port 8080
10:00:16.017 [main] INFO  org.apache.axis2.kernel.SimpleAxis2Server - [SimpleAxisServer] Started
[SimpleAxisServer] Started

三行关键日志的判读:Deploying Web service 逐个列出仓库中已部署的服务包;Listening on port 8080 表示 HTTP 监听器就绪;[SimpleAxisServer] Started 是启动完成的最终标志,出现后即可调用服务。

生产环境建议用 systemd 托管而非前台运行(单元文件写法与开机自启见《Ubuntu 22.04 安装 Apache Axis2 指南》方案 A),托管后的状态控制:

systemctl is-active axis2

回显(实测):

active

停止托管服务用 systemctl stop axis2;前台模式停止则直接 Ctrl+C(脚本不会自动重启,退出码为 130)。

4.3 堆参数:必须改脚本第 35 行

axis2server.sh 第 35 行把 JAVA_OPTS 硬置为空串,外部环境变量注入的堆参数会在脚本内被覆盖(实测确认),所以 JVM 堆只能直接改这一行。官方原始文件该行为:

grep -n '^JAVA_OPTS=' /opt/axis2/bin/axis2server.sh | head -1

回显(实测,官方原始包状态):

35:JAVA_OPTS=""

把堆限制到 256-512MB 区间并验证修改结果:

sed -i 's/^JAVA_OPTS=""/JAVA_OPTS="-Xms256m -Xmx512m"/' /opt/axis2/bin/axis2server.sh
grep -n '^JAVA_OPTS=' /opt/axis2/bin/axis2server.sh | head -1

回显(实测):

35:JAVA_OPTS="-Xms256m -Xmx512m"

重启服务后用 jps -v 确认参数真正落到进程上:

jps -v | grep Simple

回显(实测):

10097 SimpleAxis2Server -Xms256m -Xmx512m

-Xms256m -Xmx512m 出现在进程参数中,堆限制确认生效。jps 随 JDK 自带,是验证 JVM 进程参数最直接的命令。

五、axis2.sh:通用 Java 启动器

5.1 直接调用的行为

不带参数调用会落到 java 命令的用法提示(脚本把空参数原样传给了 java):

/opt/axis2/bin/axis2.sh 2>&1 | head -8

回显(实测前 8 行):

 Using AXIS2_HOME: /opt/axis2
 Using JAVA_HOME:  /usr/lib/jvm/java-17-openjdk-amd64
Usage: java [options] <mainclass> [args...]
           (to execute a class)
   or  java [options] -jar <jarfile> [args...]
           (to execute a jar file)
   or  java [options] -m <module>[/<mainclass>] [args...]
       java [options] --module <module>[/<mainclass>] [args...]

这个"报错"恰好暴露了脚本的三步机制,对照 axis2.sh 源码(关键行原文):

grep -n 'AXIS2_CLASSPATH="\$AXIS2_HOME\|classpath "\$AXIS2_CLASSPATH\|axis2.xml' /opt/axis2/bin/axis2.sh | head -4

回显(实测):

49:      if [[ $arg  == "*.jar" ]]; then
62:AXIS2_CLASSPATH="$AXIS2_HOME":"$AXIS2_HOME/conf":"$JAVA_HOME/lib/tools.jar":"$AXIS2_CLASSPATH":"$CLASSPATH"
67:"$JAVA_HOME"/bin/java -classpath "$AXIS2_CLASSPATH" \
68:-Daxis2.xml="$AXIS2_HOME/conf/axis2.xml" -Daxis2.repo="$AXIS2_HOME/repository"  $USER_COMMANDS

解读:第 62 行组装 AXIS2_CLASSPATH(顺序为:安装根目录、conf 目录、JDK tools.jar、lib 下全部 jar、外部 $CLASSPATH 环境变量);第 67-68 行用 -classpath 显式启动 JVM 并注入两个系统属性。三个要点:一是脚本用 $JAVA_HOME/bin/java 而非 PATH 中的 java;二是外部 CLASSPATH 环境变量被追加在类路径末尾(第七节会用到这一点);三是 -Daxis2.xml 与 -Daxis2.repo 已把全局配置与仓库位置锁定到本发行包。

💡 技术拓展:JAVA_HOME/lib/tools.jar 只在 JDK 8 存在,JDK 9+ 已移除该文件——把它拼进类路径不会报错(JVM 忽略不存在的类路径条目),这也是同一套脚本能在 JDK 8 与 JDK 17 上通行的原因之一。Axis2 2.0.1 要求 JDK 17+,1.8.x 兼容 JDK 8/17 的版本矩阵实测结论见《CentOS 8 安装 Apache Axis2 指南》版本选型一节。

5.2 用它运行任意主类的边界

wsdl2java.sh 的全部源码只有一行,展示了 axis2.sh 的标准用法(转发主类与参数):

cat /opt/axis2/bin/java2wsdl.sh | tail -2

回显(实测):

dir=`dirname "$0"`
sh "$dir"/axis2.sh org.apache.ws.java2wsdl.Java2WSDL $*

并非所有主类都能这样直跑——以版本类为例的实测反例:

/opt/axis2/bin/axis2.sh org.apache.axis2.Version 2>&1 | grep -A2 Exception | head -3

回显(实测):

Exception in thread "main" java.util.MissingResourceException: Can't find resource for bundle org.apache.axis2.i18n.ProjectResourceBundle, key builtOn
        at java.base/java.util.ResourceBundle.getObject(ResourceBundle.java:564)
        at java.base/java.util.ResourceBundle.getString(ResourceBundle.java:521)

解读:org.apache.axis2.Version 的 main 依赖 i18n 资源包按特定顺序初始化,脱离服务端上下文直接运行会抛 MissingResourceException。查版本号应调用 Version 服务(第三节 curl 命令)而非该类。axis2.sh 适合运行的工具类主类(如 java2wsdl/wsdl2java 的入口),不适合运行依赖服务端初始化上下文的类。

5.3 Ubuntu 下的 [[ 告警(dash 兼容性)

在 Ubuntu 上每次调用 axis2.sh(含经它转发的 wsdl2java.sh/java2wsdl.sh)都会输出两行告警:

/opt/axis2/bin/axis2.sh: 49: [[: not found
/opt/axis2/bin/axis2.sh: 49: [[: not found

根因:axis2.sh 第 49 行使用了 bash 特有的 [[ 语法,而 Ubuntu 默认 /bin/sh 链接到 dash,dash 不支持 [[;CentOS 8 的 /bin/sh 链接到 bash,同样命令无任何告警。实测确认该告警不影响任何脚本结果——[[ 只用于一个边缘分支判断(判断参数字面量是否为 "*.jar",见第七节),分支失败仅导致该能力失效,主流程照常。接受告警即可,不建议为消除告警改 /bin/sh 指向(会影响系统其他脚本)。

六、wsdl2java.sh:WSDL 转 Java 代码生成

6.1 帮助信息与参数全表

/opt/axis2/bin/wsdl2java.sh -h

回显为 Usage 段(原文混有 Log4j2 初始化 DEBUG 日志与 5.3 节的 [[ 告警,以下截取 Usage 参数段,内容逐字未动):

Usage: WSDL2Java [options] -uri <url or path> : A url or path to a WSDL

where [options] include:
  -o <path>                Specify a directory path for the generated code.
  -a                       Generate async style code only (Default: off).
  -s                       Generate sync style code only (Default: off). Takes precedence over -a.
  -p <pkg1>                Specify a custom package name for the generated code.
  -l <language>            Valid languages are java and c (Default: java).
  -t                       Generate a test case for the generated code.
  -ss                      Generate server side code (i.e. skeletons) (Default: off).
  -sd                      Generate service descriptor (i.e. services.xml). (Default: off). Valid with -ss.
  -d <databinding>         Valid databinding(s) are adb, xmlbeans, jibx and jaxbri (Default: adb).
  -g                       Generates all the classes. It generates clases for both client side and server side including derived classes of the schema.
  -pn <port_name>          Choose a specific port when there are multiple ports in the wsdl.
  -sn <service_name>       Choose a specific service when there are multiple services in the wsdl.
  -u                       Unpacks the databinding classes
  -r <path>                Specify a repository against which code is generated.
  -ns2p ns1=pkg1,ns2=pkg2  Specify a custom package name for each namespace specified in the wsdls schema.
  -ssi                     Generate an interface for the service implementation (Default: off).
  -wv <version>            WSDL Version. Valid Options : 2, 2.0, 1.1
  -S <path>                Specify a directory path for generated source
  -R <path>                Specify a directory path for generated resources
  -em <file path>          Specify an external mapping file
  -f                       Flattens the generated files
  -uw                      Switch on un-wrapping.
  -xsdconfig <file path>   Use XMLBeans .xsdconfig file. Valid only with -d xmlbeans.
  -ap                      Generate code for all ports
  -or                      Overwrite the existing classes
  -b                       Generate Axis 1.x backward compatible code.
  -sp                      Suppress namespace prefixes (Optimzation that reduces size of soap request/response)
  -E<key> <value>          Extra configuration options specific to certain databindings. Examples:
                           -Ebindingfile <path>                   (for jibx) - specify the file path for the binding file
                           -Etypesystemname <my_type_system_name> (for xmlbeans) - override the randomly generated type system name
                           -Ejavaversion 1.5                      (for xmlbeans) - generates Java 1.5 code (typed lists instead of arrays)
                           -Emp <package name> (for ADB) - extension mapper package name
                           -Eosv (for ADB) - turn off strict validation.
                           -Ewdc (for xmlbeans) - Generate code with a dummy schema. if someone use this option
                              they have to generate the xmlbeans code seperately with the scomp command comes with the
                              xmlbeans distribution and replace the Axis2 generated classes with correct classes
                           -EbindingFileName <path>               (for jaxbri) - specify the file path for the episode file
                           -Eiu (for ADB) - Ignore Unexpected elements instead of throwing ADBException
  --noBuildXML             Dont generate the build.xml in the output directory
  --noWSDL                 Dont generate WSDLs in the resources directory
  --noMessageReceiver      Dont generate a MessageReceiver in the generated sources
  --http-proxy-host <host> Proxy host address if you are behind a firewall
  --http-proxy-port <port> Proxy port address if you are behind a firewall
  -http-proxy-user <user name> Proxy user name for basic authentication if you are behind a firewall
  -http-proxy-password <password> Proxy password for basic authentication if you are behind a firewall
  -ep <package-name-list>  Exclude packages - these packages are deleted after code generation
  -sin <interface-name>    Skeleton interface name - used to specify a name for skeleton interface other than the default one
  -scn <class-name>        Skeleton class name - used to specify a name for skeleton class other than the default one
  -oaa <override-absolute-address>  -change the absolute http addresses to local file addresses generated by wsdl2java tool
  -ebc <exception-base-class>  -generated Exceptions are inherited from this exception rather than the java.lang.Exception class
  -uon <use-operation-name>  -by default the first letter of the generated method name changeed to lowercase. This option stops that and make it same as operation name
  -D<Key>=<Value>          -Java system properties

6.2 生成客户端 stub

对着运行中服务的 WSDL 地址生成客户端代码(HelloService 发布方法见《Apache Axis2 快速入门与集成示例》):

/opt/axis2/bin/wsdl2java.sh -uri http://localhost:8080/axis2/services/HelloService?wsdl -p demo.client -o /tmp/w2j-demo

回显(实测,省略环境提示与日志噪音行):

Retrieving document at 'http://localhost:8080/axis2/services/HelloService?wsdl'.
ls -la /tmp/w2j-demo/ /tmp/w2j-demo/src/demo/client/

回显(实测):

/tmp/w2j-demo/:
total 8
drwxr-xr-x  3 root root   80 Oct 13 09:54 .
drwxrwxrwt 13 root root  800 Oct 13 09:54 ..
-rw-r--r--  1 root root 5243 Oct 13 09:54 build.xml
drwxr-xr-x  3 root root   60 Oct 13 09:54 src

/tmp/w2j-demo/src/demo/client/:
total 96
drwxr-xr-x 2 root root    80 Oct 13 09:54 .
drwxr-xr-x 3 root root    60 Oct 13 09:54 ..
-rw-r--r-- 1 root root  1910 Oct 13 09:54 HelloServiceCallbackHandler.java
-rw-r--r-- 1 root root 91184 Oct 13 09:54 HelloServiceStub.java

默认(不带 -a/-s)生成同步加异步双模式 stub;Retrieving document at ... 表示 WSDL 拉取成功。stub 类是客户端调用的核心(用法见《Apache Axis2 快速入门与集成示例》),CallbackHandler 供异步回调使用,build.xml 提供无 Maven 环境的 ant 构建入口。

6.3 生成服务端骨架

-ss(skeleton)加 -sd(services.xml)从 WSDL 反向生成服务端工程,适合"契约先行"开发:

/opt/axis2/bin/wsdl2java.sh -uri /tmp/hello.wsdl -p demo.server -ss -sd -d adb -o /tmp/w2j-server
ls /tmp/w2j-server/src/demo/server/ /tmp/w2j-server/resources/

回显(实测):

/tmp/w2j-server/resources/:
HelloService.wsdl
services.xml

/tmp/w2j-server/src/demo/server/:
HelloServiceMessageReceiverInOut.java
HelloServiceSkeleton.java

-uri 也可指向本地 WSDL 文件。生成物中 Skeleton 是要填业务逻辑的骨架类,MessageReceiverInOut 是 Axis2 调用入口(勿改),resources/services.xml 是自动生成的服务描述。把编译后的类与 resources 内容按 .aar 结构打包即可发布(打包方法见《Apache Axis2 快速入门与集成示例》)。

6.4 高频参数组合速查

场景参数组合说明
客户端(默认)-uri <wsdl> -p <包名> -o <目录>同步+异步 stub,ADB 绑定
服务端骨架-ss -sd -d adb额外生成 Skeleton 与 services.xml
仅同步调用-s只生成同步方法,stub 更精简
解包数据绑定类-uadb 内部类拆为独立 .java 文件
命名空间映射-ns2p ns1=pkg1,ns2=pkg2精确控制各命名空间生成的包名
重复生成覆盖-or不带该参数时已存在的类不会被覆盖
接口化骨架-ssiSkeleton 生成接口 + 实现类两个文件

💡 技术拓展:-d 四种数据绑定的选型——ADB 是 Axis2 自带绑定,零额外依赖、生成代码体积小,适合与 Axis2 服务互调;JAXB(jaxbri)走标准 javax.xml.bind(2.0.1 中为 jakarta 系)注解体系,适合与其他 JAX-WS 栈互通;XMLBeans 功能最强但产物臃肿、构建慢;JiBX 需要额外绑定文件,仅存量项目维护时使用。不确定时用默认 ADB。

七、java2wsdl.sh:Java 转 WSDL 反向生成

7.1 帮助信息与参数全表

/opt/axis2/bin/java2wsdl.sh -h

回显为 Usage 段(同样省略日志噪音,内容逐字未动):

Usage: java2wsdl [options] -cn <fully qualified class name>

where [options] include:
  -o <output location>                    output directory
  -of <output file name>                  output file name for the WSDL
  -sn <service name>                      service name
  -l <one or more soap addresses>         location URIs, comma-delimited
  -cp <class path uri>                    list of classpath entries - (urls)
  -tn <target namespace>                  target namespace for service
  -tp <target namespace prefix>           target namespace prefix for service
  -stn <schema target namespace>          target namespace for schema
  -stp <schema target namespace prefix>   target namespace prefix for schema
  -st <binding style>                     style for the WSDL
  -u <binding use>                        use for the WSDL
  -nsg <class name>                       fully qualified name of a class that implements NamespaceGenerator
  -sg <class name>                        fully qualified name of a class that implements SchemaGenerator
  -p2n [<java package>,<namespace] [<java package>,<namespace]...
                                          java package to namespace mapping for argument and return types
  -p2n [all, <namespace>]                 to assign all types to a single namespace
  -efd <qualified/unqualified>            setting for elementFormDefault (defaults to qualified)
  -afd <qualified/unqualified>            setting for attributeFormDefault (defaults to qualified)
  -xc class1 -xc class2...                extra class(es) for which schematype must be generated.
  -wv <1.1/2.0>                           wsdl version - defaults to 1.1 if not specified
  -dlb                                    generate schemas conforming to doc/lit/bare style
  -dne                                    disallow nillable elements in the generated schema
  -doe                                    disallow optional elements in the generated schema
  -disableSOAP11                          disable binding generation for SOAP 1.1
  -disableSOAP12                          disable binding generation for SOAP 1.2
  -disableREST                            disable binding generation for REST
  -mpn <messagePartName>                  change the part name of the generated wsdl messages
  -ptn <portTypeName>                     port Type name of the WSDL
  -soap11BindingName <SOAP 1.1 name>      SOAP 1.1 binding name
  -soap12BindingName <SOAP 1.2 name>      SOAP 1.2 binding name
  -restBindingName <REST name>            REST binding name
  -res <requestElementSuffix>             Adds a suffix to the request elemment
  -dat <disallowAnonymousTypes>           Creates a named complex type for the annonymous complex type

7.2 基础生成:CLASSPATH 环境变量方式

对已编译的服务类反向生成 WSDL。前提:类文件已用 javac -g 编译(-g 保留形参名,缺失会导致 WSDL 参数退化为 args0),且 CLASSPATH 指向类文件所在目录:

export CLASSPATH=/opt/lab/hello-service/build/HelloService
/opt/axis2/bin/java2wsdl.sh -cn HelloService -o /tmp -of hello.wsdl 2>&1 | grep "WSDL created"
ls -la /tmp/hello.wsdl

回显(实测):

09:55:50.308 [main] INFO  org.apache.ws.java2wsdl.Java2WSDL - WSDL created at /tmp/hello.wsdl
-rw-r--r-- 1 root root 6215 Oct 13 09:55 /tmp/hello.wsdl
head -c 400 /tmp/hello.wsdl

回显(实测):

<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ns="http://ws.apache.org/axis2" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://org.apache.axis2/xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" targetNamespa

默认包(无 package 声明)的类,类路径必须指到 .class 文件所在目录本身;带包名的类指到包根目录。生成的 WSDL 头部 xmlns:ns="http://ws.apache.org/axis2" 是默认命名空间,下一节把它改成业务命名空间。

7.3 自定义服务名、命名空间与地址

服务要正式发布时,命名空间、服务名与访问地址都应显式指定而不是用默认值:

export CLASSPATH=/opt/lab/hello-service/build/HelloService
/opt/axis2/bin/java2wsdl.sh -cn HelloService -sn HelloServiceV2 -tn http://demo.example.com/v2 -stn http://demo.example.com/v2/xsd -l http://192.168.1.50:8080/axis2/services/HelloServiceV2 -o /tmp -of hello-ns.wsdl 2>&1 | grep "WSDL created"
grep -o 'targetNamespace="[^"]*"' /tmp/hello-ns.wsdl | sort -u
wc -c /tmp/hello-ns.wsdl

回显(实测):

09:56:59.274 [main] INFO  org.apache.ws.java2wsdl.Java2WSDL - WSDL created at /tmp/hello-ns.wsdl
targetNamespace="http://demo.example.com/v2"
targetNamespace="http://demo.example.com/v2/xsd"
6315 /tmp/hello-ns.wsdl

参数含义:-sn 改服务名;-tn 是服务级 targetNamespace;-stn 是 schema 级 targetNamespace(放请求/响应元素定义);-l 写客户端实际访问的 endpoint 地址(生成后 WSDL 的 soap:address 位置)。两个命名空间按惯例保持"服务命名空间 + /xsd"的父子关系。

7.4 -cp 参数不生效的根因与正确姿势

help 里明明有 -cp <class path uri>,实测却始终失败——先复现,再给根因:

unset CLASSPATH
/opt/axis2/bin/java2wsdl.sh -cn HelloService -cp /opt/lab/hello-service/build/HelloService -o /tmp -of hello-cp.wsdl 2>&1 | grep "ClassNotFoundException" | head -1
echo "exit=$?"
ls -la /tmp/hello-cp.wsdl

回显(实测,类路径指向完全正确的目录):

Exception in thread "main" java.lang.ClassNotFoundException: HelloService
exit=1
-rw-r--r-- 1 root root 0 Oct 13 09:54 /tmp/hello-cp.wsdl

退出码 1、产物 0 字节。即使类路径指对也一样失败,说明问题不在使用者而在脚本链路。根因在 axis2.sh 源码里(第 44-58 行参数循环 + 第 62 行类路径组装):

sed -n '44,58p' /opt/axis2/bin/axis2.sh

回显(实测):

#add any user given classpath's
USER_COMMANDS=""
prearg=""
for arg in "$@"
do
   if [ "$arg" != -classpath ] && [ "$arg" != -cp ] && [ "$prearg" != -classpath ] && [ "$prearg" != -cp  ]
   then
      USER_COMMANDS="$USER_COMMANDS ""$arg"
   fi

   if [ "$prearg"=-classpath ] || [ "$prearg"=-cp  ]
   then
      if [[ $arg  == "*.jar" ]]; then

源码判读(三层叠加导致 -cp 必然失效):

  1. 参数循环遇到 -cp 或 -classpath 时,把该参数与其值从 USER_COMMANDS 中剔除(第 50-52 行条件排除);
  2. 被剔除的值只有在字面量恰好等于 "*.jar" 这五个字符时才会并入 AXIS2_CLASSPATH(第 49 行 [[ $arg == "*.jar" ]],右值带引号是字面比较而非通配)——真实路径永远不会匹配;
  3. 即便值进了 AXIS2_CLASSPATH 之外的环境变量 CLASSPATH,最终 java 命令用的是 -classpath "$AXIS2_CLASSPATH" 显式指定(第 67 行),java 规范中该参数覆盖 CLASSPATH 环境变量。

出路在第 62 行的组装公式(5.1 节已引用):AXIS2_CLASSPATH 的最后一段拼的就是外部 $CLASSPATH 环境变量。所以 export CLASSPATH 是向 java2wsdl/wsdl2java 传递自定义类路径的唯一可靠通道,7.2/7.3 节的做法即由此而来。

八、注意事项

  • 所有脚本都要求先 export JAVA_HOME,且脚本实际使用 $JAVA_HOME/bin/java;仅切 alternatives 不设 JAVA_HOME 时脚本会以 "You must set the JAVA_HOME variable" 退出。
  • 脚本对 AXIS2_HOME 的推断基于脚本自身位置(dirname $0 上级目录),把 bin 下的脚本拷走单独执行会解析到错误仓库;用绝对路径调用发行包内脚本即可。
  • axis2server.sh 的堆参数只能改脚本第 35 行(JAVA_OPTS 会被脚本重写,外部注入无效);修改后用 jps -v 验证,不要只看脚本内容。
  • Ubuntu 22.04 下所有经 axis2.sh 的调用都伴随 [[ : not found 告警与 Log4j2 DEBUG 日志,均不影响结果;筛选回显时用 grep 锚定关键行(如 Listening on port、WSDL created)。
  • wsdl2java 重复生成时不覆盖已有文件,重生成前清理输出目录或加 -or;java2wsdl 的 -of 目标文件已存在时同样注意旧产物干扰。
  • java2wsdl 的类路径要求指到 .class 文件所在目录:无包名类指到类文件目录,带包名类指到包根;用 aar 目录布局(类在服务名子目录下)时指到该子目录。
  • 向这两个代码生成脚本传自定义类路径只能用 export CLASSPATH,-cp/-classpath 参数会被脚本丢弃(第七节根因)。

九、常见问题(FAQ)

Q1:执行任何脚本都报 "You must set the JAVA_HOME variable before running Axis2 Script." 怎么办? 这是 setenv.sh 第一道校验(JAVA_HOME 为空即退出)。确认当前 shell 里 echo $JAVA_HOME 有值且指向 JDK 根目录(其下应有 bin/javac),没有就 export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64(Ubuntu apt 安装的 17 实际路径)。想让 systemd 托管服务也拿到该变量,需在单元文件中用 Environment=JAVA_HOME=... 声明(写法见《Ubuntu 22.04 安装 Apache Axis2 指南》方案 A)。

Q2:wsdl2java 输出一堆 [[: not found 和 Log4j DEBUG 日志,是环境坏了吗? 正常现象。前者是 Ubuntu dash 不支持 bash [[ 语法的告警(5.3 节,CentOS 8 无此告警),后者是 log4j2 配置文件在工具启动期的初始化日志。两者都不影响生成结果,判定成功与否看产物文件是否生成(6.2 节的三个文件)与 Retrieving document / WSDL created 关键行。

Q3:java2wsdl 的 -cp 明明指向正确目录,为什么还是 ClassNotFoundException? 脚本链路会丢弃 -cp/-classpath 参数且 java 命令的 -classpath 覆盖 CLASSPATH 环境变量,完整根因见 7.4 节。解法:export CLASSPATH=<类文件所在目录> 后再执行,同时确认目录层级与类包名一致(无包名类指到 .class 所在目录本身,带包名类指到包根)。

Q4:重新生成时旧文件会被覆盖吗? wsdl2java 不带 -or 时不会覆盖已存在的类(help 原文:-or Overwrite the existing classes),只会写入新文件——旧 stub 残留会造成"改了 WSDL 但客户端行为没变"的假象。实操:重生成前 rm -rf 输出目录,或固定加 -or。java2wsdl 的输出文件同理,-of 指向旧文件时会直接覆盖单文件,但建议同样先清理。

Q5:怎么快速确认 standalone 服务真的在跑、参数真的生效? 两条命令固定搭配:jps -v | grep Simple 确认进程与 JVM 参数(4.3 节回显),curl -s "http://localhost:8080/axis2/services/Version/getVersion" 确认服务可调用(第三节回显)。日志层再看 Listening on port 8080 与 [SimpleAxisServer] Started 两行(4.2 节)。三者齐了才算就绪,只看进程存在不算。

十、参考链接

  1. Apache Axis2 官方主页(用户指南与快速入门):https://axis.apache.org/axis2/java/core/
  2. Apache Axis2 版本下载目录(本篇实测版本 2.0.1):https://dlcdn.apache.org/axis/axis2/java/core/
  3. WSDL2Java 参考文档(参数与数据绑定说明):https://axis.apache.org/axis2/java/core/docs/userguide.html
  4. Oracle java 命令手册(-classpath 与 CLASSPATH 的覆盖关系):https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html
  5. Apache Axis2 架构说明(传输与部署模型背景):https://axis.apache.org/axis2/java/core/docs/Axis2ArchitectureGuide.html