วันเสาร์ที่ 23 มกราคม พ.ศ. 2559

Spring part 9-2 Spring Annotation Configuration without XML

>> เพราะจาวาบีนคือพื้นฐานที่โปรเจ็กค์จำเป็นต้องมีเสมอ และ part ที่ผ่านมาได้แสดงให้เห็นว่าเราสามารถ configuration บีนทั้งหมดด้วยภาษาจาวา ใช่ครับ เรายังไม่ได้ใช้ autowire กันเลย

>> เพื่อนๆควรทราบว่า context จะมองหาบีนได้ก็ต้องใช้การสแกน ซึ่ง @ComponentScan คือคำตอบที่เราจะใช้แทนแอตทริบิวต์ component-scan ในไฟล์ applicationContext.xml ครับ (เพราะเราลบไฟล์นี้ทิ้งไปแล้วไงล่ะ หุหุ)

>> @ComponentScan ก็ให้ระบุชื่อ package ที่ต้องการเข้าไป (มันเป็นอาร์เรย์ของสตริงจึงต้องอยู่ในเครื่องหมาย { และ } หรือพื้นฐานการกำหนดค่าเริ่มต้นให้กับอาร์เรย์ของจาวานั่นแหละครับ)

>> สำหรับ @Autowired เจ้า spring จะเลือกทำงาน autowire by constructor หรือ by name หรือ by type โดยอัตโนมัติ

>> เพื่อทดสอบให้เห็นว่าบีนนั้นสำคัญขนาดไหน เราจะยังให้ context เรียกไปที่ service ที่ชื่อ bookService ซึ่งเราได้ประกาศชื่อนี้ไว้แล้วที่ไฟล์ AppConfiguration.java เอาล่ะครับ ให้เริ่มจากลบหรือ comment คำสั่งในไฟล์ BookServiceImpl.java ส่วนที่มีการประกาศใช้ออบเจ็กต์ repository ให้เป็นแบบนี้

private BookRepository repository;

แล้วใส่ autowire เข้าไปอย่างเคย

@Autowired
private BookRepository repository;

แหม~เพื่อนๆคงตอบผมว่ามันรันได้แน่นอน ก็เคยทำมาแล้วนี่ โดยมันจะอาศัย default constructor (constructor ที่เราไม่ได้เขียน) ในการสร้างออบเจ็กต์ แต่เมื่อรันดูจะปรากฏ error ดังนี้ครับ

BeanCreationException
Error creating bean with name 'bookService': Injection of autowired dependencies failed;

BookServiceImpl.repository; nested exception is NoSuchBeanDefinitionException

คือสแกนหา repository bean ไม่เจอ แน่นอนว่าไม่มีทางหาเจอได้เพราะเราไม่ได้นิยามไว้นี่ครับ แก้ไขอย่างไร? ก็กลับไปนิยามให้เรียบร้อย

ไฟล์ชื่อ AppConfiguration.java เพิ่ม

@Bean
public BookRepository getBookRepository() {
return new BookRepositoryImpl();
}

กลไกดังกล่าวนี้ spring จะถือ BookRepository ไว้ในมือก่อนโปรแกรมที่เรียกใช้จะทำงานเสียอีก เมื่อมีความต้องการใช้ไทป์นี้ spring ก็จะบอกกับพ่อบ้าน autowire ว่าจงสร้างออบเจ็กต์และฉีดมันแก่คุณผู้เรียก


>> ที่เหลือก็เป็นการใช้ autowire กับส่วนอื่น ได้แก่
- กับ constructor ก็ต้องเขียน constructor แบบที่ต้องการขึ้นมาเองด้วย
- กับ setter method ก็ต้องเขียน setter method แบบที่ต้องการขึ้นมาเองด้วย

>> by constructor หรือก็คือ constructor injection ก็เขียน constructor กับย้าย @Autowired มาวางไว้ที่มัน

- เป็นเหตุให้โค้ดบางส่วน error เพราะเราไปเปลี่ยนการรับค่าของมัน ก็จัดการ injection หรือฉีดตรงๆแบบนี้เลย (หัวเราะ) ไม่มีเวทมนตร์ใดหรอก โค้ดนี้แสนธรรมดา

- และผลลัพธ์ เย้!


>> by type หรือก็คือ setter injection ก็เขียน setter method ขึ้นมาแล้วย้าย @Autowired ไปวางไว้ที่มัน สำคัญคือใครไม่ลบ constructor ดังตัวอย่างข้างต้นนี้ออกก็ต้องเขียน default constructor ขึ้นมา ไม่งั้นเจอ error ซึ่งกรณีนี้ผมเลือกเขียนเพิ่มครับ

- แก้ไขไฟล์ bean configuration ด้วย ให้เป็นแบบนี้เลย

- ผลการรัน เย้!


>> เพื่อนๆครับหากเรา comment หรือลบบรรทัดที่ประกาศ repository bean ออกไปจากไฟล์ AppConfiguration.java ดังนี้

- สิ่งที่จะเกิดขึ้นคือ spring จะหา bean นี้ไม่เจอ

- แต่เราแก้ไขได้ครับ ด้วยการ injection มันผ่านความสามารถของ @ComponentScan กล่าวคือขอให้ spring สแกนหาก่อนว่าประดาบีนที่เราต้องการนั้นอยู่ที่ไหน นี่จึงกลายเป็นความจำเป็นที่เราต้องใช้ @Component มาช่วยระบุคลาสใดๆที่เราต้องการให้มันเตรียมหรือถือไว้ในมือก่อน นอกจากนี้เรายังจะระบุความเป็น component ของมันให้ชัดเจนขึ้นตามระดับของ layer ดังที่เพื่อนๆทราบมาแล้ว
- รูปด้านล่างนี้แสดงให้เห็นว่า @Repository คือความชัดเจนของระดับ repository layer หรือก็คือ component ตัวหนึ่งที่เราต้องการบอกแก่ spring ครับผม

- ทดสอบการรัน

ไม่มีความคิดเห็น:

แสดงความคิดเห็น