1

我正在使用 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?

提前致谢!

4

1 回答 1

0

您可以尝试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()));
    }
}

请让我知道它是否有效!

于 2019-09-11T20:51:35.667 回答