龙空技术网

OpenFaaS实战之七:java11模板解析

程序员欣宸 180

前言:

现时你们对“java程序模板”都比较关切,看官们都需要了解一些“java程序模板”的相关内容。那么小编也在网上网罗了一些对于“java程序模板””的相关文章,希望咱们能喜欢,小伙伴们一起来学习一下吧!

欢迎访问我的GitHub

内容:所有原创文章分类和汇总,及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

本篇概览本文是《OpenFaaS实战》系列的第七篇,经过前面的知识储备,咱们对OpenFaaS的服务调用和容器运行原理已经了然于胸,可以更深入的研究和使用了OpenFaaS了;想要更加自由的开发函数,加入更多符合业务需要的特性,显然官方提供的几个模板是无法满足咱们的需要,以欣宸熟悉的Java为例,现有的java11java11-vert-x存在以下问题:是基于Gradle的,而实际上习惯使用Maven的开发者并不少;没有Spring、SpringBoot;不支持类似dubbo、SpringCloud等分布式调用;综上所述,java程序员常用的技术栈很难在OpenFaaS的官方模板得到支持,没关系,咱们可以自己开发模板支持上述能力,不过这不是本章的任务,本章的目标是一起深入了解java11模板,摸清官方套路,为后面的自定义模板开发做好充分的准备,本篇文章有以下内容:解析DockerfileJava源码学习没错,java11模板很简单,很快就能了解其中原理;解析Dockerfile回顾of-watchdog的http模式内部架构,如下图:从上图可见函数功能代码能被调用的关键有以下两点:有微服务(child)在监听指定端口;of-watchdog(parent)收到外部请求会转发到微服务监听的端口;最为关键的微服务of-watchdog都聚集在同一个docker容器中,因此该docker镜像的Dockerfile文件就是一切的关键,接下来一起看看这个文件;在OpenFaaS环境执行命令faas template pull可以拉取全部官方模板,在template/java11目录下是该模板的全部文件:

