ทำความเข้าใจกับคลาส spring @Configuration


108

หลังจากคำถามทำความเข้าใจกับการใช้งาน Spring @Autowiredฉันต้องการสร้างฐานความรู้ที่สมบูรณ์สำหรับตัวเลือกอื่น ๆ ของการเดินสายสปริง@Configurationคลาส

สมมติว่าฉันมีไฟล์ XML ฤดูใบไม้ผลิที่มีลักษณะดังนี้:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <import resource="another-application-context.xml"/>

  <bean id="someBean" class="stack.overflow.spring.configuration.SomeClassImpl">
    <constructor-arg value="${some.interesting.property}" />
  </bean>

  <bean id="anotherBean" class="stack.overflow.spring.configuration.AnotherClassImpl">
    <constructor-arg ref="someBean"/>
    <constructor-arg ref="beanFromSomewhereElse"/>
  </bean>
</beans>

ฉันจะใช้@Configurationแทนได้อย่างไร? มันมีผลกับตัวโค้ดหรือไม่?

คำตอบ:


152

การโอนย้าย XML เป็น @Configuration

เป็นไปได้ที่จะย้าย xml ไปยัง@Configurationขั้นตอนต่อไปนี้:

  1. สร้าง@Configurationคลาสที่มีคำอธิบายประกอบ:

    @Configuration
    public class MyApplicationContext {
    
    }
  2. สำหรับแต่ละ<bean>แท็กให้สร้างเมธอดที่มีคำอธิบายประกอบ@Bean:

    @Configuration
    public class MyApplicationContext {
    
      @Bean(name = "someBean")
      public SomeClass getSomeClass() {
        return new SomeClassImpl(someInterestingProperty); // We still need to inject someInterestingProperty
      }
    
      @Bean(name = "anotherBean")
      public AnotherClass getAnotherClass() {
        return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse); // We still need to inject beanFromSomewhereElse
      }
    }
  3. ในการนำเข้าbeanFromSomewhereElseเราจำเป็นต้องนำเข้าคำจำกัดความ สามารถกำหนดได้ใน XML และเราจะใช้@ImportResource:

    @ImportResource("another-application-context.xml")
    @Configuration
    public class MyApplicationContext {
      ...  
    }

    ถ้า bean ถูกกำหนดใน@Configurationคลาสอื่นเราสามารถใช้@Importคำอธิบายประกอบ:

    @Import(OtherConfiguration.class)
    @Configuration
    public class MyApplicationContext {
      ...
    }
  4. หลังจากที่เรานำเข้า XML หรือ@Configurationคลาสอื่น ๆแล้วเราสามารถใช้ถั่วที่พวกเขาประกาศในบริบทของเราได้โดยการประกาศสมาชิกส่วนตัวใน@Configurationคลาสดังนี้:

    @Autowired
    @Qualifier(value = "beanFromSomewhereElse")
    private final StrangeBean beanFromSomewhereElse;

    หรือใช้เป็นพารามิเตอร์โดยตรงในวิธีการที่กำหนด bean ที่ขึ้นอยู่กับสิ่งนี้beanFromSomewhereElseโดยใช้@Qualifierดังนี้:

    @Bean(name = "anotherBean")
    public AnotherClass getAnotherClass(@Qualifier (value = "beanFromSomewhereElse") final StrangeBean beanFromSomewhereElse) {
      return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse);
    }
  5. คุณสมบัติการนำเข้าคล้ายกับการนำเข้า bean จาก xml หรือ@Configurationคลาสอื่นมาก แทนที่จะใช้@Qualifierเราจะใช้@Valueกับคุณสมบัติดังนี้:

    @Autowired
    @Value("${some.interesting.property}")
    private final String someInterestingProperty;

    สามารถใช้กับนิพจน์SpEL ได้เช่นกัน

  6. ในการอนุญาตให้สปริงจัดการคลาสเช่นคอนเทนเนอร์ถั่วเราจำเป็นต้องทำเครื่องหมายสิ่งนี้ใน xml หลักของเราโดยใส่แท็กนี้ในบริบท:

    <context:annotation-config/>

    ตอนนี้คุณสามารถนำเข้า@Configurationคลาสได้เหมือนกับที่คุณสร้าง bean ง่ายๆ:

    <bean class="some.package.MyApplicationContext"/>

    มีหลายวิธีในการหลีกเลี่ยง Spring XMLs โดยสิ้นเชิง แต่ไม่ได้อยู่ในขอบเขตของคำตอบนี้ คุณสามารถค้นหาหนึ่งในตัวเลือกเหล่านี้ได้ในบล็อกโพสต์ซึ่งฉันใช้คำตอบของฉัน


ข้อดีและข้อเสียของการใช้วิธีนี้

