JMS Producer最佳实践:Servlet过滤器内发消息的实例创建时机选择
JMSProducer创建方式性能对比结论
核心结论
从性能与资源利用率角度考量,在@PostConstruct方法中一次性创建JMSProducer明显更优,不推荐在每次请求的doFilter方法中重复创建。
具体原因
- 创建开销差异:
JMSProducer虽然属于JMS 2.0定义的轻量对象,但创建过程仍需要JMS服务提供商执行上下文校验、资源分配、权限检查等逻辑,不存在零开销。Filter是每请求必调用的组件,高并发流量下反复创建的累计开销会被明显放大,还会额外增加年轻代GC的压力。 - 线程安全支持:JMS 2.0规范明确要求
JMSProducer实现线程安全,完全支持多线程环境下复用,单实例不会出现并发调用问题,具备全局复用的前提条件。 - 资源占用差异:复用场景下全程仅占用1个
JMSProducer实例的内存及关联资源;每次请求创建的场景下,峰值流量时会同时存在大量临时JMSProducer实例,堆内存占用、JMS服务端关联临时资源消耗都会高很多。
注意事项
如果你的项目中容器注入的JMSContext默认是请求作用域(@RequestScoped,每个请求对应独立的上下文实例),无法直接在@PostConstruct阶段使用,可改为注入/创建应用作用域、生命周期和Filter绑定的JMSContext,再搭配一次性创建JMSProducer使用,示例代码如下:
public class CustomFilter implements javax.servlet.Filter { // 应用作用域JMSContext,生命周期和Filter一致 private JMSContext appScopeContext; @Resource private Queue queue; // 复用的JMSProducer实例 private JMSProducer sharedProducer; @PostConstruct public void initProducer() { // 根据你的JMS厂商实现创建应用管理的JMSContext,也可直接注入容器提供的应用作用域JMSContext appScopeContext = ConnectionFactory.createContext(); sharedProducer = appScopeContext.createProducer(); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { long start = new Date().getTime(); filterChain.doFilter(servletRequest, servletResponse); // 直接复用预创建的producer发送消息,无需重复创建 sharedProducer.send(queue, "待发送的消息内容"); } @PreDestroy public void releaseResource() { // Filter销毁时关闭JMS上下文释放关联资源 if (appScopeContext != null) { appScopeContext.close(); } } @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
内容的提问来源于stack exchange,提问作者Renato
相关产品推荐
相关产品推荐

