我有一个具有4种非常相似方法的 Controller ,该 Controller 在远程服务器上调用API以对不同类型的用户执行不同的操作。这些API调用之间的变化只是端点和一些参数。
因此,这四种方法都用非常相似的代码调用了服务:它们从服务器获取了 token ,设置了参数,返回了API的响应。由于稍后将添加更多操作,因此我决定使用通过Factory Method模式创建ServiceFactory,并在服务上使用Template模式以避免代码重复。
我的问题是,为了使工厂能够 Autowiring 服务,需要将其耦合到它们,我必须对每个实现进行@Autowire
编码。有更好的解决方案吗?
这是我到目前为止的代码:
休息 Controller
@RestController
public 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();
}
}
服务工厂
@Component
public 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;
}
}
服务库,实现MyService接口(interface)
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;
}
}
服务实现(共有4个)
@Service
public class ActivateUserService extends ServiceBase {
@Value("${api.user.activate}")
private String endpoint;
@Override
public String getEndpoint() {
return endpoint;
}
@Override
public Map<String,String> getParams(MyRequest request) {
Map<String, String> params = new HashMap<>();
// adds custom params
return params;
}
@Override
public Action getAction() {
return new Action().type(ActionType.ACTIVATED).userType(UserType.USER);
}
}
最佳答案
您可以@Autowired
或List
的MyService
,这将为实现List
接口(interface)的所有bean创建一个MyService
。然后,您可以在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();
}
有关将
@Autowired
与List
一起使用的更多信息,请参见Autowire reference beans into list by type。该解决方案的核心是将决定
MyService
实现是否可以处理MyRequest
的逻辑从ServiceFactory
(外部客户端)转移到MyService
实现本身。关于java - 如何在 Spring 使用 Autowiring 的bean创建简单工厂模式?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54134333/