有没有一种方法可以将依赖项注入到Spring RestControllers提供的POJO中?例如,如果您想实现多态行为。
下面的示例以NullPointerExcetion
失败,因为lowerCaseService
没有注入到Example
POJO中:
@RestController
public class ExampleController {
@PostMapping("/example")
String example(@RequestBody Example example) {
return example.valueToLowerCase();
}
}
@Data
@NoArgsConstructor
public class Example {
private String value;
@Autowired
private LowerCaseService lowerCaseService;
public String valueToLowerCase() {
return lowerCaseService.toLowerCase(getValue());
}
}
@Service
public class LowerCaseService {
public String toLowerCase(String value) {
return value != null ? value.toLowerCase() : null;
}
}
请注意,这个人为设计的示例刻意简单,不需要多态行为。我以这种方式创建了它,以帮助响应者快速理解它,而不会被Jackson的注释所困扰。在我的实际用例中,Jackson会生成Example
的子类,每个子类都需要做非常不同的事情,并具有不同的依赖关系。
答案 0 :(得分:1)
根据定义,POJO(普通的旧Java对象)是普通的Java对象类(即,不是JavaBean,EntityBean等),并且不充当任何其他特殊角色,也不实现任何Java框架。这个术语是由Martin Fowler,Rebbecca Parsons和Josh MacKenzie创造的,他们相信通过创建首字母缩写词POJO,此类对象将具有“花哨的名称”,从而使人们确信它们值得使用。链接:https://www.webopedia.com/TERM/P/POJO.html
换句话说,POJO应该只包含属性,而不能包含其他任何内容。
我认为在这种情况下,我们可以通过将服务注入控制器方法来解决问题。
@RestController
public class ExampleController {
@Autowired
private LowerCaseService lowerCaseService;
@PostMapping("/example")
String example(@RequestBody Example example) {
return lowerCaseService. toLowerCase(example.getValue);
}
}
答案 1 :(得分:1)
简单的答案是“不,不能”,因为在Spring的Context中实例化bean时会注入依赖项,而这个POJO只是Jackson映射的一个实例(可能)。
此答案包含更多信息:How does autowiring work in Spring?
但是,比这更重要的是架构原则,您实际上不应该将业务服务放在外部模型中(示例),因为这显然是关注点冲突的分离。
您应该将服务注入控制器类,并将DTO作为参数传递给其方法。
希望有帮助!
答案 2 :(得分:0)
您可以通过实现自己的 RequestBodyAdviceAdapter 来实现您正在尝试做的事情...基本上涉及 3 个步骤:
return ((Class) targetType).isAssignableFrom(Example.class);
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
final Example example = (Example) super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
final AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
autowireCapableBeanFactory.autowireBeanProperties(example, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
return example;
}