【问题标题】:Component bean is not injected (autowired) by spring when running AWS lambda function using Spring Cloud function AWS Adapter使用 Spring Cloud 函数 AWS Adapter 运行 AWS lambda 函数时,spring 不会注入(自动装配)组件 bean
【发布时间】:2019-08-23 13:38:20
【问题描述】:

我正在使用 Spring Cloud 函数 AWS Adapter SpringBootRequestHandler 实现 AWS lambda 函数创建处理程序。调用了GenericApplicationContext中注册的功能bean,但是组件类的自动装配给出了NullPointer Exception。

我已经在 Spring Application 中尝试使用 @ComponentScan 作为基础包。

应用类:

@Slf4j
@SpringBootApplication
@ComponentScan({ "com.poc.evthub" })
@EnableConfigurationProperties(EventHubProperties.class)
public class EventHubServerlessApplication implements ApplicationContextInitializer<GenericApplicationContext> {

    public EventHubServerlessApplication() {
    }

    public static void main(String[] args) throws Exception {
        FunctionalSpringApplication.run(EventHubServerlessApplication.class, args);
    }

    @Bean
    public KinesisEventFunction ingestEvents() {
        return new KinesisEventFunction();
    }

    @Override
    public void initialize(GenericApplicationContext context) {

        log.debug("========  initialize  ========");

        context.registerBean("ingestEvents", FunctionRegistration.class,
                () -> new FunctionRegistration<Function<KinesisEvent, ApiResponse>>(ingestEvents())
                        .type(FunctionType.from(KinesisEvent.class).to(ApiResponse.class).getType()));
    }
}

处理程序:

public class KinesisEventHandler extends SpringBootRequestHandler<KinesisEvent, ApiResponse> {

}

功能豆:

package com.poc.evthub.function;

import com.amazonaws.services.lambda.runtime.events.KinesisEvent;
import com.poc.evthub.beans.ApiResponse;
import com.poc.evthub.constant.Constants;
import com.poc.evthub.service.IngestionServiceFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.function.Function;

@Slf4j
@Component
public class KinesisEventFunction implements Function<KinesisEvent, ApiResponse> {

    private Context context = null;

    @Autowired
    private IngestionServiceFactory ingestionServiceFactory;

    @Autowired
    @Qualifier("targetExecutionContext")
    public void setContext(Context context) {
        log.info("Context: {}", context);
        this.context = context;
    }

    @Override
    public ApiResponse apply(final KinesisEvent kinesisEvent) {

        log.info("KinesisEventFunction apply called...");

        String sourceDomain = System.getenv(Constants.SYSENV.SOURCE_DOMAIN);
        log.info("Source Domain = {}", sourceDomain);

        if(null == kinesisEvent || null == kinesisEvent.getRecords()) {
            log.error("Event contains no data. {}", System.lineSeparator());
            //TODO build response NOT FOUND
            return null;
        }
        else
            log.info("Received {}  records from {}. {}",
                    kinesisEvent.getRecords().size(),                
 kinesisEvent.getRecords().get(0).getEventSourceARN(),
                    System.lineSeparator());

        log.info("ingestionServiceFactory = {}",ingestionServiceFactory);
        ingestionServiceFactory.ingest();

        return null;
    }
}

完整的代码和pom上传到: https://github.com/rjavaria/eventhub-serverless

KinesisEventFunction 应用调用... 还能够从 lambda 读取环境值(source_domain),并接收 Kinesis 事件记录。

但是@Autowired ingestionServiceFactory 为空。我正在注入这个组件bean 来委派业务逻辑。

这里遗漏了什么,所以spring不能注入这个组件bean?

提前致谢!

【问题讨论】:

  • 我怀疑@ComponentScan。不确定它是否包括com.poc.evthub.service
  • 感谢词典。 ComponentScan 不是问题,组件是自动连接的,如果我不将该函数注册为功能 bean 并且不实现 ApplicationContextInitializer。如果它作为 SpringApplication 运行,而不是 FunctionalSpringApplication 并且没有实现 ApplicationContextInitializer,则工作正常。 public static void main(String[] args) throws Exception { SpringApplication.run(EventHubServerlessApplication.class, args); }

标签: spring amazon-web-services aws-lambda amazon-kinesis spring-cloud-function


【解决方案1】:

您可以尝试通过构造函数或 setter 注入手动将 IngestionServiceFactory bean 注入到您的函数类中。

在您的函数类中,添加一个构造函数并从您的 IngestionServiceFactory 字段中删除 @Autowired,例如:

...
public class KinesisEventFunction implements Function<KinesisEvent, ApiResponse> {

...
    // No @Autowired here...
    private final IngestionServiceFactory ingestionServiceFactory;
...
    // The new constructor here...
    public KinesisEventFunction(final IngestionServiceFactory pIngestionServiceFactory) {
        this.ingestionServiceFactory = pIngestionServiceFactory;
    }
...

}

然后在你的主类(实现ApplicationContextInitializer&lt;GenericApplicationContext&gt;的那个)中,在注册函数bean时将引用传递给工厂,比如:

...
public class EventHubServerlessApplication implements ApplicationContextInitializer<GenericApplicationContext> {

...
    @Autowired
    private IngestionServiceFactory ingestionServiceFactory;
...
    @Bean
    public KinesisEventFunction ingestEvents() {
        return new KinesisEventFunction(this.ingestionServiceFactory);
    }

    @Override
    public void initialize(GenericApplicationContext context) {

        log.debug("========  initialize  ========");

        context.registerBean("ingestEvents", FunctionRegistration.class,
                () -> new FunctionRegistration<>(ingestEvents())
                        .type(FunctionType.from(KinesisEvent.class).to(ApiResponse.class).getType()));
    }
}

或者,由于您已经使用 context.registerBean() 手动注册函数 bean,您可以:

...
public class EventHubServerlessApplication implements ApplicationContextInitializer<GenericApplicationContext> {

...
    @Autowired
    private IngestionServiceFactory ingestionServiceFactory;
...
    @Override
    public void initialize(GenericApplicationContext context) {

        log.debug("========  initialize  ========");

        context.registerBean("ingestEvents", FunctionRegistration.class,
                () -> new FunctionRegistration<>(new KinesisEventFunction(this.ingestionServiceFactory))
                        .type(FunctionType.from(KinesisEvent.class).to(ApiResponse.class).getType()));
    }
}

请告诉我它是否有效!

【讨论】:

  • 不是 OP,但我的情况几乎相同,而 setter-injected IngestionServiceFactory 对我来说是空的。关于发生了什么的任何线索?
猜你喜欢
  • 1970-01-01
  • 2016-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 2014-06-30
  • 2020-05-03
  • 1970-01-01
相关资源
最近更新 更多