PDF:

Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Sử dụng các công nghệ tiêu chuẩn Java JAXB 2.x và JAX-WS 2.x cho
các dịch vụ Web Axis2
Dennis Sosnoski
Nhà tư vấn
Sosnoski Software Solutions, Inc.
15 09 2009
Apache Axis2 hỗ trợ một loạt các công nghệ liên kết dữ liệu, bao gồm tiêu chuẩn Java™ chính
thức JAXB 2.x . Axis2 cũng hỗ trợ tiêu chuẩn Java cho cấu hình dịch vụ Web, JAX-WS 2.x,
như là một sự thay thế cho kỹ thuật cấu hình tùy chỉnh riêng của nó. Dennis Sosnoski tiếp tục
loạt bài Các dịch vụ Web Java của mình bằng cách giải thích bạn có thể sử dụng mỗi tiêu chuẩn
Java này với Axis2 như thế nào và thảo luận về một số hạn chế về sự hỗ trợ hiện tại của Axis2
cho chúng.
Xem thêm bài trong loạt bài này
Về loạt bài này
Các dịch vụ Web là một phần chủ yếu của vai trò công nghệ Java™ trong điện toán doanh
nghiệp. Trong loạt bài viết này, nhà tư vấn XML và các dịch vụ Web Dennis Sosnoski trình
bày các khung công tác và công nghệ chính rất quan trọng với các nhà phát triển Java khi sử
dụng các dịch vụ Web. Hãy theo dõi loạt bài này để cập nhật những phát triển mới nhất trong
lĩnh vực này và hiểu được bạn có thể sử dụng chúng để hỗ trợ cho các dự án lập trình của bạn
như thế nào.
Axis của Apache ban đầu đã dựa vào các tiêu chuẩn Java đầu tiên cho các dịch vụ Web, JAX-RPC.
Điều này hóa ra không phải là một cách tiếp cận tốt, vì JAX-RPC đã hạn chế việc thiết kế nội bộ
của mã Axis và đã góp phần gây ra cả vấn đề hiệu năng lẫn sự thiếu linh hoạt. JAX-RPC cũng đặt
một số giả định về hướng phát triển các dịch vụ Web mà sau này hóa ra là sai.
Vào lúc mà các nỗ lực phát triển Axis2 đã bắt đầu, một sự thay thế cho JAX-RPC đã có trong các
sản phẩm, vì thế Axis2 đã được thiết kế linh hoạt đủ để thực hiện sự hỗ trợ cho tiêu chuẩn của các
dịch vụ Web thay thế bên trên đỉnh của khung công tác cơ sở. Các phiên bản mới đây của Axis2 đã
triển khai sự hỗ trợ cho cả tiêu chuẩn liên kết dữ liệu XML Java JAXB 2.x lẫn tiêu chuẩn các dịch vụ
Web Java JAX-WS 2.x thay thế cho JAX-RPC. Bài viết này cho thấy cách sử dụng JAXB và JAXWS với Axis2 và nhận biết một số hạn chế về sự hỗ trợ hiện tại của Axis2 cho các tiêu chuẩn này.
© Copyright IBM Corporation 2009
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Nhẫn hiệu đăng ký
Trang 1 của 17
developerWorks®
ibm.com/developerWorks/vn/
JAXB trong Axis2
Axis2 thực hiện hỗ trợ cho JAXB 2.x như là một trong những sự lựa chọn liên kết dữ liệu mà bạn có
thể chọn khi sinh mã từ một định nghĩa vụ dịch vụ WSDL (Web Services Description Language –
Ngôn ngữ mô tả các dịch vụ Web) bằng công cụ WSDL2Java. (Xem "Java Web Services: Axis2
Data Binding" (Các dịch vụ Web: Liên kết dữ liệu Axis2) để đọc về cuộc thảo luận các sự lựa chọn
thay thế chủ yếu khác). Như với hầu hết các lựa chọn thay thế khác, việc tạo mã từ WSDL khi sử
dụng JAXB 2.x tạo ra cả một tập các lớp liên kết và một tập các lớp mô hình dữ liệu. Các lớp liên
kết, bao gồm một gốc phía máy khách và một máy thu thông báo phía máy chủ, giao diện giữa mã
ứng dụng của bạn và Axis2. Các lớp mô hình dữ liệu biểu diễn dữ liệu thông báo thực tế.
JAXB 2.x sử dụng các chú thích trong các lớp mô hình dữ liệu để kiểm soát cách biến đổi dữ liệu
thành XML và từ XML. Cách tiếp cận dùng chú thích cho phép bạn sử dụng các triển khai thực
hiện JAXB khác nhau trong thời gian chạy mà không cần phải thay đổi mã nguồn của bạn hoặc biên
dịch lại các lớp của bạn. Chính việc triển khai thực hiện JAXB có trách nhiệm truy cập thông tin chú
thích từ các lớp mô hình dữ liệu và áp dụng các chú thích này khi biến đổi dữ liệu thành XML và từ
XML.
Phần tải mã (xem Tải về) cung cấp một ứng dụng ví dụ để giải thích cách sử dụng JAXB trong Axis2,
trong thư mục jaxb. Ứng dụng này là một phiên bản khác của dịch vụ quản lý thư viện đơn giản đã
sử dụng trong các bài viết trước thuộc loạt bài này (bao gồm việc so sánh liên kết dữ liệu trong
"Axis2 Data Binding" (Liên kết dữ liệu Axis2). Định nghĩa dịch vụ WSDL xác định bốn hoạt động:
• getBook để lấy ra các chi tiết về một cuốn sách cụ thể được xác định theo Số hiệu sách tiêu
chuẩn quốc tế (International Standard Book Number-ISBN).
• getBooksByType để lấy ra các chi tiết cho tất cả các cuốn sách của một kiểu cụ thể.
• getTypes để tìm các kiểu của các cuốn sách có sẵn.
• addBook để thêm một cuốn sách mới vào thư viện.
Liệt kê 1 cho thấy một phiên bản WSDL đã biên tập lại nhiều, chỉ gồm các phần liên quan đến hoạt
động getBook:
Liệt kê 1. WSDL của dịch vụ thư viện
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"
xmlns:wns="http://ws.sosnoski.com/library/wsdl"
xmlns:tns="http://ws.sosnoski.com/library/types"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<schema elementFormDefault="qualified"
targetNamespace="http://ws.sosnoski.com/library/wsdl"
xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://ws.sosnoski.com/library/types"
schemaLocation="types.xsd"/>
<element name="getBook">
<complexType>
<sequence>
<element name="isbn" type="string"/>
</sequence>
</complexType>
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 2 của 17
ibm.com/developerWorks/vn/
developerWorks®
</element>
<element name="getBookResponse">
<complexType>
<sequence>
<element name="getBookReturn" minOccurs="0" type="tns:BookInformation"/>
</sequence>
</complexType>
</element>
...
</schema>
</wsdl:types>
<wsdl:message name="getBookRequest">
<wsdl:part element="wns:getBook" name="parameters"/>
</wsdl:message>
<wsdl:message name="getBookResponse">
<wsdl:part element="wns:getBookResponse" name="parameters"/>
</wsdl:message>
...
<wsdl:portType name="Library">
<wsdl:operation name="getBook">
<wsdl:input message="wns:getBookRequest" name="getBookRequest"/>
<wsdl:output message="wns:getBookResponse" name="getBookResponse"/>
</wsdl:operation>
...
</wsdl:portType>
<wsdl:binding name="LibrarySoapBinding" type="wns:Library">
<wsdlsoap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getBook">
<wsdlsoap:operation soapAction="urn:getBook"/>
<wsdl:input name="getBookRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getBookResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
...
</wsdl:binding>
<wsdl:service name="jaxb-library">
<wsdl:port binding="wns:LibrarySoapBinding" name="library">
<wsdlsoap:address location="http://localhost:8080/axis2/services/jaxb-library"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 3 của 17
developerWorks®
ibm.com/developerWorks/vn/
Sự hỗ trợ JAXB của Axis2 được giả định sẽ mở rộng để tạo ra các phương thức hoạt động không
được bao bọc (ở đây các giá trị được bao bọc trong một thông báo sẽ được chuyển đổi thành các
tham số phương thức để thuận tiện cho việc lập trình — xem lại "Các dịch vụ Web: Liên kết dữ liệu
Axis2" để đọc các thảo luận về giao diện được bao bọc so với không được bao bọc). Nhưng sự hỗ
trợ không được bao bọc sử dụng công cụ WSDL2Java không làm việc với ví dụ này cả trong mã
Axis2 hiện tại lẫn trong một số các bản phát hành gần đây. Ít nhất cho đến nay, các phương thức
hoạt động có bao bọc là cách duy nhất để sử dụng JAXB với việc tạo mã Axis2 (nhưng hãy xem
thảo luận JAX-WS, sắp tới đây, để thấy một cách tiếp cận thay thế). Với giao diện hoạt động có bao
bọc, mỗi phương thức dịch vụ cần chỉ một tham số đối tượng khớp với thông báo đầu vào cho hoạt
động này và trả về một đối tượng khớp với thông báo đầu ra cho hoạt động này.
Các mã đã được cung cấp một sự triển khai thực hiện thực tế của cả dịch vụ lẫn một máy khách thử
nghiệm, thiết lập để làm việc với các lớp được tạo ra bằng cách chạy WSDL2Java. Như với đoạn
mã ví dụ cho các bài viết trước trong loạt bài này, phần tải về bao gồm các tệp build.properties và
build.xml được sử dụng để xây dựng ví dụ này bằng Ant của Apache (trong thư mục jaxb). Trước
tiên, bạn cần phải chỉnh sửa tệp build.properties để thiết lập đường dẫn đến bản cài đặt Axis2 của
bạn (và thay đổi các giá trị cài đặt khác, nếu cần thiết cho hệ thống của bạn). Sau đó, bạn có thể
gõ nhập ant vào một cửa sổ dòng lệnh mở trong thư mục jaxb để chạy WSDL2Java, biên dịch cả
mã được cung cấp lẫn mã được tạo ra và xây dựng tệp AAR để triển khai máy chủ. Để thử nghiệm
nó, đầu tiên triển khai tệp AAR được tạo ra tới bản cài đặt máy chủ Axis2 của bạn và sau đó gõ ant
run trên bàn điều khiển.
Cách sử dụng JAXB phía máy khách
Máy khách thử nghiệm tạo ra một cá thể của gốc dịch vụ bằng cách sử dụng các tham số điểm đầu
cuối dịch vụ được chuyển vào dưới dạng các đối số dòng lệnh và sau đó thi hành một chuỗi năm
cuộc gọi dịch vụ:
1. Lấy thông tin cho một cuốn sách.
2. Lấy các kiểu của các cuốn sách trong thư viện.
3. Thêm một cuốn sách vào thư viện (sẽ thất bại nếu cuốn sách đã có mặt, như sẽ xảy ra khi máy
khách chạy nhiều hơn một lần mà không khởi động lại máy chủ).
4. Nếu bước cuối cùng đã thành công, cố gắng thêm một cuốn sách khác với cùng một ISBN
(phải luôn luôn thất bại).
5. Lấy thông tin về tất cả các cuốn sách của một kiểu cụ thể.
Liệt kê 2 cho thấy toàn bộ mã máy khách thử nghiệm. Bạn có thể thấy bản chất có bao bọc của giao
diện dịch vụ trong các đối tượng của trình bao bọc (wrapper) được sử dụng cho từng hoạt động, ví
dụ như là đối tượng GetTypes đã yêu cầu một cuộc gọi đến hoạt động getTypes (mặc dù không có
dữ liệu đầu vào nào cho hoạt động này) và đối tượng GetTypesResponse được cuộc gọi này trả về.
Liệt kê 2. Mã máy khách thử nghiệm JAXB
public class WebServiceClient
{
public static void main(String[] args) throws Exception {
// check for required command line parameters
if (args.length < 3) {
System.out.println("Usage:\n java " +
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 4 của 17
ibm.com/developerWorks/vn/
developerWorks®
"com.sosnoski.ws.library.jaxb.WebServiceClient host port path");
System.exit(1);
}
// create the client stub
String target = "http://" + args[0] + ":" + args[1] + args[2];
System.out.println("Connecting to " + target);
JaxbLibraryStub stub = new JaxbLibraryStub(target);
// retrieve a book directly
String isbn = "0061020052";
GetBook gb = new GetBook();
gb.setIsbn(isbn);
GetBookResponse gbr = stub.getBook(gb);
BookInformation book = gbr.getGetBookReturn();
if (book == null) {
System.out.println("No book found with ISBN '" + isbn + '\'');
} else {
System.out.println("Retrieved '" + book.getTitle() + '\'');
}
// retrieve the list of types defined
GetTypesResponse gtr = stub.getTypes(new GetTypes());
List<TypeInformation> types = gtr.getGetTypesReturn();
System.out.println("Retrieved " + types.size() + " types:");
for (int i = 0; i < types.size(); i++) {
TypeInformation type = types.get(i);
System.out.println(" '" + type.getName() + "' with " +
type.getCount() + " books");
}
// add a new book
String title = "The Dragon Never Sleeps";
isbn = "0445203498";
try {
AddBook ab = new AddBook();
ab.setType("scifi");
ab.setIsbn(isbn);
ab.getAuthor().add("Cook, Glen");
ab.setTitle(title);
stub.addBook(ab);
System.out.println("Added '" + title + '\'');
title = "This Should Not Work";
ab.setTitle(title);
stub.addBook(ab);
System.out.println("Added duplicate book - should not happen!");
} catch (AddDuplicateFault e) {
System.out.println("Failed adding '" + title +
"' with ISBN '" + isbn + "' - matches existing title '" +
e.getFaultMessage().getBook().getTitle() + '\'');
}
// get all books of a type
GetBooksByType gbbt = new GetBooksByType();
gbbt.setType("scifi");
GetBooksByTypeResponse gbbtr = stub.getBooksByType(gbbt);
List<BookInformation> books = gbbtr.getGetBooksByTypeReturn();
System.out.println("Retrieved " + books.size() + " books of type 'scifi':");
for (int i = 0; i < books.size(); i++) {
System.out.println(" '" + books.get(i).getTitle() + '\'');
}
}
}
Nếu bạn so sánh Liệt kê 2 với các ví dụ mã máy khách trong "Các ứng dụng Web Java: Liên kết
dữ liệu Axis2," bạn sẽ thấy rằng nó rất giống với các ví dụ bao bọc về JiBX và liên kết dữ liệu Axis
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 5 của 17
developerWorks®
ibm.com/developerWorks/vn/
(ADB), khác biệt chủ yếu là các lớp bao bọc JAXB sử dụng các danh sách định kiểu Java 5 chứ
không phải là các mảng (một lựa chọn thay thế cũng được liên kết dữ liệu JiBX hỗ trợ, nhưng ADB
không hỗ trợ).
Cách sử dụng phía máy chủ
Mã phía máy chủ cho dịch vụ thư viện bao gồm hai lớp, một lớp thực hiện việc xử lý thư viện trên
thực tế và lớp kia để tiếp hợp với giao diện dịch vụ mà Axis2 trông đợi. Mã thực hiện trên thực tế
gần như giống hệt nhau trên các liên kết dữ liệu khác nhau, chỉ có các thay đổi nhỏ cần thiết cho
việc biểu diễn mô hình dữ liệu ứng dụng đã tạo ra. Liệt kê 3 cho thấy lớp giao diện dịch vụ thú vị
hơn. Giống như trên máy khách, giao diện được bao bọc yêu cầu mã ứng dụng lấy ra dữ liệu từ các
đối tượng bao bọc (wrapper) đã thu được và xây dựng các đối tượng bao bọc để gửi đi.
Liệt kê 3. Mã máy chủ JAXB
public class JaxbLibraryImpl extends JaxbLibrarySkeleton
{
private final BookServer m_server;
public JaxbLibraryImpl() {
m_server = new BookServer();
}
public AddBookResponse addBook(AddBook req) throws AddDuplicateFault {
BookInformation prior = m_server.getBook(req.getIsbn());
if (prior == null) {
BookInformation book = new BookInformation();
book.getAuthor().addAll(req.getAuthor());
book.setIsbn(req.getIsbn());
book.setTitle(req.getTitle());
book.setType(req.getType());
AddBookResponse rsp = new AddBookResponse();
rsp.setAddBookReturn(m_server.addBook(book));
return rsp;
} else {
AddDuplicateFault e =
new AddDuplicateFault("Book already present with matching ISBN");
AddDuplicate ad = new AddDuplicate();
ad.setBook(prior);
e.setFaultMessage(ad);
throw e;
}
}
public GetBookResponse getBook(GetBook req) {
BookInformation book = m_server.getBook(req.getIsbn());
GetBookResponse rsp = new GetBookResponse();
rsp.setGetBookReturn(book);
return rsp;
}
public GetBooksByTypeResponse getBooksByType(GetBooksByType req) {
GetBooksByTypeResponse rsp = new GetBooksByTypeResponse();
rsp.getGetBooksByTypeReturn().addAll(m_server.getBooksByType(req.getType()));
return rsp;
}
public GetTypesResponse getTypes(GetTypes req) {
GetTypesResponse rsp = new GetTypesResponse();
rsp.getGetTypesReturn().addAll(m_server.getTypes());
return rsp;
}
}
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 6 của 17
ibm.com/developerWorks/vn/
developerWorks®
"Các ứng dụng Web Java: liên kết dữ liệu Axis2" không cho thấy các mã giao diện máy chủ cho
các liên kết dữ liệu khác nhau trong bài viết ấy, nhưng nếu bạn so sánh Liệt kê 3 với các phần tải
mã thực tế từ bài viết đó, bạn sẽ thấy rằng nó ăn khớp hoàn toàn với các ví dụ về bao bọc ADB và
JiBX, một lần nữa sự khác biệt chỉ do việc sử dụng các danh sách định kiểu Java 5 thay cho các
mảng.
Các lớp mô hình dữ liệu JAXB
Liệt kê 4 cho thấy một số trong các lớp mô hình dữ liệu JAXB được tạo ra bằng cách chạy
WSDL2Java (đã xóa hầu hết các lời bình luận tạo ra, ngoại trừ một vài cái để lại như là các ví dụ
đại diện). Các lớp mô hình dữ liệu được tạo ra đều giống nhau đối với máy khách và máy chủ, mặc
dù chúng được tạo ra riêng rẽ bằng cách xây dựng dự án. Các lớp được hiển thị là những lớp được
sử dụng cho cuộc gọi getBook trong cả mã máy khách trong Liệt kê 2 và mã máy chủ trong Liệt kê
3. Các chú thích (in đậm) trên mỗi định nghĩa lớp và hầu hết các định nghĩa trường cung cấp thông
tin cấu hình mà JAXB sử dụng để kiểm soát việc chuyển đổi các đối tượng thành XML và từ XML.
Liệt kê 4. Các lớp mô hình dữ liệu JAXB
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "isbn" })
@XmlRootElement(name = "getBook")
public class GetBook {
@XmlElement(required = true)
protected String isbn;
/**
* Gets the value of the isbn property.
*
* @return
*
possible object is
*
{@link String }
*
*/
public String getIsbn() {
return isbn;
}
/**
* Sets the value of the isbn property.
*
* @param value
*
allowed object is
*
{@link String }
*
*/
public void setIsbn(String value) {
this.isbn = value;
}
}
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "BookInformation",
propOrder = { "author", "title" })
public class BookInformation {
protected List<String> author;
@XmlElement(required = true)
protected String title;
@XmlAttribute(required = true)
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 7 của 17
developerWorks®
ibm.com/developerWorks/vn/
protected String type;
@XmlAttribute(required = true)
protected String isbn;
public List<String> getAuthor() {
if (author == null) {
author = new ArrayList<String>();
}
return this.author;
}
public String getTitle() {
return title;
}
public void setTitle(String value) {
this.title = value;
}
public String getType() {
return type;
}
public void setType(String value) {
this.type = value;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String value) {
this.isbn = value;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "getBookReturn" })
@XmlRootElement(name = "getBookResponse")
public class GetBookResponse {
protected BookInformation getBookReturn;
public BookInformation getGetBookReturn() {
return getBookReturn;
}
public void setGetBookReturn(BookInformation value) {
this.getBookReturn = value;
}
}
Chú thích @XmlAccessorType được sử dụng ở mức gói hoặc mức lớp để kiểm soát các giá trị được
truy cập từ lớp đó như thế nào — tất cả các trường, tất cả các thuộc tính với các phương thức truy
cập get/set, chỉ các trường và các thuộc tính công cộng (public), hay là chỉ khi được chỉ rõ bởi một
chú thích riêng. Chú thích @XmlType được sử dụng trên một định nghĩa lớp hoặc định nghĩa kiểu
bảng kê (enum) khớp với một kiểu lược đồ để báo cho JAXB biết tên và vùng tên của kiểu lược đồ
(nếu có), thứ tự của các giá trị trong việc biểu diễn kiểu và có thể cả cách để xây dựng các cá thể
của lớp khi sử dụng phương thức nhà máy. Chú thích @XmlRootElement được sử dụng trên một định
nghĩa lớp hoặc định nghĩa kiểu bảng kê khớp với một định nghĩa phần tử toàn cục để cung cấp tên
và vùng tên của phần tử toàn cục này. Các chú thích @XmlElement và @XmlAttribute được sử dụng
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 8 của 17
ibm.com/developerWorks/vn/
developerWorks®
với các giá trị (như là các trường hay như là các phương thức thuộc tính JavaBean) để cung cấp
tên phần tử hoặc thuộc tính và các đặc điểm khác.
Tất cả các chú thích được JAXB sử dụng có trong gói javax.xml.bind.annotation, bao gồm các
chú thích khác ngoài những chú thích được sử dụng trong mã đã sinh ra cho ví dụ đơn giản này.
JAXB hỗ trợ cả việc tạo mã từ các lược đồ, giống như trong trường hợp này lẫn bắt đầu từ mã. Một
số trong các chú thích và các tùy chọn (ví dụ như những cái làm việc với các nhà máy đối tượng và
với các phương thức tuần tự hóa/ không tuần tự hóa (serializer/Deserializer)) chỉ được sử dụng khi
bắt đầu từ mã.
Các vấn đề JAXB trong Axis2
WSDL2Java gọi trình biên dịch liên kết XJC có chứa trong triển khai thực hiện tham chiếu JAXB để
tạo mã mô hình dữ liệu, do đó, trong hầu hết các khía cạnh việc tạo mã mô hình dữ liệu không phụ
thuộc vào Axis2. Bạn sẽ tạo ra cùng một mô hình dữ liệu nếu bạn đã chạy trình biên dịch liên kết
JAXB XJC trực tiếp trên các lược đồ được dịch vụ Web sử dụng. Thật không may, sự phối hợp nối
ghép giữa WSDL2Java và XJC không phải luôn luôn hoàn hảo và dẫn đến một số vấn đề.
Một vấn đề liên quan đến các lược đồ được cấu trúc như thế nào trong các tài liệu WSDL. Dạng
ban đầu của WSDL cho dịch vụ thư viện đã sử dụng chỉ một tài liệu, tài liệu này kết hợp hai lược
đồ riêng rẽ, một cho các phần tử thông báo WSDL và một cho dữ liệu ứng dụng (thông tin về cuốn
sách và kiểu). Lược đồ phần tử thông báo đã nhập khẩu lược đồ dữ liệu ứng dụng thông qua tham
chiếu vùng tên, như WSDL đã cho phép. WSDL này với các lược đồ nhúng trong nó, làm việc tốt
với WSDL2Java khi sử dụng liên kết dữ liệu ADB hoặc JiBX, nhưng với JAXB nó gây ra một lỗi
ngoại lệ trong lúc xử lý các lược đồ. Việc tách ra lược đồ dữ liệu ứng dụng thành một tệp riêng và
chỉ rõ tên tệp khi nhập khẩu lược đồ cho phép WSDL2Java xử lý chính xác lược đồ bằng cách sử
dụng liên kết JAXB.
Vấn đề khác là XJC cung cấp một số các tùy chọn tạo mã, cũng như rất nhiều tùy chỉnh để kiểm
soát các chi tiết của việc tạo mã cho các thành phần lược đồ cụ thể — nhưng WSDL2Java không
cung cấp bất kỳ cách nào để chuyển các tùy chọn này hoặc các tuỳ chỉnh này cho XJC, vì thế việc
tạo mã luôn luôn chạy với các giá trị cài đặt mặc định. Nếu bạn cần phải sử dụng bất kỳ các tùy
chọn hoặc tuỳ chỉnh tạo mã nào, bạn có thể phải chạy XJC tách riêng với WSDL2Java. Thật không
may, không có cách nào để sử dụng một mô hình dữ liệu JAXB được tạo ra riêng biệt trong việc tạo
mã với WSDL2Java. Nếu bạn cần phải sử dụng một mô hình dữ liệu JAXB có tùy chỉnh, thì cách
tiếp cận tốt nhất của bạn có thể sẽ là chạy WSDL2Java để tạo ra mô hình dữ liệu JAXB riêng của
nó, sau đó thay thế vào các lớp mô hình dữ liệu được tạo ra riêng rẽ của bạn và viết mã sửa đổi
bằng tay nếu cần thiết để nối tạm tất cả mọi thứ cùng nhau. Ngoài ra, bạn có thể sử dụng JAX-WS,
như được mô tả trong phần tiếp theo, cho phép bạn bỏ qua hoàn toàn việc sử dụng WSDL2Java,
nhưng có một số hạn chế lớn.
Sử dụng JAX-WS trong Axis2
Trong khi JAXB có thể được sử dụng như là một kỹ thuật liên kết dữ liệu thay thế khác cho Axis2,
thì JAX-WS có những điểm khác biệt sâu sắc hơn nhiều. JAX-WS là một cách tiếp cận khác hoàn
toàn để định nghĩa các dịch vụ Web và nó hoàn toàn thay thế cấu hình phía máy chủ và phía
máy khách của Axis2 tiêu chuẩn. Bạn tạo mã JAX-WS từ WSDL bằng cách sử dụng một công
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 9 của 17
developerWorks®
ibm.com/developerWorks/vn/
cụ WsImport, có chứa trong triển khai thực hiện tham khảo JAX-WS (phải tải xuống tách biệt với
Axis2, xem Tài nguyên), chứ không dùng WSDL2Java. Ngay cả cơ cấu triển khai cũng khác với
cách tiếp cận tệp-AAR thường được sử dụng với Axis2.
Phần tải mã cung cấp một phiên bản thứ hai của cùng một ứng dụng ví dụ được sử dụng trước đó,
ví dụ này được sửa đổi để giải thích cách sử dụng JAX-WS trong Axis2. Mã của nó nằm trong thư
mục jaxws của phần tải về này và nó có WSDL, build.properties và build.xml riêng của mình. WSDL
cho phiên bản JAX-WS này về cơ bản giống như phiên bản đã sử dụng cho JAXB, được hiển thị
trong Liệt kê 1. Sự khác biệt chính trong WSDL là nó sử dụng một lược đồ nhúng cho dữ liệu ứng
dụng, không làm việc được với WSDL2Java khi sử dụng liên kết dữ liệu JAXB.
Khi bạn tạo mã từ WSDL bằng cách sử dụng công cụ WsImport của JAX-WS, bạn nhận được một
mô hình dữ liệu và các lớp trình bao bọc JAXB giống như khi bạn sử dụng WSDL2Java cho việc tạo
mã JAXB. Các sự khác biệt ở trong mã liên kết, mã này trong trường hợp của JAX-WS bao gồm
một giao diện dịch vụ được tạo ra và một lớp của trình xây dựng dịch vụ (service-builder) của phía
máy khách. Lớp giao diện, hiển thị trong Liệt kê 5 (được định dạng lại một chút và chỉ để lại một
chú thích phương thức làm ví dụ), định nghĩa các phương thức ăn khớp với các hoạt động được
định nghĩa trong WSDL. Cả hai mã máy khách và mã máy chủ sử dụng giao diện này. Các chú
thích dài trong giao diện cung cấp tất cả thông tin cấu hình cần thiết mà JAX-WS sử dụng để liên
kết giao diện tới một dịch vụ và các phương thức giao diện tới các hoạt động của dịch vụ đó.
Liệt kê 5. Giao diện dịch vụ được tạo ra của JAX-WS
@WebService(name = "Library", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
@XmlSeeAlso({
ObjectFactory.class
})
public interface Library
{
/**
*
* @param isbn
* @return
*
returns com.sosnoski.ws.library.jaxws.BookInformation
*/
@WebMethod(action = "urn:getBook")
@WebResult(name = "getBookReturn",
targetNamespace = "http://ws.sosnoski.com/library/wsdl")
@RequestWrapper(localName = "getBook",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetBook")
@ResponseWrapper(localName = "getBookResponse",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetBookResponse")
public BookInformation getBook(
@WebParam(name = "isbn", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
String isbn);
@WebMethod(action = "urn:getBooksByType")
@WebResult(name = "getBooksByTypeReturn",
targetNamespace = "http://ws.sosnoski.com/library/wsdl")
@RequestWrapper(localName = "getBooksByType",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetBooksByType")
@ResponseWrapper(localName = "getBooksByTypeResponse",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetBooksByTypeResponse")
public List<BookInformation> getBooksByType(
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 10 của 17
ibm.com/developerWorks/vn/
developerWorks®
@WebParam(name = "type", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
String type);
@WebMethod(action = "urn:getTypes")
@WebResult(name = "getTypesReturn",
targetNamespace = "http://ws.sosnoski.com/library/wsdl")
@RequestWrapper(localName = "getTypes",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetTypes")
@ResponseWrapper(localName = "getTypesResponse",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.GetTypesResponse")
public List<TypeInformation> getTypes();
@WebMethod(action = "urn:addBook")
@WebResult(name = "addBookReturn",
targetNamespace = "http://ws.sosnoski.com/library/wsdl")
@RequestWrapper(localName = "addBook",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.AddBook")
@ResponseWrapper(localName = "addBookResponse",
targetNamespace = "http://ws.sosnoski.com/library/wsdl",
className = "com.sosnoski.ws.library.jaxws.AddBookResponse")
public boolean addBook(
@WebParam(name = "type", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
String type,
@WebParam(name = "isbn", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
String isbn,
@WebParam(name = "author",
targetNamespace = "http://ws.sosnoski.com/library/wsdl")
List<String> author,
@WebParam(name = "title", targetNamespace = "http://ws.sosnoski.com/library/wsdl")
String title)
throws AddDuplicateFault
;
}
Công cụ WsImport nhận ra WSDL được cung cấp là khớp với quy ước "được bao bọc" và tự động
tạo ra một giao diện dịch vụ không được bao bọc. Bạn có thể thấy tác dụng của điều này trong Liệt
kê 5 theo cách các phương thức lấy các giá trị riêng lẻ làm các tham số đầu vào và trả về trực tiếp
bất kỳ kiểu nào thích hợp, thay vì sử dụng một tầng các đối tượng bao bọc (mặc dù các đối tượng
của trình bao bọc vẫn được tạo ra và được sử dụng sau hậu trường trong thời gian chạy JAX-WS).
Mã được cung cấp một lần nữa đưa ra một triển khai thực hiện thực tế của cả dịch vụ lẫn máy
khách thử nghiệm. Để thử nghiệm nó, bạn cần phải chỉnh sửa tệp build.properties được cung cấp để
thiết lập đường dẫn cho cả bản cài đặt Axis2 của bạn lẫn bản cài đặt thực hiện tham khảo JAX-WS
(xem Tài nguyên). Khi chỉnh sửa xong, hãy gõ ant trong một bàn điều khiển mở tới thư mục jaxws
để chạy tạo mã JAX-WS từ WSDL, biên dịch mã được cung cấp và xây dựng một tệp JAR cho việc
triển khai máy chủ. Để chạy máy khách thử nghiệm, hãy sao chép tệp JAR đã tạo ra tới thư mục
WEB-INF/servicejars của bản cài đặt Axis2 của bạn và sau đó gõ ant run trong bàn điều khiển.
Cách sử dụng JAX-WS phía máy khách
Liệt kê 6 cho thấy toàn bộ mã máy khách thử nghiệm. Nếu bạn so sánh mã này với Liệt kê 2, bạn
sẽ thấy sự khác biệt giữa một giao diện được bao bọc và không được bao bọc, với giao diện không
được bao bọc thân thiện với lập trình viên.
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 11 của 17
developerWorks®
ibm.com/developerWorks/vn/
Liệt kê 6. Mã máy khách thử nghiệm JAX-WS
public class WebServiceClient
{
public static void main(String[] args) throws Exception {
// check for required command line parameters
if (args.length < 3) {
System.out.println("Usage:\n java " +
"com.sosnoski.ws.library.jaxws.WebServiceClient host port path");
System.exit(1);
}
// create the client stub
JaxwsLibrary service = new JaxwsLibrary();
Library stub = service.getLibrary();
// set the actual endpoint address
String target = "http://" + args[0] + ":" + args[1] + args[2];
System.out.println("Connecting to " + target);
BindingProvider provider = (BindingProvider)stub;
provider.getRequestContext(). put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
target);
// retrieve a book directly
String isbn = "0061020052";
BookInformation book = stub.getBook(isbn);
if (book == null) {
System.out.println("No book found with ISBN '" + isbn + '\'');
} else {
System.out.println("Retrieved '" + book.getTitle() + '\'');
}
// retrieve the list of types defined
List<TypeInformation> types = stub.getTypes();
System.out.println("Retrieved " + types.size() + " types:");
for (int i = 0; i < types.size(); i++) {
TypeInformation type = types.get(i);
System.out.println(" '" + type.getName() + "' with " +
type.getCount() + " books");
}
// add a new book
String title = "The Dragon Never Sleeps";
isbn = "0445203498";
try {
List<String> authors = new ArrayList<String>();
authors.add("Cook, Glen");
stub.addBook("scifi", isbn, authors, title);
System.out.println("Added '" + title + '\'');
title = "This Should Not Work";
stub.addBook("scifi", isbn, authors, title);
System.out.println("Added duplicate book - should not happen!");
} catch (AddDuplicateFault e) {
System.out.println("Failed adding '" + title +
"' with ISBN '" + isbn + "' - matches existing title '" +
e.getFaultInfo().getBook().getTitle() + '\'');
}
// get all books of a type
List<BookInformation> books = stub.getBooksByType("scifi");
System.out.println("Retrieved " + books.size() + " books of type 'scifi':");
for (int i = 0; i < books.size(); i++) {
System.out.println(" '" + books.get(i).getTitle() + '\'');
}
}
}
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 12 của 17
ibm.com/developerWorks/vn/
developerWorks®
Việc xử lý phía máy khách JAX-WS nói chung được trông chờ là có truy cập tới WSDL dịch vụ
trong thời gian chạy và nó sử dụng WSDL để khởi tạo liên kết máy chủ. Nếu bạn biết WSDL cho
dịch vụ đích sẽ luôn luôn có sẵn trực tiếp từ máy chủ trong thời gian chạy và máy chủ sẽ luôn ở
cùng một địa chỉ, bạn có thể chỉ cần cung cấp URL của WSDL cho WsImport và bắt nó mã hóa
cứng URL vào mã được tạo ra. Đối với hầu hết công việc quan trọng, tốt hơn là sử dụng một bản
sao cục bộ của WSDL và sau đó ghi đè lên địa chỉ dịch vụ đích trong thời gian chạy nếu nó khác
với địa chỉ có trong WSDL. Tệp xây dựng được cung cấp dùng cách tiếp cận này và một phần của
mã trong Liệt kê 6 được hiển thị bằng in đậm giải thích cách bạn có thể thay đổi địa chỉ dịch vụ
trong thời gian chạy mà không thay đổi WSDL.
Cách sử dụng JAX-WS phía máy chủ
Phiên bản JAX-WS của mã phía máy chủ được hiển thị trong Liệt kê 7. Chú thích @WebService trên
lớp thực hiện (được in đậm) liên kết đoạn mã thực hiện với một giao diện dịch vụ Web cụ thể. Chú
thích này trên lớp thực hiện cho phép bạn ghi đè các giá trị cài đặt từ chú thích tương ứng trong
giao diện dịch vụ được tạo ra (Liệt kê 5). Trong trường hợp này, chú thích thiết lập tên dịch vụ và
tên cổng và cũng đưa ra vị trí của định nghĩa dịch vụ WSDL (mà Axis2 chờ đợi hoặc là đường dẫn
tương đối so với gốc là đường dẫn lớp, hoặc là một URL tuyệt đối).
Liệt kê 7. Mã máy chủ JAX-WS
@javax.jws.WebService(endpointInterface="com.sosnoski.ws.library.jaxws.Library",
portName="library",
targetNamespace="http://ws.sosnoski.com/library/wsdl",
wsdlLocation="com/sosnoski/ws/library/jaxws/library.wsdl",
serviceName="JaxwsLibrary")
public class JaxwsLibraryImpl implements Library
{
private final BookServer m_server;
public JaxwsLibraryImpl() {
m_server = new BookServer();
}
public boolean addBook(String type, String isbn, List<String> author, String title)
throws AddDuplicateFault {
BookInformation prior = m_server.getBook(isbn);
if (prior == null) {
BookInformation book = new BookInformation();
book.getAuthor().addAll(author);
book.setIsbn(isbn);
book.setTitle(title);
book.setType(type);
return m_server.addBook(book);
} else {
AddDuplicate ad = new AddDuplicate();
ad.setBook(prior);
AddDuplicateFault e =
new AddDuplicateFault("Book already present with matching ISBN", ad);
throw e;
}
}
public BookInformation getBook(String isbn) {
return m_server.getBook(isbn);
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 13 của 17
developerWorks®
ibm.com/developerWorks/vn/
}
public List<BookInformation> getBooksByType(String type) {
return m_server.getBooksByType(type);
}
public List<TypeInformation> getTypes() {
return m_server.getTypes();
}
}
Phần còn lại của đoạn mã trong Liệt kê 7 chỉ là một phiên bản không được bao bọc của phiên bản
(được bao bọc) được hiển thị trong ví dụ JAXB trong Liệt kê 3.
Các vấn đề JAX-WS trong Axis2
Axis2 làm việc rất tốt ở các điểm cơ bản về xử lý JAX-WS, nhưng nó có một số hạn chế. Đáng kể
nhất là thiếu sự hỗ trợ cho WS-Security hoặc các công nghệ mở rộng các dịch vụ Web khác khi bạn
sử dụng JAX-WS trong Axis2 (mặc dù các máy chủ ứng dụng đã xây dựng xung quanh Axis2 có
thể thực hiện cách cấu hình và sử dụng WS-Security riêng của chúng). Đây là một hạn chế nghiêm
trọng cho các ứng dụng doanh nghiệp và không có bất kỳ các lợi thế bù trừ nào, ngoại trừ một
cách tiếp cận cấu hình đơn giản hơn một chút, và đó có vẻ không phải là lý do để sử dụng JAX-WS
trong Axis2 ở thời điểm hiện nay.
Tiến lên từ Axis2
Trong bài viết này, bạn đã thấy những điều cơ bản của việc sử dụng các tiêu chuẩn Java JAXB 2.x
và JAX-WS 2.x với Axis2. Sự hỗ trợ JAXB trong Axis2 có một số hạn chế, nhưng ít nhất với các
lược đồ đơn giản không yêu cầu các tùy chỉnh nó cung cấp một thay thế có ích cho các cách tiếp
cận liên kết dữ liệu khác mà Axis2 hỗ trợ. Sự hỗ trợ JAX-WS bị hạn chế nhiều hơn và hiện tại chỉ có
ích với các dịch vụ đơn giản không đòi hỏi WS-Security hoặc bất kỳ chức năng giá trị gia tăng nào
khác.
Cho đến nay các bài viết trong loạt bài này đã tập trung vào khung công tác Axis2 của Apache.
Trình bày về JAXB và JAX-WS đã tạo ra một điểm xuất phát tuyệt vời để xem xét một số các
khung công tác các dịch vụ Web Java mã nguồn mở khác cũng hỗ trợ các tiêu chuẩn này. Bài viết
tháng tới sẽ xem xét làm việc với khung công tác Các dịch vụ Web Metro được Sun phát triển kết
hợp với việc thực hiện tham khảo JAXB và JAX-WS. Nó cũng sẽ đi sâu thêm vào cách sử dụng và
các tính năng của JAX-WS.
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 14 của 17
ibm.com/developerWorks/vn/
developerWorks®
Các tải về
Mô tả
Tên
Kích thước
Source code for this article
j-jws8.zip
57KB
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 15 của 17
developerWorks®
ibm.com/developerWorks/vn/
Tài nguyên
Học tập
• Apache Axis2: Trang chủ Axis 2 có thông tin về phát triển và trạng thái của Axis2, cùng với
các đường liên kết với các danh sách gửi thư, theo dõi vấn đề và các phần tải về.
• "Các dịch vụ Web Java, Phần 3: Liên kết dữ liệu Axis2" (Dennis Sosnoski, developerWorks,
07. 2007): Bài viết này bàn về các tùy chọn liên kết dữ liệu chủ yếu cho Axis2. Mã được sử
dụng cho bài viết đó là cơ sở của đoạn mã mẫu cho mục này.
• Thực hiện tham khảo JAXB: Đây là trang chủ dành cho thực hiện tham khảo JAXB.
• Thực hiện tham khảo JAX-WS: Đây là trang chủ dành cho thực hiện tham khảo JAX-WS.
• Axis2 Jira: Trang Web này là nơi để tìm kiếm các vấn đề được biết đến với Axis2. Đối với các
vấn đề liên quan đến các lựa chọn liên kết dữ liệu thay thế, kể cả JAXB, hãy xem các loại
hình thành phần liên kết dữ liệu (Databinding). Đối với các vấn đề JAX-WS, hãy xem loại hình
thành phần jaxws.
• Duyệt qua hiệu sách công nghệ để tìm các sách về chủ đề này và các chủ đề kỹ thuật khác.
• Vùng công nghệ Java của developerWorks: Tìm hàng trăm bài viết về mọi khía cạnh của lập
trình Java.
Lấy sản phẩm và công nghệ
• Apache Axis2: Tải về bản phát hành Axis2 mới nhất
• Thực hiện tham khảo JAX-WS: Tải về thực hiện tham khảo JAX-WS.
• Tải về phiên bản đánh giá sản phẩm của IBM hoặc khám phá dùng thử trực tuyến trong IBM
SOA Sandbox và thực hành các công cụ phát triển ứng dụng và các sản phẩm phần mềm
trung gian từ DB2®, Lotus®, Rational®, Tivoli® và WebSphere®.
Thảo luận
• Dành hết tâm trí cho cộng đồng My developerWorks.
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 16 của 17
ibm.com/developerWorks/vn/
developerWorks®
Đôi nét về tác giả
Dennis Sosnoski
Dennis Sosnoski là một nhà tư vấn và nhà trợ giúp đào tạo chuyên về các dịch vụ
Web và SOA dựa trên-Java. Kinh nghiệm phát triển phần mềm chuyên nghiệp của ông
trải suốt hơn 30 năm qua, với một thập kỉ cuối tập trung vào các công nghệ XML và
Java phía máy chủ. Dennis là nhà phát triển hàng đầu về dụng cụ liên kết dữ liệu XML
JiBX mã nguồn mở, cũng là một người có duyên nợ với khung công tác của các dịch
vụ Web Apache Axis2. Ông cũng là một trong những thành viên của nhóm chuyên gia
đặc tả kỹ thuật của Jax-WS 2.0 và JAXB 2.0. Xem trang web của ông để có thông tin
về các dịch vụ đào tạo và tư vấn của ông.
© Copyright IBM Corporation 2009
(www.ibm.com/legal/copytrade.shtml)
Nhẫn hiệu đăng ký
(www.ibm.com/developerworks/vn/ibm/trademarks/)
Các dịch vụ Web Java: JAXB và JAX-WS trong Axis2
Trang 17 của 17