[root@node1 template]# tree java11java11├── build.gradle├── Dockerfile├── function│   ├── build.gradle│   ├── gradle│   │   └── wrapper│   │       ├── gradle-wrapper.jar│   │       └── gradle-wrapper.properties│   ├── gradlew│   ├── gradlew.bat│   ├── settings.gradle│   └── src│       ├── main│       │   └── java│       │       └── com│       │           └── openfaas│       │               └── function│       │                   └── Handler.java│       └── test│           └── java│               └── HandlerTest.java├── gradle│   └── wrapper│       ├── gradle-wrapper.jar│       └── gradle-wrapper.properties├── README.md├── settings.gradle└── template.yml
打开Dockerfile阅读,我在脚本的关键位置添加了注释辅助理解,如下所示:
# 使用multi-stage builds特性,将整个镜像构建分为多个阶段# 名为builder的镜像里面会生成java代码编译构建出来的结果FROM openjdk:11-jdk-slim as builderENV GRADLE_VER=6.1.1# 应用更新,并且安装后面要用到的应用RUN apt-get update -qqy \  && apt-get install -qqy \   --no-install-recommends \   curl \   ca-certificates \   unzip# 下载指定版本的gradle,并解压,再删除压缩包(避免镜像体积变大)RUN mkdir -p /opt/ && cd /opt/ \    && echo "Downloading gradle.." \    && curl -sSfL "{GRADLE_VER}-bin.zip" -o gradle-$GRADLE_VER-bin.zip \    && unzip gradle-$GRADLE_VER-bin.zip -d /opt/ \    && rm gradle-$GRADLE_VER-bin.zip# Export some environment variablesENV GRADLE_HOME=/opt/gradle-$GRADLE_VER/ENV PATH=$PATH:$GRADLE_HOME/binRUN mkdir -p /home/app/libsENV GRADLE_OPTS="-Dorg.gradle.daemon=false"WORKDIR /home/app# 把编译构建涉及的所有内容都复制到镜像的/home/app/目录,# 包括配置文件、java源码等COPY . /home/app/# 开始编译构建RUN gradle build# 打印文件列表RUN find . # 名为watchdog的镜像,注意基础镜像是openfaas/of-watchdogFROM openfaas/of-watchdog:0.7.6 as watchdog# 这个ship才是最终的镜像,前面的builder和watchdog都是为ship准备内容的# 为了控制体积,ship里面是jre,而非jdkFROM openjdk:11-jre-slim as shipRUN apt-get update -qqy \  && apt-get install -qqy \   --no-install-recommends \   unzip# 为了安全起见不使用root帐号,这里增加名为app的群组和用户RUN addgroup --system app \    && adduser --system --ingroup app app# 从watchdog镜像获取可执行文件fwatchdogCOPY --from=watchdog /fwatchdog /usr/bin/fwatchdog# 增加可执行权限RUN chmod +x /usr/bin/fwatchdog# 设置执行命令的目录WORKDIR /home/app# 从builder获取整个gradle项目的构建结果COPY --from=builder /home/app/function/build/distributions/function-1.0.zip ./function-1.0.zip# 执行运行容器进程的帐号是appuser app# 解压构建结果RUN unzip ./function-1.0.zipWORKDIR /home/app/# of-watchdog转发的地址,也就是微服务监听的地址ENV upstream_url=";# of-watchdog的模式ENV mode="http"# 微服务是java应用,要用到这个classpathENV CLASSPATH="/home/app/function-1.0/function-1.0.jar:/home/app/function-1.0/lib/*"# 启动微服务的命令ENV fprocess="java -XX:+UseContainerSupport com.openfaas.entrypoint.App"# 对外暴露的端口,of-watchdog监听的EXPOSE 8080# 监控检查HEALTHCHECK --interval=5s CMD [ -e /tmp/.lock ] || exit 1# 容器启动时执行的命令,既启动of-watchdogCMD ["fwatchdog"]
上述脚本的最后设置了好几个环境变量,这些环境变量的定义来自of-watchdog官方Github,地址是: ,内容如下图:为了更清晰的看到脚本中三个任务是如何协同的,将整个Dockerfile的脚本用下图表示,可见最终的镜像来自ship,左侧的builder和watchdog都是为ship提供内容的:java工程分析从Dockerfile中得知微服务的启动命令如下:
java -XX:+UseContainerSupport com.openfaas.entrypoint.App
只要搞清楚上述命令对应的实现,整个java11模板就全部掌握了,接下来就来研究这个com.openfaas.entrypoint.App类;打开文件template/java11/function/build.gradle,看到依赖关系如下图,红框中的库应该就是com.openfaas.entrypoint.App的来源了:上图红框中的库,代码已经开源,地址是:打开App.java文件后,一切谜底都被揭开了,这个java11模板的源码还真是简单呀,先看入口的main方法:
public static void main(String[] args) throws Exception {        // 监听8082端口,和Dockerfile中of-watchdog转发请求的端口保持一致        int port = 8082;				// handler是真正处理请求的实例        HandlerProvider p = HandlerProvider.getInstance();        IHandler handler = p.getHandler();				// 配置监听对象,并将handler绑定过来        HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);        InvokeHandler invokeHandler = new InvokeHandler(handler);		// 设置path,开始监听        server.createContext("/", invokeHandler);        server.setExecutor(null); // creates a default executor        server.start();    }
有没有觉得上述代码和sockek编程很像;App.java中还有静态类InvokeHandler的定义,这个类的主要功能就是接收web请求的数据,加工成IRequest实例,丢给IHandler实例去处理,处理完成后包装http响应,核心代码片段如下:
// 把request内容封装到IRequest实例中IRequest req = new Request(requestBody, reqHeadersMap,t.getRequestURI().getRawQuery(), t.getRequestURI().getPath());// 执行业务逻辑处理请求            IResponse res = this.handler.Handle(req);// 得到处理后的结果String response = res.getBody();...
上述代码可见业务逻辑的执行的关键是this.handler.Handle(req),而真正执行业务的代码是咱们自己写的Handler.java,要搞清楚它们之间的关系,就要看HandlerProvider.java,如下图,一些都清楚了,咱们开发函数时,编写的业务功能都在Handler.java中,而Handler是AbstractHandler的实现类,于是下图红框1中就会找到Handler,红框2可以返回Handler实例,在InvokeHandler执行this.handler.Handle(req)时,就是Handler实例在处理web请求了:至此,java代码的分析就完成了,这个微服务其实很简单,就像咱们做Socket编程练习那样,自己编码监听端口并编写处理逻辑;小结最后做个小结,将前面展开的思路收敛起来,如下图:

看到这里,对于java11模板的内部实现及其执行原理,相信在您眼里应该没有什么秘密了,为了制作更好用的java模板,咱们已经做了充分准备,接下来的文章,请随欣宸一起实战自定义java模板;欢迎关注我的公众号:程序员欣宸

标签: #java程序模板