分布式发号器(4):vesta-service

目录

service

impl

bean:IdMeta,IdMetaFactory,IdType

Converter:ID元数据与长整型ID的互相转换

populater:Id产生方案

timer:时间操作

provider:机器ID的产生

util工具类


该模块实现了发号器接口的核心项目

该模块内部包结构如下:

service

impl

bean:IdMeta,IdMetaFactory,IdType

IdType:枚举类有三种取值类型,分别对应三种Id类型

package com.robert.vesta.service.impl.bean;

public enum IdType {
    SECONDS("seconds"), MILLISECONDS("milliseconds"), SHORTID("short_id");

    private String name;

    private IdType(String name) {
        this.name = name;
    }

    public long value() {
        switch (this) {
            case SECONDS:
                return 0;
            case MILLISECONDS:
                return 1;
            case SHORTID:
                return 2;
            default:
                return 0;
        }
    }

    @Override
    public String toString() {
        return this.name;
    }

    public static IdType parse(String name) {
        if ("seconds".equals(name)) {
            return SECONDS;
        } else if ("milliseconds".equals(name)) {
            return MILLISECONDS;
        } else if ("short_id".equals(name)) {
            return SHORTID;
        }
        throw new IllegalArgumentException("Illegal IdType name <[" + name
                + "]>, available names are seconds and milliseconds");
    }

    public static IdType parse(long type) {
        if (type == 1) {
            return MILLISECONDS;
        } else if (type == 0) {
            return SECONDS;
        }
        else if(type==2){
            return SHORTID;
        }

        throw new IllegalArgumentException("Illegal IdType value <[" + type
                + "]>, available values are 0 (for seconds) and 1 (for milliseconds)");
    }
}
IdMeta:该类用来描述当前ID类型的具体信息
package com.robert.vesta.service.impl.bean;

public class IdMeta {

    private byte machineBits;

    private byte seqBits;

    private byte timeBits;

    private byte genMethodBits;

    private byte typeBits;

    private byte versionBits;

    public IdMeta(byte machineBits, byte seqBits, byte timeBits, byte genMethodBits, byte typeBits, byte versionBits) {
        super();

        this.machineBits = machineBits;
        this.seqBits = seqBits;
        this.timeBits = timeBits;
        this.genMethodBits = genMethodBits;
        this.typeBits = typeBits;
        this.versionBits = versionBits;
    }

    public byte getMachineBits() {
        return machineBits;
    }

    public void setMachineBits(byte machineBits) {
        this.machineBits = machineBits;
    }

    public long getMachineBitsMask() {
        return -1L ^ -1L << machineBits;
    }

    public byte getSeqBits() {
        return seqBits;
    }

    public void setSeqBits(byte seqBits) {
        this.seqBits = seqBits;
    }

    public long getSeqBitsStartPos() {
        return machineBits;
    }

    public long getSeqBitsMask() {
        return -1L ^ -1L << seqBits;
    }

    public byte getTimeBits() {
        return timeBits;
    }

    public void setTimeBits(byte timeBits) {
        this.timeBits = timeBits;
    }

    public long getTimeBitsStartPos() {
        return machineBits + seqBits;
    }

    public long getTimeBitsMask() {
        return -1L ^ -1L << timeBits;
    }

    public byte getGenMethodBits() {
        return genMethodBits;
    }

    public void setGenMethodBits(byte genMethodBits) {
        this.genMethodBits = genMethodBits;
    }

    public long getGenMethodBitsStartPos() {
        return machineBits + seqBits + timeBits;
    }

    public long getGenMethodBitsMask() {
        return -1L ^ -1L << genMethodBits;
    }

    public byte getTypeBits() {
        return typeBits;
    }

    public void setTypeBits(byte typeBits) {
        this.typeBits = typeBits;
    }

    public long getTypeBitsStartPos() {
        return machineBits + seqBits + timeBits + genMethodBits;
    }

    public long getTypeBitsMask() {
        return -1L ^ -1L << typeBits;
    }

    public byte getVersionBits() {
        return versionBits;
    }

    public void setVersionBits(byte versionBits) {
        this.versionBits = versionBits;
    }

    public long getVersionBitsStartPos() {
        return machineBits + seqBits + timeBits + genMethodBits + typeBits;
    }

    public long getVersionBitsMask() {
        return -1L ^ -1L << versionBits;
    }
}

getXxxxBitsMask():

假设某个字段有五个二进制位

