apache / incubator-seata

:fire: Seata is an easy-to-use, high-performance, open source distributed transaction solution.
https://seata.apache.org/
Apache License 2.0
25.35k stars 8.78k forks source link

springboot-seata-starter,custom config失败 #2536

Closed fighter2011 closed 3 years ago

fighter2011 commented 4 years ago

Ⅰ. Issue Description

使用springboot-seata-starter自定义配置时解析配置失败

Ⅱ. Describe what happened

使用cutom的形式来实现,但是yaml配置seate.config.type.custom seata.config.custom.name,CustomConfigurationProvider获取配置的时候,解析不到seata.config.custom.name配置的值 If there is an exception, please attach the exception trace:

Just paste your stack trace here!

Ⅲ. Describe what you expected to happen

Ⅳ. How to reproduce it (as minimally and precisely as possible)

  1. xxx
  2. xxx
  3. xxx

Ⅴ. Anything else we need to know?

Ⅵ. Environment:

hermitcai commented 4 years ago

可以跟进一下看看源码行吗

fighter2011 commented 4 years ago

可以跟进一下看看源码行吗

我看了源码了的,使用springboot-steata-starter没有registry.conf文件,解析得到ConfigurationFactory默认是FileConfiguration,SpringBootConfigurationProvider在获取属性的时候StarterConstants对应的PROPERTY_MAP没有Custom对应的properties然后解析出来就是null

liuzongyang255 commented 4 years ago

这个要自己定义一个Provider 放在/META-INF/seata下 这是我的配置,使用自定义配置类型,自定义从ApplicationContext.Environment里去取参数: 这样我们的配置就可以放在配置文件里了,也可以天然支持配置中心

  1. 配置文件
seata.config.type=Custom
seata.config.custom.name=CqlivingSeataConfig
  1. META-INF/seata/io.seata.config.ConfigurationProvider
org.cqliving.framework.cloud.seata.CqlivingSeataConfigurationProvider

3.META-INF/seata/io.seata.config.ExtConfigurationProvider

org.cqliving.framework.cloud.seata.CqlivingSeataConfigurationProvider

4.CqlivingSeataConfigurationProvider

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;

/********************************************************/
@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();
    }
}
  1. CqlivingSeataConfiguration
    
    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;

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;
}

}


6.SeataAutoConfiguration.java

package org.cqliving.framework.cloud.seata;

import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import io.seata.config.springcloud.EnableSeataSpringConfig; import io.seata.spring.annotation.datasource.EnableAutoDataSourceProxy;

/****/

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

}


7. 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

slievrly commented 4 years ago

@fighter2011 Welcome to contribute to the community by submitting a pr fix for this problem.