假设我想在有一个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));
调用:
javax.xml.ws.Service service = javax.xml.ws.Service.create(url,
new QName(
"http://endpoint.king.pac/",
"testMyService"));
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/"
/>