ในการใช้งานเว็บแอพพลิเคชั่นต้องมีการสร้างออบเจกต์ขึ้นมามากมาย บางออบเจกต์ก็ต้องสร้างออบเจกต์ขึ้นมาภายในตัวเองและออบเจต์นั้นก็อาจจะต้องสร้างออบเจกต์ขึ้นมาในตัวเองเพื่อใช้งานอีกเช่นกัน จึงเกิดเป็นห่วงโซ่ของออบเจต์ที่ซับซ้อนขึ้นมากมาย
Spring Boot ช่วยเราจัดการเรื่องเหล่านี้ให้ง่ายขึ้นโดยการสร้างออบเจกต์ที่จำเป็นตั้งแต่ขั้นตอนการเริ่มต้นใช้งานแอพพลิเคชั่นและเก็บออบเจกต์ที่สร้างขึ้นมารวมกันเอาไว้ในรูปแบบที่เรียกว่าคอนเทนเนอร์ (container) และเมื่อออบเจกต์ใดต้องการใช้งานออบเจกต์อื่นก็จะมาเรียกใช้ออบเจดต์จากคอนเทนเนอร์โดยไม่จำเป็นต้องสร้างออบเจกต์ขึ้นมาใหม่เอง เราเรียกออบเจกต์ต่างๆที่อยู่ในคอนเทนเนอร์ว่าบีน (bean) ส่วนคอนเทนเนอร์จะเป็น IoC container โดย IoC ย่อมาจาก inversion of control หมายถึงการกลับข้างกันของการควบคุม
ลักษณะการทำงานคือเมื่อออบเจกต์ต้นทางต้องการสร้างออบเจกต์ขึ้นมาใช้งาน IoC จะจัดให้มีออบเจกต์ที่ต้องการผ่านทางเมธอดคอนสตรัคเตอร์หรือฟิลด์ของออบเจกต์ต้นทาง จากนั้นคอนเทนเนอร์จะสร้างออบเจกต์ขึ้นมาและส่ง (inject) ให้กับออบเจกต์ต้นทางนำไปใช้งาน วิธีการนี้ช่วยลดภาระของออบเจกต์ต้นทางในการสร้าง กำหนดค่าเริ่มต้น และยกเลิกใช้งานออบเจกต์ โดย IoC จะเป็นตัวที่ทำสิ่งเหล่านั้นแทน เราจึงเรียกว่าการกลับข้างกันของการควบคุมเพราะออบเจกต์ต้นทางมอบให้ IoC จัดการวงจรชีวิตของฟิลด์ของตนเอง
เราบอกว่าออบเจกต์ใดที่เราต้องการให้เป็นบีนได้โดยการกำกับด้วย @Component และเมื่อ Spring Boot เรียกแอพพลิเคชั่นขึ้นมาทำงานจะมองหาคลาสที่กำกับด้วย @Component และสร้างออบเจกต์ขึ้นมาอย่างน้อยหนึ่งออบเจกต์และเก็บเอาไว้ในคอนเทนเนอร์ ออบเจกต์หรือบีนที่ถูกสร้างขึ้นมาจะเป็นออบเจกต์แบบ singleton ส่วนการเรียกใช้งานบีนที่อยู่ในคอนเทนเนอร์โดยบีนอื่นจะกำกับด้วย @Autowired ในคลาสที่ต้องการใช้งานเพื่อบอก Spring Boot ถึงจุดที่ต้องการใช้งานบีน ตัวอย่างเช่น เรากำหนดให้คลาส InkSupply เป็นบีน และเรียกใช้บีนในคลาส Printer ซึ่งจากตัวอย่างจะแสดงให้เห็นทั้งการเรียกใช้ผ่านเมธอดคอนสตรัคเตอร์และฟิลด์ แต่แนะนำให้เรียกใช้ผ่านเมธอดคอนสตรัคเตอร์มากกว่า เพราะชัดเจนกว่า ช่วยในเรื่องความปลอดภัยของเธรด และทำให้การทดสอบง่ายขึ้น
@Component // << บอก Spring Boot ว่าคลาสนี้เป็นบีน
public class InkSupply {
private final String INK_MESSAGE = “This is ink supply”;
public InkSupply() {
}
public String getMessage(){
return INK_MESSAGE;
}
}
@Component // << บอก Spring Boot ว่าคลาสนี้เป็นบีน
public class Printer {
private InkSupply inkSupply;
@Autowired // << บอก Spring Boot ว่าบีนถูกใช้ผ่านเมธอดคอนสตรัคเตอร์ตรงนี้ (inject to constructor)
public Printer(InkSupply inkSupply) {
this.inkSupply = inkSupply;
}
public void printHello(){
System.out.println(inkSupply.getMessage());
}
}
หรือ
@Component // << บอก Spring Boot ว่าคลาสนี้เป็นบีน
public class Printer {
@Autowired // << บอก Spring Boot ว่าบีนถูกใช้ผ่านฟิลด์ตรงนี้ (inject to field)
private InkSupply inkSupply;
public void printHello(){
System.out.println(inkSupply.getMessage());
}
}
ในกรณีที่เราต้องการให้คลาสในไลบรารี่เป็นบีนแต่เราไม่สามารถแก้ไขคลาสเพื่อกำกับด้วย @Component ได้ เราจะใช้วิธีการสร้างคลาสที่เป็นตัวสร้างบีนขึ้นมาคือเป็นคลาสที่กำกับด้วย @Configuration จากนั้นใช้เมธอดสั่งสร้างออบเจกต์จากคลาสที่เราต้องการ โดยกำกับเมธอดที่เรียกใช้คลาสที่เราต้องการด้วย @Bean ส่วนการเรียกใช้งานจะเหมือนกันกับกรณีการสร้างบีนแบบปรกติ จะเห็นว่าด้วยวิธีการนี้ Spring Boot ก็จะสร้างบีนจากคลาสในไลบรารี่ขึ้นมาให้เราได้เช่นกัน ตัวอย่างเช่น ถ้า คลาส InkSupply เป็นคลาสในไลบรารี่ที่เราต้องการสร้างบีน
// ไม่สามารถกำหนด @Component ได้เนื่องจากไม่ใช่คลาสที่เราเขียนขึ้นมาเอง
public class InkSupply {
private final String INK_MESSAGE = “This is ink supply”;
public InkSupply() {
}
public String getMessage(){
return INK_MESSAGE;
}
}
//สร้างคลาสขึ้นมาเพื่อสร้างออบเจกต์จากคลาส InkSupply และกำกับคลาสด้วย @Configuration และกำกับเมธอดที่ใช้
//สร้างออบเจกต์ด้วย @Bean
@Configuration
public class PrinterConfiguration {
@Bean
public InkSupply getInkSupply(){
InkSupply inkSupply = new InkSupply();
//setting something in the inkSupply
return inkSupply;
}
}
@Component
public class Printer {
private InkSupply inkSupply;
@Autowired // <– จากนั้นเรียกใช้บีนตามปรกติ
public Printer(InkSupply inkSupply) {
this.inkSupply = inkSupply;
}
}