ความแตกต่างระหว่าง SPI และ API หรือไม่


คำตอบ:


395
  • API คือคำอธิบายของคลาส / อินเตอร์เฟส / methods / ... ที่คุณโทรหาและใช้เพื่อให้บรรลุเป้าหมายและ
  • SPI คือคำอธิบายของคลาส / อินเตอร์เฟส / methods / ... ที่คุณขยายและนำไปใช้เพื่อให้บรรลุเป้าหมาย

API จะบอกคุณว่าคลาส / วิธีการใดที่เฉพาะเจาะจงสำหรับคุณและ SPI จะบอกคุณว่าคุณต้องทำอะไรเพื่อให้สอดคล้อง

โดยทั่วไปแล้ว API และ SPI จะแยกจากกัน ยกตัวอย่างเช่นใน JDBC ระดับเป็นส่วนหนึ่งของ SPI: ถ้าคุณเพียงแค่ต้องการใช้ JDBC คุณไม่จำเป็นต้องใช้มันโดยตรง แต่ทุกคนที่ดำเนินไดรเวอร์ JDBC ต้องใช้ชั้นเรียนที่Driver

อย่างไรก็ตามบางครั้งพวกเขาทับซ้อนกัน อินเตอร์เฟซที่เป็นทั้ง SPI และ API: คุณใช้เป็นประจำเมื่อคุณใช้ไดรเวอร์ JDBC และจะต้องมีการดำเนินการโดยนักพัฒนาของไดร์เวอร์ JDBCConnection


ฟังดูถูก เพียงว่าเส้นแบ่งระหว่าง SPI & API อาจเป็นสีเทาเล็กน้อยเนื่องจาก API ส่วนใหญ่มีคลาส / อินเทอร์เฟซที่เป็นนามธรรมสำหรับผู้ใช้เพื่อนำไปใช้ในการทำงานให้เสร็จลุล่วง ...
kctang

1
@koss: API ส่วนใหญ่? ฉันรู้ว่าคุณหมายถึงอะไร แต่ฉันไม่เห็นสิ่งเหล่านั้นมากนัก
โจอาคิมซาวเออร์

2
API มีความเกี่ยวข้องกับนักพัฒนามากขึ้นในขณะที่ SPI นั้นเกี่ยวข้องกับผู้ขาย
Azfar Niaz

7
@AzfarNiaz: กันเนื่องจากนักพัฒนาผู้ผลิตการจ้างงานที่จะสร้างผลิตภัณฑ์ของพวกเขาทั้งสองมีความเกี่ยวข้องกับนักพัฒนา ;-)
โจอาคิมซาวเออร์

ใน Java คำอธิบายประกอบเป็นส่วนหนึ่งของ SPI หรือไม่ ตัวอย่างเช่นถ้าฉันต้องเพิ่ม@SomeAnnotationคลาสของฉันเพื่อรับมันโดยกรอบบางคลาสคำอธิบายประกอบนี้SomeAnnotation.classจะถือว่าเป็นส่วนหนึ่งของ SPI แม้ว่าฉันจะไม่ขยายหรือดำเนินการในทางเทคนิคหรือไม่?
Adam Burley

59

จากEffective Java, 2nd Edition :

เฟรมเวิร์กผู้ให้บริการเป็นระบบที่ผู้ให้บริการหลายรายใช้บริการและระบบทำให้การใช้งานพร้อมใช้งานสำหรับลูกค้าของตนแยกออกจากการใช้งาน

เฟรมเวิร์กของผู้ให้บริการมีสามองค์ประกอบที่สำคัญคือส่วนต่อประสานบริการซึ่งผู้ให้บริการใช้ API การลงทะเบียนของผู้ให้บริการซึ่งระบบใช้ในการลงทะเบียนการใช้งานทำให้ลูกค้าสามารถเข้าถึงได้ และ API การเข้าถึงบริการซึ่งลูกค้าใช้เพื่อรับอินสแตนซ์ของบริการ โดยทั่วไป API การเข้าถึงบริการจะอนุญาต แต่ไม่ต้องการให้ไคลเอ็นต์ระบุเกณฑ์บางอย่างสำหรับการเลือกผู้ให้บริการ ในกรณีที่ไม่มีข้อกำหนดดังกล่าว API จะส่งคืนอินสแตนซ์ของการใช้งานเริ่มต้น Service access API เป็น“ โรงงานแบบคงที่ที่ยืดหยุ่นได้” ซึ่งเป็นพื้นฐานของเฟรมเวิร์กผู้ให้บริการ

