คำแนะนำเกี่ยวกับ Spring @Autowired

1. ภาพรวม

เริ่มต้นด้วยฤดูใบไม้ผลิ 2.5 กรอบการแนะนำให้รู้จักคำอธิบายประกอบที่ขับเคลื่อนด้วยการพึ่งพาการฉีด คำอธิบายประกอบหลักของคุณลักษณะนี้@Autowired ช่วยให้ Spring แก้ไขและฉีดถั่วร่วมลงในถั่วของเรา

ในบทช่วยสอนนี้ก่อนอื่นเราจะมาดูวิธีเปิดใช้งานการเดินสายอัตโนมัติและไฟล์ต่างๆวิธีปลูกถั่วอัตโนมัติ หลังจากนั้นเราจะพูดถึงการแก้ไขความขัดแย้งของ bean โดยใช้คำอธิบายประกอบ@Qualifierตลอดจนสถานการณ์ข้อยกเว้นที่อาจเกิดขึ้น

2. การเปิดใช้งาน@Autowired Annotations

กรอบสปริงช่วยให้การฉีดพึ่งพาอัตโนมัติ กล่าวอีกนัยหนึ่งคือการประกาศการพึ่งพา bean ทั้งหมดในไฟล์การกำหนดค่า Spring Spring container สามารถกำหนดความสัมพันธ์ระหว่าง bean ที่ทำงานร่วมกันได้โดยอัตโนมัติ นี้เรียกว่าถั่ว Spring autowiring

หากต้องการใช้การกำหนดค่าบน Java ในแอปพลิเคชันของเราให้เปิดใช้งานการแทรกคำอธิบายประกอบเพื่อโหลดการกำหนดค่า Spring ของเรา:

@Configuration @ComponentScan("com.baeldung.autowire.sample") public class AppConfig {}

หรืออีกวิธีหนึ่งคือ คำอธิบายประกอบส่วนใหญ่จะใช้เพื่อเปิดใช้งานคำอธิบายประกอบการฉีดการพึ่งพาในไฟล์ Spring XML

นอกจากนี้ฤดูใบไม้ผลิ Boot แนะนำ@SpringBootApplicationคำอธิบายประกอบ นี้มูลเดียวเทียบเท่ากับการใช้@Configuration , @EnableAutoConfigurationและ@ComponentScan

มาใช้คำอธิบายประกอบนี้ในคลาสหลักของแอปพลิเคชัน:

@SpringBootApplication class VehicleFactoryApplication { public static void main(String[] args) { SpringApplication.run(VehicleFactoryApplication.class, args); } }

ดังนั้นเมื่อเราเรียกใช้แอปพลิเคชัน Spring Boot นี้แอปพลิเคชันจะสแกนส่วนประกอบในแพ็คเกจปัจจุบันและแพ็กเกจย่อยโดยอัตโนมัติ ดังนั้นมันจึงจะลงทะเบียนไว้ในบริบทแอพลิเคชันฤดูใบไม้ผลิและช่วยให้เราสามารถใช้ถั่วฉีด@Autowired

3. ใช้@Autowired

หลังจากเปิดใช้ฉีดบันทึกย่อที่เราสามารถใช้ autowiring ในคุณสมบัติ setters และก่อสร้าง

3.1. @ อัตโนมัติเกี่ยวกับคุณสมบัติ

มาดูกันว่าเราจะใส่คำอธิบายประกอบคุณสมบัติโดยใช้@Autowiredได้อย่างไร สิ่งนี้ทำให้ไม่ต้องใช้ตัวรับและตัวตั้งค่า

ก่อนอื่นให้กำหนดfooFormatter bean:

@Component("fooFormatter") public class FooFormatter { public String format() { return "foo"; } }

จากนั้นเราจะฉีดถั่วนี้ลงในFooServiceถั่วใช้@Autowiredในความหมายภาคสนาม:

@Component public class FooService { @Autowired private FooFormatter fooFormatter; }

เป็นผลให้ Spring ฉีดfooFormatterเมื่อสร้างFooService

3.2. @Autowiredบน Setters

ทีนี้มาลองเพิ่มคำอธิบายประกอบ@Autowiredในวิธี setter

ในตัวอย่างต่อไปนี้เมธอด setter ถูกเรียกด้วยอินสแตนซ์ของFooFormatterเมื่อสร้างFooService :

public class FooService { private FooFormatter fooFormatter; @Autowired public void setFooFormatter(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } } 

3.3. @Autowired on Constructors

สุดท้ายให้ใช้@Autowiredกับตัวสร้าง

เราจะเห็นว่าอินสแตนซ์ของFooFormatterถูกฉีดโดย Spring เพื่อเป็นอาร์กิวเมนต์ของตัวสร้างFooService :

public class FooService { private FooFormatter fooFormatter; @Autowired public FooService(FooFormatter fooFormatter) { this.fooFormatter = fooFormatter; } }

4. @ การพึ่งพาอัตโนมัติและเป็นทางเลือก

เมื่อสร้าง bean ควรมีการอ้างอิง@Autowired มิฉะนั้นถ้าฤดูใบไม้ผลิไม่สามารถแก้ไขถั่วสำหรับการเดินสายก็จะโยนข้อยกเว้น

ดังนั้นจึงป้องกันไม่ให้ Spring container เปิดใช้งานได้สำเร็จยกเว้นแบบฟอร์ม:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.autowire.sample.FooDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

ในการแก้ไขปัญหานี้เราจำเป็นต้องประกาศ bean ประเภทที่ต้องการ:

public class FooService { @Autowired(required = false) private FooDAO dataAccessor; }

5. ปิดการแจ้งเตือนอัตโนมัติ

ตามค่าเริ่มต้น Spring จะแก้ไขรายการ@Autowiredตามประเภท หากมีมากกว่าหนึ่งถั่วชนิดเดียวกันที่มีอยู่ในภาชนะที่กรอบจะโยนยกเว้นร้ายแรง

ในการแก้ไขความขัดแย้งนี้เราต้องบอก Spring อย่างชัดเจนว่าเราต้องการฉีดถั่วชนิดใด

5.1. การเริ่มอัตโนมัติโดย@Qualifier

ตัวอย่างเช่นมาดูกันว่าเราจะใช้คำอธิบายประกอบ@Qualifierเพื่อระบุ bean ที่ต้องการได้อย่างไร

ขั้นแรกเราจะกำหนดฟอร์แมตเตอร์ประเภทถั่ว 2 ชนิด:

@Component("fooFormatter") public class FooFormatter implements Formatter { public String format() { return "foo"; } }
@Component("barFormatter") public class BarFormatter implements Formatter { public String format() { return "bar"; } }

ตอนนี้เรามาลองฉีดFormatter bean ลงในคลาสFooService :

public class FooService { @Autowired private Formatter formatter; }

In our example, there are two concrete implementations of Formatter available for the Spring container. As a result, Spring will throw a NoUniqueBeanDefinitionException exception when constructing the FooService:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.autowire.sample.Formatter] is defined: expected single matching bean but found 2: barFormatter,fooFormatter 

We can avoid this by narrowing the implementation using a @Qualifier annotation:

public class FooService { @Autowired @Qualifier("fooFormatter") private Formatter formatter; }

When there are multiple beans of the same type, it's a good idea to use @Qualifier to avoid ambiguity.

Please note that the value of the @Qualifier annotation matches with the name declared in the @Component annotation of our FooFormatter implementation.

5.2. Autowiring by Custom Qualifier

Spring also allows us to create our own custom @Qualifier annotation. To do so, we should provide the @Qualifier annotation with the definition:

@Qualifier @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface FormatterType { String value(); }

Then we can use the FormatterType within various implementations to specify a custom value:

@FormatterType("Foo") @Component public class FooFormatter implements Formatter { public String format() { return "foo"; } }
@FormatterType("Bar") @Component public class BarFormatter implements Formatter { public String format() { return "bar"; } }

Finally, our custom Qualifier annotation is ready to use for autowiring:

@Component public class FooService { @Autowired @FormatterType("Foo") private Formatter formatter; } 

The value specified in the @Target meta-annotation restricts where to apply the qualifier, which in our example is fields, methods, types, and parameters.

5.3. Autowiring by Name

Spring uses the bean's name as a default qualifier value. It will inspect the container and look for a bean with the exact name as the property to autowire it.

Hence, in our example, Spring matches the fooFormatter property name to the FooFormatter implementation. Therefore, it injects that specific implementation when constructing FooService:

public class FooService { @Autowired private Formatter fooFormatter; }

6. Conclusion

In this article, we discussed autowiring and the different ways to use it. We also examined ways to solve two common autowiring exceptions caused by either a missing bean or an ambiguous bean injection.

The source code of this article is available on the GitHub project.