All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cc.siyecao.uid.UidAutoConfiguration Maven / Gradle / Ivy

There is a newer version: 2.2
Show newest version
package cc.siyecao.uid;

import cc.siyecao.uid.impl.CachedUidGenerator;
import cc.siyecao.uid.worker.AssignerMode;
import cc.siyecao.uid.worker.DisposableWorkerIdAssigner;
import cc.siyecao.uid.worker.dao.*;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.time.Duration;
import java.util.Set;

/**
 * 配置
 *
 * @author lyt
 */
public class UidAutoConfiguration {

    private static final String COUNTER_ZNODE = "/uid-generator/worker_node";

    @Value("${uid-generator.time-bits:0}")
    private int timeBits;
    @Value("${uid-generator.worker-bits:0}")
    private int WorkerBits;
    @Value("${uid-generator.seq-bits:0}")
    private int seqBits;
    @Value("${uid-generator.epoch-str:}")
    private String epochStr;
    @Value("${uid-generator.boost-power:0}")
    private int boostPower;
    @Value("${uid-generator.padding-factor:0}")
    private int paddingFactor;
    @Value("${uid-generator.schedule-interval:0}")
    private int scheduleInterval;

    @Value("${uid-generator.datasource.driver-class-name:}")
    private String driverClassName;
    @Value("${uid-generator.datasource.url:}")
    private String url;
    @Value("${uid-generator.datasource.username:}")
    private String username;
    @Value("${uid-generator.datasource.password:}")
    private String password;

    @Value("${uid-generator.zookeeper.addrs:}")
    private String addrs;
    @Value("${uid-generator.zookeeper.authentication:}")
    private String authentication;
    @Value("${uid-generator.zookeeper.session-timeout-ms:15000}")
    private int sessionTimeoutMs;

    @Value("${uid-generator.redis.database:0}")
    private int database;
    @Value("${uid-generator.redis.host:}")
    private String host;
    @Value("${uid-generator.redis.password:}")
    private String redisPassword;
    @Value("${uid-generator.redis.port:0}")
    private int port;
    @Value("${uid-generator.redis.timeout:6000}")
    private long timeout;
    @Value("${uid-generator.redis.lettuce.shutdown-timeout:6000}")
    private long shutDownTimeout;
    @Value("${uid-generator.redis.lettuce.pool.max-idle:0}")
    private int maxIdle;
    @Value("${uid-generator.redis.lettuce.pool.min-idle:0}")
    private int minIdle;
    @Value("${uid-generator.redis.lettuce.pool.max-active:0}")
    private int maxActive;
    @Value("${uid-generator.redis.lettuce.pool.max-wait:0}")
    private long maxWait;
    @Value("#{'${uid-generator.redis.cluster.nodes:}'.split(',')}")
    private Set nodes;

    @Bean
    @ConditionalOnProperty(value = "uid-generator.assigner-mode", havingValue = AssignerMode.NONE)
    public WorkerNodeResposity workerNodeDefaultResposity() {
        return new WorkerNodeDefault();
    }

    @Bean
    @ConditionalOnProperty(value = "uid-generator.assigner-mode", havingValue = AssignerMode.DB)
    public WorkerNodeResposity workerNodeDaoResposity(ObjectProvider dataSourcePvd) {
        DataSource dataSource = null;
        if (StringUtils.isNotBlank( this.driverClassName ) &&
                StringUtils.isNotBlank( this.url ) &&
                StringUtils.isNotBlank( this.username ) &&
                StringUtils.isNotBlank( this.password )) {

            HikariDataSource hds = new HikariDataSource();
            hds.setDriverClassName( this.driverClassName );
            hds.setJdbcUrl( this.url );
            hds.setUsername( this.username );
            hds.setPassword( this.password );
            dataSource = hds;
        } else {
            dataSource = dataSourcePvd.getIfAvailable();
        }

        JdbcTemplate jdbcTemplate = new JdbcTemplate( dataSource );
        return new WorkerNodeDAO( jdbcTemplate );
    }