องค์ประกอบที่สี่ที่เป็นตัวเลือกของกรอบงานผู้ให้บริการคือส่วนต่อประสานผู้ให้บริการซึ่งผู้ให้บริการจะใช้เพื่อสร้างอินสแตนซ์ของการปรับใช้บริการ ในกรณีที่ไม่มีอินเตอร์เฟสผู้ให้บริการการใช้งานจะลงทะเบียนโดยชื่อคลาสและอินสแตนซ์สะท้อนแสง (รายการ 53) ในกรณีของ JDBC การเชื่อมต่อเล่นเป็นส่วนหนึ่งของส่วนต่อประสานบริการ DriverManager.registerDriver เป็น API การลงทะเบียนของผู้ให้บริการ DriverManager.getConnection เป็น API การเข้าถึงบริการและไดรเวอร์เป็นส่วนต่อประสานผู้ให้บริการ

มีหลากหลายรูปแบบของรูปแบบเฟรมเวิร์กผู้ให้บริการ ตัวอย่างเช่น API การเข้าถึงบริการสามารถส่งคืนอินเทอร์เฟซบริการที่สมบูรณ์ยิ่งขึ้นกว่าที่จำเป็นสำหรับผู้ให้บริการโดยใช้รูปแบบอะแดปเตอร์ [Gamma95, p 139] นี่คือการใช้งานอย่างง่ายกับส่วนต่อประสานผู้ให้บริการและผู้ให้บริการเริ่มต้น:

// 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
ขอบคุณสำหรับคำอธิบายที่ดีมากในกรอบผู้ให้บริการ สิ่งนี้จะเป็นประโยชน์ในการรู้ อย่างไรก็ตามมันไม่ได้อธิบายอย่างชัดเจนว่า "ความแตกต่าง" ระหว่าง api & spi ดังนั้นฉันจะไม่ทำเครื่องหมายที่นี่ ... ;-)
kctang

23

ความแตกต่างระหว่าง API และ SPI เกิดขึ้นเมื่อ API มีการใช้งานที่เป็นรูปธรรมเพิ่มเติม ในกรณีดังกล่าวผู้ให้บริการจะต้องใช้ API บางตัว (เรียกว่า SPI)

ตัวอย่างคือ JNDI:

JNDI จัดเตรียมอินเตอร์เฟสและบางคลาสสำหรับการค้นหาบริบท วิธีการเริ่มต้นในการค้นหาบริบทมีให้ใน IntialContext คลาสนี้ภายในจะใช้อินเทอร์เฟซ SPI (โดยใช้ NamingManager) สำหรับการใช้งานเฉพาะของผู้ให้บริการ

ดูสถาปัตยกรรม JNDI ด้านล่างเพื่อความเข้าใจที่ดีขึ้น

ป้อนคำอธิบายภาพที่นี่


22

APIย่อมาจาก Application Programming Interface โดยที่ API เป็นวิธีการเข้าถึงบริการ / ฟังก์ชั่นที่จัดทำโดยซอฟต์แวร์หรือแพลตฟอร์มบางประเภท

SPIย่อมาจาก Service Provider Interface ซึ่ง SPI เป็นวิธีการฉีดขยายหรือปรับเปลี่ยนพฤติกรรมของซอฟต์แวร์หรือแพลตฟอร์ม

API เป็นเป้าหมายสำหรับลูกค้าในการเข้าถึงบริการและมีคุณสมบัติดังต่อไปนี้:

