首页 > 代码库 > 【Spring】几种RPC模型的使用与比较——JAX-WS

【Spring】几种RPC模型的使用与比较——JAX-WS

看来使用web service是不可避免的。
我曾对这个有些抵触,因为他给我印象总是麻烦+慢(后来虽然方便了许多,但还是很慢)。
然后再去搜索"advantages of web service"什么的试着再让自己接受他。
简单记录一下如何用Spring导出Endpoint。


假设我想在有一个Spring应用,我需要把一个Pojo或者一部分方法导出为Web Service。
但这会有一个问题——Endpoint的生命周期是由JAX-WS runtime来管理(The lifecycle of such an endpoint instance will be managed by the JAX-WS runtime),Spring context中的Bean无法autowire到Endpoint中,而我要导出的那些东东都用到了Spring管理的Bean。


对此,我们有两个解决方法:
·org.springframework.web.context.support.SpringBeanAutowiringSupport
·JaxWsServiceExporter


我上面括号中的那段话是引用的SpringBeanAutowiringSupport的javaDoc。
使用该类的典型案例就是bean注入到JAX-WS endpoint类中(人家注释上写的),任何一个生命周期不是由Spring来管理的场景都可以用到他。
而我们只需要继承这个类,也就是说创建一个实例时会调用父类的无参构造方法,我们来看看他的构造方法:

/**
 * This constructor performs injection on this instance,
 * based on the current web application context.
 * <p>Intended for use as a base class.
 * @see #processInjectionBasedOnCurrentContext
 */
public SpringBeanAutowiringSupport() {
    processInjectionBasedOnCurrentContext(this);
}
/**
 * Process {@code @Autowired} injection for the given target object,
 * based on the current web application context.
 * <p>Intended for use as a delegate.
 * @param target the target object to process
 * @see org.springframework.web.context.ContextLoader#getCurrentWebApplicationContext()
 */
public static void processInjectionBasedOnCurrentContext(Object target) {
    Assert.notNull(target, "Target object must not be null");
    WebApplicationContext cc = ContextLoader.getCurrentWebApplicationContext();
    if (cc != null) {
        AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
        bpp.setBeanFactory(cc.getAutowireCapableBeanFactory());
        bpp.processInjection(target);
    }
    else {
        if (logger.isDebugEnabled()) {
            logger.debug("Current WebApplicationContext is not available for processing of " +
                    ClassUtils.getShortName(target.getClass()) + ": " +
                    "Make sure this class gets constructed in a Spring web application. Proceeding without injection.");
        }
    }
}


那就试试看:

@Service
@WebService(serviceName="testMyService")
public class MyServiceEndpoint extends SpringBeanAutowiringSupport{
    @Autowired
    MyService myService;
                                                                                                                                                                                                                                                                                             
    @WebMethod
    public String sayHiFarAway(String name){
        return myService.sayHiTo(name);
    }
}


接着发布一下:

ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:applicationContext*.xml");
Endpoint.publish("http://localhost:8080/myservices", (MyServiceEndpoint)context.getBean(MyServiceEndpoint.class));

调用:

QName q = new QName("http://endpoint.king.pac/","MyServiceEndpointPort");
MyClientService client = service.getPort(q,MyClientService.class);
System.out.println(client.sayHiFarAway("King"));


写一个EndPoint还要继承和业务无关的类,让人不爽...而且发布和调用都麻烦。
那试试SimpleJaxWsServiceExporter,只需要简单的配置就可以导出一个EndPoint。
但是他也有需要注意的地方,引用一下该类的javaDoc:
Note that this exporter will only work if the JAX-WS runtime actually supports publishing with an address argument, i.e. if the JAX-WS runtime ships an internal HTTP server. This is the case with the JAX-WS runtime that‘s inclued in Sun‘s JDK 1.6 but not with the standalone JAX-WS 2.1 RI.

SimpleJaxWsServiceExporter会自动detect所有被WebService注解的类,因此只需要在配置中声明即可;此时Endpoint地址直接使用默认的localhost:8080:

<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter" />

接着改善一下客户端的调用,使用JaxWsPortProxyFactoryBean:

<bean id="clientSide" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean"
    p:wsdlDocumentUrl="http://localhost:8080/testMyService?wsdl"
    p:serviceName="testMyService"
    p:portName="MyServiceEndpointPort"
    p:serviceInterface="pac.king.endpoint.MyClientService"
    p:namespaceUri="http://endpoint.king.pac/"
/>

这样就可以像使用普通bean一样使用service了:

MyClientService client = (MyClientService)context.getBean("clientSide");
System.out.println(client.sayHiFarAway("King"));


用起来方便了不少,但仍然无法改变一个事实:
Web service requests are larger than requests encoded with a binary protocol.
还有就是http/https的问题。
如果使用不当,我可能需要多做些工作去处理HTTP做不来的事情,而这时候RMI又非常适合。


本文出自 “Map.get(X)=new Object()” 博客,请务必保留此出处http://runtime.blog.51cto.com/7711135/1408024