<2021SC@SDUSC>博客(5)山东大学软件工程应用与实践Jpress代码分析(4)

2021SC@SDUSC

Jboot介绍

Jboot是一个基于JFinal和Undertow开发的微服务框架。提供了AOP、RPC、分布式缓存、限流、降级、熔断、统一配置中心、swagger
api自动生成、Opentracing数据追踪、metric数据监控、分布式session、代码生成器、shiro安全控制等功能。

这是Jpress的作者杨福海给出的对Jboot的定义,Jboot是基于Jfinal和undertow开发的微服务框架,在上一章博客中已经介绍过了JFinal,这一篇博客主要是来介绍Jboot

什么是undertow?

Undertow是一个用java编写的、灵活的、高性能的Web服务器,提供基于NIO的阻塞和非阻塞API。Undertow的架构是组合式的,可以通过组合各种小型的目的单一的处理程序来构建Web服务器。所以可以很灵活地的选择完整的JavaEE servlet 3.1容器或初级非阻塞程序处理。Undertow的设计是可以完全可嵌入的,具有简单易用的编译接口。Undertow的生命周期完全由嵌入的应用程序控制。Undertow是JBoss赞助的一个Web服务器,是Wildfly应用程序服务器中的默认Web服务器。

Untertow 的特点:

  • 轻量级:它是一个 Web 服务器,但不像传统的 Web 服务器有容器概念,它由两个核心 Jar 包组成,加载一个 Web 应用可以小于 10MB 内存
  • Servlet3.1 支持:它提供了对 Servlet3.1 的支持
  • WebSocket 支持:对 Web Socket 完全支持,用以满足 Web 应用巨大数量的客户端
  • 嵌套性:它不需要容器,只需通过 API 即可快速搭建 Web 服务器

默认情况下 Spring Cloud 使用 Tomcat 作为内嵌 Servlet 容器,可启动一个 Tomcat 的 Spring Boot 程序与一个 Undertow 的 Spring Boot 程序,通过 VisualVM 工具进行比较,可看到 Undertow 性能优于 Tomcat

Undertow 是为嵌入式而生的 Web 容器,又是 Spring Boot 默认集成的容器之一,下面栈长带大家来看下如何在 Spring Boot 中使用 Undertow。因为在 spring-boot-starter-web 启动器中,Tomcat 是 Spring Boot 默认的嵌入式容器,即:spring-boot-starter-tomcat
Spring Boot 还提供了其他两个启动器以方便进行代替:

spring-boot-starter-jetty
spring-boot-starter-undertow

下面来简单实战下,如何在 Spring Boot 中使用 Undertow。

排除 Tomcat 依赖,然后加入 Undertow 依赖:

<dependencies>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <!-- Exclude the Tomcat dependency -->
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- Use Undertow instead -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-undertow</artifactId>
    </dependency>

</dependencies>

什么是RPC?

RPC(Remote Procedure Call)远程过程调用协议,一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。RPC它假定某些协议的存在,例如TPC/UDP等,为通信程序之间携带信息数据。在OSI网络七层模型中,RPC跨越了传输层和应用层,RPC使得开发,包括网络分布式多程序在内的应用程序更加容易。

过程是什么? 过程就是业务处理、计算任务,更直白的说,就是程序,就是想调用本地方法一样调用远程的过程
RPC采用客户端/服务端的模式,通过request-response消息模式实现
在这里插入图片描述
RPC的三个过程

1:通讯协议 比如:你需要找人在国外干活,那么你可以直接飞过去或者打电话或者通过互联网的形式,去找人,这个找人的过程就是通讯协议
2:寻址 既然要找人干活,肯定要知道地址在哪,飞过去需要找到详细地址,打电话需要知道电话号码,互联网需要知道IP是多少

3:数据序列化 就是说,语言需要互通,才能够让别人干活,之间需要一个大家都懂的语言去交流

RMI远程方法调用是RPC的一种具体实现,webservice、restfull都是RPC,只是消息的组织形式、消息协议不同

和MQ做对比: MQ有一个中间节点queue,可以存储消息 RPC的特性: 同步调用,对于需要等待返回结果的场景,可以使用RPC 消息MQ的特性: 异步单向的消息,不需要等待消息处理完成 如果需要同步得到结果的场景,RPC比较适合,如果希望使用简单,RPC也适合,RPC操作基于接口,操作简单,使用的方式模拟本地方法的调用,异步的方式编程比较复杂

在这里插入图片描述
RPC有哪几步?

在这里插入图片描述

