玩转阿里云函数计算(一)----Java Http 触发器极速迁移传统 Spring 应用

简介: 前言 阿里云函数计算 Function Compute(FC),旨在帮助用户采用弹性伸缩、动态分配资源的方式,来执行业务函数。让用户无需购买部署服务器,无需考虑业务负载,就能快速搭建可处理高并发的后台服务。

前言

阿里云函数计算 Function Compute(FC),旨在帮助用户采用弹性伸缩、动态分配资源的方式,来执行业务函数。让用户无需购买部署服务器,无需考虑业务负载,就能快速搭建可处理高并发的后台服务。
函数计算平台针对 Java 语言推出的 Java HTTP 触发器功能,能够无缝迁移传统的 Java Web 应用。支持基于 Servlet 协议的 Web 框架所开发的应用,比如常用的 Spring、SpringBoot、Struts2等。
本文介绍如何使用 Java HTTP 触发器来快速迁移 Spring 提供的开源 Web 项目 GreenHouse

相关链接

开始迁移

Java HTTP 触发器使用示例代码

一、打包需要迁移的 Web 工程为 war 包

可以使用已编译好的 greenhouse.war,本步骤可直接跳过

  1. GreenHouse github 上下载 Web 工程源码。
  2. 在源码根目录执行 maven 打包命令 maven clean package -DskipTests

    注意 GreenHouse 使用的 JDK 版本是1.6,比较老。这里打包前需要修改下 pom.xml 为你使用的 JDK 版本。
    image

    打包成功后,在 target 目录下能看到 greenhouse-1.0.0.BUILD-SNAPSHOT.war 这个文件。最后为了方便将该 war 包重命名为 greenhouse.war

二、在函数计算平台创建 Java 函数

将要运行的应用 war 包可以和函数代码一起打包上传,也可以放在网络存储中比如 阿里云对象存储(OSS),或者任何其它的网络存储。以下示例将应用 war 包放在函数代码工程中和存储到 OSS 中两种方式。

