preface

SOFABoot is ant Group’s open source Spring Boot-based research and development framework that provides capabilities such as Readiness Check, class isolation, and log space isolation for rapid and agile development of Spring applications, especially for building microservice systems.

Spring Boot, based on Conditional Configuration of Spring and starter dependency mechanism, provides quick and convenient experience of developing Spring projects, which has achieved great success.

SOFABoot builds on these two capabilities by extending Spring Boot to a finance-level application development framework. Born out of ant Group’s internal Spring Boot practices, SOFABoot complements Spring Boot’s shortcomings in large-scale financial production scenarios, such as Readiness checks, class isolation, and log space isolation. In addition to enhancing Spring Boot, SOFABoot also provides the ability to easily use SOFAStack middleware in Spring Boot.

SOFABoot: github.com/sofastack/s…

Overview of function points

SOFABoot is fully compatible with Spring Boot, and the Spring Boot technology stack can be quickly switched to SOFABoot technology stack: modify the node that the project POM depends on.

Such as:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>${spring.boot.version}</version>
    <relativePath />
</parent>
Copy the code

Replace with:

<parent>
    <groupId>com.alipay.sofa</groupId>
    <artifactId>sofaboot-dependencies</artifactId>
    <version>${sofa.boot.version}</version>
    <relativePath />
</parent>
Copy the code

The latest version of SOFABoot is v3.11.1.

Application Readiness

Once an application is started, is it “ready” to handle external requests?

Can components that serve as application traffic inlets receive external connections?

Therefore, it is necessary to introduce application Readiness. SOFABoot provides application Readiness capability in addition to Spring Boot health check to ensure normal startup and safe online of application components.

SOFABoot checks the readiness of each component through HealthChecker.

After the Spring context refresh is complete (all Spring beans have been instantiated), SOFABoot retrieves all HealthChecker implementation classes in the IoC container and checks the component health they return.

The module HealthChecker also checks the health of each module after the application has turned on modular isolation. Spring’s native HealthIndicator, as part of Readiness, will also be included in the results of Readiness. If the HealthIndicator fails, application Readiness will also fail.

The Readiness check includes post-check of components. Traffic entry components (such as RPC and REST) can accept external traffic requests after the post-check passes. Applications are ready.

The differences between Application Readiness and Liveliness are:

  • Readiness refers to whether an application is “ready” after startup. Readiness remains the same after startup

  • The results of all requests for Readiness between deployments are consistent

Application modularization

There are a variety of applications for modularity. The traditional scheme is based on the application function as the boundary to do module division; During development, classes with different responsibilities are placed under different modules, but during runtime they are all under the same classpath without any isolation.

Instead of the traditional module partitioning scheme, people found that they could use Java’s ClassLoader mechanism to completely isolate modules from their classes.

When a module needs to communicate with another module, it can do so through class imports and exports. Both OSGi and SOFAArk are modular practices based on ClassLoader isolation.

The traditional modular scheme does not have any isolation means, the boundary between modules can not be guaranteed, easy to appear tight coupling between modules. However, the modularization scheme based on ClassLoader is too thorough. Researchers must be very clear about the import and export of classes and the loading system of Java classes, and the burden of module division is transferred to ordinary researchers.

SOFABoot combines the advantages and disadvantages of these two solutions to introduce a modular solution in between:

Each module has an independent Spring context. Through context isolation, Bean references between different modules cannot be directly carried out, thus achieving module isolation at run time.

This ensures not to introduce too much complexity and avoids module boundary assurance without any isolation measures.

As shown below:

All SOFABoot modules have the same Spring Context Parent, called Root Application Context.

For beans that all modules need to import, you can choose to place them in the Root Application Context and share them across all modules. In addition, the SOFABoot framework provides inter-module communication capabilities behind two Spring context isolation schemes:

  • Publishing and referencing JVM services: communication between different modules within the same application
// Publish a JVM service
@Component
@SofaService
public class MyServiceImpl implements MyService {
    // implementation goes here
}
// Reference a JVM service
public class AnyClass {
    @SofaReference
    private MyService myService;
}
Copy the code
  • Publishing and referencing RPC services: Communication between different applications

