【问题标题】:Can't autowire HttpServletRequest in multi-module Gradle app无法在多模块 Gradle 应用程序中自动装配 HttpServletRequest
【发布时间】:2020-02-08 10:06:24
【问题描述】:

我有多个由 Gradle 管理的 Spring Boot 微服务应用程序。有一个常见的 jar 和特定领域的 jar,其组织方式如下:

| common/
|-- common.jar
| p/
|-- p-ingest.jar
| g/
|-- g-ingest.jar

我的普通 jar 有一个类 BaseRESTService,它自动连接 HttpServletRequest(我已经知道这是一个坏主意 - 不是我的代码)。 p-ingest.jar 导入 common,g-ingest jar 也是如此。 geoalloc 运行没有问题。但是 p-ingest,实际上是从 g-ingest 复制的,不会运行。当上下文尝试初始化时,p-ingest 得到以下异常:

Field request in com.company.common.BaseRESTService required a bean of type 'javax.servlet.http.HttpServletRequest' that could not be found.

我对 Spring 并不陌生,我了解组件扫描和自动装配以及所有这些,但我已经为此工作了 2 天,但我不知道发生了什么。我在两个项目上都运行了gradle dependencies,并且树是相同的。下面是p-ingest的启动应用类:

@SpringBootApplication
@ComponentScan(
        basePackageClasses = com.company.common.ConfigurationSearchCriteriaFactory.class,
        basePackages = {"com.company.erd"})
@EnableJpaRepositories(basePackages = "com.company.erd")
@EntityScan(basePackages = {"com.company.erd"})
public class PortfolioRiskIngestApplication implements ApplicationRunner {

    private static final Log logger = LogFactory.getLog(IngestApplication.class);
    @Autowired
    private IngestService ingestService;

    public PIngestApplication(PIngestService ingestService) {this.ingestService = ingestService;}

    public static void main(String[] args) {

        SpringProfileHelper.setProfileFromAwsEnvironment();
        SpringApplication app = new SpringApplication(PIngestApplication.class);
        app.setWebEnvironment(false);
        app.run(args);
    }

    @PostConstruct
      void started() {
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
      }

    @Override
    public void run(ApplicationArguments applicationArguments) {
        // define the log info
        LogInfo info = LogInfo.newInstance("run", new Object[] { StringUtility.arrayToString(applicationArguments.getSourceArgs()) });

        // log entry
        logger.info(info.entry());

        ingestService.run(applicationArguments.getSourceArgs());

        // log exit
        logger.info(info.exit());
    }
}

这是BaseRestService的摘录:

public class BaseRESTService 
{
    private static final Log logger = LogFactory.getLog(BaseRESTService.class);

    @Autowired
    private HttpServletRequest request;

    @ResponseStatus(HttpStatus.NOT_FOUND)  
    @ExceptionHandler(value = EntityNotFoundException.class)  
    public ErrorResponse handleEntityNotFoundException(EntityNotFoundException e){  
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setErrorCode(HttpStatus.NOT_FOUND.value());
        errorResponse.setErrorMessage(e.getMessage());
        logger.error(e.getMessage(), e);
        return errorResponse;  
    } 

没什么特别的。所涉及的所有类都非常简单。我欢迎任何人对我做错的任何想法......

【问题讨论】:

  • 好吧,你有app.setWebEnvironment(false);。因此,您的应用程序不是 Web 应用程序。所以它不能使用 HttpServletRequest,它是通过 web 向 servlet 发出的请求,因此要求应用程序是 web 应用程序。
  • 我们所有的微服务都将其设置为 false,并且它们可以正常工作。怎么可能?
  • 我不知道,我认为这是阻止使用 HttpServletRequest 的原因可能是错误的,但我不明白为什么你会告诉 Spring 你不在网络中工作当你清楚地想要并且想要的环境。请发布异常的完整堆栈跟踪。
  • 没有堆栈跟踪。我们确实有一个需要运行的健康检查控制器……我想你是对的!但至少有 5 位开发人员和我一起研究过这个问题,但没有人注意到这一点。
  • 我被告知将网络环境设置为true 不是我们想要的。这将使应用程序始终处于活动状态,我们需要它处于休眠状态,直到它被唤醒,然后终止。就像我说的,其他应用程序正在成功地做到这一点......

标签: java spring spring-boot gradle dependency-injection


【解决方案1】:

我发现了我的问题,这是一个菜鸟错误。出于懒惰,我对整个代码库进行了组件扫描,它选择了我们在公共 jar 中的控制器,该 jar 仅适用于我们的 REST 应用程序。只扫描实际需要的包的组件才有效。

【讨论】:

    【解决方案2】:

    您可以使用RequestContext 获取HttpServletRequest

    @Inject
    private RequestContext requestContext;
    

    并在方法中调用getRequest()

    HttpServletRequest request = requestContext.getRequest();
    

    【讨论】:

    • 感谢您的回答,但不能更改代码。我们所有的微服务都注入了HttpServletRequest。我需要的是一个部署解决方案。
    猜你喜欢
    • 2020-04-30
    • 2015-09-19
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 2020-07-10
    • 2017-12-29
    • 2022-07-17
    • 1970-01-01
    相关资源
    最近更新 更多