首页 > 解决方案 > 使用 Spring Cloud 函数 AWS Adapter 运行 AWS lambda 函数时,spring 不会注入(自动装配)组件 bean

问题描述

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

我在 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 apply 调用... 还能够从 lambda 读取环境值(source_domain),并接收 Kinesis 事件记录。

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

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

提前致谢!

标签: springamazon-web-servicesaws-lambdaamazon-kinesisspring-cloud-function

解决方案


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

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

...
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<GenericApplicationContext>)中,在注册函数 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()));
    }
}

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

...
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()));
    }
}

请让我知道它是否有效!


推荐阅读