seata1.1.0+springcloud自定義配置,從springboot配置文件讀取

1. 版本:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-seata</artifactId>
    <version>2.2.0.RELEASE</version>
    <exclusions>
        <exclusion>
            <groupId>io.seata</groupId>
            <artifactId>seata-all</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-all</artifactId>
    <version>1.1.0</version>
</dependency>
<spring-boot.version>2.2.5.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>

2.自定義seata-starter

文件結構如下:

3.上源碼:

CqlivingSeataConfiguration.java

package org.cqliving.framework.cloud.seata;

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ObjectUtils;
import io.seata.config.AbstractConfiguration;
import io.seata.config.ConfigurationChangeListener;
import io.seata.spring.boot.autoconfigure.util.SpringUtils;

/********************************************************/
/*
FileName            :    CqlivingSeataConfiguration.java                            
Project Name        :	 cqliving-framework-cloud-seata                  
Author              :	 LIUZONGYANG                      
Mail                :    [email protected]                
Date                :    2020年4月12日 下午12:04:01                  
Version             :    1.0                              
Modification History:                                     
Date              Author        Version        Description
----------------------------------------------------------
2020年4月12日    LIUZONGYANG     1.0            新建
Brief Description: CqlivingSeataConfiguration        						  
caution: something to be cautioned*/
/********************************************************/

public class CqlivingSeataConfiguration extends AbstractConfiguration{
    
    private static final Logger logger = LoggerFactory.getLogger(CqlivingSeataConfiguration.class);

    private static final String CONFIG_TYPE = "CqlivingSeataConfig";
    private static final String PREFIX = "seata.";
    
    private static volatile CqlivingSeataConfiguration instance;
    
    private static final ConcurrentMap<String, Set<ConfigurationChangeListener>> LISTENER_SERVICE_MAP = new ConcurrentHashMap<>();
    
    public static CqlivingSeataConfiguration getInstance() {
        if (null == instance) {
            synchronized (CqlivingSeataConfiguration.class) {
                if (null == instance) {
                    instance = new CqlivingSeataConfiguration();
                }
            }
        }
        return instance;
    }

    private CqlivingSeataConfiguration() {}

    private static final char LINE = '-';
    
    @Override
    public String getConfig(String dataId, String defaultValue, long timeoutMills) {
        
        dataId = dataId.startsWith(PREFIX)?dataId: PREFIX.concat(formatCamel(dataId, LINE));
        String value;
        // 從系統變量獲取
        if ((value = getConfigFromSysPro(dataId)) != null) {
            return value;
        }
        
        // 從配置文件獲取
        ApplicationContext applicationContext = SpringUtils.getApplicationContext();
        if (null == applicationContext) {
            return defaultValue;
        }
        value = applicationContext.getEnvironment().getProperty(dataId);
        
        if(null == value) {
            logger.error("properties null [{}] ", dataId);
            return defaultValue;
        }
        
        return value;
    }
    
    private String formatCamel(String param, char sign) {
        if (ObjectUtils.isEmpty(param)) {
            return StringUtils.EMPTY;
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append(sign);
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
    
    @Override
    public boolean putConfig(String dataId, String content, long timeoutMills) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean putConfigIfAbsent(String dataId, String content, long timeoutMills) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeConfig(String dataId, long timeoutMills) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void addConfigListener(String dataId, ConfigurationChangeListener listener) {
        if (null == dataId || null == listener) {
            return;
        }
        LISTENER_SERVICE_MAP.putIfAbsent(dataId, ConcurrentHashMap.newKeySet());
        LISTENER_SERVICE_MAP.get(dataId).add(listener);
    }

    @Override
    public void removeConfigListener(String dataId, ConfigurationChangeListener listener) {
        if (!LISTENER_SERVICE_MAP.containsKey(dataId) || listener == null) {
            return;
        }
        LISTENER_SERVICE_MAP.get(dataId).remove(listener);
    }

    @Override
    public Set<ConfigurationChangeListener> getConfigListeners(String dataId) {
        return LISTENER_SERVICE_MAP.get(dataId);
    }

    @Override
    public String getTypeName() {
        return CONFIG_TYPE;
    }

}

 
 

CqlivingSeataConfigurationProvider.java

package org.cqliving.framework.cloud.seata;

import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.context.ApplicationContext;
import io.seata.common.loader.LoadLevel;
import io.seata.config.Configuration;
import io.seata.config.ConfigurationProvider;
import io.seata.config.ExtConfigurationProvider;
import io.seata.spring.boot.autoconfigure.util.SpringUtils;

/********************************************************/
/*
FileName            :    CqlivingSeataConfiguration.java                            
Project Name        :	 cqliving-framework-cloud-seata                  
Author              :	 LIUZONGYANG                      
Mail                :    [email protected]                
Date                :    2020年4月12日 下午12:04:01                  
Version             :    1.0                              
Modification History:                                     
Date              Author        Version        Description
----------------------------------------------------------
2020年4月12日    LIUZONGYANG     1.0            新建
Brief Description: CqlivingSeataConfiguration        						  
caution: something to be cautioned*/
/********************************************************/
@LoadLevel(name = "CqlivingSeataConfig", order = 1)
public class CqlivingSeataConfigurationProvider implements ExtConfigurationProvider, ConfigurationProvider {
    
    private static final String GET ="get";
    private static final String PREFIX ="seata.";
    
    @Override
    public Configuration provide(Configuration originalConfiguration) {
        ApplicationContext applicationContext = SpringUtils.getApplicationContext();
        
        return (Configuration)Enhancer.create(originalConfiguration.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
                throws Throwable {
                
                if (method.getName().startsWith(GET) && args.length > 0) {
                    Object result = null;
                    String rawDataId = (String)args[0];
                    if (args.length == 1) {
                        result = applicationContext.getEnvironment().getProperty(PREFIX.concat(rawDataId));
                    }
                    if (null != result) {
                        return result;
                    }
                }

                return method.invoke(originalConfiguration, args);
            }
        });
    }

    @Override
    public Configuration provide() {
        return CqlivingSeataConfiguration.getInstance();
    }
}

 
 

CustomProperties.java

@Component
@ConfigurationProperties(prefix = CustomProperties.PREFIX)
@Data
public class CustomProperties {
    
