在 AWS Lambda 上部署的一个项目中的多个 Spring Cloud Functions
Multiple Spring Cloud Functions in one project for deployment on AWS Lambda
我可能需要一些帮助...
我正在使用 Spring Cloud Functions,我想使用适用于 AWS 的适配器在 AWS Lambda 上部署我的函数。
我的申请 class 看起来像这样:
package example;
@SpringBootApplication
public class SpringCloudFunctionApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudFunctionApiGatewayApplication.class, args);
}
}
函数 1 如下所示:
package example;
@Component
public class StoreFunction implements Consumer<Message<DemoEntity>>{
@Override
public void accept(Message<DemoEntity> t) {
System.out.println("Stored entity " + ((DemoEntity)t.getPayload()).getName());
return;
}
}
最后,我的函数处理程序如下所示:
package example;
public class TestFunctionHandler extends SpringBootApiGatewayRequestHandler {
}
此设置完美运行。
部署到 Lambda 时,我在 AWS 控制台中提供 example.TestFunctionHandler 作为处理程序,Spring Cloud 会自动识别 example.QueryFunction 是上下文中唯一的函数。
日志输出如下所示:
START RequestId: 3bd996e7-ef5e-11e8-9829-1f50e2b93b6c Version: $LATEST
20:27:45.821 [main] INFO org.springframework.cloud.function.adapter.aws.SpringFunctionInitializer - Initializing: class de.margul.awstutorials.springcloudfunction.apigateway.SpringCloudFunctionApiGatewayApplication
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::
2018-11-23 20:27:48.221 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : Starting LambdaRTEntry on ip-10-153-127-174.ec2.internal with PID 1 (/var/runtime/lib/LambdaJavaRTEntry-1.0.jar started by sbx_user1060 in /)
2018-11-23 20:27:48.242 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : No active profile set, falling back to default profiles: default
2018-11-23 20:27:52.081 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : Started LambdaRTEntry in 5.941 seconds (JVM running for 7.429)
Stored entity John Doe
END RequestId: 3bd996e7-ef5e-11e8-9829-1f50e2b93b6c
REPORT RequestId: 3bd996e7-ef5e-11e8-9829-1f50e2b93b6c Duration: 7113.98 ms Billed Duration: 7200 ms Memory Size: 1088 MB Max Memory Used: 113 MB
现在,我的问题来了。
我想在一个项目中拥有多个功能。
我知道,在 Lambda 上,每个部署只能有一个函数。
但出于代码维护的原因(真实项目中有一些共享代码和配置),我们希望所有功能都在一个项目中,多次部署该项目,并在部署中定义,即相关功能。
使用适用于 Lambda 的原生 AWS 开发工具包,这很简单(如第 4.2 节中的 in this example):
RequestStreamHandler 的一种实现,具有多种方法(即使 RequestStreamHandler 只有一个 handleRequest() 方法) .
关键是可以将相关函数定义为处理程序:package.ClassName::methodName
但是,这不适用于 Spring Cloud Function(因为我们只能有一个处理程序,在本例中为 TestFunctionHandler)。
The documentations mentions 通过在 application.properties 中指定 function.name 或作为 Lambda 环境变量,可以实现多个函数FUNCTION_NAME。
无论如何,我没有得到那个工作。
我的函数 2 如下所示:
package example;
@Component
public class QueryFunction implements Function<Message<String>, Message<DemoEntity>>{
@Override
public Message<DemoEntity> apply(Message<String> m) {
String name = m.getPayload();
DemoEntity response = new DemoEntity();
response.setName(name);
Message<DemoEntity> message = MessageBuilder
.withPayload(response)
.setHeader("contentType", "application/json")
.build();
return message;
}
}
在我的 application.properties 中,我有这一行:
function.name = example.StoreFunction
如果我创建一个环境变量FUNCTION_NAME同样适用:example.StoreFunction
如果我现在部署库并触发它,我会得到以下日志:
START RequestId: 67e64098-ef5d-11e8-bdbf-9ddadadef0ce Version: $LATEST
20:21:50.802 [main] INFO org.springframework.cloud.function.adapter.aws.SpringFunctionInitializer - Initializing: class example.SpringCloudFunctionApiGatewayApplication
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::
2018-11-23 20:21:53.684 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : Starting LambdaRTEntry on ip-10-153-127-174.ec2.internal with PID 1 (/var/runtime/lib/LambdaJavaRTEntry-1.0.jar started by sbx_user1059 in /)
2018-11-23 20:21:53.687 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : No active profile set, falling back to default profiles: default
2018-11-23 20:21:57.488 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : Started LambdaRTEntry in 6.353 seconds (JVM running for 8.326)
No function defined: java.lang.IllegalStateException
java.lang.IllegalStateException: No function defined
at org.springframework.cloud.function.adapter.aws.SpringFunctionInitializer.apply(SpringFunctionInitializer.java:134)
at org.springframework.cloud.function.adapter.aws.SpringBootRequestHandler.handleRequest(SpringBootRequestHandler.java:48)
END RequestId: 67e64098-ef5d-11e8-bdbf-9ddadadef0ce
REPORT RequestId: 67e64098-ef5d-11e8-bdbf-9ddadadef0ce Duration: 7454.73 ms Billed Duration: 7500 ms Memory Size: 1088 MB Max Memory Used: 130 MB
非常感谢您的帮助!
好的,问题显然是我对 Spring Beans 的了解有限。
在查看上下文中所有可用 bean 的列表后,很明显我必须使用 class 名称,但以小写字母 i 开头。 e. function.name = storeFunction 或 function.name = queryFunction.
编辑以详细解释我的解决方案:
在我的项目中,我有几个这样的功能:
@Component
public class StoreFunction implements Consumer<String>{
@Override
public void accept(String s) {
// Logic comes here
}
}
@Component
public class QueryFunction implements Function<String, String>{
@Override
public void apply(String s) {
return s;
}
}
然后,我将它们注册为 beans,e。 G。像这样:
@SpringBootApplication
public class SpringCloudFunctionApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudFunctionApiGatewayApplication.class, args);
}
@Bean
StoreFunction storeFunction(){
return new StoreFunction();
}
@Bean
QueryFunction queryFunction(){
return new QueryFunction();
}
}
现在,我的 Spring上下文。
最后,我必须告诉 Spring 要调用哪个函数。这可以通过创建环境变量 FUNCTION_NAME 并将其设置为 bean 名称之一来完成。
当我现在将项目部署到 AWS Lambda 时,我必须告诉 Lambda 调用哪个函数(因为 Lambda 每次部署只能调用一个函数)。
顺便说一句,我为此创建了 a tutorial。
我遇到了同样的问题。在我的项目中,我有多个 springs 函数想要根据请求动态调用它们。
我的功能:
函数 1:
public class Login implements Function<AuthenticationRequestDTO, JwtTokenDTO>{
public JwtTokenDTO apply(AuthenticationRequestDTO user) {
// Logic
}
}
函数 2:
public class UserInfo implements Function<JwtTokenDTO, WhoAmIDTO>{
public WhoAmIDTO apply(JwtTokenDTO jwt) {
// Logic
}
}
在我的 Spring 引导应用程序 class 中,我添加了实现接口 MessageRoutingCallback 和 returns 来自 http headers 的 http 请求特定“func_name”的 customRouter .这样我们就不需要不支持动态函数路由的静态 FUNCTION_NAME 或 spring.cloud.function.definition。
从 UI 发送请求集 header “func_name” 到要调用的 spring 函数。
我的申请class:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
@Bean
public MessageRoutingCallback customRouter() {
return new MessageRoutingCallback() {
@Override
public String functionDefinition(Message<?> message) {
String fnName = (String) message.getHeaders().get("func_name");
return fnName;
}
};
}
}
在 AWS 处理程序中指向:org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest
我可能需要一些帮助...
我正在使用 Spring Cloud Functions,我想使用适用于 AWS 的适配器在 AWS Lambda 上部署我的函数。
我的申请 class 看起来像这样:
package example;
@SpringBootApplication
public class SpringCloudFunctionApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudFunctionApiGatewayApplication.class, args);
}
}
函数 1 如下所示:
package example;
@Component
public class StoreFunction implements Consumer<Message<DemoEntity>>{
@Override
public void accept(Message<DemoEntity> t) {
System.out.println("Stored entity " + ((DemoEntity)t.getPayload()).getName());
return;
}
}
最后,我的函数处理程序如下所示:
package example;
public class TestFunctionHandler extends SpringBootApiGatewayRequestHandler {
}
此设置完美运行。 部署到 Lambda 时,我在 AWS 控制台中提供 example.TestFunctionHandler 作为处理程序,Spring Cloud 会自动识别 example.QueryFunction 是上下文中唯一的函数。
日志输出如下所示:
START RequestId: 3bd996e7-ef5e-11e8-9829-1f50e2b93b6c Version: $LATEST
20:27:45.821 [main] INFO org.springframework.cloud.function.adapter.aws.SpringFunctionInitializer - Initializing: class de.margul.awstutorials.springcloudfunction.apigateway.SpringCloudFunctionApiGatewayApplication
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::
2018-11-23 20:27:48.221 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : Starting LambdaRTEntry on ip-10-153-127-174.ec2.internal with PID 1 (/var/runtime/lib/LambdaJavaRTEntry-1.0.jar started by sbx_user1060 in /)
2018-11-23 20:27:48.242 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : No active profile set, falling back to default profiles: default
2018-11-23 20:27:52.081 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : Started LambdaRTEntry in 5.941 seconds (JVM running for 7.429)
Stored entity John Doe
END RequestId: 3bd996e7-ef5e-11e8-9829-1f50e2b93b6c
REPORT RequestId: 3bd996e7-ef5e-11e8-9829-1f50e2b93b6c Duration: 7113.98 ms Billed Duration: 7200 ms Memory Size: 1088 MB Max Memory Used: 113 MB
现在,我的问题来了。 我想在一个项目中拥有多个功能。 我知道,在 Lambda 上,每个部署只能有一个函数。 但出于代码维护的原因(真实项目中有一些共享代码和配置),我们希望所有功能都在一个项目中,多次部署该项目,并在部署中定义,即相关功能。
使用适用于 Lambda 的原生 AWS 开发工具包,这很简单(如第 4.2 节中的 in this example): RequestStreamHandler 的一种实现,具有多种方法(即使 RequestStreamHandler 只有一个 handleRequest() 方法) . 关键是可以将相关函数定义为处理程序:package.ClassName::methodName
但是,这不适用于 Spring Cloud Function(因为我们只能有一个处理程序,在本例中为 TestFunctionHandler)。 The documentations mentions 通过在 application.properties 中指定 function.name 或作为 Lambda 环境变量,可以实现多个函数FUNCTION_NAME。 无论如何,我没有得到那个工作。
我的函数 2 如下所示:
package example;
@Component
public class QueryFunction implements Function<Message<String>, Message<DemoEntity>>{
@Override
public Message<DemoEntity> apply(Message<String> m) {
String name = m.getPayload();
DemoEntity response = new DemoEntity();
response.setName(name);
Message<DemoEntity> message = MessageBuilder
.withPayload(response)
.setHeader("contentType", "application/json")
.build();
return message;
}
}
在我的 application.properties 中,我有这一行:
function.name = example.StoreFunction
如果我创建一个环境变量FUNCTION_NAME同样适用:example.StoreFunction
如果我现在部署库并触发它,我会得到以下日志:
START RequestId: 67e64098-ef5d-11e8-bdbf-9ddadadef0ce Version: $LATEST
20:21:50.802 [main] INFO org.springframework.cloud.function.adapter.aws.SpringFunctionInitializer - Initializing: class example.SpringCloudFunctionApiGatewayApplication
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot ::
2018-11-23 20:21:53.684 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : Starting LambdaRTEntry on ip-10-153-127-174.ec2.internal with PID 1 (/var/runtime/lib/LambdaJavaRTEntry-1.0.jar started by sbx_user1059 in /)
2018-11-23 20:21:53.687 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : No active profile set, falling back to default profiles: default
2018-11-23 20:21:57.488 INFO 1 --- [ main] lambdainternal.LambdaRTEntry : Started LambdaRTEntry in 6.353 seconds (JVM running for 8.326)
No function defined: java.lang.IllegalStateException
java.lang.IllegalStateException: No function defined
at org.springframework.cloud.function.adapter.aws.SpringFunctionInitializer.apply(SpringFunctionInitializer.java:134)
at org.springframework.cloud.function.adapter.aws.SpringBootRequestHandler.handleRequest(SpringBootRequestHandler.java:48)
END RequestId: 67e64098-ef5d-11e8-bdbf-9ddadadef0ce
REPORT RequestId: 67e64098-ef5d-11e8-bdbf-9ddadadef0ce Duration: 7454.73 ms Billed Duration: 7500 ms Memory Size: 1088 MB Max Memory Used: 130 MB
非常感谢您的帮助!
好的,问题显然是我对 Spring Beans 的了解有限。
在查看上下文中所有可用 bean 的列表后,很明显我必须使用 class 名称,但以小写字母 i 开头。 e. function.name = storeFunction 或 function.name = queryFunction.
编辑以详细解释我的解决方案:
在我的项目中,我有几个这样的功能:
@Component
public class StoreFunction implements Consumer<String>{
@Override
public void accept(String s) {
// Logic comes here
}
}
@Component
public class QueryFunction implements Function<String, String>{
@Override
public void apply(String s) {
return s;
}
}
然后,我将它们注册为 beans,e。 G。像这样:
@SpringBootApplication
public class SpringCloudFunctionApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudFunctionApiGatewayApplication.class, args);
}
@Bean
StoreFunction storeFunction(){
return new StoreFunction();
}
@Bean
QueryFunction queryFunction(){
return new QueryFunction();
}
}
现在,我的 Spring上下文。
最后,我必须告诉 Spring 要调用哪个函数。这可以通过创建环境变量 FUNCTION_NAME 并将其设置为 bean 名称之一来完成。
当我现在将项目部署到 AWS Lambda 时,我必须告诉 Lambda 调用哪个函数(因为 Lambda 每次部署只能调用一个函数)。
顺便说一句,我为此创建了 a tutorial。
我遇到了同样的问题。在我的项目中,我有多个 springs 函数想要根据请求动态调用它们。
我的功能:
函数 1:
public class Login implements Function<AuthenticationRequestDTO, JwtTokenDTO>{
public JwtTokenDTO apply(AuthenticationRequestDTO user) {
// Logic
}
}
函数 2:
public class UserInfo implements Function<JwtTokenDTO, WhoAmIDTO>{
public WhoAmIDTO apply(JwtTokenDTO jwt) {
// Logic
}
}
在我的 Spring 引导应用程序 class 中,我添加了实现接口 MessageRoutingCallback 和 returns 来自 http headers 的 http 请求特定“func_name”的 customRouter .这样我们就不需要不支持动态函数路由的静态 FUNCTION_NAME 或 spring.cloud.function.definition。
从 UI 发送请求集 header “func_name” 到要调用的 spring 函数。
我的申请class:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
@Bean
public MessageRoutingCallback customRouter() {
return new MessageRoutingCallback() {
@Override
public String functionDefinition(Message<?> message) {
String fnName = (String) message.getHeaders().get("func_name");
return fnName;
}
};
}
}
在 AWS 处理程序中指向:org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest