ความแตกต่างระหว่างสิ่งที่เป็นผู้ให้บริการ Interface (SPI)และApplication Programming Interface (API) ?
โดยเฉพาะอย่างยิ่งสำหรับห้องสมุด Java สิ่งที่ทำให้พวกเขาเป็น API และ / หรือ SPI
ความแตกต่างระหว่างสิ่งที่เป็นผู้ให้บริการ Interface (SPI)และApplication Programming Interface (API) ?
โดยเฉพาะอย่างยิ่งสำหรับห้องสมุด Java สิ่งที่ทำให้พวกเขาเป็น API และ / หรือ SPI
คำตอบ:
API จะบอกคุณว่าคลาส / วิธีการใดที่เฉพาะเจาะจงสำหรับคุณและ SPI จะบอกคุณว่าคุณต้องทำอะไรเพื่อให้สอดคล้อง
โดยทั่วไปแล้ว API และ SPI จะแยกจากกัน ยกตัวอย่างเช่นใน JDBC ระดับเป็นส่วนหนึ่งของ SPI: ถ้าคุณเพียงแค่ต้องการใช้ JDBC คุณไม่จำเป็นต้องใช้มันโดยตรง แต่ทุกคนที่ดำเนินไดรเวอร์ JDBC ต้องใช้ชั้นเรียนที่Driver
อย่างไรก็ตามบางครั้งพวกเขาทับซ้อนกัน อินเตอร์เฟซที่เป็นทั้ง SPI และ API: คุณใช้เป็นประจำเมื่อคุณใช้ไดรเวอร์ JDBC และจะต้องมีการดำเนินการโดยนักพัฒนาของไดร์เวอร์ JDBCConnection
@SomeAnnotation
คลาสของฉันเพื่อรับมันโดยกรอบบางคลาสคำอธิบายประกอบนี้SomeAnnotation.class
จะถือว่าเป็นส่วนหนึ่งของ SPI แม้ว่าฉันจะไม่ขยายหรือดำเนินการในทางเทคนิคหรือไม่?
จาก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();
}
}
ความแตกต่างระหว่าง API และ SPI เกิดขึ้นเมื่อ API มีการใช้งานที่เป็นรูปธรรมเพิ่มเติม ในกรณีดังกล่าวผู้ให้บริการจะต้องใช้ API บางตัว (เรียกว่า SPI)
ตัวอย่างคือ JNDI:
JNDI จัดเตรียมอินเตอร์เฟสและบางคลาสสำหรับการค้นหาบริบท วิธีการเริ่มต้นในการค้นหาบริบทมีให้ใน IntialContext คลาสนี้ภายในจะใช้อินเทอร์เฟซ SPI (โดยใช้ NamingManager) สำหรับการใช้งานเฉพาะของผู้ให้บริการ
ดูสถาปัตยกรรม JNDI ด้านล่างเพื่อความเข้าใจที่ดีขึ้น
APIย่อมาจาก Application Programming Interface โดยที่ API เป็นวิธีการเข้าถึงบริการ / ฟังก์ชั่นที่จัดทำโดยซอฟต์แวร์หรือแพลตฟอร์มบางประเภท
SPIย่อมาจาก Service Provider Interface ซึ่ง SPI เป็นวิธีการฉีดขยายหรือปรับเปลี่ยนพฤติกรรมของซอฟต์แวร์หรือแพลตฟอร์ม
API เป็นเป้าหมายสำหรับลูกค้าในการเข้าถึงบริการและมีคุณสมบัติดังต่อไปนี้:
-> API เป็นวิธีการเขียนโปรแกรมในการเข้าถึงบริการเพื่อให้บรรลุพฤติกรรมหรือผลลัพธ์บางอย่าง
-> จากมุมมองวิวัฒนาการของ API การเพิ่มจะไม่มีปัญหาสำหรับลูกค้า
-> แต่ API ของลูกค้าที่ใช้งานครั้งเดียวจะไม่สามารถเปลี่ยนแปลง / ลบ (และไม่ควร) เว้นแต่จะมีการสื่อสารที่เหมาะสมเนื่องจากความคาดหวังของลูกค้าลดลงอย่างสมบูรณ์
SPI ในส่วนอื่น ๆ มีเป้าหมายสำหรับผู้ให้บริการและมีคุณสมบัติดังต่อไปนี้:
-> SPI เป็นวิธีที่จะขยาย / เปลี่ยนแปลงพฤติกรรมของซอฟต์แวร์หรือแพลตฟอร์ม (โปรแกรมเทียบกับแบบเป็นโปรแกรม)
-> วิวัฒนาการ SPI แตกต่างจากวิวัฒนาการ API ในการกำจัด SPI ไม่ใช่ปัญหา
-> การเพิ่มส่วนต่อประสาน SPI จะทำให้เกิดปัญหาและอาจทำให้การนำไปใช้งานผิดพลาด
สำหรับคำอธิบายเพิ่มเติมคลิกที่นี่: ส่วนต่อประสานผู้ให้บริการ
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) ไม่จำเป็นต้องสนใจว่ามีระบบควบคุมเวอร์ชันหรือเป็นอะไร
มีแง่มุมหนึ่งที่ดูเหมือนจะไม่ได้รับการเน้นมากนัก แต่สำคัญมากที่จะต้องเข้าใจเหตุผลที่อยู่เบื้องหลังการแบ่ง API / SPI
การแยก API / SPI จำเป็นเฉพาะเมื่อคาดว่าแพลตฟอร์มจะมีวิวัฒนาการ หากคุณเขียน API และ"รู้"มันไม่จำเป็นต้องมีการปรับปรุงใด ๆ ในอนาคตไม่มีเหตุผลที่แท้จริงสำหรับการแยกรหัสของคุณออกเป็นสองส่วน (นอกเหนือจากการออกแบบวัตถุให้สะอาด)
แต่สิ่งนี้แทบจะไม่เคยเกิดขึ้นเลยและผู้คนจำเป็นต้องมีอิสระในการพัฒนา API พร้อมกับความต้องการในอนาคต - ด้วยวิธีที่เข้ากันได้แบบย้อนหลัง
โปรดทราบว่าทั้งหมดข้างต้นถือว่าคุณกำลังสร้างแพลตฟอร์มที่คนอื่นใช้และ / หรือขยายและไม่ใช่ API ของคุณที่คุณมีรหัสลูกค้าทั้งหมดภายใต้การควบคุมและสามารถปรับโครงสร้างได้ตามที่คุณต้องการ
ให้แสดงบนหนึ่งที่รู้จักกันดีวัตถุ Java และCollection
Collections
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
วิธีการที่กำหนดไว้ในส่วนต่อประสาน
ฉันคิดว่าสล็อต SPI เข้าสู่ระบบที่มีขนาดใหญ่ขึ้นโดยการใช้คุณสมบัติบางอย่างของ API แล้วลงทะเบียนตัวเองว่าสามารถใช้งานได้ผ่านกลไกการค้นหาบริการ API ถูกใช้งานโดยรหัสแอปพลิเคชันผู้ใช้ปลายทางโดยตรง แต่อาจรวมส่วนประกอบ SPI มันเป็นความแตกต่างระหว่างการห่อหุ้มและการใช้โดยตรง
ส่วนต่อประสานผู้ให้บริการเป็นส่วนต่อประสานบริการที่ผู้ให้บริการทุกรายต้องปฏิบัติ หากการใช้งานของผู้ให้บริการที่มีอยู่ไม่ทำงานสำหรับคุณคุณต้องเขียนผู้ให้บริการของคุณเอง (ใช้ส่วนต่อประสานบริการ) และลงทะเบียนที่ไหนสักแห่ง (ดูโพสต์ที่มีประโยชน์โดย Roman)
หากคุณนำการใช้งานอินเทอร์เฟซผู้ให้บริการที่มีอยู่กลับมาใช้ใหม่โดยทั่วไปคุณจะใช้ API ของผู้ให้บริการรายนั้นซึ่งรวมถึงวิธีการทั้งหมดของอินเทอร์เฟซบริการรวมถึงวิธีการสาธารณะบางประการ หากคุณใช้วิธีการของผู้ให้บริการ API ภายนอก SPI คุณกำลังใช้คุณลักษณะเฉพาะของผู้ให้บริการ
ในโลกของ Java เทคโนโลยีที่แตกต่างนั้นมีความหมายว่าเป็นแบบแยกส่วนและ "เสียบได้" ลงในแอพพลิเคชันเซิร์ฟเวอร์ จากนั้นมีความแตกต่างระหว่าง
ตัวอย่างของเทคโนโลยีดังกล่าวคือ JTA (ผู้จัดการธุรกรรม) และ JCA (อะแดปเตอร์สำหรับ JMS หรือฐานข้อมูล) แต่มีคนอื่น
ผู้ดำเนินการของเทคโนโลยีที่เสียบได้นั้นจะต้องติดตั้ง SPI เพื่อให้สามารถเสียบได้ในแอป เซิร์ฟเวอร์และระบุ API ที่จะใช้โดยแอปพลิเคชันผู้ใช้ปลายทาง ตัวอย่างจาก JCA คืออินเตอร์เฟสManagedConnectionซึ่งเป็นส่วนหนึ่งของ SPI และการเชื่อมต่อที่เป็นส่วนหนึ่งของ API ของผู้ใช้ปลายทาง