WebLogic内置JMS消息服务:本地部署与外部访问配置实战 先说明一个容易让人绕进去的点WebLogic 严格来说不是消息中间件它是应用服务器。但这个标题又确实有现实依据——WebLogic 内置了相当完整的 JMS 消息服务能力很多团队就用它来承载队列、订阅等消息场景省掉一套独立中间件。所以这篇文章我围绕“本地部署 WebLogic 并实现外部访问”这个实操目标展开先把概念理清楚然后把安装、域创建、JMS 资源配置、外部连接串写法、常见故障排查这些步骤完整走一遍。适合谁看一是刚接手老系统、需要临时在本地搭一套 WebLogic 环境的技术人员二是想把 WebLogic 现有的 JMS 服务暴露给别的机器调用、但不太确定网络配置怎么做的开发者。内容偏落地不整虚的。1. 开篇先纠偏WebLogic 与“消息中间件”的关系1.1 为什么“消息中间件”这个说法总让人对不上号做 Java 后端的朋友应该都有印象ActiveMQ、RabbitMQ、Kafka 这类才是大家口中的消息中间件。而 WebLogic 的官方定位是“应用服务器”主要干的是部署 Java EE 应用、管理 Web 服务、提供容器能力的活。但 WebLogic 从早期收购来的产品里继承了一套 JMSJava Message Service实现它提供了完整的消息服务队列、发布订阅、持久化、事务性消息、消息桥接都有。所以“本地部署消息中间件 Weblogic”这个描述并不准确但在实际业务里你确实可以用它当消息中间件用。这种情况最常出现在哪里公司本来就有 WebLogic 部署了若干业务系统项目组不想再为一个小场景引入 ActiveMQ 或 RabbitMQ于是直接把 WebLogic 上的 JMS Server 借用过来配一个连接工厂和队列应用之间通过 JNDI 拿到连接就能发消息收消息了。同时也能在 WebLogic 管理控制台上看消息堆积、做统计比单独再搭一套中间件要省事很多。1.2 它的真实定位应用服务器里的 JMS 服务既然要说清楚怎么用我先把 WebLogic JMS 的组成结构说透。WebLogic JMS 是一个基于 JMS 1.1/2.0 规范的实现JMS 本身只是一套 Java 接口定义底层消息的存储、传输、连接管理全部由 WebLogic 自己实现。它允许你定义队列Queue和主题Topic消息发送方和接收方通过连接工厂ConnectionFactory建立连接再通过目的地Destination收发消息。所有这些资源都归属于 JMS Module 统一管理模块再挂到 JMS Server 上JMS Server 则是消息真正的运行容器。用生活化的方式理解JMS Server 就像一家快递公司的转运中心消息队列就是一条条分拣滑道连接工厂就是快递员手里的扫码枪你往滑道上扔包裹对面的人从滑道上取包裹整个过程不关心发件人收件人在哪只要大家都能连到同一个转运中心就行。WebLogic 在这里扮演的角色就是转运中心它可以和应用跑在同一台服务器上也可以独立部署但资源都是通过管理台来配置和监控。2. 本地部署实操从安装包到管理域2.1 版本与安装包怎么选本地部署我先说版本选择。现在主流还在用的两代版本10.3.6 和 12.2.1.x。10.3.6 是老系统的标配JMS 规范是 1.1很多旧项目都跑在它上面今天仍有大量存量系统在维护。12.2.1 是后期较稳定的版本JMS 支持 2.0对 JDK 版本要求更高开发新功能优先考虑它。安装包方面Oracle 官方提供的安装文件有几种形态最常见的是 - generic 的 jar 包。这个 jar 包本身是图形化安装程序但同时支持静默安装参数。我特别提醒一点安装 WebLogic 之前一定要先装好对应版本的 JDK而且是 64 位的否则后续建域时会遇到各种诡异问题。比如 10.3.6 需要 JDK 1.6 或 1.712.2.1 需要 JDK 1.8 以上。各位如果机器上已经装了新版 JDK 17跑老版本 WebLogic 很容易起不来倒不是 WebLogic 本身不兼容而是安装程序在检查 JVM 参数时直接抛异常。2.2 搭建前的 Java 环境准备在正式开始前我建议建一个干净的部署目录结构。以我自己常用的一套为例# 假设统一放在 /opt 目录下 /opt/jdk1.8.0_202 /opt/weblogic/Middleware /opt/weblogic/Middleware/wlserver /opt/weblogic/Middleware/user_projects /opt/weblogic/Middleware/user_projects/domainsJDK 安装完成之后务必做三步检查java -version 能正确输出版本、JAVA_HOME 环境变量已设置、PATH 中最前面的 java 命令确实指向刚装的 JDK。很多人本地环境装了不止一个 JDK比如 IntelliJ IDEA 自带了 JBR命令行里 java -version 输出的是另一个版本这会导致安装 WebLogic 时版本检测那一步直接失败。所以部署前先执行 which java 看一下路径如果不对就去调整。另外要预留磁盘空间。WebLogic 安装包本身不到 2G但域目录、日志、消息持久化文件会不断增长。尤其是消息服务队列里如果堆积了大量消息持久化存储文件会占用额外空间建议独立给一个数据盘或目录来存放不要全塞在系统盘。我见过消息堆积把磁盘填满导致整机不可用的案例所以我把持久化目录单独挂载这件事列为部署必做项。2.3 创建域的两条路线向导与 WLST 脚本安装完成后创建域有两种方式初学者一般用图形向导自动化部署用 WLST 脚本。本地部署如果只是自己练手图形向导最快安装目录下执行 configure.shWindows 上是 configure.cmd弹出来一个界面按提示选择域模板下一步下一步就能出一个可启动的管理服务器。但实际问题是想实现外部访问时很多配置项都在这个向导里已经固定了监听地址默认是 localhost这就意味着外部机器永远连不进来。所以我更建议直接用 WLST 脚本创建域之后的监听地址、端口、JMS 资源全部用脚本控制整个过程可重复可审查。下面这段 WLST 脚本我常用创建了两个服务器一个是管理服务器 AdminServer另一个是受管服务器 ManagedSrv1。管理服务器承载控制台和 JMS 服务受管服务器可有可无本地只测消息的话先不建也行但建了可以之后把应用部署上去# 创建域脚本 create_domain.py readTemplate(/opt/weblogic/Middleware/wlserver/common/templates/wls/wls.jar) cd(/Security/baseDomain) set(Name, base_domain) set(DomainPassword, weblogic2024) cd(/Servers/AdminServer) set(ListenAddress, 0.0.0.0) set(ListenPort, 7001) set(SSLEnabled, true) create(ManagedSrv1, Server) cd(/Servers/ManagedSrv1) set(ListenAddress, 0.0.0.0) set(ListenPort, 8001) cd(/Machine/localhost) set(ListenAddress, 127.0.0.1) set(ListenPort, 8453) setOption(OverwriteDomain, true) writeDomain(/opt/weblogic/Middleware/user_projects/domains/base_domain) closeTemplate() exit()这里最关键的一行是set(ListenAddress, 0.0.0.0)。如果是默认创建的域AdminServer 的监听地址是 localhost也就是只绑定本机回环地址外部请求根本不会进入这个端口。改成 0.0.0.0 的意思是监听本机所有网卡上的对应端口这样只要网络通路和防火墙是通的外部机器就能连上。但注意监听所有网卡也意味着局域网内任何机器都可以尝试连接这个端口安全上要配合访问控制不能光靠应用层密码保护。脚本执行方式是进入 WLST 交互环境cd /opt/weblogic/Middleware/wlserver/common/bin ./wlst.sh create_domain.py创建完成后启动管理服务器cd /opt/weblogic/Middleware/user_projects/domains/base_domain/bin ./startWebLogic.sh日志出现Server state changed to ADMIN然后RUNNING就算启动成功控制台地址默认是 http://服务器IP:7001/console。3. 消息服务配置队列、连接工厂与持久化存储3.1 先建存储还是先建会话到管理控制台之后不少人的第一反应是直接创建一个 JMS 队列发一条消息试试。但正确顺序其实是先把存储和 JMS Server 建好然后再建队列和连接工厂。原因很简单队列里的消息必须有个地方放这个存放位置就是 JMS 持久化存储。如果队列不绑定持久化存储WebLogic 默认用本地文件存储消息落到服务器文件系统里这对验证场景够用但对生产环境来说是隐患因为一旦归档文件损坏消息数据就可能丢。所以我的习惯是先建 File Store给它一个专门的存储路径然后再建 JMS Server 并关联到这个 Store。在管理控制台的路径是服务 - 消息服务 - 存储 - 新建。配置项里最重要的就是目录路径我一般会设置成类似/data/weblogic/msgstore这样的独立路径。路径里不要用中文不要放在安装目录下也不要放在系统临时目录里原因很简单安装目录卸载时会一起被清掉临时目录可能被系统自动清理。这就等于你上班把重要文件放在公司门口垃圾箱旁边风险完全不可控。3.2 JMS Server 与 JMS Module 的关系存储建好了接下来创建 JMS Server。可以把它理解为消息的运行容器每个 JMS Server 可以承载多个队列和主题但它需要绑定一个 Target也就是部署到哪个 WebLogic 服务器实例上。在单机本地部署场景里Target 一般选择 AdminServer 或 ManagedSrv1端口分别是 7001 和 8001。真正管理队列和连接工厂的地方是 JMS Module它是一组消息资源的集合配置。创建模块时需要注意一个细节模块必须 Target 到 JMS Server 所在的服务器实例上否则资源虽然建出来了但没有任何服务器加载它客户端 JNDI 查询时就会报NameNotFoundException。很多人在本地测试时折腾半天找不到队列最后发现是模块没有 Target。这是一个非常经典的坑。模块创建完成后就可以在模块里添加 Connection Factory 和 Queue 了。Connection Factory 相当于消息连接的模板客户端先通过 JNDI 查到它再通过它创建真正的连接。Queue 则要配置 JNDI 名称客户端查队列也是通过这个名称。命名上我建议统一前缀比如jms/TestCF和jms/TestQueue方便区分和后续管理。每次配置完资源都要点控制台左下角的“激活更改”更改才会真正生效。这个步骤新手特别容易漏觉得配了资源就能用结果客户端一直连不上其实只是没激活。3.3 一个最小可用的资源清单综合下来本地搭建一个最小可用的消息服务资源清单如下表资源类型名称示例关键配置项用途服务器实例AdminServer监听地址 0.0.0.0端口 7001承载服务持久化存储MsgFileStore目录 /data/weblogic/msgstore消息可靠落盘JMS ServerJMSServer1Target 到 AdminServer关联 MsgFileStore消息运行容器JMS ModuleModuleTestTarget 到 AdminServer资源集合连接工厂jms/TestCF默认事务型、消息最大长度等建立连接目的地队列jms/TestQueue关联 jms/TestCF所属模块发送接收消息这些资源配置完成后一切看起来就绪但实际上外部访问能不能成关键不在这张表里而在于接下来要讲的网络和监听层面。本地部署要是只在本机测现在就可以收工但题目要求是外部访问那就还要继续往下做。4. 外部访问配置监听地址、端口与客户端连接4.1 为什么外部机器连不上本地 WebLogic外部访问的失败十次有九次是监听地址的问题。默认建出来的域服务器监听地址就是 localhost。外部机器发起连接时TCP 包是会发到这台服务器的网卡 IP 上但如果 WebLogic 只监听了回环地址操作系统的网络栈会把发往网卡 IP 的请求直接丢掉应用层根本收不到。这个现象非常迷惑因为你在本机测试一切正常换台机器就连接超时不少人还以为是防火墙拦截。解决办法我在建域脚本里已经埋进去了把 AdminServer 的监听地址从 localhost 改成 0.0.0.0也就是监听本机所有网卡。如果机器有多块网卡比如一个是内网网段、一个连接公网而你只想让某块网卡对外提供服务那就把监听地址直接设成那个网卡的 IP而不是 0.0.0.0这样更安全更收敛。需要注意修改监听地址之后一定要重启管理服务器才生效。判断当前监听地址是什么可以直接看域目录里的 config.xml打开后搜server标签找 AdminServer 配置段落里的 ListenAddress。这个文件是域的配置中心很多网络相关设置都写在这里改错了还能手动改回来。不过我更推荐用控制台改环境 - 服务器 - AdminServer - 监听地址改完保存并激活然后重启。图形界面不容易改坏适合不熟悉的同学。4.2 端口规划7001 是管理端口不是万能入口WebLogic 默认的监听端口很多控制台和 JMS 走的是 7001 普通端口7002 是 SSL 端口。如果你建了受管服务器还会有一个 8001 端口之类。外部客户端连 JMS 服务时用的是 t3 协议默认也是走 7001。管理控制台 Web 界面走 HTTP用的也是 7001。所以从功能角度讲至少要把 7001 这个 TCP 端口在防火墙里放开。但这里我要说一个安全建议如果只是给外部应用程序调用 JMS不要开放 7001 的管理控制台端口。因为 7001 同时承载了管理控制台暴露出去相当于把整个服务器管理入口开放给了网络上的其他人。更稳妥的做法是单独建一个受管服务器比如 ManagedSrv_External把 JMS Server Target 到它上面设置一个专门的端口如 8002防火墙只放开这个端口。管理控制台所在的 AdminServer 只允许内网访问或者干脆不绑定外部网卡。端口映射或者网络策略方面按环境的实际规则来配置即可原则是最小权限外部到内部只放行明确要用的端口不要把整段端口都打开。如果公司内部网络有防火墙规则通常是提交一个变更申请写明源网段、目的端口和协议就可以。不要自己直接在服务器上把防火墙关了来图省事那样代价会很高。4.3 外部客户端连接串怎么写当服务端监听地址、端口、防火墙都准备妥当后外部客户端要连上来核心就靠两个东西JNDI 的环境参数和用户认证。我贴一段常见的 JMS 客户端连接代码发送一条文本消息到队列里import javax.jms.*; import javax.naming.*; import java.util.Hashtable; public class JmsSendTest { public static void main(String[] args) throws Exception { HashtableString, String env new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, weblogic.jndi.WLInitialContextFactory); env.put(Context.PROVIDER_URL, t3://192.168.1.100:7001); env.put(Context.SECURITY_PRINCIPAL, weblogic); env.put(Context.SECURITY_CREDENTIALS, 你的密码); Context ctx new InitialContext(env); ConnectionFactory factory (ConnectionFactory) ctx.lookup(jms/TestCF); Queue queue (Queue) ctx.lookup(jms/TestQueue); try (JMSContext jmsContext factory.createContext()) { jmsContext.createProducer().send(queue, hello from remote client); System.out.println(发送成功); } ctx.close(); } }这里最需要注意的是 PROVIDER_URL 的写法一定要用t3://开头IP 换成这台服务器的实际 IP而不是 localhost。如果服务端启用了 SSL那协议要改成t3s://并且客户端的信任库要导入服务端证书。很多人在本地测试一直用 localhost 没出过问题搬到外部机器上就忘改这里。4.4 外部访问验证清单我把外部访问验证按顺序列了一下按照这个顺序排查基本能定位 90% 的问题从外部机器执行telnet 服务器IP 7001检查端口是否通。这一步能区分是网络不通还是应用层问题。在外部机器上测试t3://服务器IP:7001能否建立 JNDI 连接。用管理控制台查看服务器实例状态确认是 RUNNING。确认 JMS Module 已经 Target 到对外提供服务的服务器上。确认连接工厂和队列的 JNDI 名称没有写错。确认客户端机器的 JDK 和 WebLogic 客户端库版本与服务端匹配。这套清单看起来简单但每次排查我都是从头走一遍因为问题往往不是你以为的那一层。有一次我排查了半天发现是外部机器和服务器之间隔了防火墙端口没放开telnet 直接卡住跟 WebLogic 本身一点关系都没有。5. 高频故障清单与排查思路5.1 外部连接超时一定是网络问题吗外部客户端连接 WebLogic JMS 超时表象是网络不通但原因可能是这几个方向。最常见的是监听地址没改服务器还在监听 localhost连接请求被内核丢弃。第二个常见原因是防火墙拦截既要看本机防火墙也要看网络边界防火墙。第三个原因是服务端负载已经很高等待队列满导致新连接被挂起这在消息大量堆积时会出现。第四个原因是客户端连接的端口和实际监听端口不一致比如服务端改了端口但客户端还在连旧端口。排查顺序建议先 telnet 再检查监听端口监听情况。在 Linux 服务器上执行netstat -anp | grep 7001如果看到 127.0.0.1:7001说明监听地址还是 localhost问题就在这。如果看到 0.0.0.0:7001 或者是具体 IP:7001那网络层是通的再查防火墙和客户端代码。5.2 客户端 JNDI 查询报 NameNotFoundException报错信息里如果出现NameNotFoundException说明客户端已经成功连上了服务端但查不到指定的资源名称。这种问题的原因基本就是资源没创建成功、模块没 Target、或者 JNDI 名称写错。我遇到过一种情况在管理台上看到队列名称是TestQueue但客户端查的是jms/TestQueue两者不同自然查不到。从管理控制台查实际 JNDI 名称的方法环境 - 服务器 - 选择 AdminServer - 查看 JNDI 树选项卡能看到当前服务器上已经注册的所有 JNDI 名称。队列和连接工厂应该对应显示。如果 JNDI 树里看不到资源说明资源虽然创建了但没生效到这台服务器上回过去检查 JMS Module 的 Target 配置。5.3 JMS 客户端版本和服务端版本不匹配WebLogic JMS 的客户端库适配没有你想象的那么宽松。服务端如果是 10.3.6客户端最好用同版本的 weblogic.jar。服务端 12.2.1客户端也尽量一致。跨大版本偶尔能连但协议层可能出现奇怪的行为比如连接建立成功但发消息报错。最简单的方案是在客户端工程里引入与服务端版本一致的 weblogic.jar避免用较新版本去连老服务端。这里要注意的一个点是weblogic.jar 体积很大而且里面包含一些依赖其他库的类比如 JMS 客户端运行时会用到 wlclient.jar、wljmxclient.jar 这些。偷懒方案是直接把整个 weblogic.jar 放到客户端的 classpath 里多数场景都能跑起来。如果想做精简可以只放必要的几个 jar但初学者我不建议精简白白增加排查成本。5.4 高频问题速查表现象可能原因优先排查动作外部机器 telnet 端口不通防火墙拦截 / 监听地址未改netstat 查看监听地址检查防火墙JNDI 查询 NameNotFound模块未 Target / JNDI 名称不一致看服务器 JNDI 树核实名称连接建立后发消息失败客户端版本不一致 / 队列无持久化空间核对客户端 jar 版本查看存储目录消息堆积后发送越来越慢存储目录空间不足 / 临时消息堆积查看磁盘空间和管理台消息计数控制台访问速度极慢内存不足 / 日志量过大检查 GC 日志和 access.log 大小这张表是日常运维中最常见的几个场景碰到问题先按表里的方向查大多数时候能很快定位。排查 WebLogic 问题的思路跟排查普通 Java 应用一样的先分层次网络层、服务层、应用层一层层剥离不要一开始就陷到细节里。6. 关于这套方案的几点个人建议最后聊几个我做这类部署时积累下来的习惯不一定写进文档但很实用。第一点我从不把持久化存储跟安装目录放一起。安装目录是程序文件重装、升级、打补丁都可能是针对它的操作消息存储放这里容易在操作过程中被误删。单独挂一个数据目录备份也方便只要把这块目录定期备份消息就能找回来。第二点监听地址尽可能用具体 IP 而不是 0.0.0.0。虽然 0.0.0.0 配置简单但它把所有网卡都暴露出来了。如果你这台机器既连内网又连其他网络0.0.0.0 会让不在预期范围内的网络也能尝试访问端口增大被扫描的风险。用一个固定 IP 或至少用控制台的访问列表来收敛是更稳妥的做法。第三点给消息服务的 JNDI 名称做一套命名规范。比如队列都用jms/业务名/QueueName连接工厂用jms/连接工厂名时间长了资源多了之后没有规范就是灾难。一个队列叫TestQueue另一个叫MyQueue2三个月后没人记得哪个是干什么的。这套“本地部署 WebLogic 并实现外部访问”的流程本质上就是把一个默认只服务于本机的应用服务器改造成一个可被网络内其他应用调用的消息服务节点。整个过程不算复杂但每一步都要做对概念上分清应用服务器和 JMS 服务的关系部署上把监听地址和端口规划好资源上把存储和队列建对最后客户端连接串和服务端配置对齐。如果你是在已有 WebLogic 环境上做这件事那更简单只需要补建 JMS 资源、调监听地址、改防火墙三个动作就行按文章里的排查表走一遍外部访问很快就能通。