为了账号安全,请及时绑定邮箱和手机立即绑定

如何在 Spring 中使用自动装配的 bean 创建简单工厂模式?

如何在 Spring 中使用自动装配的 bean 创建简单工厂模式?

米琪卡哇伊 2022-04-28 16:43:18
我有一个控制器,它有 4 个非常相似的方法,调用远程服务器上的 API 来对不同类型的用户执行不同的操作。这些 API 调用之间的变化只是端点和一些参数。因此,这 4 个方法都以非常相似的代码调用服务:它们从服务器获取令牌、设置参数、返回 API 的响应。由于稍后将添加更多操作,因此我决定使用使用工厂方法模式创建 ServiceFactory 并在服务上使用模板模式以避免代码重复。我的问题是,为了让工厂自动装配服务,它需要与它们耦合,我必须对@Autowire每个实现进行。有更好的解决方案吗?这是我到目前为止的代码:休息控制器@RestControllerpublic class ActionController {  @Autowired  private SsoService ssoService;  // this is the factory  @Autowired  private ServiceFactory factory;  @PostMapping("/action")  public MyResponse performAction(@RequestBody MyRequest request, HttpServletRequest req) {    // template code (error treatment not included)    request.setOperator(ssoService.getOperator(req));    request.setDate(LocalDateTime.now());    return serviceFactory.getService(request).do();  }}服务工厂@Componentpublic class ServiceFactory {  @Autowired private ActivateUserService activateUserService;  @Autowired private Action2UserType2Service anotherService;  //etc  public MyService getService(request) {    if (Action.ACTIVATE.equals(request.getAction()) && UserType.USER.equals(request.getUserType()) {      return activateUserService;    }    // etc    return anotherService;  }}Service Base,实现MyService接口public abstract class ServiceBase implements MyService {  @Autowired private ApiService apiService;  @Autowired private ActionRepository actionRepository;  @Value("${api.path}") private String path;  @Override  public MyResponse do(MyRequest request) {    String url = path + getEndpoint();    String token = apiService.getToken();    Map<String, String> params = getParams(request);    // adds the common params to the hashmap    HttpResult result = apiService.post(url, params);     if (result.getStatusCode() == 200) {      // saves the performed action      actionRepository.save(getAction());    }    // extracts the response from the HttpResult    return response;  }}
查看完整描述

1 回答

?
慕哥9229398

TA贡献1877条经验 获得超6个赞

您可以@Autowireda Listof MyService,这将创建一个List实现该MyService接口的所有 bean。然后您可以添加一个方法来MyService接受一个MyRequest对象并决定它是否可以处理该请求。List然后,您可以过滤MyService以找到MyService可以处理请求的第一个对象。


例如:


public interface MyService {


    public boolean canHandle(MyRequest request);


    // ...existing methods...

}


@Service

public class ActivateUserService extends ServiceBase {


    @Override

    public boolean canHandle(MyRequest request) {

        return Action.ACTIVATE.equals(request.getAction()) && UserType.USER.equals(request.getUserType());

    }


    // ...existing methods...

}


@Component

public class ServiceFactory {


    @Autowired

    private List<MyService> myServices;


    public Optional<MyService> getService(MyRequest request) {

        return myServices.stream()

            .filter(service -> service.canHandle(request))

            .findFirst();

    }

}

请注意,ServiceFactory上面的实现使用 Java 8+。如果 Java 8 或更高版本无法实现,则可以ServiceFactory通过以下方式实现该类:


@Component

public class ServiceFactory {


    @Autowired

    private List<MyService> myServices;


    public Optional<MyService> getService(MyRequest request) {


        for (MyService service: myServices) {

            if (service.canHandle(request)) {

                return Optional.of(service);

            }

        }


        return Optional.empty();

}

有关使用@Autowiredwith的更多信息List,请参阅Autowire 将 bean 引用到按类型列表中。


该解决方案的核心是将决定MyService实现是否可以处理MyRequest来自ServiceFactory(外部客户端)的逻辑转移到MyService实现本身。


查看完整回答
反对 回复 2022-04-28
  • 1 回答
  • 0 关注
  • 154 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信