Sự khác biệt giữa Giao diện nhà cung cấp dịch vụ (SPI) và Giao diện lập trình ứng dụng (API) là gì?
Cụ thể hơn, đối với các thư viện Java, điều gì làm cho chúng trở thành API và / hoặc SPI?
Sự khác biệt giữa Giao diện nhà cung cấp dịch vụ (SPI) và Giao diện lập trình ứng dụng (API) là gì?
Cụ thể hơn, đối với các thư viện Java, điều gì làm cho chúng trở thành API và / hoặc SPI?
Câu trả lời:
Nói cách khác, API cho bạn biết một lớp / phương thức cụ thể làm gì cho bạn và SPI cho bạn biết những gì bạn phải làm để tuân thủ.
Thông thường API và SPI là riêng biệt. Ví dụ, trong JDBC , Driver
lớp là một phần của SPI: Nếu bạn chỉ muốn sử dụng JDBC, bạn không cần sử dụng trực tiếp, nhưng mọi người thực hiện trình điều khiển JDBC phải thực hiện lớp đó.
Đôi khi chúng trùng nhau, tuy nhiên. Các Connection
giao diện là cả SPI và API: Bạn sử dụng nó thường xuyên khi bạn sử dụng một trình điều khiển JDBC và nó cần phải được thực hiện bởi các nhà phát triển của trình điều khiển JDBC.
@SomeAnnotation
vào lớp của mình để được nó chọn bởi một số khung, thì lớp chú thích này SomeAnnotation.class
có được coi là một phần của SPI không, mặc dù tôi không mở rộng hoặc triển khai về mặt kỹ thuật?
Từ Java hiệu quả, tái bản lần 2 :
Khung nhà cung cấp dịch vụ là một hệ thống trong đó nhiều nhà cung cấp dịch vụ triển khai một dịch vụ và hệ thống này cung cấp các triển khai cho khách hàng của mình, tách chúng ra khỏi các triển khai.
Có ba thành phần thiết yếu của khung nhà cung cấp dịch vụ: giao diện dịch vụ, nhà cung cấp thực hiện; API đăng ký nhà cung cấp, mà hệ thống sử dụng để đăng ký triển khai, cho phép khách hàng truy cập vào chúng; và API truy cập dịch vụ mà khách hàng sử dụng để lấy phiên bản dịch vụ. API truy cập dịch vụ thường cho phép nhưng không yêu cầu khách hàng chỉ định một số tiêu chí để chọn nhà cung cấp. Trong trường hợp không có thông số kỹ thuật như vậy, API sẽ trả về một thể hiện của việc triển khai mặc định. API truy cập dịch vụ là nhà máy tĩnh linh hoạt của nhà mạng, hình thành nên cơ sở của khung nhà cung cấp dịch vụ.
Thành phần thứ tư tùy chọn của khung nhà cung cấp dịch vụ là giao diện nhà cung cấp dịch vụ, nhà cung cấp thực hiện để tạo các phiên bản triển khai dịch vụ của họ. Trong trường hợp không có giao diện nhà cung cấp dịch vụ, việc triển khai được đăng ký theo tên lớp và được khởi tạo một cách phản xạ (Mục 53). Trong trường hợp của JDBC, Connection đóng vai trò là một phần của giao diện dịch vụ, DriverManager.registerDriver là API đăng ký nhà cung cấp, DriverManager.getConnection là API truy cập dịch vụ và Driver là giao diện nhà cung cấp dịch vụ.
Có rất nhiều biến thể của mẫu khung nhà cung cấp dịch vụ. Ví dụ: API truy cập dịch vụ có thể trả về giao diện dịch vụ phong phú hơn giao diện yêu cầu của nhà cung cấp, sử dụng mẫu Bộ điều hợp [Gamma95, p. 139]. Đây là một cách thực hiện đơn giản với giao diện nhà cung cấp dịch vụ và nhà cung cấp mặc định:
// Service provider framework sketch
// Service interface
public interface Service {
... // Service-specific methods go here
}
// Service provider interface
public interface Provider {
Service newService();
}
// Noninstantiable class for service registration and access
public class Services {
private Services() { } // Prevents instantiation (Item 4)
// Maps service names to services
private static final Map<String, Provider> providers =
new ConcurrentHashMap<String, Provider>();
public static final String DEFAULT_PROVIDER_NAME = "<def>";
// Provider registration API
public static void registerDefaultProvider(Provider p) {
registerProvider(DEFAULT_PROVIDER_NAME, p);
}
public static void registerProvider(String name, Provider p){
providers.put(name, p);
}
// Service access API
public static Service newInstance() {
return newInstance(DEFAULT_PROVIDER_NAME);
}
public static Service newInstance(String name) {
Provider p = providers.get(name);
if (p == null)
throw new IllegalArgumentException(
"No provider registered with name: " + name);
return p.newService();
}
}
Sự khác biệt giữa API và SPI xuất hiện khi API cung cấp thêm một số triển khai cụ thể. Trong trường hợp đó, nhà cung cấp dịch vụ phải triển khai một vài API (được gọi là SPI)
Một ví dụ là JNDI:
JNDI cung cấp giao diện và một số lớp để tra cứu ngữ cảnh. Cách mặc định để tra cứu một bối cảnh được cung cấp trong IntialContext. Lớp này trong nội bộ sẽ sử dụng các giao diện SPI (sử dụng NamingManager) để triển khai cụ thể của nhà cung cấp.
Xem Kiến trúc JNDI dưới đây để hiểu rõ hơn.
API là viết tắt của Giao diện lập trình ứng dụng, trong đó API là phương tiện để truy cập dịch vụ / chức năng được cung cấp bởi một loại phần mềm hoặc nền tảng nào đó.
SPI là viết tắt của Giao diện nhà cung cấp dịch vụ, trong đó SPI là cách để tiêm, mở rộng hoặc thay đổi hành vi cho phần mềm hoặc nền tảng.
API thường nhắm mục tiêu cho khách hàng truy cập dịch vụ và nó có các thuộc tính sau:
-> API là một cách lập trình truy cập dịch vụ để đạt được một hành vi hoặc đầu ra nhất định
-> Từ quan điểm tiến hóa API, việc bổ sung không có vấn đề gì với khách hàng
-> Nhưng API đã từng được khách hàng sử dụng một lần, nó không thể (và không nên) bị thay đổi / xóa trừ khi có một thông tin liên lạc phù hợp, vì sự suy giảm hoàn toàn của kỳ vọng khách hàng
SPI trên phần khác được nhắm mục tiêu cho các nhà cung cấp và có các thuộc tính sau:
-> SPI là cách mở rộng / thay đổi hành vi của phần mềm hoặc nền tảng (lập trình so với lập trình)
-> Tiến hóa SPI khác với tiến hóa API, trong việc loại bỏ SPI không phải là vấn đề
-> Bổ sung giao diện SPI sẽ gây ra sự cố và có thể phá vỡ các triển khai hiện có
Để giải thích thêm bấm vào đây: Giao diện nhà cung cấp dịch vụ
Câu hỏi thường gặp của NetBeans: SPI là gì? Nó khác với API như thế nào?
API là một thuật ngữ chung - từ viết tắt của Giao diện lập trình ứng dụng - nó có nghĩa là một cái gì đó (trong Java, thường là một số lớp Java) một phần mềm lộ ra, cho phép các phần mềm khác giao tiếp với nó.
SPI là viết tắt của Giao diện nhà cung cấp dịch vụ. Nó là tập hợp con của tất cả những thứ có thể là API cụ thể cho các tình huống trong đó thư viện đang cung cấp các lớp được ứng dụng (hoặc thư viện API) gọi và thường thay đổi những thứ mà ứng dụng có thể làm.
Ví dụ cổ điển là JavaMail. API của nó có hai mặt:
- Phía API - mà bạn gọi nếu bạn đang viết ứng dụng thư khách hoặc muốn đọc hộp thư
- Phía SPI nếu bạn đang cung cấp trình xử lý giao thức dây để cho phép JavaMail nói chuyện với một loại máy chủ mới, chẳng hạn như máy chủ tin tức hoặc IMAP
Người dùng API hiếm khi cần xem hoặc nói chuyện với các lớp SPI và ngược lại.
Trong NetBeans, khi bạn thấy thuật ngữ SPI, người ta thường nói về các lớp mà một mô-đun có thể tiêm trong thời gian chạy cho phép NetBeans thực hiện những điều mới. Ví dụ, có một SPI chung để thực hiện các hệ thống kiểm soát phiên bản. Các mô-đun khác nhau cung cấp việc triển khai SPI đó cho CVS, Subversion, Mercurial và các hệ thống kiểm soát sửa đổi khác. Tuy nhiên, mã liên quan đến các tệp (phía API) không cần quan tâm nếu có hệ thống kiểm soát phiên bản hay nó là gì.
Có một khía cạnh dường như không được làm nổi bật nhiều nhưng rất quan trọng để hiểu lý do đằng sau sự tồn tại của phân tách API / SPI.
Việc phân tách API / SPI chỉ được yêu cầu khi nền tảng dự kiến sẽ phát triển. Nếu bạn viết API và "biết" thì nó sẽ không yêu cầu bất kỳ cải tiến nào trong tương lai, không có lý do thực sự nào để chia mã của bạn thành hai phần (ngoài việc thiết kế đối tượng sạch).
Nhưng điều này gần như không bao giờ xảy ra và mọi người cần có quyền tự do phát triển API cùng với các yêu cầu trong tương lai - theo cách tương thích ngược.
Lưu ý rằng tất cả các giả định ở trên bạn đang xây dựng nền tảng mà người khác sử dụng và / hoặc mở rộng chứ không phải API của riêng bạn nơi bạn có tất cả mã khách hàng được kiểm soát và do đó có thể cấu trúc lại theo cách bạn cần.
Hãy hiển thị nó trên một trong những đối tượng Java nổi tiếng Collection
và Collections
.
API: Collections
là một tập hợp các phương thức tĩnh tiện ích. Thông thường các lớp đại diện cho đối tượng API được định nghĩa vì final
nó đảm bảo (tại thời gian biên dịch) mà không khách hàng nào có thể "thực hiện" đối tượng đó và họ có thể phụ thuộc vào "gọi" các phương thức tĩnh của nó, ví dụ
Collections.emptySet();
Vì tất cả các máy khách đang "gọi" nhưng không "thực hiện" , các tác giả của JDK có thể tự do thêm các phương thức mới vào Collections
đối tượng trong phiên bản tương lai của JDK. Họ có thể chắc chắn rằng nó không thể phá vỡ bất kỳ khách hàng nào, ngay cả khi có thể có hàng triệu lần sử dụng.
SPI: Collection
là một giao diện ngụ ý rằng bất kỳ ai cũng có thể thực hiện phiên bản của chính nó. Do đó, các tác giả của JDK không thể thêm các phương thức mới vào nó vì nó sẽ phá vỡ tất cả các khách hàng đã viết Collection
triển khai của riêng họ (*).
Thông thường khi cần thêm phương thức bổ sung, giao diện mới, ví dụ như Collection2
mở rộng phương thức cũ cần được tạo. Sau đó, khách hàng SPI có thể quyết định có nên chuyển sang phiên bản SPI mới hay không và thực hiện phương thức bổ sung của nó hoặc có nên gắn bó với phiên bản cũ hơn hay không.
Bạn có thể đã nhìn thấy điểm. Nếu bạn kết hợp cả hai phần lại với nhau thành một lớp duy nhất, API của bạn sẽ bị chặn khỏi mọi bổ sung. Đó cũng là lý do tại sao các API và Khung Java tốt không phơi bày abstract class
vì chúng sẽ ngăn chặn sự tiến hóa trong tương lai của chúng đối với khả năng tương thích ngược.
Nếu một cái gì đó vẫn chưa rõ ràng, tôi khuyên bạn nên kiểm tra trang này giải thích chi tiết ở trên.
(*) Lưu ý rằng điều này chỉ đúng cho đến khi Java 1.8 giới thiệu khái niệm về các default
phương thức được định nghĩa trong một giao diện.
Tôi cho rằng một vị trí SPI vào một hệ thống lớn hơn bằng cách triển khai các tính năng nhất định của API và sau đó đăng ký chính nó là có sẵn thông qua các cơ chế tra cứu dịch vụ. API được sử dụng trực tiếp bởi mã ứng dụng của người dùng cuối, nhưng có thể tích hợp các thành phần SPI. Đó là sự khác biệt giữa đóng gói và sử dụng trực tiếp.
Giao diện nhà cung cấp dịch vụ là giao diện dịch vụ mà tất cả các nhà cung cấp phải thực hiện. Nếu không có triển khai nhà cung cấp hiện tại nào phù hợp với bạn, bạn cần viết nhà cung cấp dịch vụ của riêng bạn (triển khai giao diện dịch vụ) và đăng ký ở đâu đó (xem bài đăng hữu ích của Roman).
Nếu bạn đang sử dụng lại việc triển khai giao diện dịch vụ hiện có của nhà cung cấp, về cơ bản, bạn đang sử dụng API của nhà cung cấp cụ thể đó, bao gồm tất cả các phương thức giao diện dịch vụ cộng với một vài phương thức công khai. Nếu bạn đang sử dụng các phương pháp API nhà cung cấp ngoài SPI, bạn đang sử dụng các tính năng cụ thể của nhà cung cấp.
Trong thế giới Java, các công nghệ khác nhau có nghĩa là được mô đun hóa và "cắm được" vào một máy chủ ứng dụng. Có một sự khác biệt giữa
Hai ví dụ về các công nghệ như vậy là JTA (trình quản lý giao dịch) và JCA (bộ điều hợp cho JMS hoặc cơ sở dữ liệu). Nhưng có những người khác.
Người triển khai công nghệ có thể cắm như vậy sau đó phải triển khai SPI để có thể cắm trong ứng dụng. máy chủ và cung cấp API được sử dụng bởi ứng dụng người dùng cuối. Một ví dụ từ JCA là giao diện ManagedConnection là một phần của SPI và Kết nối là một phần của API người dùng cuối.