1:客户端处理过程中调用client sub,就像调用本地方法一样,传入参数
2:client sub将参数编组为消息,然后通过系统调用向服务端发送消息
3:客户端本地的操作系统将消息从客户端发送到服务端
4:服务端将接收到的数据包传递给server sub
5:server sub将接收到的数据解组为参数
6:server sub再调用服务端的过程,过程执行的结果以反方向的相同步骤响应给客户端

sub(存根) :分布式计算中的存根是一段代码,它转换在远程过程调用(RPC)期间client和server之间传递的参数

需要处理的问题:
1:client sub、server sub的开发
2:参数的编组和解组
3:消息如何发送
4:过程结果如何表示、异常情况如何处理
5:如何实现安全的访问控制

RPC调用过程中需要将消息进行编组然后发送,接收方需要解组消息为参数,过程处理结果也需要经过编组、解组;消息由哪些部分构成以及消息的表示形式就构成了消息协议。 RPC协议规定请求消息、响应消息的格式,在TCP之上我们可以选用或者自定义消息协议来实现RPC的交互

封装好了参数编组、消息解组、底层网络通信的RPC程序开发框架,可以直接在此基础上编写,只关注过程代码 java领域中常用的RPC框架有: 传统的webservice框架:apache CXF、apache Axis2 新兴的微服务框架:Dubbo、springcloud、apache Thrift、ICE、GRPC等

如何进行通信?

在这里插入图片描述

Jboot开发手册

在Jboot中配置JFinalConfig

凡是开发过 JFinal 的同学,都知道 JFinalConfig 是 JFinal 的核心配置,详情:JFianlConfig,其内容如下:

    public class DemoConfig extends JFinalConfig {
        public void configConstant(Constants me) {}
        public void configRoute(Routes me) {}
        public void configEngine(Engine me) {}
        public void configPlugin(Plugins me) {}
        public void configInterceptor(Interceptors me) {}
        public void configHandler(Handlers me) {}
    }

默认情况下,我们不需要对 JFinal 进行任何的配置,因为 Jboot 已经对 JFinal 进行了默认的配置,同时,Controller 等的配置完全是通过注解 @RequestMapping 来配置了,数据库也只是在 jboot.properties 里添加就可以。

但是可能在某些特殊情况下,我们对 JFinal 进行自己特殊的配置,如何来做呢?

第一步:编写一个类继承 JbootAppListenerBase
第二步:复写对应的方法

JbootAppListenerBase 提供的方法如下:

    public class JbootAppListenerBase implements JbootAppListener {
        @Override
        public void onInit() { 
            //会在以下所有方法之前进行优先调用
        }
        @Override
        public void onConstantConfig(Constants constants) { 
            //对应 JFinalConfig 的 configConstant
        }
        @Override
        public void onRouteConfig(Routes routes) {
            //对应 JFinalConfig 的 configRoute
        }
        @Override
        public void onEngineConfig(Engine engine) {
            //对应 JFinalConfig 的 configEngine
        }
        @Override
        public void onPluginConfig(JfinalPlugins plugins) {
            //对应 JFinalConfig 的 configPlugin
        }
        @Override
        public void onInterceptorConfig(Interceptors interceptors) {
            //对应 JFinalConfig 的 configInterceptor
        }
        @Override
        public void onFixedInterceptorConfig(FixedInterceptors fixedInterceptors) {
            //FixedInterceptor 类似 Interceptor,
            // 但是 FixedInterceptor 不会被注解 @Clear 清除
        }
        @Override
        public void onHandlerConfig(JfinalHandlers handlers) {
            //对应 JFinalConfig 的 configHandler
        }
        @Override
        public void onStartBefore() {
            // 此方法会在 onStart() 之前调用
        }
        @Override
        public void onStart() {
            //对应 JFinalConfig 的 onStart()
        }
        @Override
        public void onStop() {
            //对应 JFinalConfig 的 onStop()
        }
    }

编写的继承 JbootAppListenerBase 的类名可以是任意名称,Jboot 的 ClassScanner 会自动扫描到并在 App 启动的时候自动执行,同时 ,一个应用在可以存在多个继承至 JbootAppListenerBase 的类,这样更加方便团队配合和模块化开发,每个团队(或模块)都可以有自己的配置类,不会造成代码冲突。

RPC远程调用

添加依赖