-1L的补码:   1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111

-1 << xxxBits: 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1110 0000

-1L ^ -1L << machineBits:000... 0001 1111

IdMetaFactory用来产生描述ID类型信息的对象:
package com.robert.vesta.service.impl.bean;

public class IdMetaFactory {

    private static IdMeta maxPeak = new IdMeta((byte) 10, (byte) 20, (byte) 30, (byte) 1, (byte) 1, (byte) 1);

    private static IdMeta minGranularity = new IdMeta((byte) 10, (byte) 10, (byte) 40, (byte) 1, (byte) 1, (byte) 1);

    private static IdMeta shortId=new IdMeta((byte)10,(byte) 10,(byte) 30,(byte)1,(byte) 1,(byte) 1);

    public static IdMeta getIdMeta(IdType type) {
        if (IdType.SECONDS.equals(type)) {
            return maxPeak;
        } else if (IdType.MILLISECONDS.equals(type)) {
            return minGranularity;
        } else if(IdType.SHORTID.equals(type)){
            return shortId;
        }
        return null;
     }
}

Converter:ID元数据与长整型ID的互相转换

IdConverter:

package com.robert.vesta.service.impl.converter;

import com.robert.vesta.service.bean.Id;
import com.robert.vesta.service.impl.bean.IdMeta;

public interface IdConverter {
   
    long convert(Id id, IdMeta idMeta);

    Id convert(long id, IdMeta idMeta);

}
IdConverterImpl:
package com.robert.vesta.service.impl.converter;

import com.robert.vesta.service.bean.Id;
import com.robert.vesta.service.impl.bean.IdMeta;

public class IdConverterImpl implements IdConverter {

    public IdConverterImpl() {
    }
    
    public long convert(Id id, IdMeta idMeta) {
        return doConvert(id, idMeta);
    }
    //把id转换成long
    protected long doConvert(Id id, IdMeta idMeta) {
        long ret = 0;

        ret |= id.getMachine();

        ret |= id.getSeq() << idMeta.getSeqBitsStartPos();

        ret |= id.getTime() << idMeta.getTimeBitsStartPos();

        ret |= id.getGenMethod() << idMeta.getGenMethodBitsStartPos();

        ret |= id.getType() << idMeta.getTypeBitsStartPos();

        ret |= id.getVersion() << idMeta.getVersionBitsStartPos();

        return ret;
    }
    //把long转换成Id
    public Id convert(long id, IdMeta idMeta) {
        return doConvert(id, idMeta);
    }

    protected Id doConvert(long id, IdMeta idMeta) {
        Id ret = new Id();

        ret.setMachine(id & idMeta.getMachineBitsMask());

        ret.setSeq((id >>> idMeta.getSeqBitsStartPos()) & idMeta.getSeqBitsMask());

        ret.setTime((id >>> idMeta.getTimeBitsStartPos()) & idMeta.getTimeBitsMask());

        ret.setGenMethod((id >>> idMeta.getGenMethodBitsStartPos()) & idMeta.getGenMethodBitsMask());

        ret.setType((id >>> idMeta.getTypeBitsStartPos()) & idMeta.getTypeBitsMask());

        ret.setVersion((id >>> idMeta.getVersionBitsStartPos()) & idMeta.getVersionBitsMask());

        return ret;
    }

}
 

long doConvert(Id id, IdMeta idMeta)转换器根据ID元数据(IdMate)的信息对象获取每个属性所在ID的位数,然后通过左移来实现将各个属性拼接到一个长整型字里。

Id doConvert(long id, IdMeta idMeta)根据ID元数据(IdMate)的信息对象将long类型的ID内部的字段分解到对应Id类型的对象中:

首先将ID整体右移,将想要得到的字段右移到从第0位开始:id >>> idMeta.getTypeBitsStartPos(),注意这里使用的是无符号右移操作。

然后和BitsMask进行&操作,得到对应的字段:id>>>idMeta.getTypeBitsStartPos()&idMeta.getTypeBitsMask()

 

populater:Id产生方案

IdPopulator:

package com.robert.vesta.service.impl.populater;

import com.robert.vesta.service.bean.Id;
import com.robert.vesta.service.impl.bean.IdMeta;
import com.robert.vesta.service.impl.timer.Timer;

/**
 * 需要计算构成唯一ID的格式中的时间和序列号,提供了由Synchronized锁,ReentrantLock,CAS无锁技术来提供
 */
public interface IdPopulator {

