วิธีการเรียกวิธีหลังจากการเริ่มต้นถั่วเสร็จสมบูรณ์แล้ว?


237

ฉันมีกรณีการใช้งานที่ฉันต้องการเรียกใช้เมธอด (แบบไม่คงที่) ใน bean เพียงครั้งเดียวที่ ApplicationContext โหลดขึ้น ไม่เป็นไรถ้าฉันใช้ MethodInvokingFactoryBean สำหรับสิ่งนี้ หรือเรามีทางออกที่ดีกว่า

ในฐานะที่เป็นข้อความด้านข้างฉันใช้ ConfigContextLoaderListener เพื่อโหลด Application Context ในเว็บแอปพลิเคชัน และต้องการว่าถ้า bean 'A' ถูกสร้างอินสแตนซ์เพียงแค่เรียกเมธอด A () หนึ่งครั้ง

วิธีนี้สามารถทำได้อย่างดี?

คำตอบ:


196

คุณสามารถใช้สิ่งที่ชอบ:

<beans>
    <bean id="myBean" class="..." init-method="init"/>
</beans>

สิ่งนี้จะเรียกเมธอด "init" เมื่อ bean ถูกสร้างอินสแตนซ์


15
postConstruct ควรจะดีกว่าในกรณีส่วนใหญ่เนื่องจากเราไม่ต้องการรบกวนการเริ่มต้นของ Spring bean
lwpro2

4
@ lwpro2 คุณหมายถึงอะไรโดย "ไม่ต้องการสับสนกับการเริ่มต้นสปริงถั่ว" ที่นี่?
Yngve Sneen Lindal

@Mercer Traieste ฉันควรให้อะไรกับแอตทริบิวต์ class ที่นี่ ฉันให้คลาสควบคุมที่นี่ได้ไหม
KJEjava48

314

หากต้องการขยายคำแนะนำ @PostConstruct ในคำตอบอื่น ๆ นี่เป็นทางออกที่ดีที่สุดในความคิดของฉัน

  • มันทำให้รหัสของคุณแยกจาก Spring API (@PostConstruct อยู่ใน javax. *)
  • มันอธิบายวิธีการเริ่มต้นของคุณอย่างชัดเจนว่าเป็นสิ่งที่จำเป็นต้องเรียกเพื่อเริ่มต้นถั่ว
  • คุณไม่จำเป็นต้องจำไว้ว่าให้เพิ่มแอททริบิวต์ init- method ในการกำหนด Spring bean ของคุณสปริงจะเรียกเมธอดโดยอัตโนมัติ (สมมติว่าคุณลงทะเบียนตัวเลือกคำอธิบายประกอบ -config ที่อื่นในบริบท)

9
ขอบคุณมันใช้งานได้ หมายเหตุถ้าคุณต้องการใช้กับ Spring คุณต้องรวม "<context: annotation-config />" เพื่อลงทะเบียน CommonAnnotationBeanPostProcessor bean (ดังที่ได้กล่าวไว้ข้างต้น)
khylo

2
ที่เหมาะสม<context:component-scan>ยังใช้งานได้และสามารถเป็นประโยชน์ในการลดเวลาเริ่มต้นถ้าคุณมีไลบรารี่ที่ไม่ใช่สปริงขนาดใหญ่ใน classpath
Donal Fellows

5
JavaDoc สำหรับ PostConstruct บอกว่ามีเพียงวิธีเดียวที่สามารถใส่คำอธิบายประกอบไว้ในแต่ละคลาส: docs.oracle.com/javaee/5/api/javax/annotation/ ......
Andrew Swan

@PostConstruct ไม่ทำงานกับผู้จัดการการทำธุรกรรมโปรดดูที่: forum.spring.io/forum/spring-projects/data/…
mmm

2
@ PostConstruct จะไม่ใช้กับคุณมากนักเมื่อ bean ที่คุณกำลังอินสแตนซ์นั้นไม่ใช่คลาสของคุณเอง แต่เป็นคลาสของบุคคลที่สามบางคน
John Rix

102

มีสามวิธีที่แตกต่างกันที่จะต้องพิจารณาตามที่อธิบายไว้ในการอ้างอิง

ใช้แอตทริบิวต์ init- method

ข้อดี:

  • ไม่ต้องใช้ bean เพื่อใช้อินเตอร์เฟส