Jboot 支持 dubbo 和 motan,假设我们需要使用 dubbo 作为底层的 RPC 框架,需要添加如下依赖:

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo</artifactId>
        <version>${dubbo.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.alibaba.spring</groupId>
                <artifactId>spring-context-support</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-dependencies-zookeeper</artifactId>
        <version>${dubbo.version}</version>
        <type>pom</type>
    </dependency>

配置

在 Jboot 中,默认实现了对 Dubbo、motan 的 RPC 调用支持。在使用 RPC 远程调用之前,需要做一些基本的配置。

    jboot.rpc.type = dubbo
    jboot.rpc.urls = com.yourdomain.AAAService:127.0.0.1:8080,com.yourdomain.XXXService:127.0.0.1:8080
    jboot.rpc.providers = com.yourdomain.AAAService:providerName,com.yourdomain.XXXService:providerName
    jboot.rpc.consumers = com.yourdomain.AAAService:consumerName,com.yourdomain.XXXService:consumerName
    jboot.rpc.defaultVersion = 1.0.0
    jboot.rpc.versions = com.yourdomain.AAAService:1.0.0,com.yourdomain.XXXService:1.0.1
    jboot.rpc.defaultGroup = 
    jboot.rpc.groups = com.yourdomain.AAAService:group1,com.yourdomain.XXXService:group2
    jboot.rpc.autoExportEnable = true
jboot.rpc.type : RPC 的类型,目前只支持 dubbo 和 motan
jboot.rpc.urls : 一般不用配置,只有直连模式下才会去配置,此处是配置 Service接口和URL地址的映射关系。
jboot.rpc.providers : 配置 Service 和 Provider 的映射关系( Motan下配置的是 Service 和 BasicService 的映射关系)。
jboot.rpc.consumers : 配置 Reference 和 consumer 的映射关系( Motan下配置的是 Referer 和 BaseReferer 的映射关系)。
jboot.rpc.defaultVersion : 当service不配置版本时,默认的版本号,默认值为 1.0.0
jboot.rpc.versions : 每个服务对应的版本号
jboot.rpc.defaultGroup : 当服务不配置 group 时,默认的 gourp
jboot.rpc.groups : 每个服务对应的 group
jboot.rpc.autoExportEnable : 当 Jboot 启动的时候,是否自动暴露 @RPCBean 注解的接口。

开始使用

一般情况下,RPC 调用需要以下几个步骤:

1、定义接口
2、编写实现类
3、启动 Server(Provider) 暴露服务
4、启动客户端、通过 RPC 调用 Server 提供的服务

定义接口

    public interface BlogService {
        public String findById();
        public List<String> findAll();
    }

编写实现类

    @RPCBean
    public class BlogServiceProvider implements BlogService {
        @Override
        public String findById() {
            return "id from provider";
        }
        @Override
        public List<String> findAll() {
            return Lists.newArrayList("item1","item2");
        }
    }

启动 Server 暴露服务

    public class DubboServer {
        public static void main(String[] args)  {
            JbootApplication.setBootArg("undertow.port", "9998");
            JbootApplication.setBootArg("jboot.rpc.type", "dubbo");
            // 开启 @RPCBean 自动暴露功能,默认情况下是开启的,无需配置,
            // 但是此测试代码的 jboot.properties 文件关闭了,这里需要开启下
            JbootApplication.setBootArg("jboot.rpc.autoExportEnable", true);
            //dubbo 的通信协议配置
            JbootApplication.setBootArg("jboot.rpc.dubbo.protocol.name", "dubbo");
            JbootApplication.setBootArg("jboot.rpc.dubbo.protocol.port", "28080");
            // dubbo 注册中心的配置,
            // 当不配置注册中心的时候,默认此服务只提供了直联模式的请求
            // JbootApplication.setBootArg("jboot.rpc.dubbo.registry.protocol", "zookeeper");
            // JbootApplication.setBootArg("jboot.rpc.dubbo.registry.address", "127.0.0.1:2181");
            JbootApplication.run(args);
            System.out.println("DubboServer started...");
        }
    }

备注:以上的 JbootApplication.setBootArg() 里设置的内容,都可以配置到 jboot.properties 里。例如: JbootApplication.setBootArg(“jboot.rpc.autoExportEnable”, true); 在 jboot.properties 里对应的配置是 jboot.rpc.autoExportEnable = true 。

启动客户端、通过 RPC 调用 Server 提供的服务

    @RequestMapping("/dubbo")
    public class DubboClient extends JbootController{
        public static void main(String[] args)  {
           //Undertow端口号配置
           JbootApplication.setBootArg("undertow.port", "9999");
           //RPC配置
           JbootApplication.setBootArg("jboot.rpc.type", "dubbo");
           //设置直连模式,方便调试,默认为注册中心
           JbootApplication.setBootArg("jboot.rpc.urls", "io.jboot.test.rpc.commons.BlogService:127.0.0.1:28080");
            JbootApplication.run(args);
        }
        @RPCInject
        private  BlogService blogService;
        public void index() {
            System.out.println(blogService);
            renderText("blogId : " + blogService.findById());
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值