    void populateId(Timer timer, Id id, IdMeta idMeta);

}

ResetPopulator:reset方法在子类中负责将序列号字段和时间字段复位

package com.robert.vesta.service.impl.populater;

public interface ResetPopulator {

    void reset();

}

BasePopulator:

package com.robert.vesta.service.impl.populater;

import com.robert.vesta.service.bean.Id;
import com.robert.vesta.service.impl.bean.IdMeta;
import com.robert.vesta.service.impl.timer.Timer;
/**
 * 提供锁同步的公共模板
 */
public abstract class BasePopulator implements IdPopulator, ResetPopulator {
    protected long sequence = 0;//本个时间单位内的序列号
    protected long lastTimestamp = -1;//时间字段,用来记录上一个时间

    public BasePopulator() {
        super();
    }

    /**
     * idMeta里存储着ID的每个字段的信息
     * @param timer
     * @param id
     * @param idMeta
     */
    public void populateId(Timer timer, Id id, IdMeta idMeta) {
        long timestamp = timer.genTime();//timer来获取当前时间
        timer.validateTimestamp(lastTimestamp, timestamp);//校验时间是否正确
        /**
         * 如果当前时间和上一个时间相同,则直接对序列号累加
         * 否则,序列号清零,然后获得当前的时间,并且更新上一个时间。
         */
        if (timestamp == lastTimestamp) {
            
            sequence++;
            sequence &= idMeta.getSeqBitsMask();
            //如果当前时间段内产生的序列号达到最大值,则使用乐观锁一直等待到下一个时间值
            if (sequence == 0) {
                timestamp = timer.tillNextTimeUnit(lastTimestamp);
            }
        } else {
            lastTimestamp = timestamp;
            sequence = 0;
        }

        id.setSeq(sequence);
        id.setTime(timestamp);
    }

    public void reset() {
        this.sequence = 0;
        this.lastTimestamp = -1;
    }
}

LockIdPopulator:

package com.robert.vesta.service.impl.populater;

import com.robert.vesta.service.bean.Id;
import com.robert.vesta.service.impl.bean.IdMeta;
import com.robert.vesta.service.impl.timer.Timer;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockIdPopulator extends BasePopulator {

    private Lock lock = new ReentrantLock();

    public LockIdPopulator() {
        super();
    }

    public void populateId(Timer timer, Id id, IdMeta idMeta) {
        //采用Reentranlock可重入锁进行同步,性能高于synchronized
        lock.lock();
        try {
            super.populateId(timer, id, idMeta);
        } finally {
            lock.unlock();
        }
    }

}

SyncIdPopulator:

package com.robert.vesta.service.impl.populater;

import com.robert.vesta.service.bean.Id;
import com.robert.vesta.service.impl.bean.IdMeta;
import com.robert.vesta.service.impl.timer.Timer;

public class SyncIdPopulator extends BasePopulator {

    public SyncIdPopulator() {
        super();
    }
    
    public synchronized void populateId(Timer timer, Id id, IdMeta idMeta) {
        super.populateId(timer, id, idMeta);
    }

}

AtomicIdPopulator:采用CAS底层基础设施实现了无锁版本,CAS无锁版本在高并发的场景下,能够高性能的处理唯一ID的产生,但是要安全并发的修改两个变量:时间字段和序列号字段,这里通过原子变量引用来实现。

首先定义一个联合的数据结构:

 class Variant {
        private long sequence = 0;
        private long lastTimestamp = -1;
    }
package com.robert.vesta.service.impl.populater;

import com.robert.vesta.service.bean.Id;
import com.robert.vesta.service.impl.bean.IdMeta;
import com.robert.vesta.service.impl.timer.Timer;

import java.util.concurrent.atomic.AtomicReference;

public class AtomicIdPopulator implements IdPopulator, ResetPopulator {

    class Variant {
        private long sequence = 0;
        private long lastTimestamp = -1;
    }
//这里定义一个原子变量的引用,这个引用可以保证CAS操作中Variant的
//sequence和lastTimestamp字段中的任意一个被修改了,都可以安全的被更新
    private AtomicReference<Variant> variant = new AtomicReference<Variant>(new Variant());

    public AtomicIdPopulator() {
        super();
    }