    @Bean
    @ConditionalOnProperty(value = "uid-generator.assigner-mode", havingValue = AssignerMode.ZK)
    public WorkerNodeResposity workerNodeZkResposity() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry( 1000, 10 );
        CuratorFramework cf = null;
        if (StringUtils.isNotBlank( this.authentication )) {
            cf = CuratorFrameworkFactory.builder()
                    .connectString( this.addrs )
                    .sessionTimeoutMs( this.sessionTimeoutMs )
                    .retryPolicy( retryPolicy )
                    .authorization( "digest", this.authentication.getBytes() )
                    .build();
        } else {
            cf = CuratorFrameworkFactory.builder()
                    .connectString( this.addrs )
                    .sessionTimeoutMs( this.sessionTimeoutMs )
                    .retryPolicy( retryPolicy )
                    .build();
        }
        cf.start();
        DistributedAtomicLong distAtomicLong = new DistributedAtomicLong( cf, COUNTER_ZNODE, retryPolicy );
        return new WorkerNodeZK( distAtomicLong );
    }


    @Bean
    @ConditionalOnProperty(value = "uid-generator.assigner-mode", havingValue = AssignerMode.REDIS)
    public LettuceConnectionFactory lettuceConnectionFactory() {
        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
        genericObjectPoolConfig.setMaxIdle( maxIdle );
        genericObjectPoolConfig.setMinIdle( minIdle );
        genericObjectPoolConfig.setMaxTotal( maxActive );
        genericObjectPoolConfig.setMaxWait( Duration.ofMillis( maxWait ) );
        genericObjectPoolConfig.setTimeBetweenEvictionRuns( Duration.ofMillis( 60 * 1000 ) );
        LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                .commandTimeout( Duration.ofMillis( timeout ) )
                .shutdownTimeout( Duration.ofMillis( shutDownTimeout ) )
                .poolConfig( genericObjectPoolConfig )
                .build();
        LettuceConnectionFactory factory = null;
        if (StringUtils.isNotEmpty( host )) {
            RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
            redisConfig.setDatabase( database );
            redisConfig.setHostName( host );
            redisConfig.setPort( port );
            if (StringUtils.isNotEmpty( redisPassword )) {
                redisConfig.setPassword( RedisPassword.of( redisPassword ) );
            }
            factory = new LettuceConnectionFactory( redisConfig, clientConfig );
        } else if (nodes != null && nodes.size() > 0) {
            RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration( nodes );
            factory = new LettuceConnectionFactory( redisClusterConfiguration, clientConfig );
        }
        return factory;
    }

    @Bean
    @ConditionalOnProperty(value = "uid-generator.assigner-mode", havingValue = AssignerMode.REDIS)
    public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        RedisTemplate template = new RedisTemplate<>();
        template.setConnectionFactory( lettuceConnectionFactory );
        return template;
    }

    @Bean
    @ConditionalOnProperty(value = "uid-generator.assigner-mode", havingValue = AssignerMode.REDIS)
    public WorkerNodeResposity workerNodeRedisResposity(RedisTemplate template) {
        return new WorkerNodeRedis( template );
    }

    @Bean
    public DisposableWorkerIdAssigner disposableWorkerIdAssigner() {
        return new DisposableWorkerIdAssigner();
    }

    @Bean
    public CachedUidGenerator cachedUidGenerator(DisposableWorkerIdAssigner workerIdAssigner) {
        CachedUidGenerator generator = new CachedUidGenerator();
        generator.setWorkerIdAssigner( workerIdAssigner );

        // 以下为可选配置, 如未指定将采用默认值
        if (this.timeBits > 0) {
            generator.setTimeBits( this.timeBits );
        }
        if (this.WorkerBits > 0) {
            generator.setWorkerBits( this.WorkerBits );
        }
        if (this.seqBits > 0) {
            generator.setSeqBits( this.seqBits );
        }
        if (StringUtils.isNotEmpty( this.epochStr )) {
            generator.setEpochStr( this.epochStr );
        }

        // RingBuffer size扩容参数, 可提高UID生成的吞吐量
        // 默认:3, 原bufferSize=8192, 扩容后bufferSize= 8192 << 3 = 65536
        if (this.boostPower > 0) {
            generator.setBoostPower( this.boostPower );
        }

        // 指定何时向RingBuffer中填充UID, 取值为百分比(0, 100), 默认为50
        // 举例: bufferSize=1024, paddingFactor=50 -> threshold=1024 * 50 / 100 = 512.
        // 当环上可用UID数量 < 512时, 将自动对RingBuffer进行填充补全
        if (this.paddingFactor > 0) {
            generator.setPaddingFactor( this.paddingFactor );
        }

        // 另外一种RingBuffer填充时机, 在Schedule线程中, 周期性检查填充
        // 默认:不配置此项, 即不使用Schedule线程. 如需使用, 请指定Schedule线程时间间隔, 单位:秒
        if (this.scheduleInterval > 0) {
            generator.setScheduleInterval( this.scheduleInterval );
        }

        // 拒绝策略: 当环已满, 无法继续填充时
        // 默认无需指定, 将丢弃Put操作, 仅日志记录. 如有特殊需求, 请实现RejectedPutBufferHandler接口(支持Lambda表达式)
        // 
        // cachedUidGenerator.setRejectedPutBufferHandler();
        // 拒绝策略: 当环已空, 无法继续获取时 -->
        // 默认无需指定, 将记录日志, 并抛出UidGenerateException异常. 如有特殊需求,
        // 请实现RejectedTakeBufferHandler接口(支持Lambda表达式) -->
        // 

        return generator;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy