SOFABoot源码解析之模块化开发

1.SOFABoot源码解析

1.1  模块化开发

1.1.1 简述

        关于SOFABoot模块化开发的文档来自于Alipay开源社区Wiki,链接地址为:

        https://github.com/alipay/sofa-boot/wiki/Modular-Development

        此处直接引用该文档内容,主要是便于大家理解源码解析部分。

1.1.1.1  模块化开发简述

        SOFABoot从 2.4.0 版本开始支持基于 Spring 上下文隔离的模块化开发能力。为了更好的理解 SOFABoot 模块化开发的概念,我们来区分几个常见的模块化形式:

        1).  基于代码组织上的模块化:这是最常见的形式,在开发期,将不同功能的代码放在不同 Java 工程下,在编译期被打进不同 jar 包,在运行期,所有 Java 类都在一个 classpath 下,没做任何隔离;

        2).  基于 Spring 上下文隔离的模块化:借用 Spring 下文来做不同功能模块的隔离,在开发期和编译期,代码和配置也会分在不同Java 工程中,但在运行期,不同的 Spring Bean 相互不可见,IoC 只在同一个上下文内部发生,但是所有的 Java 类还是在一个 ClassLoader 下;

        3).  基于 ClassLoader 隔离的模块化:借用 ClassLoader 来做隔离,每个模块都有独立的 ClassLoader,模块与模块之间的 classpath 不同,SOFAArk 就是这种模块化的实践方式。

        SOFABoot模块化开发属于第二种模块化形式,基于 Spring 上下文隔离的模块化。每个 SOFABoot 模块使用独立的 Spring 上下文,避免不同 SOFABoot 模块间的 BeanId 冲突,有效降低企业级多模块开发时团队间的沟通成本。


        1.  SOFABoot模块

        SOFABoot框架定义了 SOFABoot 模块的概念,一个 SOFABoot 模块是一个包括 Java 代码、Spring 配置文件、SOFABoot 模块标识等信息的普通 Jar 包,一个 SOFABoot 应用可以包含多个 SOFABoot 模块,每个 SOFABoot 模块都含有独立的 Spring 上下文。

        以 SOFABoot模块为单元的模块化方式为开发者提供了以下功能:

        1)  运行时,每个SOFABoot模块的 Spring 上下文是隔离的,模块间定义的 Bean 不会相互影响。

        2)  每个 SOFABoot 模块是功能完备且自包含的,可以很容易在不同的 SOFABoot 应用中进行模块迁移和复用,只需将 SOFABoot 模块整个拷贝过去,调整 Maven 依赖,即可运行。

        2.  SOFABoot模块间通信

        上下文隔离后,模块与模块间的 Bean 无法直接注入,模块间需要通过 SOFA 服务进行通信,目前SOFABoot 提供了两种形式的服务发布和引用,用于解决不同级别的模块间调用的问题:

        1)  JVM 服务发布和引用:解决一个 SOFABoot 应用内部各个SOFABoot 模块之间的调用问题。

        2)  RPC 服务发布和引用:解决多个 SOFABoot 应用之间的远程调用问题,RPC服务发布与引用。

        3.  模块并行化启动

        每个 SOFABoot 模块都是独立的 Spring 上下文,多个 SOFABoot 模块支持并行化启动,与 Spring Boot 的单 Spring 上下文模式相比,模块并行化启动能够加快应用的启动速度。

        4.  RootApplication Context

        SOFABoot应用运行时,本身会产生一个Spring Context,我们把它叫做 Root Application Context,它是每个 SOFABoot 模块创建的 Spring Context 的 Parent。这样设计的目的是为了保证每个 SOFABoot 模块的 Spring Context 都能发现 Root ApplicationContext 中创建的 Bean,这样当应用新增Starter 时,不仅 Root Application Context 能够使用 Starter 中新增的 Bean,每个 SOFABoot 模块的 Spring Context 也能使用这些 Bean。

1.1.1.2  SOFABoot模块简述

        SOFABoot 模块是一个普通的 Jar 包加上一些 SOFABoot 特有的配置,这些 SOFABoot 特有的配置,让一个 Jar 包能够被 SOFABoot 识别,使之具备模块化的能力。

        一个完整的 SOFABoot 模块和一个普通的 Jar 包有两点区别:

        1) SOFABoot 模块包含一份 sofa-module.properties 文件,这份文件里面定义了 SOFABoot模块的名称以及模块之间的依赖关系。

        2) SOFABoot 模块的 META-INF/spring 目录下,可以放置任意多的 Spring 配置文件,SOFABoot 会自动把它们作为本模块的 Spring 配置加载起来。

        1.  sofa-module.properties 文件详解

        先来看一份完整的 sofa-module.properties 文件:

1.  Module-Name=com.alipay.test.biz.service.impl
2.  Spring-Parent=com.alipay.test.common.dal
3.  Require-Module=com.alipay.test.biz.shared
4.  Module-Profile=dev

        1) Module-Name

        Module-Name 是SOFABoot 模块的名称,也是 SOFABoot 模块的唯一标示符。在一个 SOFABoot 应用中,一个 SOFABoot 模块的 Module-Name 必须和其他的 SOFABoot 模块的 Module-Name 不一样。需要注意的一点是,一个 SOFABoot 应用运行时的 SOFABoot 模块,不仅仅只包含本应用的模块,还包括依赖了其他应用的SOFABoot 模块,确定是否唯一的时候需要把这些 SOFABoot 模块也考虑进去。

        2) Require-Module

        Require-Module 用于定义模块之间的依赖顺序,值是以逗号分隔的 SOFABoot 模块名列表,比如上面的配置中,就表示本模块依赖于com.alipay.test.biz.shared 模块。对于这种依赖关系的处理,SOFABoot 会将 com.alipay.test.biz.shared 模块在本模块之前启动,即com.alipay.test.biz.shared模块将先启动 Spring 上下文。

        一般情况下,是不需要为模块定义 Require-Module 的,只有当模块的 Spring 上下文的启动依赖于另一个模块的 Spring 上下文的启动时,才需要定义 Require-Module。举一个例子,如果你在 A 模块中发布了一个 SOFA JVM Service。在 B 模块的某一个 Bean 的 init 方法里面,需要使用 SOFA Reference 调用这个 JVM Service。假设 B 模块在 A 模块之前启动了,那么B 模块的 Bean 就会因为 A 模块的 JVM Service 没有发布而 init 失败,导致 Spring 上下文启动失败。这个时候,我们就可以使用 Require-Module 来强制 A 模块在 B 模块之前启动。

        3) Spring-Parent

        在 SOFABoot 应用中,每一个 SOFABoot 模块都是一个独立的 Spring 上下文,并且这些 Spring 上下文之间是相互隔离的。虽然这样的模块化方式可以带来诸多好处,但是,在某些场景下还是会有一些不便,这个时候,你可以通过 Spring-Parent 来打通两个 SOFABoot 模块的 Spring 上下文。Spring-Parent 属性可以配置一个模块的名称,比如上面的配置中,就将 com.alipay.test.common.dal 的 Spring 上下文设置为当前模块的 Spring 上下文的父 Spring 上下文。

        由于 Spring 的限制,一个模块的 Spring-Parent 只能有一个模块。

        关于 Spring 的父上下文的作用可以看 Spring 的 BeanFactory 的说明:http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactory.html

        4) Module-Profile

        支持 SOFABoot Profile 能力。

1.1.1.3  模块并发启动

        SOFABoot 会根据Require-Module 计算模块依赖树,例如以下依赖树表示模块B 和模块C 依赖模块A,模块E 依赖模块D,模块F 依赖模块E:

        该依赖树会保证模块A 必定在模块B 和模块C 之前启动,模块D 在模块E 之前启动,模块E 在模块F 之前启动,但是依赖树没有定义模块B 与模块C,模块B、C与模块D、E、F之间的启动顺序,这几个模块之间可以串行启动,也可以并行启动。

        SOFABoot 默认会并行启动模块,在使用过程中,如果希望关闭并行启动,可以在 application.properties 中增加以下参数:

1.  com.alipay.sofa.boot.module-start-up-parallel=false

 1.1.1.4  SOFABoot Profile

        Spring 框架从3.1.X 版本开始提供了 profile 功能: BeanDefinition Profiles,SOFABoot 支持模块级 profile 能力,即在各个模块启动的时候决定模块是否能够启动。

        1.   使用Module-Profile激活module

        使用 SOFABoot 的profile 功能,需要在 application.properties 文件增加 com.alipay.sofa.boot.active-profiles 字段,该字段的值为逗号分隔的字符串,表示允许激活的 profile 列表,指定该字段后,SOFABoot 会为每个可以激活的模块指定此字段表示的 profile 列表。

        SOFABoot 模块的sofa-module.properties 文件支持 Module-Profile 字段,该字段的值为逗号分隔的字符串,表示当前模块允许在哪些 profile 激活。Module-Profile 支持取反操作, !dev 表示com.alipay.sofa.boot.active-profiles 不包含 dev 时被激活。

        当应用未指定com.alipay.sofa.boot.active-profiles 参数时,表示应用所有模块均可启动。SOFABoot模块未指定 Module-Profile 时,表示当前SOFABoot 模块可以在任何 profile 启动。

        2.   使用例子

        1) 激活 dev SOFABoot 模块

        application.properties 中增加配置如下:

1.  com.alipay.sofa.boot.active-profiles=dev

        该配置表示激活 profile 为 dev 的模块。

        在每个需要限定为 dev profile 被激活模块的 sofa-module.properties 文件中增加如下配置:

1.  Module-Profile=dev

        2) 配置多个激活 profile

        application.properties 中增加配置如下:

1.  com.alipay.sofa.boot.active-profiles=dev,test

        该配置表示激活 profile 为 dev 或者 test 的模块。

        在 SOFABoot 模块的 sofa-module.properties 文件中增加如下配置:

1.  Module-Profile=test,product

        该配置表示当 com.alipay.sofa.boot.active-profiles包含 test 或者 product 时激活模块,由于当前指定的 com.alipay.sofa.boot.active-profiles 为dev,test ,此模块将被激活。

        3) Module-Profile 取反

        application.properties 中增加配置如下:

1.  com.alipay.sofa.boot.active-profiles=dev

        该配置表示激活 profile 为 dev 的模块。

        在 SOFABoot 模块的 sofa-module.properties 文件中增加如下配置:

1.  Module-Profile=!product

        该配置表示当com.alipay.sofa.boot.active-profiles 不包含 product 时激活模块,由于当前指定的 com.alipay.sofa.boot.active-profiles 为 dev ,此模块将被激活。

        4) 设置激活模块 Spring 上下文的 spring.profiles.active 属性

        application.properties 中增加配置如下:

1.  com.alipay.sofa.boot.active-profiles=dev,test

        该配置表示激活 profile 为 dev 或者 test 的模块,当一个模块满足上面的激活条件时,这个模块就会被启动,同时 Spring 上下文的环境信息 spring.profiles.active 也被设置为了 dev,test ,这样如下的配置 beanId 为 devBeanId 和 testBeanId 的bean都会被激活。

1.  <?xml version="1.0"encoding="UTF-8"?>
2.  <beansxmlns="http://www.springframework.org/schema/beans"
3.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4.         xmlns:jdbc="http://www.springframework.org/schema/jdbc"
5.         xmlns:jee="http://www.springframework.org/schema/jee"
6.         xsi:schemaLocation="http://www.springframework.org/schema/beans
7.                                                  http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
8.                                                  http://www.springframework.org/schema/context
9.                                                  http://www.springframework.org/schema/context/spring-context.xsd"
10.        default-autowire="byName">      
11.  
12.     <beans profile="dev">
13.         <bean id="devBeanId"class="com.alipay.cloudenginetest.sofaprofilesenv.DemoBean">
14.             <propertyname="name">
15.                 <value>demoBeanDev</value>
16.             </property>
17.         </bean>
18.     </beans>
19.  
20.     <beans profile="test">
21.         <bean id="testBeanId"class="com.alipay.cloudenginetest.sofaprofilesenv.DemoBean">
22.             <propertyname="name">
23.                 <value>demoBeanTest</value>
24.             </property>
25.         </bean>
26.     </beans>
27. </beans>

1.1.2 源码解析

        以SOFABoot自带的模块化案例sofaboot-sample-with-isle为例,详细描述SOFABoot模块化启动原理。

        在此提前说明,源码分析主要分析主流程,以及本人认为比较重要的一些内容,对于其它部分,大家可以基于本文档,自行研读。

        sofaboot-sample-with-isle项目主要包括:

        1.  sofa-boot-run:主模块;

        2.  service-facade:服务接口模块

        3.  service-provider:服务提供者模块;

        4.  service-consumer:服务消费者模块;

        由于项目基于SpringBoot框架开发,所以运行主模块sofa-boot-run中ApplicationRun类main方法,通过SpringApplication.run方法启动应用。

1. 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

任性之闲来无事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值