    public void populateId(Timer timer, Id id, IdMeta idMeta) {
        Variant varOld, varNew;
        long timestamp, sequence;

        while (true) {

            // 获得原来的变量,变量中包含原来的时间和序列号版本
            varOld = variant.get();

            //这部分对时间字段和序列号字段的更新逻辑和用ReentranLock和Synchronized实现的版本相同
            timestamp = timer.genTime();
            timer.validateTimestamp(varOld.lastTimestamp, timestamp);

            sequence = varOld.sequence;

            if (timestamp == varOld.lastTimestamp) {
                sequence++;
                sequence &= idMeta.getSeqBitsMask();
                if (sequence == 0) {
                    timestamp = timer.tillNextTimeUnit(varOld.lastTimestamp);
                }
            } else {
                sequence = 0;
            }

           // 保存新的变量
            varNew = new Variant();
            varNew.sequence = sequence;
            varNew.lastTimestamp = timestamp;
            //CAS更新原来的变量
            if (variant.compareAndSet(varOld, varNew)) {
                id.setSeq(sequence);
                id.setTime(timestamp);

                break;
            }

        }
    }

    public void reset() {
        variant = new AtomicReference<Variant>(new Variant());
    }

}

timer:时间操作

Timer:假设在某个秒中序列号被用光了怎么办?这种情况下,我们认为等待的时间不会太长,而且阻塞线程没有任何意义,所以采用自旋锁直到时间到下一秒中,这样就减少了因线程切换而导致的性能损耗。

package com.robert.vesta.service.impl.timer;

import com.robert.vesta.service.impl.bean.IdMeta;
import com.robert.vesta.service.impl.bean.IdType;

import java.util.Date;

public interface Timer {
    long EPOCH = 1514736000000L;

    void init(IdMeta idMeta, IdType idType);

    Date transTime(long time);

    void validateTimestamp(long lastTimestamp, long timestamp);

    long tillNextTimeUnit(long lastTimestamp);

    long genTime();

}
SimpleTimer:
package com.robert.vesta.service.impl.timer;

import com.robert.vesta.service.impl.bean.IdMeta;
import com.robert.vesta.service.impl.bean.IdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

public class SimpleTimer implements Timer {
    protected static final Logger log = LoggerFactory.getLogger(SimpleTimer.class);
    protected IdMeta idMeta;
    protected IdType idType;
    protected long maxTime;
    protected long epoch = EPOCH;

    public void init(IdMeta idMeta, IdType idType) {
        this.idMeta = idMeta;
        this.maxTime = (1L << idMeta.getTimeBits()) - 1;
        this.idType = idType;
        this.genTime();
        this.timerUsedLog();
    }

    public void timerUsedLog(){
        Date expirationDate = transTime(maxTime);
        long days = ((expirationDate.getTime() - System.currentTimeMillis())/(1000 * 60 * 60 * 24));
        log.info("The current time bit length is {}, the expiration date is {}, this can be used for {} days.",
                idMeta.getTimeBits(), expirationDate, days);
    }

    public void setEpoch(long epoch) {
        this.epoch = epoch;
    }

    public Date transTime(long time) {
        if (idType == IdType.MILLISECONDS) {
            return new Date(time + epoch);
        } else {
            return new Date(time * 1000 + epoch);
        }
    }

    /**
     * 校验机器时间是否被调慢了
     * @param lastTimestamp
     * @param timestamp
     */
    public void validateTimestamp(long lastTimestamp, long timestamp) {
        if (timestamp < lastTimestamp) {
            if (log.isErrorEnabled())
                log.error(String
                        .format("Clock moved backwards.  Refusing to generate id for %d second/milisecond.",
                                lastTimestamp - timestamp));

            throw new IllegalStateException(
                    String.format(
                            "Clock moved backwards.  Refusing to generate id for %d second/milisecond.",
                            lastTimestamp - timestamp));
        }
    }
    //获得下一个时间值
    public long tillNextTimeUnit(final long lastTimestamp) {
        if (log.isInfoEnabled())
            log.info(String
                    .format("Ids are used out during %d. Waiting till next second/milisencond.",
                            lastTimestamp));
        //乐观锁一直等待到下一个时间值
        long timestamp = genTime();
        while (timestamp <= lastTimestamp) {
            timestamp = genTime();
        }

        if (log.isInfoEnabled())
            log.info(String.format("Next second/milisencond %d is up.",
                    timestamp));

        return timestamp;
    }
    //通过id类型来确认时间单位,并且通过epoch来压缩
    public long genTime() {
        long time;
        if (idType == IdType.MILLISECONDS) {
            time = (System.currentTimeMillis() - epoch);
        } else {
            time = (System.currentTimeMillis() - epoch) / 1000;
        }
        validateTimestamp(time);
        return time;
    }

