看来使用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又非常适合。
【Spring】几种RPC模型的使用与比较——JAX-WS