คำอธิบายประกอบของ @Service ควรเก็บไว้ที่ไหน อินเทอร์เฟซหรือการใช้งาน?


133

ฉันกำลังพัฒนาแอปพลิเคชันโดยใช้ Spring ฉันจำเป็นต้องใช้@Serviceคำอธิบายประกอบ ฉันมีServiceIและดังกล่าวว่าServiceImpl ServiceImpl implements ServiceIฉันสับสนตรงนี้ว่าฉันควรเก็บ@Serviceคำอธิบายประกอบไว้ที่ไหน

ฉันควรใส่คำอธิบายประกอบอินเทอร์เฟซหรือการใช้งานด้วย@Service? อะไรคือความแตกต่างระหว่างสองแนวทางนี้?


นี่คือคำตอบของฉันสำหรับโพสต์ที่คล้ายกัน: stackoverflow.com/questions/38618995/…
AgustíSánchez

คำตอบ:


141

ฉันไม่เคยใส่@Component(หรือ@Service, ... ) ที่อินเทอร์เฟซเพราะสิ่งนี้ทำให้อินเทอร์เฟซไร้ประโยชน์ ให้ฉันอธิบายว่าทำไม

อ้างสิทธิ์ 1:หากคุณมีอินเทอร์เฟซแล้วคุณต้องการใช้อินเทอร์เฟซนั้นสำหรับประเภทจุดฉีด

ข้อเรียกร้อง 2:วัตถุประสงค์ของอินเทอร์เฟซคือการกำหนดสัญญาที่สามารถดำเนินการได้โดยการนำไปใช้งานหลาย ๆ ในอีกด้านหนึ่งคุณมีจุดฉีดยา ( @Autowired) มีเพียงหนึ่งในอินเตอร์เฟซและเพียงหนึ่งชั้นเรียนที่ใช้มันเป็น (IMHO) ไร้ประโยชน์และละเมิดYAGNI

ข้อเท็จจริง:เมื่อคุณใส่:

  • @Component(หรือ@Service, ... ) ที่อินเทอร์เฟซ
  • มีหลายชั้นเรียนที่ใช้มัน
  • อย่างน้อยสองชั้นเรียนกลายเป็น Spring Beans และ
  • มีจุดฉีดที่ใช้อินเทอร์เฟซสำหรับการฉีดตามประเภท

จากนั้นคุณจะได้รับและNoUniqueBeanDefinitionException (หรือคุณมีการตั้งค่าการกำหนดค่าที่พิเศษมากพร้อมด้วยสภาพแวดล้อมโปรไฟล์หรือรอบคัดเลือก ... )

สรุป:หากคุณใช้@Component(หรือ@Service, ... ) ที่อินเทอร์เฟซคุณต้องละเมิดอย่างน้อยหนึ่งในสอง Clains ดังนั้นฉันคิดว่ามันไม่มีประโยชน์ (ยกเว้นบางสถานการณ์ที่หายาก) ที่จะวางไว้@Componentที่ระดับอินเทอร์เฟซ


Spring-Data-JPA Repository อินเทอร์เฟซเป็นสิ่งที่แตกต่างกันโดยสิ้นเชิง


3
มันน่าสนใจมากในสิ่งที่คุณเขียน ... แล้ววิธีไหนล่ะ? มันไม่ได้ใส่คำอธิบายประกอบอินเทอร์เฟซเลยและให้คำอธิบายประกอบบริการแก่การนำไปใช้งานหรือไม่? Spring ยังคงสามารถสั่งงานอัตโนมัติโดยใช้ประเภทอินเทอร์เฟซได้หรือไม่ คำตอบของคุณคืออะไร> stackoverflow.com/questions/12899372/…
corlaez

3
ฉันมีคำถามทำไมเราต้องสร้างอินเทอร์เฟซสำหรับเลเยอร์บริการเมื่อมีเพียงคลาสเดียวที่ใช้งานได้ ฉันได้เห็นหลายโครงการที่พวกเขามีชั้นควบคุมชั้นบริการ ** ( servicInterface , serviceInterfaceImpl ) และพื้นที่เก็บข้อมูลชั้น
Yubaraj

4
@Yubaraj: ประเด็นที่ยุติธรรม แต่คำถามของคุณเกี่ยวกับหัวข้ออื่น ๆ (สำหรับคำตอบของฉันฉันใช้สมมติฐานว่ามีอินเทอร์เฟซและคำถามไม่เกี่ยวกับการมีอินเทอร์เฟซ แต่เกี่ยวกับตำแหน่งที่จะวางคำอธิบายประกอบ) สำหรับคำถามของคุณ: แทบไม่มีเหตุผลที่จะต้องมีอินเทอร์เฟซสำหรับคลาสบริการธุรกิจที่ไม่มีการใช้งานสองอย่าง (BTW: ตราบใดที่คุณไม่ได้สร้าง api สำหรับอันอื่นคุณสามารถ refactor โค้ดของคุณและแนะนำอินเทอร์เฟซได้ในภายหลังเมื่อคุณต้องการ)
Ralph

