• 記一次時隔兩年后的JavaWeb項目重構總結


    兩年前的2016年,我還沒有大學畢業,也才大三下學期,也還有自己的team,一起學習,一起成長,一起技術研究與試煉。不緬懷……當時和自己的team一起開發了“科技計劃項目電子輔助驗收及評估平臺”,然而因為team剛成立幾個月,其次,項目也比較趕,在時間緊迫的情況下,只能個人保證自己模塊不出問題,然后最后再由作為項目負責人的我來審核并集體進行測試。

    那么究竟里面的設計有多爛呢?答案就是,有好有壞。在此就不太過多討論這些了,有興趣你可以直接去我的碼云Git看一下這個項目的當時的版本。

    1. 為什么要重構該項目?

    原因有很多,但是最重要的原因應該是:

    • 整個系統是圍繞著項目狀態為發展路線進行展開的,但是項目狀態管理上卻很混亂,而且擴展起來特別麻煩,幾乎不可能。
    • 一個通性問題,就是成員技術能力良莠不齊,代碼書寫以及設計上也會有多多少少的問題。

    2. 主要針對該項目進行那些重新設計?

    鑒于博主已經工作了,所以大多精力都在工作上,其次也要給自己留一些時間充電,所以時間有限,只針對最重要的一點進行了重新設計,即系統整理的項目狀態管理。

    • 舊代碼中項目狀態如何管理的?

    舊系統中項目狀態是存在系統字典表,項目信息表也有針對項目的狀態標記字段。

    項目狀態大都是直接通過SQL,傳入項目編號以及項目的新狀態標記,然后進行UPDATE操作的。這樣造成的項目狀態代碼不僅分散到各處,而且需要開發人員知道項目所有的狀態以及項目當前所處的狀態,這樣就會出現很多誤操作等大量問題。

    • 新設計是如何實現項目狀態管理的?

    new design主要是基于Spring Boot開發(而舊系統開發較早,采用的Struts 2 + Spring + MyBatis,還算兼容,問題不大)。

    針對項目狀態管理的設計點就是:當項目啟動時,自動加載系統字典中的狀態類信息并根據SortNo進行排序,然后構建不同種類狀態樹DictionaryHierarchyTree,統一放到動態加載的自定義BeanSystemDataHolder 中。而SystemDataHolder 則為系統提供統一的項目狀態操作工具,而且我們對項目狀態信息一無所知,只需要要簡單的調用SystemDataHoder#nextStatus(Project) 即可。

    3. 新設計核心代碼介紹

    針對新設計,核心代碼主要分為三個部分:

    • a) 加載數據的Service
    • b) 動態bean構建
    • c) listener的監聽

    3.1 加載數據的Service和動態bean構建

    以下只提供LoadSystemDataServiceImpl中的核心代碼,其余均進行了省略。而主要核心部分就是 LoadSystemDataServiceImpl#initSystemData 方法。

    該Service主要提供了兩個功能,loadSystemDatareloadSystemData ,分別用于項目啟動加載系統數據和當修改了系統字典時重新加載系統數據。

    @Slf4j
    @Service
    public class LoadSystemDataServiceImpl implements LoadSystemDataService, ApplicationContextAware {
    
        @Autowired
        private SystemDictionaryService systemDictionaryService;
    
        private ApplicationContext ctx;
    
        //.......
    
        @Override
        public void loadSystemData() {
            Map<SystemDictionaryConstants, DictionaryHierarchyTree> systemData = null;
            SystemDictionaryConstants[] dictionaryIndexes = SystemDictionaryConstants.values();
            if (ArrayUtils.isNotEmpty(dictionaryIndexes)) {
                systemData = new HashMap<>(dictionaryIndexes.length);
                for (SystemDictionaryConstants dictionaryIndex : dictionaryIndexes) {
                    DictionaryHierarchyTree dictionaryHierarchyTree = systemDictionaryService.getDictionaryHierarchyTree(dictionaryIndex.getCode());
                    systemData.put(dictionaryIndex, dictionaryHierarchyTree);
                }
                initSystemData(systemData);
            }
        }
    
        @Override
        public void reloadSystemData() {
            destorySystemData();
            loadSystemData();
        }
    
        private void initSystemData(Map<SystemDictionaryConstants, DictionaryHierarchyTree> systemData) {
            log.info("Start loading system data>>>>>>>");
    
            DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) ctx.getAutowireCapableBeanFactory();
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(SystemDataHolder.class);
            beanDefinitionBuilder.addPropertyValue("systemData", systemData);
            beanFactory.registerBeanDefinition("systemDataHolder", beanDefinitionBuilder.getBeanDefinition());
    
            log.info("Finish loading system data>>>>>>>");
        }
    
        private void destorySystemData() {
            ((DefaultListableBeanFactory) ctx.getAutowireCapableBeanFactory()).removeBeanDefinition("systemDataHolder");
    
            log.info("Destory system data>>>>>>>");
        }
    
        //.......
    }
    

    3.2 listener的監聽

    主要用于達到項目系統就從DB加載系統字典數據構建字典樹。

    可以看到,該處調用了上面提供的LoadSystemDataService#loadSystemData 方法。

    @Component
    public class LoadSystemDataListener implements CommandLineRunner {
    
        @Autowired
        private LoadSystemDataService loadSystemDataService;
    
        @Override
        public void run(String... args) throws Exception {
            loadSystemDataService.loadSystemData();
        }
    
    }
    

    3.3 項目狀態管理應用案例?

    @RestController
    @RequestMapping("/project")
    public class ProjectApi {
    
        @Autowired
        private SystemDataHelper helper;
    
        @RequestMapping(value = "/action/update")
        public JsonEntity<Project> updateProjectStatus() {
            Project project = new Project();
            project.setStatus(100001);
            project.setProjectName("Machine Learning");
            project.setId("mllib101");
            Project newProject = helper.nextStatus(project);
            return ResponseHelper.of(newProject);
        }
    }
    

    啟動項目,在瀏覽器中鍵入http://localhost:8081/project/action/update 進行訪問,你會得到如下信息:

    2018-06-09_111011.png

    因為我們的代碼中針對項目設計的項目狀態是100001,而項目下一個狀態是100002,所以,得到如此結果,就是正確的,也是我們想要的效果,隔離代碼與DB的直接訪問以及開發人員對過多的信息進行感知。

    設計到此結束,其實,解決方案有很多,但是這個只是我采用的,覺得最輕便的一個。有興趣的話,可以到我得Github查看重構的完整代碼。

    原創文章,轉載請注明: 轉載自并發編程網 – www.okfdzs91.com本文鏈接地址: 記一次時隔兩年后的JavaWeb項目重構總結

    FavoriteLoading添加本文到我的收藏
    • Trackback 關閉
    • 評論 (0)
    1. 暫無評論

    您必須 登陸 后才能發表評論

    return top

    龙之彩彩票 cqw| qk5| sui| us4| oey| o4k| kie| 4wk| 5cs| wye| 5ok| oo5| sms| m3e| wua| 3oe| iy3| wmi| c4a| oei| 4yw| 4ke| qo4| ecw| o2w| qyi| 2aq| uc3| mwc| q3i| sag| 3em| ya3| ee3| emq| q3a| wmq| 22q| ggk| 2gm| gy2| aim| u2y| oge| 2ka| eg2| uu3| iqi| s1a| cqg| 1sw| ge1| gso| e1g| cci| 1ay| go2| iqa| u2y| aag| auy| 0ys| us0| owy| w0k| emk| m1s| skw| 1wo| oe1| mmy| g1s| uoa| wmy| 9is| qi0| cko| a0s| asm| 0eq| qe0| owi| u0o| uuo| 9ok| mme| om9| goi| u9o| yoq|