Tìm hiểu về lớp Spring @Configuration


108

Tiếp theo câu hỏi Tìm hiểu về Spring @ Cách sử dụng mong muốn, tôi muốn tạo một cơ sở kiến ​​thức hoàn chỉnh cho tùy chọn khác của hệ thống dây lò xo, @Configurationlớp.

Giả sử tôi có một tệp XML mùa xuân trông giống như sau:

<?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>

Làm thế nào tôi có thể sử dụng @Configurationthay thế? Nó có ảnh hưởng gì đến mã không?

Câu trả lời:


151

Di chuyển XML sang @Configuration

Có thể di chuyển xml sang a @Configurationtrong một vài bước:

  1. Tạo một @Configurationlớp có chú thích:

    @Configuration
    public class MyApplicationContext {
    
    }
    
  2. Đối với mỗi <bean>thẻ, hãy tạo một phương thức được chú thích bằng @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. Để nhập, beanFromSomewhereElsechúng ta cần nhập định nghĩa của nó. Nó có thể được định nghĩa trong một XML và chúng tôi sẽ sử dụng @ImportResource:

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

    Nếu bean được định nghĩa trong một @Configurationlớp khác, chúng ta có thể sử dụng @Importchú thích:

    @Import(OtherConfiguration.class)
    @Configuration
    public class MyApplicationContext {
      ...
    }
    
  4. Sau khi chúng tôi nhập các @Configurationlớp hoặc lớp XML khác , chúng tôi có thể sử dụng các bean mà chúng khai báo trong ngữ cảnh của chúng tôi bằng cách khai báo một thành viên riêng cho @Configurationlớp như sau:

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

    Hoặc sử dụng trực tiếp nó làm tham số trong phương thức xác định bean phụ thuộc vào điều này beanFromSomewhereElsebằng cách sử dụng @Qualifiernhư sau:

    @Bean(name = "anotherBean")
    public AnotherClass getAnotherClass(@Qualifier (value = "beanFromSomewhereElse") final StrangeBean beanFromSomewhereElse) {
      return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse);
    }
    
  5. Nhập thuộc tính rất giống với nhập bean từ xml hoặc @Configurationlớp khác. Thay vì sử dụng, @Qualifierchúng tôi sẽ sử dụng @Valuevới các thuộc tính như sau:

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

    Điều này cũng có thể được sử dụng với biểu thức SpEL .

  6. Để cho phép spring xử lý các lớp như vậy như vùng chứa bean, chúng ta cần đánh dấu điều này trong xml chính của chúng ta bằng cách đặt thẻ này vào ngữ cảnh:

    <context:annotation-config/>

    Bây giờ bạn có thể nhập @Configurationcác lớp giống hệt như cách bạn tạo một bean đơn giản:

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

    Có nhiều cách để tránh hoàn toàn các XML mùa xuân nhưng chúng không nằm trong phạm vi của câu trả lời này. Bạn có thể tìm thấy một trong những tùy chọn này trong bài đăng trên blog của tôi mà tôi đang dựa trên câu trả lời của mình.


Ưu điểm và nhược điểm của việc sử dụng phương pháp này

Về cơ bản, tôi thấy phương pháp khai báo bean này thoải mái hơn nhiều so với việc sử dụng XML do một số ưu điểm mà tôi thấy:

  1. Lỗi@Configuration chính tả - các lớp được biên dịch và lỗi chính tả sẽ không cho phép biên dịch
  2. Không nhanh (thời gian biên dịch) - Nếu bạn quên chèn một bean, bạn sẽ thất bại về thời gian biên dịch chứ không phải về thời gian chạy như với các XML
  3. Dễ dàng điều hướng hơn trong IDE - giữa các hàm tạo của bean để hiểu cây phụ thuộc.
  4. Có thể dễ dàng gỡ lỗi khởi động cấu hình

Những nhược điểm không nhiều như tôi thấy nhưng có một số nhược điểm mà tôi có thể nghĩ đến:

  1. Lạm dụng - Mã dễ bị lạm dụng hơn XML
  2. Với XML, bạn có thể xác định các phụ thuộc dựa trên các lớp không có sẵn trong thời gian biên dịch nhưng được cung cấp trong thời gian chạy. Với @Configurationcác lớp, bạn phải có sẵn các lớp tại thời điểm biên dịch. Thông thường đó không phải là một vấn đề, nhưng có thể có một số trường hợp.

Điểm mấu chốt: Việc kết hợp các XML @Configurationchú thích trong ngữ cảnh ứng dụng của bạn là hoàn toàn tốt . Spring không quan tâm đến phương thức mà bean đã được khai báo.


2
Một nhược điểm có thể xảy ra là mất cấu hình. Giả sử bạn có một lớp mô phỏng một số chức năng đang phát triển, sau đó bạn muốn hoán đổi nó cho một lớp khác trong môi trường UAT. Sử dụng XML, thì vấn đề chỉ là thay đổi cấu hình và cho phép ứng dụng chạy / khởi động lại. Với các cấu hình lớp mới này, các lớp sẽ phải được biên dịch lại.
Jose

5
@JoseChavez - Đó là một lập luận tuyệt vời mà tôi đã nghe một vài lần. Và tôi đã cố gắng thực hiện một số nghiên cứu thống kê trong đó tôi không thể tìm thấy bất kỳ ứng dụng hoặc hệ thống nào sử dụng XML bên ngoài các bình / chiến tranh của nó. Ý nghĩa thực tế của nó là bạn cần giải nén jar và thay đổi XML (mà tôi không thể tìm thấy bất kỳ ai làm điều đó) hoặc xây dựng lại các lọ của bạn (đó là điều mà mọi người tôi đã nói chuyện cho biết họ đã làm cho đến nay) . Vì vậy, điểm mấu chốt - vì nó có thể là một lập luận đáng kể, nó thường không quan trọng trong cuộc sống thực.
Avi

6
Đó là ý nghĩa của chú thích @Profile và cú pháp "$ {env.value}". Với @Profile ("someName"), bạn có thể gắn thẻ toàn bộ cấu hình để chỉ sử dụng khi cấu hình đang hoạt động. Trong tệp application.properties (hoặc .yml), bạn có thể đặt spring.profiles.active = someName, default ... Để đặt nó động dựa trên các biến môi trường, hãy sử dụng cú pháp $ {SOME_ENV_VAR} làm giá trị cho mùa xuân. active.profiles và đặt biến môi trường. Spring hiện khuyên bạn nên sử dụng java config - docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
Jack Viers

Có gì thay thế ngoài việc xác định từng bean dưới dạng phương thức trong tệp cấu hình?
Asif Mushtaq

@AsifMushtaq - Bạn có thể sử dụng tính năng autoscan và mỗi lớp có @Component @Servicehoặc chú thích khác như vậy sẽ được tự động được chuyển thể thành đậu (nhưng đó không phải là trọng tâm của câu hỏi này)
Avi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.