จุดด้อย:

  • ไม่จำเป็นต้องมีการระบุวิธีนี้ในทันทีหลังจากการก่อสร้างเพื่อให้แน่ใจว่ามีการกำหนดค่าถั่วอย่างถูกต้อง

ใช้งาน InitializingBean

ข้อดี:

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

จุดด้อย:

  • มีการบุกรุกมากกว่าวิธีการเริ่มต้น

ใช้คำอธิบายประกอบlifecyle lifecyle ของ JSR-250

ข้อดี:

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

จุดด้อย:

  • การเริ่มต้นไม่ได้ระบุไว้ในการกำหนดค่าจากศูนย์กลางอีกต่อไป
  • คุณต้องจำไว้ว่าให้เปิดการประมวลผลคำอธิบายประกอบ (ซึ่งบางครั้งอาจถูกลืม)

4
ฉันคิดว่ามันเป็นสิ่งที่ดีที่จะใช้@PostConstructอย่างแม่นยำเพราะเป็นส่วนหนึ่งของคลาสที่ต้องการวิธีการเรียกเมื่อสิ้นสุดการประมวลผลเริ่มต้น
Donal Fellows

ถ้าคลาสนั้นต้องการมันจริงๆและคุณไม่สามารถทำได้ในตัวสร้าง
user482745

39

คุณได้ลองใช้งานแล้วInitializingBeanหรือยัง ดูเหมือนว่าสิ่งที่คุณหลังจาก

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


2
มีเหตุผลที่คุณจะเลือกใช้อินเทอร์เฟซมากกว่าการระบุวิธีการเริ่มต้นใน XML หรือไม่
Mark

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

7
Oliver ให้ข้อแก้ตัวที่ดี แต่จริงๆแล้วฉันเพิ่งลืมเกี่ยวกับวิธีการเริ่มต้น :) เหตุผลอีกอย่างหนึ่งก็คือประเภทตัวเองรู้ว่ามันต้องเป็น "เสร็จสิ้น" หลังจากคุณสมบัติทั้งหมดถูกตั้งค่า - ไม่ใช่ สิ่งพื้นฐานที่ควรจะอยู่ในการกำหนดค่า
Jon Skeet

8

คุณสามารถปรับใช้BeanPostProcessorแบบกำหนดเองในบริบทแอปพลิเคชันของคุณเพื่อดำเนินการ หรือถ้าคุณไม่คำนึงถึงการใช้งานส่วนต่อประสาน Spring ในถั่วของคุณคุณสามารถใช้ส่วนต่อประสานInitializingBeanหรือคำสั่ง "init-method" (ลิงค์เดียวกัน)


ใครบ้างมีรายละเอียดเกี่ยวกับวิธีการเขียน BeanPostProcessor นั่นฟังดูเป็นสิ่งที่ฉันต้องการ ไชโย :)
สูงสุด

ฤดูใบไม้ผลิเรือด้วยตัวอย่างมากมาย เพียงดูที่ JavaDoc API สำหรับ BeanPostProcessor แล้วคุณจะพบลิงก์ไปยังคลาสที่ใช้งานหลายตัว จากนั้นดูซอร์สโค้ดสำหรับพวกเขา
Rob H

-7

เพื่อให้ชัดเจนยิ่งขึ้นเกี่ยวกับความสับสนใด ๆ ของทั้งสองวิธีเช่นการใช้

  1. @PostConstruct และ
  2. init-method="init"

จากประสบการณ์ส่วนตัวฉันรู้ว่าการใช้ (1) ทำงานในคอนเทนเนอร์ servlet เท่านั้นในขณะที่ (2) ทำงานได้ในทุกสภาพแวดล้อมแม้แต่ในแอปพลิเคชันบนเดสก์ท็อป ดังนั้นหากคุณต้องการใช้ Spring ในแอปพลิเคชันแบบสแตนด์อโลนคุณจะต้องใช้ (2) เพื่อดำเนินการดังกล่าว "เรียกใช้วิธีนี้หลังจากเริ่มต้น


4
ในทางเทคนิค@PostConstruct(เมื่อใช้ในแอพแบบสปริง) จะเชื่อมโยงกับอายุการใช้งานของบริบทสปริงที่เป็นเจ้าของ บริบทดังกล่าวสามารถใช้ในแอปพลิเคชันทุกประเภท
Donal Fellows

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