-> API เป็นวิธีการเขียนโปรแกรมในการเข้าถึงบริการเพื่อให้บรรลุพฤติกรรมหรือผลลัพธ์บางอย่าง

-> จากมุมมองวิวัฒนาการของ API การเพิ่มจะไม่มีปัญหาสำหรับลูกค้า

-> แต่ API ของลูกค้าที่ใช้งานครั้งเดียวจะไม่สามารถเปลี่ยนแปลง / ลบ (และไม่ควร) เว้นแต่จะมีการสื่อสารที่เหมาะสมเนื่องจากความคาดหวังของลูกค้าลดลงอย่างสมบูรณ์

SPI ในส่วนอื่น ๆ มีเป้าหมายสำหรับผู้ให้บริการและมีคุณสมบัติดังต่อไปนี้:

-> SPI เป็นวิธีที่จะขยาย / เปลี่ยนแปลงพฤติกรรมของซอฟต์แวร์หรือแพลตฟอร์ม (โปรแกรมเทียบกับแบบเป็นโปรแกรม)

-> วิวัฒนาการ SPI แตกต่างจากวิวัฒนาการ API ในการกำจัด SPI ไม่ใช่ปัญหา

-> การเพิ่มส่วนต่อประสาน SPI จะทำให้เกิดปัญหาและอาจทำให้การนำไปใช้งานผิดพลาด

สำหรับคำอธิบายเพิ่มเติมคลิกที่นี่: ส่วนต่อประสานผู้ให้บริการ


12

NetBeans 'FAQ: SPI คืออะไร มันแตกต่างจาก API อย่างไร

API เป็นคำทั่วไป - ตัวย่อสำหรับ Application Programming Interface - มันหมายถึงบางสิ่ง (ใน Java, โดยปกติบางคลาส Java) ส่วนหนึ่งของซอฟต์แวร์เปิดเผยซึ่งช่วยให้ซอฟต์แวร์อื่นสามารถสื่อสารกับมัน

SPI หมายถึงส่วนต่อประสานผู้ให้บริการ มันเป็นส่วนย่อยของทุกสิ่งที่สามารถเป็น API เฉพาะกับสถานการณ์ที่ห้องสมุดกำลังจัดเตรียมคลาสซึ่งถูกเรียกใช้โดยแอปพลิเคชัน (หรือไลบรารี API) และโดยทั่วไปจะเปลี่ยนสิ่งที่แอปพลิเคชันสามารถทำได้

ตัวอย่างคลาสสิกคือ JavaMail API มีสองด้าน:

  • ด้าน API - ซึ่งคุณโทรถ้าคุณกำลังเขียนไคลเอ็นต์อีเมลหรือต้องการอ่านกล่องจดหมาย
  • ฝั่ง SPI หากคุณให้บริการตัวจัดการสายโพรโทคอลเพื่ออนุญาตให้ JavaMail พูดคุยกับเซิร์ฟเวอร์ชนิดใหม่เช่นข่าวสารหรือเซิร์ฟเวอร์ IMAP

ผู้ใช้ API ไม่ค่อยต้องการเห็นหรือพูดคุยกับคลาส SPI และในทางกลับกัน

ใน NetBeans เมื่อคุณเห็นคำว่า SPI มักจะพูดถึงคลาสที่โมดูลสามารถแทรกในรันไทม์ซึ่งทำให้ NetBeans สามารถทำสิ่งใหม่ได้ ตัวอย่างเช่นมี SPI ทั่วไปสำหรับการนำระบบควบคุมเวอร์ชันมาใช้ โมดูลที่แตกต่างกันให้การใช้งานของ SPI สำหรับ CVS, การโค่นล้ม, Mercurial และระบบควบคุมการแก้ไขอื่น ๆ อย่างไรก็ตามรหัสที่เกี่ยวข้องกับไฟล์ (ฝั่ง API) ไม่จำเป็นต้องสนใจว่ามีระบบควบคุมเวอร์ชันหรือเป็นอะไร


5

มีแง่มุมหนึ่งที่ดูเหมือนจะไม่ได้รับการเน้นมากนัก แต่สำคัญมากที่จะต้องเข้าใจเหตุผลที่อยู่เบื้องหลังการแบ่ง API / SPI