    protected void validateTimestamp(long timestamp){
        if (timestamp > maxTime) {
            String error = String.format(
                    "The current timestamp (%s >= %s) has overflowed, Vesta Service will be terminate.", timestamp, maxTime);
            log.error(error);
            throw new RuntimeException(error);
        }
    }

}

provider:机器ID的产生

MachineIdProvider
package com.robert.vesta.service.impl.provider;

public interface MachineIdProvider {
    public long getMachineId();
}
MachineIdsProvider
package com.robert.vesta.service.impl.provider;

public interface MachineIdsProvider extends MachineIdProvider {

    long getNextMachineId();

}
PropertyMachineIdProvider:基于属性配置进行实现的,也是一种用于测试环境的方式,使用这种方式时,需要在部署的每台机器上配置不同的机器号
package com.robert.vesta.service.impl.provider;

public class PropertyMachineIdProvider implements MachineIdProvider {
    private long machineId;

    public long getMachineId() {
        return machineId;
    }

    public void setMachineId(long machineId) {
        this.machineId = machineId;
    }
}
PropertyMachineIdsProvider
package com.robert.vesta.service.impl.provider;

public class PropertyMachineIdsProvider implements MachineIdsProvider {
    private long[] machineIds;
    private int currentIndex;

    public long getNextMachineId() {
        return getMachineId();
    }

    public long getMachineId() {
        return machineIds[currentIndex++%machineIds.length];
    }

    public void setMachineIds(long[] machineIds) {
        this.machineIds = machineIds;
    }
}

IpConfigurableMachineIdProvider:通过IP的机器列表位每个机器生成一个唯一的ID号,主要是和服务节点比较少的情况,生成ID是轻量级的服务,不会需要太大的服务池。

这种实现方式通过发布前配置所有的服务节点IP的映射,每个服务节点必须具有相同的映射,运行时每个服务节点根据本机IP取得在IP映射中的位置,作为自己的机器号。

package com.robert.vesta.service.impl.provider;

import com.robert.vesta.util.IpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

public class IpConfigurableMachineIdProvider implements MachineIdProvider {
    private static final Logger log = LoggerFactory
            .getLogger(IpConfigurableMachineIdProvider.class);

    private long machineId;

    private Map<String, Long> ipsMap = new HashMap<String, Long>();

    public IpConfigurableMachineIdProvider() {
        log.debug("IpConfigurableMachineIdProvider constructed.");
    }

    public IpConfigurableMachineIdProvider(String ips) {
        setIps(ips);
        init();
    }

    public void init() {
        String ip = IpUtils.getHostIp();

        if (StringUtils.isEmpty(ip)) {
            String msg = "Fail to get host IP address. Stop to initialize the IpConfigurableMachineIdProvider provider.";

            log.error(msg);
            throw new IllegalStateException(msg);
        }

        if (!ipsMap.containsKey(ip)) {
            String msg = String
                    .format("Fail to configure ID for host IP address %s. Stop to initialize the IpConfigurableMachineIdProvider provider.",
                            ip);

            log.error(msg);
            throw new IllegalStateException(msg);
        }

        machineId = ipsMap.get(ip);

        log.info("IpConfigurableMachineIdProvider.init ip {} id {}", ip,
                machineId);
    }

    public void setIps(String ips) {
        log.debug("IpConfigurableMachineIdProvider ips {}", ips);
        if (!StringUtils.isEmpty(ips)) {
            String[] ipArray = ips.split(",");

            for (int i = 0; i < ipArray.length; i++) {
                ipsMap.put(ipArray[i], (long) i);
            }
        }
    }

    public long getMachineId() {
        return machineId;
    }

    public void setMachineId(long machineId) {
        this.machineId = machineId;
    }
}

DbMachineIdProvider:通过在数据库中配置机器ID来实现,适用情况范围光,但是使用起来需要依赖数据库。

package com.robert.vesta.service.impl.provider;

import com.robert.vesta.util.IpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.StringUtils;

public class DbMachineIdProvider implements MachineIdProvider {
    private static final Logger log = LoggerFactory
            .getLogger(DbMachineIdProvider.class);

    private long machineId;

    private JdbcTemplate jdbcTemplate;

    public DbMachineIdProvider() {
        log.debug("IpConfigurableMachineIdProvider constructed.");
    }