โดยทั่วไปฉันพบว่าวิธีการประกาศถั่วนี้สะดวกสบายมากกว่าการใช้ XML เนื่องจากมีข้อดีบางประการที่ฉันเห็น:

  1. Typos - @Configurationคลาสถูกรวบรวมและการพิมพ์ผิดจะไม่อนุญาตให้รวบรวม
  2. ล้มเหลวอย่างรวดเร็ว (เวลาคอมไพล์) - หากคุณลืมฉีด bean คุณจะล้มเหลวในเรื่องเวลาคอมไพล์และไม่อยู่ในรันไทม์เช่นเดียวกับ XML
  3. ง่ายต่อการนำทางใน IDE - ระหว่างผู้สร้างถั่วเพื่อทำความเข้าใจกับแผนผังการพึ่งพา
  4. สามารถดีบักการเริ่มต้นการกำหนดค่าได้อย่างง่ายดาย

ข้อเสียมีไม่มากเท่าที่ฉันเห็น แต่มีบางส่วนที่ฉันคิดได้:

  1. การละเมิด - โค้ดนั้นละเมิดง่ายกว่า XML
  2. ด้วย XML คุณสามารถกำหนดการอ้างอิงตามคลาสที่ไม่พร้อมใช้งานในช่วงเวลาคอมไพล์ แต่มีให้ในระหว่างรันไทม์ ด้วย@Configurationชั้นเรียนคุณต้องมีชั้นเรียนพร้อมใช้งานในเวลารวบรวม โดยปกติแล้วนั่นไม่ใช่ปัญหา แต่ก็มีหลายกรณีเช่นกัน

บรรทัดด้านล่าง: เป็นการดีที่จะรวม XML @Configurationและคำอธิบายประกอบในบริบทแอปพลิเคชันของคุณ Spring ไม่สนใจวิธีการประกาศถั่ว


2
ข้อเสียที่เป็นไปได้อย่างหนึ่งคือการสูญเสียการกำหนดค่า สมมติว่าคุณมีคลาสที่เลียนแบบฟังก์ชันการทำงานบางอย่างในการพัฒนาแล้วคุณต้องการเปลี่ยนเป็นคลาสอื่นในสภาพแวดล้อม UAT การใช้ XML นั้นเป็นเพียงเรื่องของการเปลี่ยนการกำหนดค่าและอนุญาตให้แอปพลิเคชันทำงาน / รีสตาร์ท ด้วยการกำหนดค่าคลาสใหม่เหล่านี้จะต้องคอมไพล์คลาสใหม่
Jose

5
@JoseChavez - นั่นเป็นข้อโต้แย้งที่ดีที่ฉันได้ยินมาสองสามครั้งแล้ว และฉันพยายามทำการวิจัยทางสถิติซึ่งฉันไม่พบแอปหรือระบบใด ๆ ที่ใช้ XML นอกขวด / สงคราม ความหมายในทางปฏิบัติของมันคือคุณต้องคลายซิปและเปลี่ยน XML (ซึ่งฉันไม่พบใครที่ทำแบบนั้น) หรือสร้างไหของคุณขึ้นมาใหม่ (ซึ่งเป็นสิ่งที่ทุกคนที่ฉันคุยด้วยบอกว่าพวกเขาทำไปแล้ว) . ดังนั้นบรรทัดล่าง - เนื่องจากอาจเป็นข้อโต้แย้งที่มาก แต่โดยปกติแล้วจะไม่สำคัญในชีวิตจริง
Avi

6
นั่นคือสิ่งที่หมายเหตุประกอบ @Profile และไวยากรณ์ "$ {env.value}" มีไว้สำหรับ ด้วย @Profile ("someName") คุณสามารถแท็กการกำหนดค่าทั้งหมดเพื่อใช้เฉพาะเมื่อโปรไฟล์ทำงานอยู่ ในไฟล์ application.properties (หรือ .yml) ของคุณคุณสามารถตั้งค่า spring.profiles.active = someName เป็นค่าเริ่มต้น ... ในการตั้งค่าแบบไดนามิกตามตัวแปรสภาพแวดล้อมให้ใช้ไวยากรณ์ $ {SOME_ENV_VAR} เป็นค่าสำหรับ spring active.profiles และตั้งค่าตัวแปรสภาพแวดล้อม Spring แนะนำให้ใช้ java config - docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
Jack Viers

มีทางเลือกอื่นนอกเหนือจากการกำหนดแต่ละ bean เป็นวิธีการในไฟล์ config?
Asif Mushtaq

@AsifMushtaq - คุณสามารถใช้คุณสมบัติการสแกนอัตโนมัติและแต่ละคลาสที่มี@Component @Serviceหรือคำอธิบายประกอบอื่น ๆ จะถูกสร้างเป็นถั่วโดยอัตโนมัติ (แต่นั่นไม่ใช่ประเด็นสำคัญของคำถามนี้)
Avi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.