目录:
- SOA体系结构简要介绍
- 实现思路
- 具体实现
- 执行结果
- 遇到的坑
SOA体系结构简要介绍
Service-Oriented Architecture,面向服务的框架。SOA系统主要是来解决实现异构子系统间的信息传递问题。
其实刚开始学习SOA体系结构时,大家容易混淆SOA和WebService这两个概念。
那么WebService本身并不是一个体系结构,他是实现SOA的一种技术。
而WebService又可以主要通过两种方式,jaxws和jaxrs来实现。
而这里,我介绍通过JAX-WS来实现WebService,从而实现SOA体系结构,让两个子系统可以传递信息。
(详情可以看这个:SOA详细介绍)
实现思路
- 因为我们知道,WebService共分为两种角色:服务端(提供服务),客户端(使用服务)
- 而服务端这个角色又由3个最基本的类组成,接口类(定义服务提供的抽象方法),接口的具体实现类,服务端的Main类。
- 客户端角色由一个客户端Main类组成
具体实现
这里以一个“获取天气信息过程”举例:
实现的要求流程如下,
客户端需使用服务端的服务(调用服务端接口类的方法)从而获取服务端存储的天气信息。
工程结构截图:
服务端角色:
- 接口类(WeatherService)
import javax.jws.WebService;
@WebService//
public interface WeatherService {
public String query(String cityName);
}
注意:在接口前面的“@WebService”不能少,这是标识这个接口是一个提供WebService服务的接口。
2. 接口的具体实现类(WeatherServiceImpl)
package com.webservice;
import javax.jws.WebService;
@WebService(endpointInterface ="com.webservice.WeatherService")
public class WeatherServiceImpl implements WeatherService{
@Override
public String query(String cityName) {
System.out.println("city:"+cityName);
return "大晴天";
}
}
注意:@WebService(endpointInterface =“com.webservice.WeatherService”)
类前的这句是标识这个类是实现了哪个包(com.webservice)下的哪个接口(WeatherService)的服务,不能少。
3.服务端的Main类(ServerMain)
package com.webservice.main;
import javax.xml.ws.Endpoint;
import com.webservice.WeatherServiceImpl;
public class ServerMain {
public static void main(String[] args) {
Endpoint.publish("http://localhost:10009/weatherService", new WeatherServiceImpl());
System.out.println("发布成功!!!");
}
}
注意:
Endpoint.publish后面跟着的url是服务最终发布的url。
4. 客户端Main类(ClientMain)
package com.webservice.main;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import com.webservice.WeatherService;
public class ClientMain {
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("http://localhost:10009/weatherService?wsdl");
// 1st argument service URI, refer to wsdl document above
// 2nd argument is service name, refer to wsdl document above
QName qname = new QName("http://webservice.com/", "WeatherServiceImplService");
Service service = Service.create(url, qname);
while(true) {
WeatherService iWeather = service.getPort(WeatherService.class);
String query = iWeather.query("深圳");
System.out.println("深圳天气是:"+query);
}
};
}
注意:客户端方法的执行思路
1. 先创建一个URL对象(URL即为服务端的URL+“?wsdl”)因为是访问“服务端发布的服务的wsdl(WebService Description language)”
wsdl如下
- 再创建一个QName对象,第一个参数为http://类名+包名/,或者在wsdl中的targetNamespace属性找:
第二个参数为接口具体实现类类名+Service
或者在wsdl的service name中找对应参数。
3. 创建一个Service去,构造参数为url和qname
4. 然后service对象的getPort方法获取发布的接口实现具体类对象,(这里使用了“接口”作为引用接受其子类的对象)。
5. 执行子类的方法。
执行结果
服务端启动成功:
客户端访问成功:
遇到的坑
1.要将类放入一个写好的“包”中,不能放在default 包下。
否则报错
“Exception in thread “main” com.sun.xml.internal.ws.model.RuntimeModelerException: 必须在没有程序包的类上指定 @WebService.targetNamespace。类: SimpleCounterImpl”。
- 报错:
Exception in thread “main” com.sun.xml.internal.ws.server.ServerRtException: 服务器运行时错误: java.net.BindException: Address already in use: bind
解决方法:服务端发布的服务端口在该主机下已经被其他应用占用了,请更换服务端口。
3.报错:Exception in thread “main” com.sun.xml.internal.ws.server.ServerRtException: 服务器运行时错误: java.lang.IllegalArgumentException: Context with URL path /OnlineShoppingPlatform already exists on the server /127.0.0.1:9999
一个服务(一个接口的具体实现类只能绑定在一个单独的URL上,不能把1个以上的服务绑定在同一个URL中)