// Publish a RPC service
@Component
@SofaService(interfaceType = MyService.class, bindings = { @SofaServiceBinding(bindingType = "bolt") })
public class MyServiceImpl implements MyService {
    // implementation goes here
}
// Reference a RPC service
public class AnyClass {
    @SofaReference(binding = @SofaReferenceBinding(bindingType = "bolt"))
    private MyService myService;
}
Copy the code

In addition to annotations, SOFABoot also supports configuration of XML files and programming apis.

In addition to module to module communication capabilities, SOFABoot provides:

  • Module-profile: specifies whether a Module is enabled or not
  • Extension point: Provides extension point entry for beans using the Nuxeo Runtime
  • Require-module: declares dependencies between modules

Apply parallelization startup

Module parallelization started

Dependencies between SOFABoot modules can be specified by Require-Module, and SOFABoot calculates dependencies between modules to form a directed acyclic graph (DAG).

SOFABoot starts dependent modules in topology order and free modules in parallel.

For example, there are intermodule dependencies as follows:

As can be seen from the figure, module A must be started before modules B and C, module D must be started before module E, and modules A and D can be started in parallel (free modules at the start point). Parallel startup of SOFABoot applications can significantly speed up application startup times compared to applications where all modules share a Spring context.

Spring beans are initialized asynchronously

In actual Spring/Spring Boot development, Spring beans often need to perform preparation operations during initialization, such as pulling remote configurations, initializing data sources, and so on.

Also, these preparations take up a significant amount of time during Bean initialization, significantly slowing down the Spring context refresh rate. However, the preparation of Bean initialization and the post-processing of beans are often not enforced sequentially and can be done in parallel.

SOFABoot captures this feature by providing configurable options to asynchronize the execution of init-method methods on beans, thus speeding up the Spring context refresh process.

As you can see in the figure, Spring executes the custom init-method method asynchronously and immediately postprocesses the BeanPostProcessor, essentially “skipping” the most time-consuming init-method part.

Spring Bean asynchronous initialization configuration method:

<! -- By setting async-init totrue, enable asynchronous initialization of corresponding bean --> <bean id="testBean" class="com.alipay.sofa.beans.TimeWasteBean" init-method="init" async-init="true"/>
Copy the code

Middleware integration Management

SOFABoot manages middleware dependencies through the starter mechanism.

The use of a middleware does not need to introduce a long list of JAR dependencies, but only needs a starter dependency, treating the middleware as an independently pluggable “plug-in”; The starter dependency is responsible for passing the JAR package dependencies required by the middleware.

Middleware starter versions are associated with SOFABoot versions and ensure that the delivery dependencies of these middleware starter versions are rigorously tested for compatibility with each other. However, SOFABoot’s dependency management is still weak, and if users want to specify the version of a JAR package, they can override the version configured in starter.

SOFABoot supports dependency configuration for Maven and Gradle.

logs

SOFABoot integrates isolation capabilities for log space through SOFA-common-Tools.

The framework automatically discovers the logging implementation in the application, avoiding the binding of middleware and application logging implementation.

Binary package or introduced middleware logging oriented programming interface SLF4J to program, specific logging implementation to SOFABoot application developers to choose; At the same time, binary packages or middleware provide configuration for each logging implementation to output logs to a file in a relatively fixed directory.

Application of the selected logging implementation, the framework can automatically sense and select the corresponding configuration file log output.

Application Class Isolation

SOFABoot provides class isolation capabilities and application consolidation deployment capabilities through SOFAArk.

SOFAArk uses an isolated class loading model. Low-level plug-ins and service applications are isolated from each other during runtime. Single plug-ins and applications are loaded by different Classloaders, which effectively avoids package conflicts and improves the function reuse capability of plug-ins and modules.

Supports the combined deployment of multiple applications. Multiple applications are packaged into executable Fat Jars in the development stage, and applications are dynamically installed and uninstalled using APIS or configuration centers during runtime.