方式一:应用 war 包放在函数代码工程

  1. 在本地创建 maven 工程,并创建一个 package 比如 com.aliyun.fc.example,在 package 中添加 Java 类 HelloWebLocal.java:

    public class HelloWebLocal implements FunctionInitializer, HttpRequestHandler {
        private FcAppLoader fcAppLoader = new FcAppLoader();
    
        private String key = "greenhouse.war";
        private String userContextPath = "/2016-08-15/proxy/${YourServiceName}/${YourFunctionName}";
      
        @Override
        public void initialize(Context context) throws IOException {
            FunctionComputeLogger fcLogger = context.getLogger();
          
            fcAppLoader.setFCContext(context);
          
            // Set war file path
            fcAppLoader.loadCodeFromLocalProject(key);
          
            // Init webapp from code
            long timeBegin = System.currentTimeMillis();
            fcLogger.info("Loading webapp: " + key);
            boolean initSuccess = fcAppLoader.initApp(userContextPath, HelloWebOSS.class.getClassLoader());
            if(! initSuccess) {
                throw new IOException("Init web app failed");
            }
            fcLogger.info("Loaded webapp, elapsed: " + (System.currentTimeMillis() - timeBegin) + "ms");
        }
      
        @Override
        public void handleRequest(HttpServletRequest request, HttpServletResponse response, Context context)
                throws IOException, ServletException {
            try {
                fcAppLoader.forward(request, response);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    其中引用的 maven 库:

    <dependency>
       <groupId>com.aliyun.fc.runtime</groupId>
       <artifactId>fc-java-core</artifactId>
       <version>1.3.0</version>
      </dependency>
    
    <dependency>
       <groupId>com.aliyun.fc.runtime</groupId>
       <artifactId>fc-java-common</artifactId>
       <version>1.0.0</version>
      </dependency>
  2. 将 greenhouse.war 拷贝到 Java 工程中,上述代码中 loadCodeFromLocalProject 方法参数为 greenhouse.war 文件在工程中的相对路径。比如放在 src/main/resources 目录,那就和上述代码保持一样,否则改成对应的相对路径。

方式二:应用 war 包存储到 OSS 中

如果将 war 包放在创建函数的 Java 工程中,会增加创建函数时上传的代码包大小。对于代码包大小函数计算有限制最大为 50M ,请参考函数计算使用限制。往往 Java 的 web 应用 war 包会比较大,因而更好的方式是将 war 包放在 OSS 中,然后通过初始化函数 initializer 来下载 war 包到执行环境中。同样可以调用 fc-java-common 库中的 loadCodeFromOSS 方法即可,该方法会将对应的 war 包下载到执行环境的临时磁盘目录 /tmp 中。

  1. 将 greenhouse.war 上传到 OSS 中
  2. 方式一创建 maven 工程以及 Java package,并创建 HelloWebOSS.java:

    public class HelloWebOSS implements FunctionInitializer, HttpRequestHandler {
        private FcAppLoader fcAppLoader = new FcAppLoader();
    
        private String ossEndPoint = "${YourOSSEndpoint}";
        private String bucket = "${YourOSSBucket}";
        private String key = "greenhouse.war";
        private String userContextPath = "/2016-08-15/proxy/${YourServiceName}/${YourFunctionName}";
      
        @Override
        public void initialize(Context context) throws IOException {
            FunctionComputeLogger fcLogger = context.getLogger();
          
            fcAppLoader.setFCContext(context);
          
            // Load code from OSS
            fcLogger.info("Begin load code: " + key);
            boolean codeSuccess = fcAppLoader.loadCodeFromOSS(ossEndPoint, bucket, key);
            if (! codeSuccess) {
                throw new IOException("Download code failed");
            }
            fcLogger.info("End load code");
          
            // Init webapp from code
            long timeBegin = System.currentTimeMillis();
            fcLogger.info("Begin load webapp");
            boolean initSuccess = fcAppLoader.initApp(userContextPath, HelloWebOSS.class.getClassLoader());
            if(! initSuccess) {
                throw new IOException("Init web app failed");
            }
            fcLogger.info("End load webapp, elapsed: " + (System.currentTimeMillis() - timeBegin) + "ms");
        }
      
        @Override
        public void handleRequest(HttpServletRequest request, HttpServletResponse response, Context context)
                throws IOException, ServletException {
            try {
                fcAppLoader.forward(request, response);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

函数计算平台创建函数

关于怎么在函数计算平台创建函数请参考: Hello World 示例
关于怎么使用 Java 语言请参考:Java 运行环境

将上述的 maven 工程打包,并在函数计算平台创建服务和函数,这里需要注意的点:

  1. 需要将您创建的服务名和函数名,填充到上述 HelloWebLocal.java 中:

    private String userContextPath = "/2016-08-15/proxy/${YourServiceName}/${YourFunctionName}";
  2. 如果您使用的是 OSS 存储方式,需要填充 OSS 相关信息到 HelloWebOSS.java 中:

      private String ossEndPoint = "${YourOSSEndpoint}";
      private String bucket = "${YourOSSBucket}";
      private String userContextPath = "/2016-08-15/proxy/${YourServiceName}/${YourFunctionName}";
  3. 创建函数时除了需要设置函数入口外,还需要设置初始化入口指向上述代码的 initialize 函数。
  4. Web 应用使用的内存较多,请注意函数内存大小设置,比如我这里设置的是 512M

示例配置如下:
image

为函数创建 HTTP 触发器

关于怎么创建 HTTP 触发器请参考:HTTP 触发器

测试函数运行

在函数计算控制台执行 HTTP 触发器,看到如下返回:
image

可以看到成功返回了 greenhouse 的 web 页面。
但是如果在浏览器中执行 HTTP 触发器的请求地址,web 页面将会已文件的形式下载。这是因为函数计算为了安全强制设置了请求返回的 header 为 Content-Disposition: attachment,所以返回结果会以附件形式下载。

为 HTTP 触发器绑定自定义域名

为了解决这个问题,需要用户申请自定义域名,并绑定域名解析到函数计算中,请参考函数计算绑定自定义域名
使用自定义域名访问,需要将最初的 Java 代码中 userContextPath 改为自定义域名的 contextPath 比如/ /greenhouse 等,这样才能保证页面中的超链接是相对于当前请求的域名:

// Not use custom domain
//private String userContextPath = "/2016-08-15/proxy/${YourServiceName}/${YourFunctionName}";

// Use custom domain
private String userContextPath = "/greenhouse";

自定义域名绑定到 HTTP 触发的示例配置:
image

自定义域名路径前缀必须和代码中 userContextPath 保持一致,比如这里都是 /greenhouse。当然可以选择其它的路径名,也可以使用根路径,即路径配置为 /* 对应的 userContextPath 为 /
通过修改配置路径和对应的 userContextPath,可映射到不同的 HTTP 触发器函数,从而映射到不同的 web 应用中。这样就能同一个域名同时复用到不同的 web 应用。

浏览器中访问自定义域名:
shop

大功告成!

后语

函数计算是 serverless 服务,对于传统的 Web 应用支持目前还是存在一些瑕疵。

  1. 无状态性,每次函数执行都是无状态的。对于 Web 应用往往有很多状态需要保持,比如 session,用户需要在自己的 Web 应用中去处理。当然很多 web 框架已经提供了很方便的分布式 session 方案,只需简单的配置即可。
  2. 冷启动,新的执行环境中第一次请求 web 应用会比较耗时,这是由于执行环境需要启动 JVM 以及加载 web 应用,针对这个可通过定时预热的方式来解决。

但这些相对于 serverless 提供的弹性伸缩和按需付费的优点不值一提,个人认为 serverless 必定会取代传统物理机或虚拟机的服务器方式,从而让有限的资源得到更高效的利用。

相关实践学习
【AI破次元壁合照】少年白马醉春风,函数计算一键部署AI绘画平台
本次实验基于阿里云函数计算产品能力开发AI绘画平台,可让您实现“破次元壁”与角色合照,为角色换背景效果,用AI绘图技术绘出属于自己的少年江湖。
从 0 入门函数计算
在函数计算的架构中,开发者只需要编写业务代码,并监控业务运行情况就可以了。这将开发者从繁重的运维工作中解放出来,将精力投入到更有意义的开发任务上。
目录
相关文章
|
4月前
|
人工智能 运维 Kubernetes
Serverless 应用引擎 SAE:为传统应用托底,为 AI 创新加速
在容器技术持续演进与 AI 全面爆发的当下,企业既要稳健托管传统业务,又要高效落地 AI 创新,如何在复杂的基础设施与频繁的版本变化中保持敏捷、稳定与低成本,成了所有技术团队的共同挑战。阿里云 Serverless 应用引擎(SAE)正是为应对这一时代挑战而生的破局者,SAE 以“免运维、强稳定、极致降本”为核心,通过一站式的应用级托管能力,同时支撑传统应用与 AI 应用,让企业把更多精力投入到业务创新。
604 30
|
5月前
|
存储 人工智能 Serverless
函数计算进化之路:AI 应用运行时的状态剖析
AI应用正从“请求-响应”迈向“对话式智能体”,推动Serverless架构向“会话原生”演进。阿里云函数计算引领云上 AI 应用 Serverless 运行时技术创新,实现性能、隔离与成本平衡,开启Serverless AI新范式。
611 12
|
5月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
646 3
|
6月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
1074 3
|
5月前
|
SQL Java 数据库连接
Spring Data JPA 技术深度解析与应用指南
本文档全面介绍 Spring Data JPA 的核心概念、技术原理和实际应用。作为 Spring 生态系统中数据访问层的关键组件,Spring Data JPA 极大简化了 Java 持久层开发。本文将深入探讨其架构设计、核心接口、查询派生机制、事务管理以及与 Spring 框架的集成方式,并通过实际示例展示如何高效地使用这一技术。本文档约1500字,适合有一定 Spring 和 JPA 基础的开发者阅读。
580 0
|
4月前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
4月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
280 8
|
5月前
|
人工智能 运维 安全
聚焦 AI 应用基础设施,云栖大会 Serverless AI 全回顾
2025 年 9 月 26 日,为期三天的云栖大会在杭州云栖小镇圆满闭幕。随着大模型技术的飞速发展,我们正从云原生时代迈向一个全新的 AI 原生应用时代。为了解决企业在 AI 应用落地中面临的高成本、高复杂度和高风险等核心挑战,阿里云基于函数计算 FC 发布一系列重磅服务。本文将对云栖大会期间 Serverless+AI 基础设施相关内容进行全面总结。
|
5月前
|
人工智能 Kubernetes 安全
重塑云上 AI 应用“运行时”,函数计算进化之路
回顾历史,电网的修建,深刻地改变了世界的经济地理和创新格局。今天,一个 AI 原生的云端运行时的进化,其意义也远不止于技术本身。这是一次设计哲学的升华:从“让应用适应平台”到“让平台主动理解和适应智能应用”的转变。当一个强大、易用、经济且安全的 AI 运行时成为像水电一样的基础设施时,它将极大地降低创新的门槛。一个独立的开发者、一个小型创业团队,将有能力去创造和部署世界级的 AI 应用。这才是技术平权的真谛,是激发全社会创新潜能的关键。
|
6月前
|
Java 应用服务中间件 开发者
Spring Boot 技术详解与应用实践
本文档旨在全面介绍 Spring Boot 这一广泛应用于现代企业级应用开发的框架。内容将涵盖 Spring Boot 的核心概念、核心特性、项目自动生成与结构解析、基础功能实现(如 RESTful API、数据访问)、配置管理以及最终的构建与部署。通过本文档,读者将能够理解 Spring Boot 如何简化 Spring 应用的初始搭建和开发过程,并掌握其基本使用方法。
501 2

热门文章

最新文章

相关产品

  • 函数计算