好得很程序员自学网

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

springboot如何通过不同的策略动态调用不同的实现类

通过不同的策略动态调用不同的实现类

经常遇到这样的一个需求,前端传的实体类型相同,后端需要根据实体类中的某一个字符串,动态地调用某一个类的方法。

在SpringBoot中,我们可以理解成,一个Controller接口对应多个ServiceImpl,使用这种方式,如果后期需要添加一个功能,仅仅创建一个ServiceImpl就可以满足需求,而不用再额外创建一个Controller接口。

现在假设一个情景,前端传入不同的用户类型,后端返回该用户的任务。

你可能问我,为什么不直接把(用户类型,用户任务)存入数据库?

现在只是一个简单的场景而已,实际中更为复杂,无法直接存入数据库。

代码演示

我们先定义一个接口

?

1

2

3

4

public interface UserService {

     //返回用户的主要任务

     String task();

}

两个实现类

?

1

2

3

4

5

6

7

@Service ( "student" )

public class StudentServiceImpl implements UserService {

    @Override

    public String task() {

        return "学习" ;

    }

}

?

1

2

3

4

5

6

7

@Service ( "teacher" )

public class TeacherServiceImpl implements UserService {

    @Override

    public String task() {

        return "教书" ;

    }

}

实现动态调用的核心类

?

1

2

3

4

5

6

7

8

9

@Service

public class UserContext { 

    @Autowired

    Map<String, UserService> userMap;

 

    public UserService getUserService(String type) {

        return userMap.get(type);

    }

}

Spring会自动地将形如(@Service后面的名称,实现该接口的类)注入到该userMap中

在启动后,userMap中就存在两个元素,("student",StudentServiceImpl)与("teacher",TeacherServiceImpl)

getUserService方法返回userMap中key=type的UserService对象

实体类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

public class User {

     private String type;

     private String task;

     public String getType() {

         return type;

     }

 

     public void setType(String type) {

         this .type = type;

     }

 

     public String getTask() {

         return task;

     }

 

     public void setTask(String task) {

         this .task = task;

     }

}

Controller层接口

?

1

2

3

4

5

6

7

8

9

10

11

12

@RestController

@RequestMapping ( "/user" )

public class UserController {

     @Autowired

     UserContext userContext;

 

     @PostMapping ( "/getTask" )

     public String getTask( @RequestBody User user) {

         UserService userService = userContext.getUserService(user.getType());

         return userService.task();

     }

}

测试样例:

可能用到的场景举例

关于库存的仪表盘统计

前端传入区域id,仓库id,物品id等信息

后端依据参数动态地选择某一个物品实现类,最后返回统计的信息。

这里有几个问题,为什么不一次性将所有物品id传入,一次性获取所有物品的库存?

一次性传入,可能后端处理时间边长,失败率也高,一旦失败,整个仪表盘没有任何数据。而且后期可能面临的一个需求,不同的物品,需要有不同的接口刷新速度,畅销的物品接口调用频率快。所以可能需要将物品分组,一个小组是同一种类型,使用一个实现类。

比如,这里有100种物品,按类型或者其他属性分成了10组,每个组之间,有一个不同的属性groupId,但10组共用一个接口,进入接口后,再进入10个不同的实现类,在实现类中调用具体的计算逻辑。

spring中动态选择实现类

在spring中当一个接口有多个实现类的时候,通过创建简单工厂类,根据传入的不同的参数获取不同的接口实现类。

?

1

2

3

4

5

public interface ExecuteService {    

     ExecuteEnum getCode();

    // 业务方法

    void execute();

}

?

1

2

3

4

5

6

7

8

9

10

11

@Service

public class FirstExecuteServiceImpl implements ExecuteService {    

     @Override

     public ExecuteEnum getCode() {

         return ExecuteEnum.FIRST;

     }

    

     public void execute() {

         System.out.println( "11111111111" );

     }

}

?

1

2

3

4

5

6

7

8

9

10

11

@Service

public class SecondExecuteServiceImpl implements ExecuteService {    

     @Override

     public ExecuteEnum getCode() {

         return ExecuteEnum.SECOND;

     }

    

     public void execute() {

         System.out.println( "222222222" );

     }

}

?

1

2

3

4

     public enum ExecuteEnum {

         FIRST,

         SECOND,;

     }

方案一

?

1

2

3

4

5

6

7

8

9

10

@Component

public class ExecuteServiceFactory implements ApplicationContextAware {

    

     private final static Map<ExecuteEnum, ExecuteService> EXECUTE_SERVICES = new HashMap<>();

     @Override

     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

         Map<String, ExecuteService> types = applicationContext.getBeansOfType(ExecuteService. class );

         types.values().forEach(e -> EXECUTE_SERVICES.putIfAbsent(e.getCode(), e));

     }    

}

方案二

?

1

2

3

4

5

6

7

8

9

10

@Component

public class ExecuteServiceFactory implements InitializingBean {

    @Autowired

    private List<ExecuteService> executeServices;

    public final static Map<ExecuteEnum, ExecuteService> EXECUTE_SERVICES = new HashMap<>();

    @Override

    public void afterPropertiesSet() throws Exception {

        executeServices.forEach(l -> EXECUTE_SERVICES.putIfAbsent(l.getCode(), l));

    }

}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/qq_33591903/article/details/104813512

查看更多关于springboot如何通过不同的策略动态调用不同的实现类的详细内容...

  阅读:18次