: Injection เหล่าคลาสโดยการใช้ Autowire
ถาม : ขอคำตอบง่ายๆทำไมต้อง Injection?
ตอบ : เพราะไม่อยาก new object เอง ถึงเวลา (want) ก็ฉีด (injection) object นั้นให้ไปใช้เลย
ถาม : ขอคำตอบง่ายๆทำไมต้อง Autowire?
ตอบ : เพราะไม่อยากเขียน config ที่ไฟล์ XML เยอะๆไง (มันเยอะมันยุ่ง มันงง)
ถาม : แล้ว Injection เกี่ยวกับ Autowire อย่างไร?
ตอบ : มันเป็น concept บวกกับวิธีการที่ว่า How to? อธิบายง่ายๆได้ว่า โดยปกติแล้ว object ที่จะถูกใช้งานก็ต้อง new มันขึ้นมาก่อนใช่ไหม? ใช่ นอกจากนี้บรรดา object อาจต้องการทรัพยากร (arguments) หนึ่งสองสามสี่ห้า ไม่รู้แหละ (ใครเคยโค้ดโปรแกรมใหญ่ๆจะรู้ว่ามันทรมารใจมากที่เห็น parameter ยาวเป็นหางงู) จึงต้องหาวิธีการสักอย่างที่จะนำทรัพยากรดังกล่าวใส่ลงไปใน object แบบโค้ดสะอาดที่สุด
- โค้ดในไฟล์ .xml น้อยลงก็ต้องใช้ Autowire
- เตรียม object พร้อมใช้ ก็แค่รอฉีด (injection) มันเข้าไป (ไม่ต้อง new เอง)
ถาม : ชักอยากเห็นการใช้ Injection และ Autowire
ตอบ : เอา project จาก part 6 มาแก้และเพิ่มเติมโค้ดดังนี้สิ
>> autowire="constructor"
เปิดไฟล์ applicationContext.xml ลบหรือ comment แท็ก <property ... ></property> แล้วเพิ่ม autowire เข้าไปแทน (ลดโค้ด โค้ดน้อยลง โค้ดก็สะอาดขึ้น) ดังด้านล่าง
<bean name="customerService" class="com.sample.service.CustomerServiceImpl" autowire="constructor" >
</bean>
ทดสอบการ run ก็จะได้ผลลัพธ์ตามเดิม เรียกวิธีการนี้ว่า 'Constructor Injection' โดยจะมองไปที่ไทป์และจำนวนของไทป์ที่จะส่งให้ constructor นั้นๆเป็นสำคัญ
ทดลองเปลี่ยน autowire เป็นแบบ byName และ byType แล้ว run สลับกับการ comment หรือ uncomment ในไฟล์ CustomerServiceImpl.java พลางสังเกตผลลัพธ์ ด้วยเงื่อนไขต่างๆต่อไปนี้
>> autowire="byName"
ทำงานกับชื่อของ setter method ต่างๆ ดังนั้น setCustomerRepository จึงถูกเรียกให้ทำงาน โดยจะตัด set ออกเหลือเพียง customerRepository แล้วเทียบกับแท็ก bean ในไฟล์ .xml ที่ระบุชื่อเดียวกันนี้ นั่นก็คือ
<bean name="customerRepository" class="com.sample.repository.HibernateCustomerRepositoryImpl" />
หมายความว่าอย่างไร? หมายความว่า ถ้าเราเขียน setter method ในไฟล์ CustomerServiceImpl.java เป็น setCustomerRepository1 ก็ต้องเขียน bean name ข้างต้นเป็น customerRepository1 ด้วย นี่จึงเรียกว่าการ 'Injection by Name'
*** หมายเหตุ หากว่ารันเจอ error แบบนี้หมายความว่าอย่างไร?
- แสดงว่าคลาส CustomerServiceImpl ขาด default constructor ตามที่มันบอกงั้นเหรอ? ไม่เชิงเสียทีเดียว เพราะว่าเราได้ไปสร้าง constructor ขึ้นมาเองและบังคับให้มันผ่านออบเจ็กต์ของคลาส CustomerRepository ซึ่งไม่ใช่ constructor แบบที่มันต้องการ, มันต้องการ constructor เพิ่มอีกหนึ่งตัว (หากว่าเราไม่ลบ constructor เดิมทิ้งก่อน) ที่มีหน้าตาเหมือน default constructor เป๊ะๆ ดังรูปนี้ครับ
>> autowire="byType"
ทำงานกับไทป์ของ setter method ต่างๆ ขอเพียงไทป์ตรงกัน setter method นั้นๆก็จะถูกเรียกให้ทำงานทันที
หมายความว่าอย่างไร? หมายความว่า สมมติว่าถ้ามี
setCustomerRepository1,
setCustomerRepository2,
setCustomerRepository3 และ setFoo (ชื่อไม่เกี่ยวกับชาวบ้านเลย)
ที่รับไทป์แบบเดียวกันทั้งหมด มันก็จะไล่ทำ setter ข้างต้นนี้หมดเบยไงก๊าบ นี่จึงเรียกว่าการ 'Injection by Type'
*** ตามที่ได้บอกไป ทั้ง byName และ byType จะต้องมี default constructor แบบเขียนเองด้วยเสมอ (ยกเว้นเราไม่เขียน constructor เลยสักตัว แต่ปล่อยให้จาวาสร้างให้ ก็จะมี default constructor ให้ใช้โดยอัตโนมัติ)
part นี้ไม่มีไฟล์ให้นะครับ คืนนี้ฝันดีครับ
>> กลับมาตอบข้อสงสัยของเพื่อนๆที่ว่า มันเรียงลำดับการทำงานของ setter methods อย่างไรกับ autowire="byType"
คำตอบนี้ตามภาพเลยครับ
ขอบคุณเพื่อน Phruds Kaewmuang ที่ช่วยให้คำตอบครับ :)
คือมันไล่ทำงานตาม Method ที่เราเขียนเรียงไว้ใน file จากบนลงล่างด้วยใช่ไหมคับ
ตอบลบสำหรับ autowire="byType" มันจะไล่ทำงานเรียงตาม method ที่เราเขียนไว้ ใช่ครับ แต่จะเรียงอย่างไรนั้นผมก็ไม่ได้สังเกต ทว่าหัวใจของการ byType ก็คือไทป์ ดังนั้นให้พึงทราบว่ามันจะทำงานครบทุก method ที่เข้าเงื่อนไขอย่างแน่นอนครับ
ลบความคิดเห็นนี้ถูกผู้เขียนลบ
ตอบลบเหมือนจะไล่ตามชื่อครับ
ตอบลบเปลี่ยนชื่อ setter ตัวสุดท้ายเป็น setBxxxxxx แล้วรัน ดูผลการเรียง
เปลี่ยนชื่อ setter ตัวสุดท้ายเป็น setDxxxxxx แล้วรัน ดูผลการเรียง