    public static final String PREFIX = "seata.config.custom";
    
    private String name = "CqlivingSeataConfig";
    
}

SeataAutoConfiguration.java


@Configuration
@PropertySource("classpath:seata.properties")
@EnableAutoDataSourceProxy
@EnableSeataSpringConfig
@EnableConfigurationProperties({CustomProperties.class})
public class SeataAutoConfiguration {
    
}

io.seata.config.ConfigurationProvider

org.cqliving.framework.cloud.seata.CqlivingSeataConfigurationProvider

io.seata.config.ExtConfigurationProvider

org.cqliving.framework.cloud.seata.CqlivingSeataConfigurationProvider

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.cqliving.framework.cloud.seata.SeataAutoConfiguration

seata.properties

seata.config.type=Custom
seata.config.custom.name=CqlivingSeataConfig

spring.cloud.alibaba.seata.tx-service-group=cqliving-seata-group

# ClientProperties.class
seata.client.rm.async-commit-buffer-limit=10000
seata.client.rm-report-retry-count=5
seata.client.rm.table-meta-check-enable=false
seata.client.rm-report-success-enable=false
seata.client.rm.sql-parser-type=druid
seata.client.tm-commit-retry-count=5
seata.client.tm-rollback-retry-count=5

# LockProperties.class
seata.client.rm.lock.lock-retry-interval=10
seata.client.rm.lock.lock-retry-times=30
seata.client.rm.lock.lock-retry-policy-branch-rollback-on-conflict=true

# LogProperties.class
seata.client.log.exception-rate=100

# ServiceProperties
seata.service.vgroupMapping.cqliving-seata-group=seata-server
seata.service.enable-degrade=false
seata.service.disable-global-transaction=false

# ShutdownProperties
seata.transport.shutdown.wait=3

# SpringProperties
seata.client.support.spring.datasource-autoproxy=true

# ThreadFactoryProperties
seata.transport.thread-factory.boss-thread-prefix=NettyBoss
seata.transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker
seata.transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler
seata.transport.thread-factory.share-boss-worker=false
seata.transport.thread-factory.client-selector-thread-prefix=NettyClientSelector
seata.transport.thread-factory.client-selector-thread-size=1
seata.transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread
seata.transport.thread-factory.boss-thread-size=1
seata.transport.thread-factory.worker-thread-size=8

# TransportProperties
seata.transport.type=TCP
seata.transport.server=NIO
seata.transport.heartbeat=true
seata.transport.serialization=seata
seata.transport.compressor=none
seata.transport.enable-client-batch-send-request=false

# UndoProperties
seata.client.undo.undo-data-validation=true
seata.client.undo.undo-log-serialization=jackson
seata.client.undo.undo-log-table=undo_log

# registry
seata.registry.type=eureka
seata.registry.eureka.application=${spring.application.name}
seata.registry.eureka.serviceUrl=${eureka.client.service-url.defaultZone}
seata.registry.eureka.weight=1

最後,創建幾個微服務,註冊到eureka,試試全局事物吧

注意:

1.每個服務數據庫要創建一個表:undo_log,用於記錄回滾日誌

CREATE TABLE `undo_log` (
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(128) NOT NULL,
  `context` text,
  `rollback_info` text,
  `log_status` varchar(32) DEFAULT NULL,
  `log_created` datetime DEFAULT NULL,
  `log_modified` datetime DEFAULT NULL,
  PRIMARY KEY (`branch_id`),
  KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

2.配置文件不要跟着源碼properties類裏去定義,容易踩坑,要看運行時取的什麼配置名,進org.cqliving.framework.cloud.seata.CqlivingSeataConfiguration.getConfig(String, String, long)裏查看

3.注意配置:

seata.service.vgroupMapping.cqliving-seata-group=seata-server

這裏的seata-server是seata註冊到eureka的服務名,根據自己需要修改

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章