การแยก API / SPI จำเป็นเฉพาะเมื่อคาดว่าแพลตฟอร์มจะมีวิวัฒนาการ หากคุณเขียน API และ"รู้"มันไม่จำเป็นต้องมีการปรับปรุงใด ๆ ในอนาคตไม่มีเหตุผลที่แท้จริงสำหรับการแยกรหัสของคุณออกเป็นสองส่วน (นอกเหนือจากการออกแบบวัตถุให้สะอาด)

แต่สิ่งนี้แทบจะไม่เคยเกิดขึ้นเลยและผู้คนจำเป็นต้องมีอิสระในการพัฒนา API พร้อมกับความต้องการในอนาคต - ด้วยวิธีที่เข้ากันได้แบบย้อนหลัง

โปรดทราบว่าทั้งหมดข้างต้นถือว่าคุณกำลังสร้างแพลตฟอร์มที่คนอื่นใช้และ / หรือขยายและไม่ใช่ API ของคุณที่คุณมีรหัสลูกค้าทั้งหมดภายใต้การควบคุมและสามารถปรับโครงสร้างได้ตามที่คุณต้องการ

ให้แสดงบนหนึ่งที่รู้จักกันดีวัตถุ Java และCollectionCollections


API: Collectionsเป็นชุดของวิธีการคงที่ยูทิลิตี้ การเรียนที่เป็นตัวแทนของวัตถุ API มักจะถูกกำหนดเป็นfinalมันทำให้มั่นใจ (ในเวลาเรียบเรียง) ที่ลูกค้าไม่เคยที่จะสามารถ"ใช้"วัตถุนั้นและพวกเขาสามารถขึ้นอยู่กับ"เรียก"วิธีการคงที่เช่น

Collections.emptySet();

เนื่องจากไคลเอนต์ทั้งหมดเป็น"การโทร"แต่ไม่ใช่"การนำไปใช้"ผู้เขียนของ JDK มีอิสระที่จะเพิ่มวิธีการใหม่ในCollectionsวัตถุใน JDK รุ่นอนาคต พวกเขาสามารถมั่นใจได้ว่ามันไม่สามารถทำลายลูกค้าใด ๆ แม้ว่าจะมีหลายล้านประเพณี


SPI: Collectionเป็นอินเทอร์เฟซที่บอกเป็นนัยว่าทุกคนสามารถใช้เวอร์ชันของเธอเองได้ ดังนั้นผู้เขียนของ JDK ไม่สามารถเพิ่มวิธีการใหม่ลงในนั้นเพราะมันจะทำลายลูกค้าทั้งหมดที่เขียนCollectionการใช้งานของตัวเอง(*)

โดยทั่วไปเมื่อจำเป็นต้องมีการเพิ่มเมธอดเพิ่มเติมอินเทอร์เฟซใหม่เช่นCollection2ซึ่งจำเป็นต้องสร้างขึ้นมาก่อน ไคลเอนต์ SPI สามารถตัดสินใจได้ว่าจะโยกย้ายไปยังเวอร์ชันใหม่ของ SPI และใช้วิธีการเพิ่มเติมหรือไม่หรือติดกับรุ่นเก่ากว่า


คุณอาจเห็นจุดนั้นแล้ว หากคุณรวมทั้งสองส่วนเข้าด้วยกันเป็นคลาสเดียว API ของคุณจะถูกปิดกั้นไม่ให้มีการเพิ่มเติมใด ๆ นั่นเป็นเหตุผลที่ Java APIs และ Framework ที่ดีไม่เปิดเผยabstract classเพราะพวกเขาจะปิดกั้นวิวัฒนาการในอนาคตของพวกเขาด้วยความเคารพต่อความเข้ากันได้ย้อนหลัง

หากบางสิ่งยังไม่ชัดเจนฉันแนะนำให้ตรวจสอบหน้านี้ซึ่งอธิบายรายละเอียดเพิ่มเติมข้างต้น