1
@Yubaraj อินเทอร์เฟซอนุญาตให้สร้างพร็อกซี jdk ที่ใช้อินเทอร์เฟซน้ำหนักเบาไปยังถั่วเมื่อจำเป็น เมื่อไม่มีอินเทอร์เฟซ spring จะต้องทำ subclassing หรือปรับเปลี่ยน bean โดยใช้ cglib เพื่อสร้างพร็อกซี @Transactionalเป็นหนึ่งในตัวอย่างที่ใช้พร็อกซีไปยัง bean AOP เป็นอีกหนึ่ง
Yoory N.

1
แม้ว่าบางครั้งคุณจะไม่มีคลาสการใช้งานมากกว่าหนึ่งคลาส แต่ฉันก็ยังชอบที่จะประกาศวิธีการของฉันในอินเทอร์เฟซมากกว่า เพื่อนนักพัฒนาจะพบว่าง่ายขึ้นในการตรวจสอบว่ามีบริการใดบ้างโดยดูจากประกาศและเอกสารประกอบโดยไม่ต้องกังวลกับการใช้งาน
HFSDev

32

โดยพื้นฐานแล้วคำอธิบายประกอบเช่น@Service , @Repository , @Componentฯลฯ ล้วนมีจุดประสงค์เดียวกัน:

การตรวจจับอัตโนมัติเมื่อใช้การกำหนดค่าตามคำอธิบายประกอบและการสแกนคลาสพา ธ

จากประสบการณ์ของฉันฉันมักจะใช้@Serviceคำอธิบายประกอบบนอินเทอร์เฟซหรือคลาสนามธรรมและคำอธิบายประกอบเช่น@Componentและ@Repositoryสำหรับการนำไปใช้งาน @Componentคำอธิบายประกอบที่ฉันใช้ในชั้นเรียนเหล่านั้นซึ่งมีจุดประสงค์พื้นฐานถั่วสปริงธรรมดา ๆ ไม่มีอะไรมาก @Repositoryคำอธิบายประกอบที่ฉันใช้ในDAOเลเยอร์เช่นหากฉันต้องสื่อสารกับฐานข้อมูลมีธุรกรรมบางอย่างเป็นต้น

ดังนั้นฉันขอแนะนำให้ใส่คำอธิบายประกอบอินเทอร์เฟซของคุณด้วย@Serviceและเลเยอร์อื่น ๆ ขึ้นอยู่กับฟังก์ชันการทำงาน


10
คุณบอกได้ไหมว่าอะไรคือความแตกต่างระหว่างอินเทอร์เฟซการใส่คำอธิบายประกอบและการใส่คำอธิบายประกอบการใช้งาน
TheKojuEffect

28
จากเอกสารฤดูใบไม้ผลิ , "คำอธิบายประกอบนี้ทำหน้าที่เป็นความเชี่ยวชาญของ @Component ที่ช่วยให้การดำเนินงานสำหรับการเรียนจะต้องผ่านการสแกน autodetected classpath"บอกว่ามันมีจุดมุ่งหมายที่จะใช้ในระดับการดำเนินการ
nbrooks

1
@TheKojuEffect โพสต์นี้อธิบายรายละเอียดความแตกต่างระหว่างอินเทอร์เฟซคำอธิบายประกอบกับการใช้งาน - stackoverflow.com/questions/3120143/…
Mahesh

@ user3257644 โปรดทราบว่าคำแนะนำที่ได้รับจากคำตอบในโพสต์นั้นเกี่ยวข้องกับคำอธิบายประกอบ "@Transactional" โดยเฉพาะไม่ใช่คำอธิบายประกอบทั้งหมดโดยทั่วไป
Jonathan

3
คำอธิบายประกอบ @service บนอินเทอร์เฟซไม่มีผลเช่นเดียวกับคำอธิบายประกอบแบบตายตัวอื่น ๆ คำอธิบายประกอบแบบตายตัวทั้งหมดควรใส่ในคลาสนามธรรมหรือรูปธรรม
บิ๊กฟุต

13

ผมใช้@Component, @Service, @Controllerและ@Repositoryคำอธิบายประกอบเฉพาะในชั้นเรียนดำเนินการและไม่ได้อยู่ในอินเตอร์เฟซ แต่@Autowiredคำอธิบายประกอบกับอินเทอร์เฟซยังคงใช้งานได้สำหรับฉัน


7

ข้อดีของการใส่คำอธิบายประกอบใน @Service คือให้คำใบ้ว่าเป็นบริการ ฉันไม่รู้ว่าคลาสการใช้งานใด ๆ จะสืบทอดคำอธิบายประกอบนี้ตามค่าเริ่มต้นหรือไม่

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


