如何在控制器的方法中注入服务?

How to inject service in controller's method?

我在控制器方法中注入服务时遇到问题。我有以下服务:

@Service
@RequiredArgsConstructor
public class CreateFranchiseUseCase {
    private final FranchiseService franchiseService;
    private final UserService userService;
    private final ACLEntryService aclEntryService;
    private final FranchiseDTOMapper franchiseDTOMapper;

    public Franchise execute(CreateFranchiseDTO dto) {
        // ...
    }
}

然后在控制器中:

@RestController
@RequiredArgsConstructor
public class FranchiseController {

    // ...
    
    @PostMapping("/api/franchises")
    public ResponseEntity<Object> createFranchise(CreateFranchiseDTO dto, CreateFranchiseUseCase useCase) {
        Frachise franchise = useCase.execute(dto);
        // ...
    }
}

当我调用此端点时,我得到 NullPointerException。异常发生在执行方法和调试方法我发现所有属性:franchiseServiceuserServiceaclEntryServicefranchiseDTOMapper都是NULL。

所有 classes:FranchiseServiceUserServiceACLEntryService 都带有 @Service 注释。 FranchiseDTOMapper 被注释为 @Mapper(componentModel = "spring")

Spring是否支持方法注入?或者有什么方法可以在 createFranchise() 方法中请求 CreateFranchiseUseCase class 的实例,如下所示:

@PostMapping("/api/franchises")
public ResponseEntity<Object> createFranchise(CreateFranchiseDTO dto) {
    CreateFranchiseUseCase useCase = container.get(CreateFranchiseUseCase.class) // <-- something like this
    Frachise franchise = useCase.execute(dto);
    // ...
}

据我所知,不可能让 Spring 将对象注入到方法中。
相反,您可以让 Spring 通过控制器的构造函数注入对象。

这会导致这样的结果:

@RestController
public class FranchiseController {

    private final CreateFranchiseUseCase createFranchiseUseCase;

    public FranchiseController(CreateFranchiseUseCase createFranchiseUseCase) {
        this.createFranchiseUseCase = createFranchiseUseCase;
    }

    @PostMapping("/api/franchises")
    public ResponseEntity<Object> createFranchise(CreateFranchiseDTO dto) {
        Frachise franchise = createFranchiseUseCase.execute(dto);
        // ...
    }
}

即使您使用 Lombok 创建构造函数,这也应该有效。

你可以像这样注入它,但考虑通过你的控制器构造函数注入服务。

@PostMapping("/api/franchises")
public ResponseEntity<Object> createFranchise(CreateFranchiseDTO dto) {
    CreateFranchiseUseCase useCase = new CreateFranchiseUseCase();
    Frachise franchise = useCase.execute(dto);
    // ...
}

编辑: 但请记住,您必须向 CreateFranchiseUseCase 注入其他服务。您可以像这样在构造函数中执行此操作:

public CreateFranchiseUseCase () {
    FranchiseService franchiseService = new FranchiseService();
    UserService userService = new UserService();
    ACLEntryService aclEntryService = new ACLEntryService();
    FranchiseDTOMapper franchiseDTOMapper = new FranchiseDTOMapper();
}

或者像这样在没有构造函数的情况下注入它:

@Service
@RequiredArgsConstructor
public class CreateFranchiseUseCase {
    private final FranchiseService franchiseService = new FranchiseService();
    private final UserService userService = new UserService();
    private final ACLEntryService aclEntryService = new ACLEntryService();
    private final FranchiseDTOMapper franchiseDTOMapper = new FranchiseDTOMapper();

    public Franchise execute(CreateFranchiseDTO dto) {
        // ...
    }
}

Does Spring support Method Injection?

没有。按参数列出的可接收对象如下:

您可以使用 ApplicatonContext#getBean():

    @Autowired
    private ApplicationContext context;

    @PostMapping("/api/franchises")
    public ResponseEntity<Object> createFranchise(CreateFranchiseDTO dto) {
        reateFranchiseUseCase useCase = context.getBean(CreateFranchiseUseCase.class);
        // ...
    }

如果每个请求都需要CreateFranchiseUseCase对象实例化,则需要添加@Scope(WebApplicationContext.SCOPE_REQUEST):

@Service
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class CreateFranchiseUseCase {