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

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

前言

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

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

现在假设一个情景,前端传入不同的用户类型,后端返回该用户的任务。你可能问我,为什么不直接把(用户类型,用户任务)存入数据库?

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

实现

我们先定义一个接口:

public interface UserService {
    /**
     * 返回用户的主要任务
     * @return 任务
     */
    String task();
}

两个实现类:

@Service("student")
public class StudentService implements UserService{
    @Override
    public String task() {
        return "学习";
    }
}
@Service("teacher")
public class TeacherService implements UserService{
    @Override
    public String task() {
        return "教书";
    }
}

实现动态调用的核心类

@Service
public class UserContext {
    @Autowired
    private Map<String, UserService> userMap;

    public UserService getUserService(String type) {
        return userMap.get(type);
    }
}

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

在启动后,userMap中就存在两个元素("student",StudentService)与("teacher",TeacherService)。

getUserService方法返回userMapkey=typeUserService对象

实体类:

@Data
public class User {
    /**
     * 类型
     */
    private String type;
    /**
     * 任务
     */
    private String task;
}

Controller 层接口:

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserContext context;

    @PostMapping("/get-task")
    public String getTask(@RequestBody User user) {
        UserService service = context.getUserService(user.getType());
        log.info("User Service Task is {}", service.task());
        return service.task();
    }
}

使用 Spring 自带的 RestTemplate 来测试,先创建配置类:

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        return new RestTemplate(factory);
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        // 超时设置
        factory.setReadTimeout(60000); // ms
        factory.setConnectTimeout(60000);// ms
        return factory;
    }
}

编写测试类:

@SpringBootTest
class SpringDynamicCallClassApplicationTests {

    @Autowired
    private RestTemplate restTemplate;

    @Test
    void restTest() throws JSONException {
        HttpHeaders headers = new HttpHeaders();
        // 因为 UserController 使用了 @RequestBody 注解,所以需要 POST Json
        headers.setContentType(MediaType.APPLICATION_JSON);

        JSONObject UserJsonObject = new JSONObject();
        UserJsonObject.put("type", "student");
        UserJsonObject.put("task", "学习");

        HttpEntity<String> request =
                new HttpEntity<>(UserJsonObject.toString(), headers);

        String UserResultAsJsonStr =
                restTemplate.postForObject("http://localhost:8080/user/get-task", request, String.class);

        System.out.println(UserResultAsJsonStr);
    }
}

运行结果:


本文参考:

springboot通过不同的策略动态调用不同的实现类_《小书生》的博客-CSDN博客

A Guide to the RestTemplate | Baeldung