1
ฉันคิดว่าเราทุกคนเคยได้ยินอาร์กิวเมนต์การมีเพศสัมพันธ์ที่แข็งแกร่งหลายครั้ง แต่โปรดจำไว้ว่าคำอธิบายประกอบสามารถนำเสนอได้โดยไม่ต้องใส่โถดังนั้นโดยพื้นฐานแล้วตราบใดที่การมีเพศสัมพันธ์ของคุณอยู่ในคำอธิบายประกอบก็ยังสามารถแยกออกได้
Niels Bech Nielsen

1

ประโยชน์อย่างหนึ่งของสปริงคือการเปลี่ยนการใช้งานบริการ (หรืออื่น ๆ ) ได้อย่างง่ายดาย สำหรับสิ่งนี้คุณต้องใส่คำอธิบายประกอบบนอินเทอร์เฟซและประกาศตัวแปรดังนี้:

@Autowired
private MyInterface myVariable;

และไม่ :

@Autowired
private MyClassImplementationWhichImplementsMyInterface myVariable;

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


4
"MyClassImplementationWhichImplementsMyInterface" LOL
inafalcao

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

1

ฉันจะใส่@Serviceคลาสของคุณ แต่ใส่ชื่อของอินเทอร์เฟซเป็นพารามิเตอร์ให้กับคำอธิบายประกอบเช่น

interface ServiceOne {}

@Service("ServiceOne")
class ServiceOneImpl implements ServiceOne{}

การทำเช่นนั้นคุณจะได้รับประโยชน์ทั้งหมดและยังสามารถฉีดอินเทอร์เฟซ แต่ได้รับคลาส

@Autowired 
private ServiceOne serviceOne;

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

ดังนั้นถ้าฉันต้องการเปลี่ยนคลาสการใช้งานฉันสามารถใส่คำอธิบายประกอบคลาสใหม่และลบออกจากคลาสแรก แต่นั่นคือทั้งหมดที่จำเป็นต้องเปลี่ยน หากคุณฉีดคลาสคุณอาจมีงานมากมายเมื่อคุณต้องการเปลี่ยนคลาสโดยนัย


-1

เพื่อให้ง่ายขึ้น:

@Serviceคือคำอธิบายประกอบ Stereotype สำหรับชั้นบริการ

@Repositoryเป็นคำอธิบายประกอบมโนทัศน์สำหรับการติดตาชั้น

@Componentเป็นคำอธิบายประกอบแบบตายตัวทั่วไปที่ใช้เพื่อบอกให้ Spring สร้างอินสแตนซ์ของวัตถุใน Application Context เป็นไปได้ที่จะกำหนดชื่อใด ๆ สำหรับอินสแตนซ์ค่าเริ่มต้นคือชื่อคลาสเป็นกรณีอูฐ


3
ไม่มีการค้นหาความหมายของคำอธิบายประกอบเหล่านี้ แต่จะใส่ไว้ที่ไหนในอินเทอร์เฟซหรือการนำไปใช้งาน
nanosoft

-3

มีคำอธิบายประกอบ 5 รายการที่สามารถใช้ในการทำถั่วสปริงได้ ระบุคำตอบด้านล่าง

คุณต้องการอินเทอร์เฟซจริงๆหรือ? หากคุณกำลังจะมีการนำไปใช้งานหนึ่งสำหรับอินเทอร์เฟซบริการแต่ละรายการให้หลีกเลี่ยงใช้เฉพาะคลาส แน่นอนถ้าคุณไม่มี RMI หรือเมื่อต้องใช้พร็อกซีอินเทอร์เฟซ

@Repository - ใช้สำหรับฉีดคลาส dao ของคุณ

@Service - ใช้สำหรับการฉีดคลาสชั้นบริการของคุณ ในชั้นบริการคุณอาจต้องใช้คำอธิบายประกอบ @Transactional สำหรับการจัดการธุรกรรม db

@Controller - ใช้สำหรับตัวควบคุมชั้นส่วนหน้าของคุณเช่นการฉีดถั่วที่มีการจัดการ JSF เป็นถั่วสปริง

@RestController - ใช้สำหรับตัวควบคุมสปริงที่เหลือซึ่งจะช่วยให้คุณหลีกเลี่ยงทุกครั้งที่ใส่คำอธิบายประกอบ @ResponseBody และ @RequestBody ในวิธีการพักของคุณ

@ ส่วนประกอบ - ใช้ในกรณีอื่น ๆ เมื่อคุณต้องการฉีดถั่วสปริงที่ไม่ใช่ตัวควบคุมบริการหรือคลาส dao


ใช่คุณต้องมีอินเทอร์เฟซบนขอบของเลเยอร์ของคุณ (เช่นชั้นการเข้าถึงข้อมูลและชั้นบริการ) เปิดใช้งานการเชื่อมต่อแบบหลวม ๆ ของโมดูลที่มีการใช้งานเลเยอร์เหล่านั้น หากไม่มีพวกเขาลูกค้าของเลเยอร์ที่กล่าวถึงจะต้องรู้จักประเภทคอนกรีตและคุณจำเป็นต้องเปลี่ยนเมื่อคุณพูดว่าต้องการตกแต่ง BasicDao ด้วย CachingDao ...
Igand
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.