好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

详解spring-boot下如何满足多生产环境中个性化定制功能

在项目的开发中,我们很难做到开发一套标准的流程来解决所有客户的需求。比如,我们当前的计量项目,分别运行于赤峰市和河北省。虽然两个区域处理的业务相同,但是对细节的实现要求却不同。前面也学习过计量检定软件,其为了解决各个定制者使用的功能需求,最后采取的方案是:将基础项目复制多份,进而满足不同的客户需求。优点当然是有的,但比起缺点来,优点便不值一提。缺点很明显,总结为一句话就是:项目变得难以维护。所以,当前让我们看到的就是,几个开发人员,每天处于解决问题当中。本文将给出一种方案,来有效的规避上述问题。

资源与环境

示例代码: https://github.com/mengyunzhi/springbootsamplecode/tree/master/dynamic-autowire

开发环境:java1.8 + spring-boot:2.1.3.release

需求假设

假设使用本项目的人员为:中国人、美国人,分别能接受的语言为中文和英文。 项目运行后,可以根据当前的访问人员是国籍来动态显示: 你好 或 hello 有新的需求后,比如:增加德国人并显示 hallo 。增加功能时,不更改核心代码。 不使用if else

注意:如果你看完需求假设后,毫无触动,请忽略本文以下内容

解决方案

解决方案中,我们涉及了两种设计模块,分别为: 策略模式 及 工厂模式 。

策略模式:一般用于将具体的 算法 进行抽象及剥离。此项目中,我们的具体算法是 说你好 。

工厂模式:一般用于根据环境来动态的创建bean的情况下。引项目中,我们将根据不同国家的人,来返回不同的 说你好 这个算法。

先给出uml图:

speakservice

speakservice 即为我们供其它模块调用的 说话服务 ,调用其中的 sayhello() 来完成 说你好 功能。

?

1

2

3

4

5

6

7

8

package com.mengyunzhi.demo.dynamicautowire;

 

/**

  * 你好

  */

public interface speakservice {

   void sayhello();

}

在其实现类中,我们注入 sayhellofactory ,让其来返回正确的 sayhelloservice ,最终调用 sayhello() 来完成目标。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

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

?

1

2

3

4

5

6

7

8

9

10

11

package com.mengyunzhi.demo.dynamicautowire;

 

/**

  * 说话工厂

  */

public interface sayhellofactory {

 

   void setcountrycode(countrycode countrycode);

 

   sayhelloservice getsayhelloservice();

}

在此,我们增加一个 countrycode 表示当前访问者的国家。其实在获取访问者国家时,我们也可以调用其它bean的其它来实现。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

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时发生异常。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

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获取到的所以实现了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() 来根据当前国家代码来返回相应的bean。

sayhelloservice

?

1

2

3

4

5

6

7

8

9

10

package com.mengyunzhi.demo.dynamicautowire;

 

/**

  * 说话

  */

public interface sayhelloservice {

   void sayhello();

 

   byte getcode();

}

将 sayhello() 方法抽离, getcode() 以获取国家代码。

中国人你好

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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();

   }

}

测试

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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. springboot test;

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 中,增加德国.

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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();

   }

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

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;

   }

}

单元测试

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

@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
您好

总结

在解决问题时,只所有我们看的不够远,可能是由于自己站的不够高。同样的问题,困惑我了多日,直到近期系统的学习 设计模式 、 angular官方教程 、 spring 实战 后,结合近期项目变更带来的新需求,才在使用设计模式解决此问题上有所启发。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

原文链接:https://segmentfault.com/a/1190000018673552

查看更多关于详解spring-boot下如何满足多生产环境中个性化定制功能的详细内容...

  阅读:16次