(*) โปรดทราบว่านี่เป็นความจริงจนกระทั่ง Java 1.8 ซึ่งแนะนำแนวคิดของdefaultวิธีการที่กำหนดไว้ในส่วนต่อประสาน


4

ฉันคิดว่าสล็อต SPI เข้าสู่ระบบที่มีขนาดใหญ่ขึ้นโดยการใช้คุณสมบัติบางอย่างของ API แล้วลงทะเบียนตัวเองว่าสามารถใช้งานได้ผ่านกลไกการค้นหาบริการ API ถูกใช้งานโดยรหัสแอปพลิเคชันผู้ใช้ปลายทางโดยตรง แต่อาจรวมส่วนประกอบ SPI มันเป็นความแตกต่างระหว่างการห่อหุ้มและการใช้โดยตรง


ขอบคุณสำหรับการตอบสนองคริส ตัวอย่างใด ๆ ของห้องสมุด Java ที่มีอยู่ (เช่น Servlet, JDBC ฯลฯ ) ... ชอบวิธีที่ทำให้เป็น API / SPI อาจเป็นเรื่องยากที่จะเห็นความแตกต่างด้วยคำอธิบายเพียงอย่างเดียว
kctang

1
API คือ JDBC, SPI สำหรับ JDBC เป็นอินเตอร์เฟสตัวเชื่อมต่อฐานข้อมูลที่นักพัฒนา SPI สามารถใช้เพื่อสร้างตัวเชื่อมต่อฐานข้อมูลใหม่ซึ่งนักพัฒนาสามารถเลือกใช้งานได้
Chris Dennett

4

ส่วนต่อประสานผู้ให้บริการเป็นส่วนต่อประสานบริการที่ผู้ให้บริการทุกรายต้องปฏิบัติ หากการใช้งานของผู้ให้บริการที่มีอยู่ไม่ทำงานสำหรับคุณคุณต้องเขียนผู้ให้บริการของคุณเอง (ใช้ส่วนต่อประสานบริการ) และลงทะเบียนที่ไหนสักแห่ง (ดูโพสต์ที่มีประโยชน์โดย Roman)

หากคุณนำการใช้งานอินเทอร์เฟซผู้ให้บริการที่มีอยู่กลับมาใช้ใหม่โดยทั่วไปคุณจะใช้ API ของผู้ให้บริการรายนั้นซึ่งรวมถึงวิธีการทั้งหมดของอินเทอร์เฟซบริการรวมถึงวิธีการสาธารณะบางประการ หากคุณใช้วิธีการของผู้ให้บริการ API ภายนอก SPI คุณกำลังใช้คุณลักษณะเฉพาะของผู้ให้บริการ


2

ในโลกของ Java เทคโนโลยีที่แตกต่างนั้นมีความหมายว่าเป็นแบบแยกส่วนและ "เสียบได้" ลงในแอพพลิเคชันเซิร์ฟเวอร์ จากนั้นมีความแตกต่างระหว่าง

  • แอ็พพลิเคชันเซิร์ฟเวอร์
    • [SPI]
  • เทคโนโลยีที่เสียบได้
    • [API]
  • แอปพลิเคชันผู้ใช้ปลายทาง

ตัวอย่างของเทคโนโลยีดังกล่าวคือ JTA (ผู้จัดการธุรกรรม) และ JCA (อะแดปเตอร์สำหรับ JMS หรือฐานข้อมูล) แต่มีคนอื่น

ผู้ดำเนินการของเทคโนโลยีที่เสียบได้นั้นจะต้องติดตั้ง SPI เพื่อให้สามารถเสียบได้ในแอป เซิร์ฟเวอร์และระบุ API ที่จะใช้โดยแอปพลิเคชันผู้ใช้ปลายทาง ตัวอย่างจาก JCA คืออินเตอร์เฟสManagedConnectionซึ่งเป็นส่วนหนึ่งของ SPI และการเชื่อมต่อที่เป็นส่วนหนึ่งของ API ของผู้ใช้ปลายทาง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.