一种基于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;

/**
 * 
 * <p>
 * 标题:DynamicJaxWsPortProxyFactoryBean
 * </p>
 * <p>
 * 描述:
 * <ol>
 * <li>在Spring实例化阶段,默认不创建WebService的Stub,不单独设置WsdlDocumentUrl;
 * <li>使用多例模式维持一个Service的Map,以路由标识(本项目使用组织机构代码前缀)为查找Key,
 * 在进行WebService 调用时,首先查询以路由标识(先前就以存储于线程本地变量)为Key的映射
 * 中是否已经存在Stub,若不存在,创建并保存到多例映射池中。
 * </ol>
 * </p>
 */
public class DynamicJaxWsPortProxyFactoryBean extends JaxWsPortClientInterceptor implements FactoryBean<Object> {
	private final Logger log = LoggerFactory.getLogger(getClass());
	private Map<String, URL> regionWsdls;
	private Map<String, Service> wsHolder = Collections.<String, Service>synchronizedMap(new HashMap<String, Service>());
	
	public DynamicJaxWsPortProxyFactoryBean(Map<String, URL> 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;
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值