    public void init() {
        String ip = IpUtils.getHostIp();

        if (StringUtils.isEmpty(ip)) {
            String msg = "Fail to get host IP address. Stop to initialize the DbMachineIdProvider provider.";

            log.error(msg);
            throw new IllegalStateException(msg);
        }

        Long id = null;
        try {
            id = jdbcTemplate.queryForObject(
                    "select ID from DB_MACHINE_ID_PROVIDER where IP = ?",
                    new Object[]{ip}, Long.class);

        } catch (EmptyResultDataAccessException e) {
            // Ignore the exception
            log.error("No allocation before for ip {}.", ip);
        }

        if (id != null) {
            machineId = id;
            return;
        }

        log.info(
                "Fail to get ID from DB for host IP address {}. Next step try to allocate one.",
                ip);

        int count = jdbcTemplate
                .update("update DB_MACHINE_ID_PROVIDER set IP = ? where IP is null limit 1",
                        ip);

        if (count <= 0 || count > 1) {
            String msg = String
                    .format("Fail to allocte ID for host IP address {}. The {} records are updated. Stop to initialize the DbMachineIdProvider provider.",
                            ip, count);

            log.error(msg);
            throw new IllegalStateException(msg);
        }

        try {
            id = jdbcTemplate.queryForObject(
                    "select ID from DB_MACHINE_ID_PROVIDER where IP = ?",
                    new Object[]{ip}, Long.class);

        } catch (EmptyResultDataAccessException e) {
            // Ignore the exception
            log.error("Fail to do allocation for ip {}.", ip);
        }

        if (id == null) {
            String msg = String
                    .format("Fail to get ID from DB for host IP address {} after allocation. Stop to initialize the DbMachineIdProvider provider.",
                            ip);

            log.error(msg);
            throw new IllegalStateException(msg);
        }

        machineId = id;
    }

    public long getMachineId() {
        return machineId;
    }

    public void setMachineId(long machineId) {
        this.machineId = machineId;
    }

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}

util工具类

CommonUtils:

package com.robert.vesta.util;


import java.util.Arrays;

public class CommonUtils {
    public static String[] SWITCH_ON_EXP = new String[]{"ON", "TRUE", "on", "true"};

    public static String[] SWITCH_OFF_EXP = new String[]{"OFF", "FALSE", "off", "false"};

    public static boolean isOn(String swtch) {

        if (Arrays.asList(SWITCH_ON_EXP).contains(swtch)) {
            return true;
        }
            return false;
    }

    public static boolean isPropKeyOn(String key) {

        String prop = System.getProperty(key);

        if (Arrays.asList(SWITCH_ON_EXP).contains(prop)) {
            return true;
        }

        return false;
    }
}

IpUtils:

package com.robert.vesta.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

public class IpUtils {
    private static final Logger log = LoggerFactory.getLogger(IpUtils.class);

    public static String getHostIp() {
        String ip = null;
        try {
            Enumeration<NetworkInterface> en = NetworkInterface
                    .getNetworkInterfaces();
            while (en.hasMoreElements()) {
                NetworkInterface intf = (NetworkInterface) en.nextElement();
                Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();
                while (enumIpAddr.hasMoreElements()) {
                    InetAddress inetAddress = (InetAddress) enumIpAddr
                            .nextElement();
                    if (!inetAddress.isLoopbackAddress()
                            && !inetAddress.isLinkLocalAddress()
                            && inetAddress.isSiteLocalAddress()) {
                        ip = inetAddress.getHostAddress();
                    }
                }
            }
        } catch (SocketException e) {
            log.error("Fail to get IP address.", e);
        }
        return ip;
    }

    public static String getHostName() {
        String hostName = null;
        try {
            Enumeration<NetworkInterface> en = NetworkInterface
                    .getNetworkInterfaces();
            while (en.hasMoreElements()) {
                NetworkInterface intf = (NetworkInterface) en.nextElement();
                Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses();
                while (enumIpAddr.hasMoreElements()) {
                    InetAddress inetAddress = (InetAddress) enumIpAddr
                            .nextElement();
                    if (!inetAddress.isLoopbackAddress()
                            && !inetAddress.isLinkLocalAddress()
                            && inetAddress.isSiteLocalAddress()) {
                        hostName = inetAddress.getHostName();
                    }
                }
            }
        } catch (SocketException e) {
            log.error("Fail to get host name.", e);
        }
        return hostName;
    }
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值