【问题标题】:Spring Dependency Injection in RestController POJOsRestController POJO 中的 Spring 依赖注入
【发布时间】:2018-10-23 03:57:34
【问题描述】:

有没有办法将依赖项注入 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 将生成 Example 的子类,每个子类需要做非常不同的事情,具有不同的依赖关系。

【问题讨论】:

    标签: java spring spring-boot jackson


    【解决方案1】:

    根据定义,POJO(Plain Old Java Object)是一个普通的 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);
      }
    
    }
    

    【讨论】:

      【解决方案2】:

      简单的答案是否定的,你不能,因为在 Spring 的 Context 中实例化 bean 时会注入依赖项,而这个 POJO 只是 Jackson 映射(可能)的一个实例。

      这个答案有更多关于它的信息:How does autowiring work in Spring?

      但是比这更重要的是架构原则,你真的不应该将你的业务服务放在你的外部模型中(示例),因为它显然违反了关注点分离。

      您应该在控制器类中注入您的服务,并将 DTO 作为参数传递给它的方法。

      希望对你有帮助!

      【讨论】:

        【解决方案3】:

        您可以实现自己的 RequestBodyAdviceAdapter... 基本上涉及 3 个步骤:

        1. 创建一个扩展 RequestBodyAdviceAdapter 并实现 ApplicationContextAware 的类(因此您可以访问应用程序上下文)。
        2. 实现 support() 方法:
        return ((Class) targetType).isAssignableFrom(Example.class);
        
        1. 重写 afterRead() 方法:
        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;
        }
        

        【讨论】:

          猜你喜欢
          • 2015-10-04
          • 1970-01-01
          • 1970-01-01
          • 2012-08-02
          • 1970-01-01
          • 2018-11-21
          • 2012-12-23
          • 1970-01-01
          相关资源
          最近更新 更多