如何從Spring之外的非託管物件訪問 Spring Bean?
實體、值物件、DTO或VO、record之類基本都是隻有getXX/setXX的物件(record除外),當DDD領域設計為這些物件賦予業務行為以後,這些業務行為會與技術環境如Srping管理的bean相互互動,在clean架構中實現為介面卡或埠,但是具體如何在Java中落地?
另外,我們可能需要將 Spring Beans 注入 JPA 實體或其他一些非託管物件,這可能表明我們需要重新考慮我們的架構,但有時這是無法避免的。可以使用@Configurable註釋來做到這一點,但要使其工作,必須使用 AspectJ 編織器來編織帶註釋的型別。在本教程中,我們將研究一種從非託管物件訪問 Spring 託管元件的替代方法,該方法可以說比注入更好。
作為示例,我們將使用一個簡單的 Spring 應用程式,我們將在其中建立一個TaxCalculator元件,該元件又可能具有一些依賴項,但在我們的示例中,它非常簡單:
@Component public class TaxCalculator { public double calculate(double price) { return price * 0.25; } } |
現在我們將為非託管物件建立一條記錄:
public record Invoice(double price) {} |
假設我們希望他們提供稅款。為了計算它,我們需要使用TaxCalculator,但是由於這個類的例項不是由 Spring 管理的,我們不能簡單地將這個依賴注入到它們中。
選項 1:使用靜態方式公開例項
由於 Spring bean預設是單例的InitializingBean,我們可以通過實現介面,或者使用註解將其注入到自己的靜態欄位中@PostConstruct,然後用靜態方法將其暴露出來。在本例中,我們將使用註解:
public class TaxCalculator { private static TaxCalculator instance; public static TaxCalculator getInstance() { return instance; } @PostConstruct private void registerInstance() { instance = this; } // ... } |
現在我們可以在我們的非託管物件中使用這個方法:
public record Invoice(double price) { public double calculateTaxUsingComponent() { return TaxCalculator.getInstance().calculate(this.price); } } |
讓我們通過執行來編寫一個測試,我們可以驗證一切正常:
@SpringBootTest class InvoiceTest { @Test void calculateTaxUsingComponent() { // given var invoice = new Invoice(20); // when var result = invoice.calculateTaxUsingComponent(); // then assertThat(result).isEqualTo(5.0); } } |
選項 2:實現一個提供者
也許我們不想改變元件的類或者不想依賴特定的實現,在這種情況下,我們可以實現一個提供者來為我們提供元件,或者如果我們使用介面然後是例項在 IoC 容器中找到它的實現。例如,讓我們更新我們的元件並使其實現以下介面:
public interface ITaxCalculator { double calculate(double price); } |
然後我們實現一個提供者實現,在它的靜態欄位中我們注入我們的元件並使用靜態方法公開它:
@Component public class TaxCalculatorProvider { private static ITaxCalculator calculator; public TaxCalculatorProvider(ITaxCalculator calculator) { TaxCalculatorProvider.calculator = calculator; } public static ITaxCalculator getCalculator() { return calculator; } } |
現在我們可以在我們的非託管物件中使用提供者:
public record Invoice(double price) { public double calculateTaxUsingProvider() { return TaxCalculatorProvider.getCalculator().calculate(this.price); } } |
最後,我們可以通過一個簡單的測試來驗證一切是否正常:
@SpringBootTest class InvoiceTest { @Test void calculateTaxUsingProvider() { // given var invoice = new Invoice(50); // when var result = invoice.calculateTaxUsingProvider(); // then assertThat(result).isEqualTo(12.5); } } |
相關文章
- Spring Boot中從自定義Logback訪問Spring Bean三種方法Spring BootBean
- spring中如何向一個單例bean中注入非單例beanSpring單例Bean
- 談談Spring中的物件跟Bean,你知道Spring怎麼建立物件的嗎?Spring物件Bean
- Spring 原始碼(14)Spring Bean 的建立過程(6)物件的提前暴露Spring原始碼Bean物件
- Spring Bean如何初始化的SpringBean
- 利用IDisposable介面構建包含非託管資源物件物件
- 從C++看C#託管記憶體與非託管記憶體C++C#記憶體
- [Spring]BeanSpringBean
- func-spring-boot-starter 匿名函式託管Springboot函式
- 匿名函式託管 func-spring-boot-starter函式Springboot
- Spring資料訪問Spring
- 如何訪問Docker容器中的Spring Boot日誌DockerSpring Boot
- 如何讓 Bean 深度感知 Spring 容器BeanSpring
- Spring Bean容器SpringBean
- 【Spring】Bean管理SpringBean
- 匿名函式託管器 spring-boot-func-starter函式Springboot
- Spring如何控制Bean的載入順序SpringBean
- Spring bean到底是如何建立的?(上)SpringBean
- 《Spring》(六)---- Bean的scopeSpringBean
- Spring Boot專案微信雲託管入門部署Spring Boot
- 4、Spring IOC容器 Bean物件例項化的3種方式SpringBean物件
- Spring 原始碼(17)Spring Bean的建立過程(8)Bean的初始化Spring原始碼Bean
- Spring裝配Bean(六)Bean的作用域SpringBean
- Spring bean 裝配SpringBean
- Spring Bean 綜述SpringBean
- Spring Bean作用域SpringBean
- spring boot factory beanSpring BootBean
- 淺談Spring BeanSpringBean
- Spring基礎(Bean)SpringBean
- Spring Bean 詳解SpringBean
- C#如何載入嵌入到資源的非託管dllC#
- 獲取spring裡的beanSpringBean
- Spring中bean的含義SpringBean
- Spring Bean 的一生SpringBean
- Spring IoC bean 的建立(上)SpringBean
- Spring Bean的生命週期SpringBean
- 關於Spring的bean注入SpringBean
- Spring中Bean的作用域SpringBean