Tiêm hạt đậu mùa xuân vào các vật thể không được quản lý

1. Lực lượng lái xe

Trong ứng dụng Spring, việc tiêm một hạt đậu này vào một hạt đậu khác là rất phổ biến. Tuy nhiên, đôi khi bạn muốn tiêm một hạt đậu vào một vật thể bình thường. Ví dụ: chúng tôi có thể muốn lấy tham chiếu đến các dịch vụ từ bên trong một đối tượng thực thể.

May mắn thay, đạt được điều đó không khó như bạn tưởng. Các phần sau đây sẽ trình bày cách thực hiện bằng cách sử dụng chú thích @Configurable và trình dệt AspectJ.

2. Chú thích @Configurable

Chú thích này cho phép các thể hiện của lớp được trang trí chứa các tham chiếu đến Spring bean.

2.1. Xác định và đăng ký một Spring Bean

Trước khi bao gồm chú thích @Configurable , hãy thiết lập định nghĩa Spring bean:

@Service public class IdService { private static int count; int generateId() { return ++count; } }

Lớp này được trang trí với chú thích @Service ; do đó nó có thể được đăng ký với bối cảnh Spring thông qua quét thành phần.

Đây là một lớp cấu hình đơn giản cho phép cơ chế đó:

@ComponentScan public class AspectJConfig { }

2.2. Sử dụng @Configurable

Ở dạng đơn giản nhất, chúng ta có thể sử dụng @Configurable mà không cần bất kỳ phần tử nào:

@Configurable public class PersonObject { private int id; private String name; public PersonObject(String name) { this.name = name; } // getters and other code shown in the next subsection }

Các @Configurable chú thích, trong trường hợp này, đánh dấu sự PersonObject lớp có đủ điều kiện để cấu hình Spring-driven.

2.3. Đưa Spring Bean vào một vật thể không được quản lý

Chúng ta có thể đưa IdService vào PersonObject , giống như chúng ta làm trong bất kỳ Spring bean nào:

@Configurable public class PersonObject { @Autowired private IdService idService; // fields, constructor and getters - shown in the previous subsection void generateId() { this.id = idService.generateId(); } }

Tuy nhiên, chú thích chỉ hữu ích nếu được trình xử lý công nhận và xử lý. Đây là lúc thợ dệt AspectJ phát huy tác dụng. Cụ thể, các AnnotationBeanConfigurerAspect sẽ hành động dựa trên sự hiện diện của @Configurable và không xử lý cần thiết.

3. Kích hoạt AspectJ Dệt

3.1. Khai báo plugin

Để kích hoạt dệt AspectJ, trước tiên chúng ta cần có plugin AspectJ Maven:

 org.codehaus.mojo aspectj-maven-plugin 1.11  

Và nó yêu cầu một số cấu hình bổ sung:

 1.8 ignore   org.springframework spring-aspects   

Yếu tố bắt buộc đầu tiên là tuân thủ Cấp độ . Giá trị 1,8 đặt cả phiên bản JDK nguồn và đích thành 1,8. Nếu không được đặt rõ ràng, phiên bản nguồn sẽ là 1.3 và đích sẽ là 1.1. Những giá trị này rõ ràng đã lỗi thời và không đủ cho một ứng dụng Java hiện đại.

Để đưa một bean vào một đối tượng không được quản lý, chúng ta phải dựa vào lớp AnnotationBeanConfigurerAspect được cung cấp trong spring-domains.jar . Vì đây là khía cạnh được biên dịch trước, chúng tôi sẽ cần thêm cấu phần chứa vào cấu hình plugin.

Lưu ý rằng một tạo tác được tham chiếu như vậy phải tồn tại dưới dạng phụ thuộc trong dự án:

 org.springframework spring-aspects 5.2.7.RELEASE 

Chúng tôi có thể tìm thấy phiên bản mới nhất của khía cạnh mùa xuân trên Maven Central.

3.2. Thực thi plugin

Để hướng dẫn plugin dệt tất cả các lớp có liên quan, chúng tôi cần cấu hình thực thi sau:

   compile   

Lưu ý rằng mục tiêu biên dịch của plugin liên kết với giai đoạn vòng đời biên dịch theo mặc định.

3.2. Cấu hình Bean

Bước cuối cùng để kích hoạt dệt AspectJ là thêm @EnableSpringConfigured vào lớp cấu hình:

@ComponentScan @EnableSpringConfigured public class AspectJConfig { }

Chú thích bổ sung định cấu hình AnnotationBeanConfigurerAspect , lần lượt đăng ký các cá thể PersonObject với một vùng chứa Spring IoC.

4. Thử nghiệm

Bây giờ, hãy xác minh rằng bean IdService đã được đưa thành công vào PersonObject :

@RunWith(SpringRunner.class) @ContextConfiguration(classes = AspectJConfig.class) public class PersonUnitTest { @Test public void givenUnmanagedObjects_whenInjectingIdService_thenIdValueIsCorrectlySet() { PersonObject personObject = new PersonObject("Baeldung"); personObject.generateId(); assertEquals(1, personObject.getId()); assertEquals("Baeldung", personObject.getName()); } }

5. Tiêm hạt đậu vào thực thể JPA

Theo quan điểm của Spring container, một thực thể không là gì khác ngoài một đối tượng bình thường. Như vậy, không có gì đặc biệt khi tiêm Spring bean vào một thực thể JPA.

Tuy nhiên, vì việc tiêm vào các thực thể JPA là một trường hợp sử dụng điển hình, chúng ta hãy trình bày chi tiết hơn.

5.1. Lớp thực thể

Hãy bắt đầu với khung của lớp thực thể:

@Entity @Configurable(preConstruction = true) public class PersonEntity { @Id private int id; private String name; public PersonEntity() { } // other code - shown in the next subsection }

Lưu ý phần tử preConstruction trong chú thích @Configurable : nó cho phép chúng tôi đưa một phần phụ thuộc vào đối tượng trước khi nó được xây dựng hoàn chỉnh.

5.2. Dịch vụ tiêm

Bây giờ chúng ta có thể đưa IdService vào PersonEntity , tương tự như những gì chúng ta đã làm với PersonObject :

// annotations public class PersonEntity { @Autowired @Transient private IdService idService; // fields and no-arg constructor public PersonEntity(String name) { id = idService.generateId(); this.name = name; } // getters }

The @Transient annotation is used to tell JPA that idService is a field not to be persisted.

5.3. Test Method Update

Finally, we can update the test method to indicate that the service can be injected into the entity:

@Test public void givenUnmanagedObjects_whenInjectingIdService_thenIdValueIsCorrectlySet() { // existing statements PersonEntity personEntity = new PersonEntity("Baeldung"); assertEquals(2, personEntity.getId()); assertEquals("Baeldung", personEntity.getName()); }

6. Caveats

Although it's convenient to access Spring components from an unmanaged object, it's often not a good practice to do so.

The problem is that unmanaged objects, including entities, are usually part of the domain model. These objects should carry data only to be reusable across different services.

Injecting beans into such objects could tie components and objects together, making it harder to maintain and enhance the application.

7. Conclusion

Hướng dẫn này đã trình bày về quá trình đưa một Spring bean vào một đối tượng không được quản lý. Nó cũng đề cập đến một vấn đề thiết kế liên quan đến việc tiêm phụ thuộc vào các đối tượng.

Bạn có thể tìm thấy mã triển khai trên GitHub.