跳转到内容

关于

Feat Cloud 提供了一种面向企业级应用开发的解决方案,它的定位有点像 SpringBoot。

设计方面,Feat Cloud 尽最大可能保留了 SpringBoot 的使用习惯,以此降低开发者的学习成本。

技术方面,Feat Cloud 在编译期对代码进行静态分析,最大化提升服务运行性能,降低资源消耗。

准备工作

引入 Maven 依赖

创建一个 Maven 项目,在 pom.xml 文件中添加以下依赖:

pom.xml
<dependency>
<groupId>tech.smartboot.feat</groupId>
<artifactId>feat-cloud-starter</artifactId>
<version>${feat.version}</version>
</dependency>

配置 IDEA

调整 IDEA 编译配置,以启用 Feat Cloud 的静态优化功能,否则请求将无法正常路由

设置路径为:Preferences -> Build, Execution, Deployment -> Build Tools -> Maven -> Runner, 勾选Delegate IDE build/run actions to Maven 并点击 OK 保存配置。

hello world

快速启动

在 Maven 工程中创建一个 FeatCloudDemo.java 文件,添加以下代码:

FeatCloudDemo.java
@Controller
public class FeatCloudDemo {
@RequestMapping("/cloud")
public String helloWorld() {
return "hello Feat Cloud";
}
public static void main(String[] args) {
Feat.cloudServer().listen();
}
}

启动程序,打开浏览器访问 http://localhost:8080/cloud

hello world

工作原理

从上面的代码可以看出,Feat Cloud 是基于注解的方式进行服务开发的。 通常来说,框架会在运行时解析注解并生成对应的服务。

但是,Feat Cloud 却是在编译时对代码进行静态分析,生成对应的服务。 其核心原理是运用了 APT(Annotation Processing Tool)技术,并结合 ServiceLoader 实现了 0 反射的服务加载机制

静态转码

以 FeatCloudDemo 为例,开发人员编写的源代码在编译时经过一次静态转码,生成了一个新的 java 文件 FeatCloudDemoBeanAptLoader.java

FeatCloudDemo.java
@Controller
public class FeatCloudDemo {
@RequestMapping("/cloud")
public String helloWorld() {
return "hello Feat Cloud";
}
public static void main(String[] args) {
Feat.cloudServer().listen();
}
}

可以从静态转码后的代码中看出,对于 bean 的实例化,是通过 new 关键字进行的,而不是通过反射。

对于路由的配置,也是通过调用 Feat Server 中的 Router 方法进行的,也不是通过反射。

因此,Feat Cloud 可以在提供优雅的开发体验的同时,也极大地保留了 Feat Server 框架的性能优势。

服务载入

Controller 在编译时完成转码后,下一步便是需要在程序启动后能够被正确加载,此处需要用到的技术便是 java.util.ServiceLoader

Controller 静态转码所生成的类文件默认实现了 tech.smartboot.feat.cloud.service.CloudService 接口,同时会自动生成一个 service 文件:

META-INF/services/tech.smartboot.feat.cloud.service.CloudService

当调用 ApplicationContext@start 方法时:

  1. 首先通过 ServiceLoader.load(CloudService.class) 加载所有实现了 CloudService 接口的类。并根据 isIgnore 规则过滤出有效的服务。
  2. 遍历所有服务,调用其 loadBean 方法,完成 bean 的实例化。
  3. 遍历所有服务,调用其 autowired 方法,完成各实例的依赖注入。
  4. 遍历所有服务,调用其 postConstruct 方法,完成各实例的初始化。
  5. 遍历所有服务,调用其 router 方法,完成 Controller 路由的配置。
ApplicationContext.java
public class ApplicationContext {
...
public void start() throws Throwable {
for (CloudService service : ServiceLoader.load(CloudService.class)) {
if (isIgnore(service)) {
continue;
}
services.add(service);
}
for (CloudService service : services) {
service.loadBean(this);
}
for (CloudService service : services) {
service.autowired(this);
}
for (CloudService service : services) {
service.postConstruct(this);
}
for (CloudService service : services) {
service.router(router);
}
}
...
}

启动服务

在这个步骤中,由于 ApplicationContext@start 中已经完成了所有服务的实例化、依赖注入、初始化、路由配置等工作,因此,最后一步便是将 Router 实例设置到 HttpServer 中,启动服务。

Feat.java
public static HttpServer cloudServer(Consumer<CloudOptions> options) {
CloudOptions opt = new CloudOptions();
options.accept(opt);
opt.serverName("feat-cloud");
ApplicationContext application = new ApplicationContext(opt);
opt.getExternalBeans().forEach(application::addBean);
application.start();
HttpServer server = Feat.httpServer(opt);
...
server.httpHandler(application.getRouter());
return server;
}