ที่เก็บข้อมูล Spring ถูกนำไปใช้จริงอย่างไร?


111

ฉันทำงานกับที่เก็บ Spring Data JPA ในโครงการของฉันมาระยะหนึ่งแล้วและฉันรู้ประเด็นด้านล่าง:

  • ในอินเทอร์เฟซที่เก็บเราสามารถเพิ่มเมธอดเช่นfindByCustomerNameAndPhone()(สมมติว่าcustomerNameและphoneเป็นฟิลด์ในอ็อบเจ็กต์โดเมน)
  • จากนั้น Spring จัดเตรียมการนำไปใช้โดยการนำเมธอดอินเทอร์เฟซที่เก็บข้อมูลข้างต้นไปใช้ที่รันไทม์ (ระหว่างการรันแอปพลิเคชัน)

ฉันสนใจว่ารหัสนี้ถูกเข้ารหัสอย่างไรและฉันได้ดูซอร์สโค้ดและ API ของ Spring JPA แล้ว แต่ฉันไม่พบคำตอบสำหรับคำถามด้านล่าง:

  1. คลาสการใช้งานที่เก็บถูกสร้างขึ้นที่รันไทม์ & วิธีการที่ถูกนำไปใช้และฉีดอย่างไร?
  2. Spring Data JPA ใช้ CGlib หรือไลบรารีการจัดการ bytecode เพื่อใช้วิธีการและฉีดแบบไดนามิกหรือไม่

คุณช่วยกรุณาตอบคำถามข้างต้นและให้เอกสารที่รองรับได้หรือไม่?

คำตอบ:


144

ประการแรกไม่มีการสร้างรหัสเกิดขึ้นซึ่งหมายความว่า: ไม่มี CGLib ไม่มีการสร้างรหัสไบต์เลย แนวทางพื้นฐานคืออินสแตนซ์พร็อกซี JDK ถูกสร้างขึ้นโดยใช้โปรแกรมโดยใช้ProxyFactoryAPI ของ Spring เพื่อสำรองอินเทอร์เฟซและMethodInterceptorสกัดกั้นการเรียกทั้งหมดไปยังอินสแตนซ์และกำหนดเส้นทางวิธีการไปยังตำแหน่งที่เหมาะสม:

  1. หากที่เก็บเริ่มต้นด้วยส่วนการนำไปใช้งานที่กำหนดเอง (ดูรายละเอียดในส่วนของเอกสารอ้างอิง ) และวิธีการเรียกใช้ถูกนำไปใช้ในคลาสนั้นการเรียกจะถูกกำหนดเส้นทางไปที่นั่น
  2. ถ้าเมธอดนั้นเป็นเมธอดDefaultRepositoryInformationคิวรี(ดูวิธีการกำหนด) กลไกการดำเนินการเคียวรีที่จัดเก็บจะเริ่มทำงานและเรียกใช้คิวรีที่กำหนดให้ดำเนินการสำหรับเมธอดนั้นเมื่อเริ่มต้น ด้วยเหตุนี้กลไกการแก้ปัญหาจึงถูกนำมาใช้ซึ่งพยายามระบุการสืบค้นที่ประกาศไว้อย่างชัดเจนในที่ต่างๆ (โดยใช้@Queryวิธีการค้นหาชื่อ JPA) ในที่สุดก็กลับไปสู่การสืบค้นที่มาจากชื่อเมธอด JpaQueryLookupStrategyสำหรับการตรวจสอบกลไกการสอบถามดู ตรรกะการแยกวิเคราะห์สำหรับการสร้างแบบสอบถามสามารถพบได้ในPartTree. JpaQueryCreatorแปลร้านที่เฉพาะเจาะจงลงในแบบสอบถามที่เกิดขึ้นจริงสามารถมองเห็นได้เช่นใน
  3. หากไม่มีวิธีใดข้างต้นใช้วิธีการที่ดำเนินการจะต้องถูกนำไปใช้โดยคลาสฐานที่เก็บเฉพาะที่เก็บ ( SimpleJpaRepositoryในกรณีของ JPA) และการเรียกจะถูกกำหนดเส้นทางไปยังอินสแตนซ์ของสิ่งนั้น

วิธีการดำเนินการสกัดกั้นที่เส้นทางตรรกะเป็นQueryExecutorMethodInterceptorระดับสูงเส้นทางตรรกะที่สามารถพบได้ที่นี่

การสร้างพร็อกซีเหล่านั้นถูกห่อหุ้มไว้ในการใช้งานรูปแบบโรงงานที่ใช้ Java มาตรฐาน การสร้างพร็อกซีระดับสูงสามารถพบได้ในRepositoryFactorySupport. การใช้งานเฉพาะร้านค้าจากนั้นเพิ่มส่วนประกอบโครงสร้างพื้นฐานที่จำเป็นเพื่อให้ JPA สามารถดำเนินการต่อได้และเขียนโค้ดดังนี้:

EntityManager em =  // obtain an EntityManager
JpaRepositoryFactory factory = new JpaRepositoryFactory(em);
UserRepository repository = factory.getRepository(UserRepository.class);

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

เพื่อความสะดวกในการรวมกับคอนเทนเนอร์ DI เราได้สร้างการผสานรวมกับการกำหนดค่า Spring Java ซึ่งเป็นเนมสเปซ XML แต่ยังรวมถึงส่วนขยาย CDIเพื่อให้ Spring Data สามารถใช้ในสถานการณ์ CDI ธรรมดาได้


3
สวัสดี Oliver คุณสามารถอธิบายรายละเอียดเกี่ยวกับวิธีที่ Spring ค้นพบ@Repositoryอินเทอร์เฟซที่มีคำอธิบายประกอบตั้งแต่แรกได้หรือไม่? เมื่อดูที่RepositoryFactorySupport#getRepository()แสดงว่าใช้คลาสอินเทอร์เฟซเป็นพารามิเตอร์ดังนั้นจึงต้องค้นพบที่อื่น ฉันพยายามหาวิธีค้นหาอินเทอร์เฟซที่มีคำอธิบายประกอบและสร้าง JDK proxy bean โดยอัตโนมัติซึ่งใช้อินเทอร์เฟซเหมือนกับข้อมูลสปริง แต่สำหรับวัตถุประสงค์เฉพาะแอปพลิเคชันที่ไม่เกี่ยวข้องกับที่เก็บ
Chris Rice

1
RepositoryComponentProviderคุณอาจต้องการที่จะมีลักษณะที่ ไม่มีสิ่งที่เกิดขึ้นโดยอัตโนมัติ แต่จะสแกนส่วนประกอบสำหรับบางประเภท (ไม่ว่าจะเป็นคำอธิบายประกอบหรือมีคำอธิบายประกอบ) และFactoryBeanกำหนดค่าไว้สำหรับแต่ละประเภท
Oliver Drotbohm

2
ขออภัยที่แสดงความคิดเห็นในกระทู้เก่า แต่อยากรู้อยากเห็น ... พร็อกซีที่เก็บเป็นอ็อบเจ็กต์เดี่ยวหรือไม่? เราพบปัญหาที่โค้ดของเราพยายามเรียกเมธอด repo แต่ดูเหมือนว่าจะไม่สามารถโทรออกจากพร็อกซีได้ มันก็แฮงค์ ฉันสงสัยว่ามันกำลังรอสายเดี่ยวที่ไม่ว่าง
iu.david
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.