Java tutorial
package com.yn.keygen; /* * Copyright 1999-2015 dangdang.com. * <p> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * </p> */ import org.apache.commons.lang3.StringUtils; import org.springframework.util.Assert; import java.util.Calendar; /** * ?. * * <p> * 64bit,??? * </p> * * <pre> * 1bit ?? * 41bits ???2016111 * 10bits Id * 12bits ?? * </pre> * * <p> * Id?: ??{@code sharding-jdbc.default.key.generator.worker.id} ??{@code SHARDING_JDBC_DEFAULT_KEY_GENERATOR_WORKER_ID} * ,??@{@code DefaultKeyGenerator.setWorkerId} * </p> * * @author yangnan */ public final class DefaultKeyGenerator implements KeyGenerator { public static final long EPOCH; public static final String WORKER_ID_PROPERTY_KEY = "spring-tools.default.key.generator.worker.id"; public static final String WORKER_ID_ENV_KEY = "SPRING_TOOLS_DEFAULT_KEY_GENERATOR_WORKER_ID"; private static final long SEQUENCE_BITS = 12L; private static final long WORKER_ID_BITS = 10L; private static final long SEQUENCE_MASK = (1 << SEQUENCE_BITS) - 1; private static final long WORKER_ID_LEFT_SHIFT_BITS = SEQUENCE_BITS; private static final long TIMESTAMP_LEFT_SHIFT_BITS = WORKER_ID_LEFT_SHIFT_BITS + WORKER_ID_BITS; private static final long WORKER_ID_MAX_VALUE = 1L << WORKER_ID_BITS; private static TimeService timeService = new TimeService(); private static long workerId; static { Calendar calendar = Calendar.getInstance(); calendar.set(2016, Calendar.NOVEMBER, 1); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); EPOCH = calendar.getTimeInMillis(); initWorkerId(); } private long sequence; private long lastTime; public static void initWorkerId() { String workerId = System.getProperty(WORKER_ID_PROPERTY_KEY); if (StringUtils.isNotBlank(workerId)) { setWorkerId(Long.valueOf(workerId)); return; } workerId = System.getenv(WORKER_ID_ENV_KEY); if (StringUtils.isBlank(workerId)) { return; } setWorkerId(Long.valueOf(workerId)); } /** * Id. * * @param workerId Id */ public static void setWorkerId(final long workerId) { Assert.isTrue(workerId >= 0L && workerId < WORKER_ID_MAX_VALUE); DefaultKeyGenerator.workerId = workerId; } /** * ?Id. * * @return @{@link Long}Id */ @Override public synchronized Number generateKey() { long currentMillis = timeService.getCurrentMillis(); // Assert.isTrue(lastTime <= currentMillis, String.format("Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds", lastTime, currentMillis)); if (lastTime == currentMillis) { if (0L == (sequence = ++sequence & SEQUENCE_MASK)) { currentMillis = waitUntilNextTime(currentMillis); } } else { sequence = 0; } lastTime = currentMillis; return ((currentMillis - EPOCH) << TIMESTAMP_LEFT_SHIFT_BITS) | (workerId << WORKER_ID_LEFT_SHIFT_BITS) | sequence; } private long waitUntilNextTime(final long lastTime) { long time = timeService.getCurrentMillis(); while (time <= lastTime) { time = timeService.getCurrentMillis(); } return time; } }