詳解spring-boot下如何滿足多生產(chǎn)環(huán)境中個性化定制功能
在項目的開發(fā)中,我們很難做到開發(fā)一套標準的流程來解決所有客戶的需求。比如,我們當前的計量項目,分別運行于赤峰市和河北省。雖然兩個區(qū)域處理的業(yè)務相同,但是對細節(jié)的實現(xiàn)要求卻不同。前面也學習過計量檢定軟件,其為了解決各個定制者使用的功能需求,最后采取的方案是:將基礎項目復制多份,進而滿足不同的客戶需求。優(yōu)點當然是有的,但比起缺點來,優(yōu)點便不值一提。缺點很明顯,總結為一句話就是:項目變得難以維護。所以,當前讓我們看到的就是,幾個開發(fā)人員,每天處于解決問題當中。本文將給出一種方案,來有效的規(guī)避上述問題。
資源與環(huán)境
示例代碼:https://github.com/mengyunzhi/springBootSampleCode/tree/master/dynamic-autowire
開發(fā)環(huán)境:java1.8 + spring-boot:2.1.3.RELEASE
需求假設
- 假設使用本項目的人員為:中國人、美國人,分別能接受的語言為中文和英文。
- 項目運行后,可以根據(jù)當前的訪問人員是國籍來動態(tài)顯示:
你好
或hello
- 有新的需求后,比如:增加德國人并顯示
Hallo
。增加功能時,不更改核心代碼。 - 不使用if else
注意:如果你看完需求假設后,毫無觸動,請忽略本文以下內(nèi)容
解決方案
解決方案中,我們涉及了兩種設計模塊,分別為:策略模式
及工廠模式
。
策略模式:一般用于將具體的算法
進行抽象及剝離。此項目中,我們的具體算法是說你好
。
工廠模式:一般用于根據(jù)環(huán)境來動態(tài)的創(chuàng)建BEAN的情況下。引項目中,我們將根據(jù)不同國家的人,來返回不同的說你好
這個算法。
先給出UML圖:
SpeakService
SpeakService
即為我們供其它模塊調用的說話服務
,調用其中的SayHello()
來完成說你好
功能。
package com.mengyunzhi.demo.dynamicautowire; /** * 你好 */ public interface SpeakService { void sayHello(); }
在其實現(xiàn)類中,我們注入SayHelloFactory
,讓其來返回正確的SayHelloService
,最終調用sayHello()
來完成目標。
package com.mengyunzhi.demo.dynamicautowire; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 你好 */ @Service public class SpeakServiceImpl implements SpeakService { private final SayHelloFactory sayHelloFactory; // 說話工廠 @Autowired public SpeakServiceImpl(SayHelloFactory sayHelloFactory) { this.sayHelloFactory = sayHelloFactory; } @Override public void sayHello() { this.sayHelloFactory.getSayHelloService().sayHello(); } }
SayHelloFactory
package com.mengyunzhi.demo.dynamicautowire; /** * 說話工廠 */ public interface SayHelloFactory { void setCountryCode(CountryCode countryCode); SayHelloService getSayHelloService(); }
在此,我們增加一個CountryCode
表示當前訪問者的國家。其實在獲取訪問者國家時,我們也可以調用其它Bean的其它來實現(xiàn)。
package com.mengyunzhi.demo.dynamicautowire; /** * 國家代碼 */ public enum CountryCode { CHINA((byte) 0, "中國"), USA((byte) 1, "美國"); private Byte code; private String name; CountryCode(Byte code, String name) { this.code = code; this.name = name; } public Byte getCode() { return code; } public String getName() { return name; } }
使用enum
來控制范圍,避免Factory
在獲取Bean時發(fā)生異常。
package com.mengyunzhi.demo.dynamicautowire; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 說話工廠 */ @Service public class SayHelloFactoryImpl implements SayHelloFactory { /** * BEAN列表 */ private final Map<Byte, SayHelloService> servicesByCode = new HashMap<>(); /** * 國家代碼 */ private CountryCode countryCode = CountryCode.CHINA; @Override public void setCountryCode(CountryCode countryCode) { this.countryCode = countryCode; } /** * 初始化 * * @param sayHelloServices spring獲取到的所以實現(xiàn)了SpeakService的BEAN */ @Autowired public void init(List<SayHelloService> sayHelloServices) { for (SayHelloService sayHelloService : sayHelloServices) { this.register(sayHelloService.getCode(), sayHelloService); } } /** * 注冊Bean * * @param code 代碼 * @param sayHelloService BEAN */ private void register(Byte code, SayHelloService sayHelloService) { this.servicesByCode.put(code, sayHelloService); } /** * 獲取BEAN * * @return 對應的SayHelloService BEAN */ @Override public SayHelloService getSayHelloService() { return this.servicesByCode.get(this.countryCode.getCode()); } }
增加Map<Byte, SayHelloService> servicesByCode
來存儲對應國家的SayHelloService
BEAN。增加getSayHelloService()
來根據(jù)當前國家代碼來返回相應的Bean。
SayHelloService
package com.mengyunzhi.demo.dynamicautowire; /** * 說話 */ public interface SayHelloService { void sayHello(); Byte getCode(); }
將sayHello()
方法抽離,getCode()
以獲取國家代碼。
中國人你好
package com.mengyunzhi.demo.dynamicautowire; import org.springframework.stereotype.Component; /** * 中國話 */ @Component public class SayHelloServiceChineseImpl implements SayHelloService { @Override public void sayHello() { System.out.println("您好"); } @Override public Byte getCode() { return CountryCode.CHINA.getCode(); } }
美國人Hello
package com.mengyunzhi.demo.dynamicautowire; import org.springframework.stereotype.Component; /** * 美國話 */ @Component public class SayHelloServiceEnglishImpl implements SayHelloService { @Override public void sayHello() { System.out.println("hello"); } @Override public Byte getCode() { return CountryCode.USA.getCode(); } }
測試
package com.mengyunzhi.demo.dynamicautowire; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @SpringBootTest @RunWith(SpringRunner.class) public class SpeakServiceImplTest { @Autowired SpeakService speakService; @Autowired SayHelloFactory sayHelloFactory; @Test public void sayHello() { // 默認說你好 speakService.sayHello(); // 將國家設置為美國,再說你好 sayHelloFactory.setCountryCode(CountryCode.USA); speakService.sayHello(); // 將國家設置為中國,再說你好 sayHelloFactory.setCountryCode(CountryCode.CHINA); speakService.sayHello(); } }
您好
hello
您好
時序圖
增加德國人
增加德國人SayHelloServiceGermanyImpl
.
在CountryCode
中,增加德國.
package com.mengyunzhi.demo.dynamicautowire; import org.springframework.stereotype.Component; @Component public class SayHelloServiceGermanyImpl implements SayHelloService { @Override public void sayHello() { System.out.println("Hallo"); } @Override public Byte getCode() { return CountryCode.GERMANY.getCode(); } }
package com.mengyunzhi.demo.dynamicautowire; /** * 國家代碼 */ public enum CountryCode { CHINA((byte) 0, "中國"), USA((byte) 1, "美國"), GERMANY((byte) 2, "德國"); private Byte code; private String name; CountryCode(Byte code, String name) { this.code = code; this.name = name; } public Byte getCode() { return code; } public String getName() { return name; } }
單元測試
@Test public void sayHello1() { // 默認說你好 speakService.sayHello(); // 將國家設置為美國,再說你好 sayHelloFactory.setCountryCode(CountryCode.USA); speakService.sayHello(); // 將國家設置為德國,再說你好 sayHelloFactory.setCountryCode(CountryCode.GERMANY); speakService.sayHello(); // 將國家設置為中國,再說你好 sayHelloFactory.setCountryCode(CountryCode.CHINA); speakService.sayHello(); }
測試結果如下:
您好
hello
Hallo
您好
總結
在解決問題時,只所有我們看的不夠遠,可能是由于自己站的不夠高。同樣的問題,困惑我了多日,直到近期系統(tǒng)的學習設計模式
、angular官方教程
、Spring 實戰(zhàn)
后,結合近期項目變更帶來的新需求,才在使用設計模式解決此問題上有所啟發(fā)。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- spring中通過ApplicationContext getBean獲取注入對象的方法實例
- Springboot-dubbo-fescar 阿里分布式事務的實現(xiàn)方法
- Spring 中優(yōu)雅的獲取泛型信息的方法
- spring @Transactional 無效的解決方案
- spring boot定時任務接收郵件并且存儲附件的方法講解
- activemq整合springboot使用方法(個人微信小程序用)
- Springboot項目打war包docker包找不到resource下靜態(tài)資源的解決方案
- Spring自帶的校驗框架Validation的使用實例
- 詳解Spring框架下向異步線程傳遞HttpServletRequest參數(shù)的坑
- Spring通過ApplicationContext主動獲取bean的方法講解
相關文章
Spring之動態(tài)注冊bean的實現(xiàn)方法
這篇文章主要介紹了Spring之動態(tài)注冊bean的實現(xiàn)方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08關于IDEA使用jsp可以訪問頁面轉換為html彈出頁面為404的問題
這篇文章主要介紹了關于IDEA使用jsp可以訪問頁面轉換為html彈出頁面為404的問題及解決方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12Java 客戶端操作 FastDFS 實現(xiàn)文件上傳下載替換刪除功能
這篇文章主要介紹了Java 客戶端操作 FastDFS 實現(xiàn)文件上傳下載替換刪除功能,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10Jpa 實現(xiàn)自動更新表中的創(chuàng)建日期和修改時間
這篇文章主要介紹了Jpa 實現(xiàn)自動更新表中的創(chuàng)建日期和修改時間,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01