一种基于Spring扩展的WebService动态路由实现机制

在某系统开发项目中,需要调用分别部署于不同节点但相同WSDL的WebService接口,为此,通过扩展Spring现有WebService实现机制,实现根据不同路由标识调用不同节点的WebService接口的动态路由。

思路:
      通过扩展JaxWsPortClientInterceptor类,实现一个DynamicJaxWsPortProxyFactoryBean类:
  • 在Spring实例化阶段,默认不创建WebService的Stub,不单独设置WsdlDocumentUrl;
  • 使用多例模式维持一个Service的Map,以路由标识(本项目使用某组织机构代码前缀)为查找Key,在进行WebService 调用时,首先查询以路由标识(先前存储的线程本地变量)为Key的映射中是否已经存在Stub,若不存在,创建并保存到多例映射池中。

/**
 * 
 */
package jmy.test;

import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.remoting.jaxws.JaxWsPortClientInterceptor;

/**
 * 
 * 

* 标题:DynamicJaxWsPortProxyFactoryBean *

*

* 描述: *

    *
  1. 在Spring实例化阶段,默认不创建WebService的Stub,不单独设置WsdlDocumentUrl; *
  2. 使用多例模式维持一个Service的Map,以路由标识(本项目使用组织机构代码前缀)为查找Key, * 在进行WebService 调用时,首先查询以路由标识(先前就以存储于线程本地变量)为Key的映射 * 中是否已经存在Stub,若不存在,创建并保存到多例映射池中。 *
*

*/ public class DynamicJaxWsPortProxyFactoryBean extends JaxWsPortClientInterceptor implements FactoryBean { private final Logger log = LoggerFactory.getLogger(getClass()); private Map regionWsdls; private Map wsHolder = Collections.synchronizedMap(new HashMap()); public DynamicJaxWsPortProxyFactoryBean(Map regionWsdls) { this.regionWsdls = regionWsdls; } /** * 直接抛出异常,动态WebService端口代理不允许设置wsdlDocumentUrl。 * @throw IllegalAccessError * @see org.springframework.remoting.jaxws.LocalJaxWsServiceFactory#setWsdlDocumentUrl(java.net.URL) */ @Override public void setWsdlDocumentUrl(URL wsdlDocumentUrl) { throw new IllegalAccessError("动态WebService端口代理不允许设置wsdlDocumentUrl"); } /** * 动态查找服务,所以setLookupServiceOnStartup(false) * @see org.springframework.remoting.jaxws.JaxWsPortClientInterceptor#afterPropertiesSet() */ @Override public void afterPropertiesSet() { super.setLookupServiceOnStartup(false); super.afterPropertiesSet(); } /* (non-Javadoc) * @see org.springframework.remoting.jaxws.JaxWsPortClientInterceptor#isPrepared() */ @Override protected boolean isPrepared() { return false;//要求父类永远调用prepare()方法 } /* (non-Javadoc) * @see org.springframework.remoting.jaxws.LocalJaxWsServiceFactory#createJaxWsService() */ @Override public Service createJaxWsService() { String currentRegion = RegionRouter.getRegion(); log.debug(String.format("创建路由区域为【%s】的WebService", currentRegion)); super.setWsdlDocumentUrl(regionWsdls.get(currentRegion)); Service svc = super.createJaxWsService(); this.wsHolder.put(currentRegion, svc); return svc; } /* (non-Javadoc) * @see org.springframework.remoting.jaxws.JaxWsPortClientInterceptor#getJaxWsService() */ @Override public Service getJaxWsService() { String currentRegion = RegionRouter.getRegion(); Service obj = wsHolder.get(currentRegion); log.debug(String.format("获取路由区域为【%s】的WebService,是否获取到?【%s】", currentRegion, obj != null)); return obj; } /* (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#getObject() */ @Override public Object getObject() throws Exception { // Build a proxy that also exposes the JAX-WS BindingProvider interface. ProxyFactory pf = new ProxyFactory(); pf.addInterface(getServiceInterface()); pf.addInterface(BindingProvider.class); pf.addAdvice(this); return pf.getProxy(getBeanClassLoader()); } /* (non-Javadoc) * @see org.springframework.beans.factory.FactoryBean#getObjectType() */ @Override public Class getObjectType() { return getServiceInterface(); } /** * 本FactoryBean以多例模式实现对象创建。 * * @return false * @see org.springframework.beans.factory.FactoryBean#isSingleton() */ @Override public boolean isSingleton() { return false; } }

你可能感兴趣的:(Spring)