Sự khác biệt giữa SPI và API?


Câu trả lời:


395
  • API là mô tả về các lớp / giao diện / phương thức / ... mà bạn gọi và sử dụng để đạt được mục tiêu và
  • SPI là mô tả về các lớp / giao diện / phương thức / ... mà bạn mở rộng và thực hiện để đạt được mục tiêu.

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 , Driverlớ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 Connectiongiao diệncả 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.


Âm thanh về đúng. chỉ là các đường giữa SPI & API có thể hơi xám vì hầu hết các API đều có các lớp / giao diện trừu tượng để người dùng thực hiện để hoàn thành công việc ...
kctang

1
@koss: API nhất? Tôi biết ý của bạn là gì, nhưng tôi không thấy những điều đó nhiều lắm.
Joachim Sauer

2
API phù hợp hơn với các nhà phát triển trong khi SPI dành cho các nhà cung cấp.
Azfar Niaz

7
@AzfarNiaz: tốt, vì các nhà cung cấp thuê các nhà phát triển để xây dựng các sản phẩm của họ, cả hai đều phù hợp với các nhà phát triển ;-)
Joachim Sauer

Trong Java, các chú thích có phải là một phần của SPI không? Ví dụ, nếu tôi phải thêm @SomeAnnotationvà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.classcó đượ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?
Adam Burley

59

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();
    }
}

3
cảm ơn vì mô tả rất hay về khung nhà cung cấp dịch vụ. Điều này sẽ hữu ích để biết. tuy nhiên, nó không mô tả rõ ràng "sự khác biệt" giữa api & spi vì vậy tôi sẽ không đánh dấu vào đây ... ;-)
kctang

23

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.

Nhập mô tả hình ảnh ở đây


22

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ụ


12

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ì.


5

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 CollectionCollections.


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ì finalnó đả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 Collectiontriể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ư Collection2mở 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 classvì 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 defaultphương thức được định nghĩa trong một giao diện.


4

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.


cảm ơn vì phản ứng chris. bất kỳ ví dụ nào về các thư viện Java (ví dụ: Servlet, JDBC, v.v.) không? ... Giống như cách nó biến chúng thành API / SPI. có thể khó hình dung sự khác biệt với mô tả một mình.
kctang

1
API là JDBC, SPI cho JDBC là giao diện trình kết nối cơ sở dữ liệu mà nhà phát triển SPI có thể sử dụng để tạo trình kết nối cơ sở dữ liệu mới mà nhà phát triển có thể chọn để sử dụng.
Chris Dennett

4

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.


2

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

  • máy chủ ứng dụng
    • [SPI]
  • công nghệ cắm
    • [API]
  • ứng dụng người dùng cuối

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.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.