Technology Sharing

Apache Seata module source code analysis

2024-07-08

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

This article comes from Apache Seata official documentation, welcome to visit the official website to view more in-depth articles.
This article comes fromApache Seata official documentation, welcome to visit the official website to view more in-depth articles.

1. Introduction

according toBig BrotherThere are three types of configurations defined: environment configuration, description configuration, and extension configuration.

Environmental configuration: such as parameters when some components are started, usually discrete simple values, mostly key-value data.

Description configuration: related to business logic, such as transaction initiators and participants, usually embedded in the life cycle management of the business. Description configuration contains a lot of information, and even has a hierarchical relationship.

Extended configuration: The product needs to discover third-party implementations and has high requirements for configuration aggregation, such as various configuration centers and registration centers. The usual practice is to place the interface class full name file under META-INF/services of the jar package, with one implementation class name per line.

2. Environment Configuration

When loading, seata server will use resources/registry.conf to determine the type of configuration center and registration center. After version 1.0, seata client can not only use conf files to load configuration, but also use seata.config.{type} in the springboot yml configuration file to select the configuration center. The registration center is similar. The source code for loading configuration through yml is in the io.seata.spring.boot.autoconfigure.properties.registry package.

If the user of the seata client places both the conf configuration file under resources and the configuration in the yml file, the configuration in the yml file will be used first. Code:

CURRENT_FILE_INSTANCE = null == extConfiguration ? configuration : extConfiguration;

Here, extConfiguration is an external configuration instance, that is, provided by the ExtConfigurationProvider#provide() external configuration provider class, and configuration is provided by another configuration provider class ConfigurationProvider#provide(). These two configuration provider classes are in the static block of the ConfigurationFactory of the config module and are loaded through SPI.

EnhancedServiceLoader.load(ExtConfigurationProvider.class).provide(configuration);

The above is about the selection of configuration center types. To load the configuration environment, you need to determine the type of configuration center to use and then load the environment configuration through the corresponding configuration center. File, or text configuration, is also a type of configuration center.

The client and server obtain configuration parameters by using ConfigurationFactory#getInstance() to obtain the configuration class instance, and then use the configuration class instance to obtain configuration parameters. The definitions of these constants of configuration keys are mainly in the config file under the core module.

The meaning of some important environment configuration properties,The official website has introduction

When the configuration is obtained through ConfigurationFactory during instantiation and injected into the constructor, a restart is required to take effect. When it is used, it is obtained in real time through ConfigurationFactory, and the configuration can take effect as soon as it is changed.

However, the config module provides the ConfigurationChangeListener#onChangeEvent interface method to modify the internal properties of the instance. That is, in this method, the dynamically changing properties are monitored. If it is detected that the properties used by itself are different from those when they were first injected, the properties saved in the instance are modified to be consistent with the configuration center, thus realizing dynamic configuration.

public class GlobalTransactionalInterceptor implements ConfigurationChangeListener {
private volatile boolean disable = ConfigurationFactory.getInstance().getBoolean(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,false);
@Override public Object invoke(Param param) {
   if(disable){//事务业务处理}
}
@Override public void onChangeEvent(Param param) {
   disable = param;
}}

The above is the pseudo code related to the GlobalTransactionalInterceptor and downgrade properties under the spring module. When the GlobalTransactionalScanner interceptor class above is instantiated, the interceptor is registered in the configuration change listener list. When the configuration is changed, the listener will be called:

ConfigurationFactory.getInstance().addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,(ConfigurationChangeListener)interceptor);

Downgrade means that when a certain function of the service is unavailable, the function is disabled through the dynamically configured properties, so as to avoid repeated attempts to handle failures. interceptor#invoke() will only execute seata transaction-related services when the disable property is true.

3. Description Configuration

The descriptive configuration of a general framework usually contains a lot of information, and even has a hierarchical relationship. It is more convenient to use XML configuration because the tree structure is more descriptive. However, the current practice is to promote the use of conventions instead of cumbersome constraint configuration.

The seata AT mode processes transactions by proxying data sources, which has less intrusion on the business side. It only requires seata to identify which business parties need to start global transactions when it starts, so descriptive configuration can be achieved using annotations.

@GlobalTransactional(timeoutMills = 300000, name = "busi-doBiz")
public String doBiz(String msg) {}

If it is tcc mode, transaction participants also need to use annotations:

@TwoPhaseBusinessAction(name = "tccActionForSpringTest" , commitMethod = "commit", rollbackMethod = "rollback")
public boolean prepare(BusinessActionContext actionContext, int i);
public boolean commit(BusinessActionContext actionContext);
public boolean rollback(BusinessActionContext actionContext);

4. Extended Configuration

Extended configuration usually has higher requirements for product aggregation, because the product needs to discover third-party implementations and add them to the product.

insert image description here
This is an example of a custom configuration center class. Place a text file with the same name as the interface under META-INF/services, and the content of the file is the implementation class of the interface. This is the standard spi method. Then modify config.type=test in the configuration file registry.conf.

But if you think that this will be recognized by Seata and replace the configuration center, you are wrong. When Seata loads the configuration center, it uses enum ConfigType to wrap the value of the type of the configuration center configured in the configuration file:

private static Configuration buildConfiguration() {
   configTypeName = "test";//registry.conf中配置的config.type
   configType = ConfigType.getType(configTypeName);//ConfigType获取不到会抛异常
}

If the configuration center type test is not defined in ConfigType, an exception will be thrown. Therefore, simply modifying the configuration file without changing the source code will not allow you to use configuration center classes other than those defined in ConfigType.

Currently, the configuration center types defined in ConfigType in version 1.0 are: File, ZK, Nacos, Apollo, Consul, Etcd3, SpringCloudConfig, Custom. If the user wants to use a custom configuration center type, the Custom type can be used.

insert image description here
Here we can use an inelegant way, that is, to provide an implementation class with a specified name ZK but a higher level order=3 (ZK default order=1), so that ConfigurationFactory can use TestConfigurationProvider as the configuration center provider class.

Through the above steps, we can let Seata use the code we provide. In Seata, the codec, compressor, discovery, integration and other modules all use the SPI mechanism to load functional classes, which is in line with the design concept of micro-kernel plug-in and equal treatment of third parties.

5. Seata source code analysis series address

Author: Zhao Runze,Series Address