Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
commons
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
3
Merge Requests
3
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DevOps
commons
Commits
e8f5fbb8
Commit
e8f5fbb8
authored
May 15, 2018
by
xiaoguang.xu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat : IDGenerator AutoConfiguration
parent
9b8246e4
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
215 additions
and
415 deletions
+215
-415
OIDGenerator.java
...g/src/main/java/cn/quantgroup/tech/util/OIDGenerator.java
+0
-152
BitsAllocator.java
...c/main/java/cn/quantgroup/tech/util/id/BitsAllocator.java
+0
-129
IDGenerateException.java
.../java/cn/quantgroup/tech/util/id/IDGenerateException.java
+0
-44
pom.xml
idgenerator-spring-boot-starter/pom.xml
+31
-0
IDGenerator.java
...c/main/java/cn/quantgroup/tech/generator/IDGenerator.java
+36
-90
GeneratorAutoConfiguration.java
...h/generator/configuration/GeneratorAutoConfiguration.java
+61
-0
GeneratorFactoryBean.java
...up/tech/generator/configuration/GeneratorFactoryBean.java
+79
-0
spring.factories
...boot-starter/src/main/resources/META-INF/spring.factories
+2
-0
pom.xml
pom.xml
+6
-0
No files found.
commons-spring/src/main/java/cn/quantgroup/tech/util/OIDGenerator.java
deleted
100644 → 0
View file @
9b8246e4
package
cn
.
quantgroup
.
tech
.
util
;
import
com.google.common.cache.CacheBuilder
;
import
com.google.common.cache.CacheLoader
;
import
com.google.common.cache.LoadingCache
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnClass
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.data.redis.core.StringRedisTemplate
;
import
org.springframework.stereotype.Component
;
import
javax.annotation.PostConstruct
;
import
java.text.SimpleDateFormat
;
import
java.util.Date
;
import
java.util.Locale
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.concurrent.locks.Lock
;
import
java.util.concurrent.locks.ReentrantLock
;
/**
* 注意事项:
* 1. 使用前在配置文件内配置 DATA_CENTER_ID
* <p>
* <p>
*
* @author zhiguo.liu
* @date 2017/5/18
*/
@Slf4j
@Component
@ConditionalOnClass
(
RedisTemplate
.
class
)
@ConditionalOnProperty
(
name
=
"data.center.id"
)
public
class
OIDGenerator
{
private
static
final
String
REDIS_WORK_ID_KEY
=
"GLOBAL:WORK:ID:"
;
private
static
final
String
ID_FORMAT
=
"yyyyMMddHHmmss"
;
private
static
Lock
lock
=
new
ReentrantLock
();
/**
* data center,默认为 1
*/
private
static
int
DATA_CENTER_ID
=
1
;
/**
* 最高支持同时1W台机器
*/
private
static
final
int
MAX_WORK_ID
=
10000
;
/**
* 最高每秒发号 100w
*/
private
static
final
int
MAX_COUNT
=
999999
;
private
static
AtomicInteger
COUNTER
=
new
AtomicInteger
(
0
);
private
static
long
MAX_TIME_SECOND
;
/**
* Worker ID 字符串
*/
private
static
String
WORKER_ID_STR
;
/**
* data center 字符串
*/
private
static
String
DATA_CENTER_STR
;
/**
* 最长回退时间,120 秒
*/
private
static
int
MAX_BACK_SECOND
=
120
;
static
{
Date
now
=
new
Date
();
MAX_TIME_SECOND
=
now
.
getTime
()
/
1000
;
}
private
static
LoadingCache
cache
=
CacheBuilder
.
newBuilder
()
.
expireAfterWrite
(
MAX_BACK_SECOND
,
TimeUnit
.
SECONDS
)
.
build
(
new
CacheLoader
<
Long
,
AtomicInteger
>()
{
@Override
public
AtomicInteger
load
(
Long
key
)
throws
Exception
{
return
new
AtomicInteger
(
0
);
}
});
@Autowired
private
StringRedisTemplate
redis
;
@Value
(
"${data.center.id}"
)
public
void
setDataCenterId
(
Integer
dataCenterId
)
{
DATA_CENTER_ID
=
dataCenterId
;
}
@PostConstruct
public
void
init
()
{
int
workerId
=
(
int
)
(
redis
.
opsForValue
().
increment
(
REDIS_WORK_ID_KEY
+
DATA_CENTER_ID
,
1
)
%
MAX_WORK_ID
);
WORKER_ID_STR
=
String
.
format
(
"%04d"
,
workerId
);
DATA_CENTER_STR
=
String
.
format
(
"%03d"
,
DATA_CENTER_ID
);
}
/**
* 1. 需要获取 dataCenterId 和 workeId
*/
public
static
String
getId
(
String
prefix
)
{
Date
now
=
new
Date
();
Long
timeSecond
=
now
.
getTime
()
/
1000
;
Integer
counter
=
0
;
if
(
timeSecond
>
MAX_TIME_SECOND
)
{
lock
.
lock
();
if
(
timeSecond
>
MAX_TIME_SECOND
)
{
cache
.
put
(
MAX_TIME_SECOND
,
COUNTER
);
COUNTER
=
new
AtomicInteger
(
0
);
MAX_TIME_SECOND
=
timeSecond
;
}
lock
.
unlock
();
}
if
(
timeSecond
==
MAX_TIME_SECOND
)
{
counter
=
COUNTER
.
incrementAndGet
();
}
// 时间回退时到 cache 里拿,或者直接抛出错误
if
(
timeSecond
<
MAX_TIME_SECOND
)
{
if
(
timeSecond
+
MAX_BACK_SECOND
<
MAX_TIME_SECOND
)
{
throw
new
RuntimeException
(
"时间回撤, 请稍后再试"
);
}
try
{
AtomicInteger
historyCounter
=
(
AtomicInteger
)
cache
.
get
(
timeSecond
);
counter
=
historyCounter
.
incrementAndGet
();
}
catch
(
ExecutionException
e
)
{
log
.
error
(
"取出缓存时出错"
);
}
}
// 达到计数器上上限, 休眠半秒并重试
if
(
counter
>=
MAX_COUNT
)
{
try
{
Thread
.
sleep
(
500
);
return
getId
(
prefix
);
}
catch
(
InterruptedException
e
)
{
log
.
error
(
"发号器休眠时发生错误:{}"
,
e
);
}
}
String
currentTimeStr
=
new
SimpleDateFormat
(
ID_FORMAT
,
Locale
.
SIMPLIFIED_CHINESE
).
format
(
now
);
return
prefix
+
currentTimeStr
+
DATA_CENTER_STR
+
WORKER_ID_STR
+
String
.
format
(
"%06d"
,
counter
);
}
}
commons-spring/src/main/java/cn/quantgroup/tech/util/id/BitsAllocator.java
deleted
100644 → 0
View file @
9b8246e4
package
cn
.
quantgroup
.
tech
.
util
.
id
;
import
org.apache.commons.lang3.builder.ToStringBuilder
;
import
org.apache.commons.lang3.builder.ToStringStyle
;
import
org.springframework.util.Assert
;
import
java.math.BigInteger
;
/**
* Allocate 64 bits for the UID(long)<br>
* sign (fixed 1bit) -> deltaSecond -> workerId -> sequence(within the same second)
*/
public
class
BitsAllocator
{
/**
* Total 64 bits
* dataCenterIdBits + workerIdBits + sequenceBits
*/
public
static
final
int
TOTAL_BITS
=
1
<<
6
;
private
final
int
timestampBits
;
private
final
int
dataCenterIdBits
;
private
final
int
workerIdBits
;
private
final
int
sequenceBits
;
/**
* Max value for dataCenterId & workerId & sequence
*/
private
final
long
maxDeltaSeconds
;
private
final
long
maxDataCenterId
;
private
final
long
maxWorkerId
;
private
final
long
maxSequence
;
/**
* Shift for dataCenterId & workerId & sequence
*/
private
final
int
timestampShift
;
private
final
int
dataCenterIdShift
;
private
final
int
workerIdShift
;
/**
* Constructor with timestampBits, workerIdBits, sequenceBits<br>
* The highest bit used for sign, so <code>63</code> bits for timestampBits, workerIdBits, sequenceBits
*/
public
BitsAllocator
(
int
timestampBits
,
int
dataCenterIdBits
,
int
workerIdBits
,
int
sequenceBits
)
{
// make sure allocated 64 bits
int
allocateTotalBits
=
dataCenterIdBits
+
workerIdBits
+
sequenceBits
;
Assert
.
isTrue
(
allocateTotalBits
+
1
<
TOTAL_BITS
,
"allocate greater than 64 bits"
);
// initialize bits
this
.
timestampBits
=
timestampBits
;
this
.
dataCenterIdBits
=
dataCenterIdBits
;
this
.
workerIdBits
=
workerIdBits
;
this
.
sequenceBits
=
sequenceBits
;
// initialize max value
this
.
maxDeltaSeconds
=
~(-
1L
<<
timestampBits
);
this
.
maxDataCenterId
=
~(-
1L
<<
dataCenterIdBits
);
this
.
maxWorkerId
=
~(-
1L
<<
workerIdBits
);
this
.
maxSequence
=
~(-
1L
<<
sequenceBits
);
// initialize shift
this
.
timestampShift
=
dataCenterIdBits
+
workerIdBits
+
sequenceBits
;
this
.
dataCenterIdShift
=
workerIdBits
+
sequenceBits
;
this
.
workerIdShift
=
sequenceBits
;
}
/**
* Allocate bits for UID according to delta seconds & workerId & sequence<br>
*
* @param deltaSeconds
* @param workerId
* @param sequence
* @return
*/
public
long
allocate
(
long
deltaSeconds
,
long
dataCenterId
,
long
workerId
,
long
sequence
)
{
return
(
deltaSeconds
<<
timestampShift
)
|
(
dataCenterId
<<
dataCenterIdShift
)
|
(
workerId
<<
workerIdShift
)
|
sequence
;
}
public
BigInteger
allocateBigInteger
(
long
deltaSeconds
,
long
dataCenterId
,
long
workerId
,
long
sequence
)
{
return
BigInteger
.
ZERO
.
or
(
BigInteger
.
valueOf
(
deltaSeconds
).
shiftLeft
(
timestampShift
))
.
or
(
BigInteger
.
valueOf
(
dataCenterId
).
shiftLeft
(
dataCenterIdShift
))
.
or
(
BigInteger
.
valueOf
(
workerId
).
shiftLeft
(
workerIdShift
))
.
or
(
BigInteger
.
valueOf
(
sequence
));
}
public
int
getTimestampBits
()
{
return
timestampBits
;
}
public
int
getDataCenterIdBits
()
{
return
dataCenterIdBits
;
}
public
int
getWorkerIdBits
()
{
return
workerIdBits
;
}
public
int
getSequenceBits
()
{
return
sequenceBits
;
}
public
long
getMaxDeltaSeconds
()
{
return
maxDeltaSeconds
;
}
public
long
getMaxDataCenterId
()
{
return
maxDataCenterId
;
}
public
long
getMaxWorkerId
()
{
return
maxWorkerId
;
}
public
long
getMaxSequence
()
{
return
maxSequence
;
}
public
int
getTimestampShift
()
{
return
timestampShift
;
}
public
int
getWorkerIdShift
()
{
return
workerIdShift
;
}
@Override
public
String
toString
()
{
return
ToStringBuilder
.
reflectionToString
(
this
,
ToStringStyle
.
SHORT_PREFIX_STYLE
);
}
}
\ No newline at end of file
commons-spring/src/main/java/cn/quantgroup/tech/util/id/IDGenerateException.java
deleted
100644 → 0
View file @
9b8246e4
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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.
*/
package
cn
.
quantgroup
.
tech
.
util
.
id
;
/**
* IDGenerateException
*/
public
class
IDGenerateException
extends
RuntimeException
{
/**
* Serial Version UID
*/
private
static
final
long
serialVersionUID
=
-
27048199131316992L
;
/**
* Default constructor
*/
public
IDGenerateException
()
{
super
();
}
/**
* Constructor with cause
*
* @param cause
*/
public
IDGenerateException
(
Throwable
cause
)
{
super
(
cause
);
}
}
idgenerator-spring-boot-starter/pom.xml
0 → 100644
View file @
e8f5fbb8
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<parent>
<artifactId>
commons-parent
</artifactId>
<groupId>
cn.quantgroup
</groupId>
<version>
0.2.1
</version>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<artifactId>
idgenerator-spring-boot-starter
</artifactId>
<dependencies>
<dependency>
<groupId>
org.springframework.data
</groupId>
<artifactId>
spring-data-redis
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.apache.commons
</groupId>
<artifactId>
commons-lang3
</artifactId>
<version>
3.7
</version>
<scope>
compile
</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
commons-spring/src/main/java/cn/quantgroup/tech/util/id
/IDGenerator.java
→
idgenerator-spring-boot-starter/src/main/java/cn/quantgroup/tech/generator
/IDGenerator.java
View file @
e8f5fbb8
package
cn
.
quantgroup
.
tech
.
util
.
id
;
package
cn
.
quantgroup
.
tech
.
generator
;
import
org.apache.commons.lang3.StringUtils
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.time.DateFormatUtils
;
import
org.apache.commons.lang3.time.DateUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnClass
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.data.redis.core.StringRedisTemplate
;
import
org.springframework.stereotype.Component
;
import
org.springframework.util.Assert
;
import
java.math.BigInteger
;
import
java.text.ParseException
;
import
java.util.Date
;
import
java.util.concurrent.TimeUnit
;
...
...
@@ -57,65 +44,41 @@ import java.util.concurrent.TimeUnit;
*
* @author zhiguo.liu
*/
@Component
@ConditionalOnClass
(
RedisTemplate
.
class
)
@ConditionalOnProperty
(
name
=
"id.epochStr"
)
public
class
IDGenerator
implements
InitializingBean
{
@Slf4j
public
class
IDGenerator
{
private
static
final
String
DATETIME_PATTERN
=
"yyyy-MM-dd HH:mm:ss"
;
private
static
final
String
DAY_PATTERN
=
"yyyy-MM-dd"
;
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
IDGenerator
.
class
);
private
static
final
String
REDIS_WORK_ID_KEY
=
"GLOBAL:WORK:ID:"
;
/**
* Bits allocate
*/
@Value
(
"${id.dataCenterIdBits:0}"
)
protected
int
dataCenterIdBits
;
@Value
(
"${id.seqBits:13}"
)
protected
int
seqBits
;
@Value
(
"${id.workerBits:8}"
)
protected
int
workerBits
;
protected
static
long
DATA_CENTER_ID
;
private
long
dataCenterId
;
/**
* Customer epoch, unit as second. For example 2018-03-01 (ms: 1463673600000)
*/
protected
String
epochStr
;
private
static
long
EPOCH_SECONDS
;
private
long
epochSeconds
;
/**
* Stable fields after spring bean initializing
*/
private
static
BitsAllocator
ALLOCATOR
;
private
static
long
WORKER_ID
;
private
BitsAllocator
allocator
;
private
long
workerId
;
/**
* Volatile fields caused by nextId()
*/
private
static
long
SEQUENCE
=
0L
;
private
static
long
LAST_SECOND
=
-
1L
;
/**
* Spring property
*/
@Autowired
private
StringRedisTemplate
redisTemplate
;
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
// initialize bits allocator
int
timeBits
=
64
-
1
-
dataCenterIdBits
-
workerBits
-
seqBits
;
ALLOCATOR
=
new
BitsAllocator
(
timeBits
,
dataCenterIdBits
,
workerBits
,
seqBits
);
// initialize worker id
WORKER_ID
=
redisTemplate
.
opsForValue
().
increment
(
REDIS_WORK_ID_KEY
+
DATA_CENTER_ID
,
1
)
%
ALLOCATOR
.
getMaxWorkerId
();
Assert
.
isTrue
(
WORKER_ID
<
ALLOCATOR
.
getMaxWorkerId
(),
"WORKER_ID is too big"
);
Assert
.
isTrue
(
ALLOCATOR
.
getMaxDataCenterId
()
!=
0
&&
DATA_CENTER_ID
<
ALLOCATOR
.
getMaxDataCenterId
(),
"DATA_CENTER_ID is too big"
);
LOGGER
.
info
(
"Initialized bits dataCenterBits:{}, workerBits:{}, seqBits:{}"
,
dataCenterIdBits
,
workerBits
,
seqBits
);
LOGGER
.
info
(
"Initialized nodes, WORKER_ID:{}, DATA_CENTER_ID:{}"
,
WORKER_ID
,
DATA_CENTER_ID
);
private
long
sequence
=
0L
;
private
long
lastSecond
=
-
1L
;
public
IDGenerator
(
Long
dataCenterId
,
Long
epochSeconds
,
Long
workerId
,
BitsAllocator
allocator
)
{
this
.
dataCenterId
=
dataCenterId
;
this
.
epochSeconds
=
epochSeconds
;
this
.
workerId
=
workerId
;
this
.
allocator
=
allocator
;
}
public
String
getID
(
String
prefix
)
throws
IDGenerateException
{
try
{
return
nextId
(
prefix
);
}
catch
(
Exception
e
)
{
LOGGER
.
error
(
"Generate unique id exception. "
,
e
);
log
.
error
(
"Generate unique id exception. "
,
e
);
throw
new
IDGenerateException
(
e
);
}
}
...
...
@@ -124,9 +87,9 @@ public class IDGenerator implements InitializingBean {
BigInteger
bigInteger
=
new
BigInteger
(
idStr
);
int
totalBits
=
bigInteger
.
bitLength
();
long
dataCenterIdBits
=
ALLOCATOR
.
getDataCenterIdBits
();
long
workerIdBits
=
ALLOCATOR
.
getWorkerIdBits
();
long
sequenceBits
=
ALLOCATOR
.
getSequenceBits
();
long
dataCenterIdBits
=
allocator
.
getDataCenterIdBits
();
long
workerIdBits
=
allocator
.
getWorkerIdBits
();
long
sequenceBits
=
allocator
.
getSequenceBits
();
if
(
totalBits
<
64
)
{
totalBits
=
64
;
long
id
=
bigInteger
.
longValue
();
...
...
@@ -137,7 +100,7 @@ public class IDGenerator implements InitializingBean {
dataCenterId
=
0
;
}
long
deltaSeconds
=
id
>>>
(
dataCenterIdBits
+
workerIdBits
+
sequenceBits
);
Date
thatTime
=
new
Date
(
TimeUnit
.
SECONDS
.
toMillis
(
EPOCH_SECONDS
+
deltaSeconds
));
Date
thatTime
=
new
Date
(
TimeUnit
.
SECONDS
.
toMillis
(
epochSeconds
+
deltaSeconds
));
String
thatTimeStr
=
DateFormatUtils
.
format
(
thatTime
,
DATETIME_PATTERN
);
return
String
.
format
(
"{\"ID\":\"%d\",\"timestamp\":\"%s\",\"DATA_CENTER_ID\":\"%d\",\"WORKER_ID\":\"%d\",\"SEQUENCE\":\"%d\"}"
,
id
,
thatTimeStr
,
dataCenterId
,
workerId
,
sequence
);
...
...
@@ -149,7 +112,7 @@ public class IDGenerator implements InitializingBean {
dataCenterId
=
0
;
}
long
deltaSeconds
=
bigInteger
.
shiftRight
((
int
)
dataCenterIdBits
+
(
int
)
workerIdBits
+
(
int
)
sequenceBits
).
longValue
();
Date
thatTime
=
new
Date
(
TimeUnit
.
SECONDS
.
toMillis
(
EPOCH_SECONDS
+
deltaSeconds
));
Date
thatTime
=
new
Date
(
TimeUnit
.
SECONDS
.
toMillis
(
epochSeconds
+
deltaSeconds
));
String
thatTimeStr
=
DateFormatUtils
.
format
(
thatTime
,
DATETIME_PATTERN
);
return
String
.
format
(
"{\"ID\":\"%d\",\"timestamp\":\"%s\",\"DATA_CENTER_ID\":\"%d\",\"WORKER_ID\":\"%d\",\"SEQUENCE\":\"%d\"}"
,
bigInteger
,
thatTimeStr
,
dataCenterId
,
workerId
,
sequence
);
...
...
@@ -170,29 +133,29 @@ public class IDGenerator implements InitializingBean {
long
currentSecond
=
getCurrentSecond
();
// Clock moved backwards, wait for newest time
if
(
currentSecond
<
LAST_SECOND
)
{
getNextSecond
(
LAST_SECOND
);
if
(
currentSecond
<
lastSecond
)
{
getNextSecond
(
lastSecond
);
}
// At the same second, increase SEQUENCE
if
(
currentSecond
==
LAST_SECOND
)
{
SEQUENCE
=
(
SEQUENCE
+
1
)
&
ALLOCATOR
.
getMaxSequence
();
if
(
currentSecond
==
lastSecond
)
{
sequence
=
(
sequence
+
1
)
&
allocator
.
getMaxSequence
();
// Exceed the max SEQUENCE, we wait the next second to generate ID
if
(
SEQUENCE
==
0
)
{
currentSecond
=
getNextSecond
(
LAST_SECOND
);
if
(
sequence
==
0
)
{
currentSecond
=
getNextSecond
(
lastSecond
);
}
// At the different second, SEQUENCE restart from zero
}
else
{
SEQUENCE
=
0L
;
sequence
=
0L
;
}
LAST_SECOND
=
currentSecond
;
lastSecond
=
currentSecond
;
// 当前时间小于设定的最大时间,即总位数在 64 位以下,用 long 生成数字
if
(
currentSecond
-
EPOCH_SECONDS
<=
ALLOCATOR
.
getMaxDeltaSeconds
())
{
return
preFix
+
ALLOCATOR
.
allocate
(
currentSecond
-
EPOCH_SECONDS
,
DATA_CENTER_ID
,
WORKER_ID
,
SEQUENCE
);
if
(
currentSecond
-
epochSeconds
<=
allocator
.
getMaxDeltaSeconds
())
{
return
preFix
+
allocator
.
allocate
(
currentSecond
-
epochSeconds
,
dataCenterId
,
workerId
,
sequence
);
}
return
preFix
+
ALLOCATOR
.
allocateBigInteger
(
currentSecond
-
EPOCH_SECONDS
,
DATA_CENTER_ID
,
WORKER_ID
,
SEQUENCE
);
return
preFix
+
allocator
.
allocateBigInteger
(
currentSecond
-
epochSeconds
,
dataCenterId
,
workerId
,
sequence
);
}
/**
...
...
@@ -214,21 +177,4 @@ public class IDGenerator implements InitializingBean {
return
TimeUnit
.
MILLISECONDS
.
toSeconds
(
System
.
currentTimeMillis
());
}
@Value
(
"${data.center.id}"
)
public
void
setDataCenterId
(
Integer
dataCenterId
)
{
DATA_CENTER_ID
=
dataCenterId
;
}
@Value
(
"${id.epochStr:2018-04-01}"
)
public
void
setEpochStr
(
String
epochStr
)
{
if
(
StringUtils
.
isNotBlank
(
epochStr
))
{
this
.
epochStr
=
epochStr
;
try
{
EPOCH_SECONDS
=
TimeUnit
.
MILLISECONDS
.
toSeconds
(
DateUtils
.
parseDate
(
epochStr
,
new
String
[]{
DAY_PATTERN
}).
getTime
());
}
catch
(
ParseException
e
)
{
e
.
printStackTrace
();
}
}
}
}
idgenerator-spring-boot-starter/src/main/java/cn/quantgroup/tech/generator/configuration/GeneratorAutoConfiguration.java
0 → 100644
View file @
e8f5fbb8
package
cn
.
quantgroup
.
tech
.
generator
.
configuration
;
import
lombok.Data
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnClass
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.boot.context.properties.EnableConfigurationProperties
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.data.redis.core.StringRedisTemplate
;
/**
* 只要有 redis 就可以使用id generator
*
* @author zhiguo.liu
*/
@ConditionalOnClass
(
RedisTemplate
.
class
)
@EnableConfigurationProperties
(
GeneratorAutoConfiguration
.
IdGeneratorProperties
.
class
)
public
class
GeneratorAutoConfiguration
{
private
StringRedisTemplate
redisTemplate
;
@Autowired
public
void
setApplicationContext
(
ApplicationContext
applicationContext
)
{
redisTemplate
=
applicationContext
.
getBean
(
StringRedisTemplate
.
class
);
}
@Bean
public
GeneratorFactoryBean
generatorFactoryBean
(
IdGeneratorProperties
properties
)
{
return
GeneratorFactoryBean
.
builder
()
.
dataCenterId
(
properties
.
getDataCenter
())
.
dataCenterIdBits
(
properties
.
getDataCenterIdBits
())
.
epochStr
(
properties
.
getEpochStr
())
.
seqBits
(
properties
.
getSeqBits
())
.
workerBits
(
properties
.
getWorkerBits
())
.
stringRedisTemplate
(
redisTemplate
)
.
build
();
}
@Data
@ConfigurationProperties
(
prefix
=
"tech.id"
)
protected
static
class
IdGeneratorProperties
{
/**
* 这里每个服务都需要单独配置一个
*/
private
int
dataCenter
=
1
;
/**
* 下面每一个配置,如果不懂就不建议修改.
* dataCenterIdBits 1024个服务
*/
private
int
dataCenterIdBits
=
10
;
private
int
seqBits
=
13
;
private
int
workerBits
=
8
;
private
String
epochStr
=
"2018-04-01"
;
}
}
idgenerator-spring-boot-starter/src/main/java/cn/quantgroup/tech/generator/configuration/GeneratorFactoryBean.java
0 → 100644
View file @
e8f5fbb8
package
cn
.
quantgroup
.
tech
.
generator
.
configuration
;
import
cn.quantgroup.tech.generator.BitsAllocator
;
import
cn.quantgroup.tech.generator.IDGenerator
;
import
lombok.Builder
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.time.DateUtils
;
import
org.springframework.beans.factory.FactoryBean
;
import
org.springframework.beans.factory.InitializingBean
;
import
org.springframework.data.redis.core.StringRedisTemplate
;
import
org.springframework.util.Assert
;
import
java.util.concurrent.TimeUnit
;
@Slf4j
@Builder
public
class
GeneratorFactoryBean
implements
FactoryBean
<
IDGenerator
>,
InitializingBean
{
private
static
final
String
REDIS_WORK_ID_KEY
=
"GLOBAL:WORK:ID:"
;
private
static
final
String
DAY_PATTERN
=
"yyyy-MM-dd"
;
/**
* from config
*/
private
int
dataCenterIdBits
;
private
int
seqBits
;
private
int
workerBits
;
private
long
dataCenterId
;
private
String
epochStr
;
private
long
workerId
;
private
StringRedisTemplate
stringRedisTemplate
;
/**
* local construct
*/
private
long
epochSeconds
;
private
BitsAllocator
allocator
;
private
IDGenerator
idGenerator
;
@Override
public
IDGenerator
getObject
()
throws
Exception
{
return
idGenerator
;
}
@Override
public
Class
<?>
getObjectType
()
{
return
IDGenerator
.
class
;
}
@Override
public
boolean
isSingleton
()
{
return
true
;
}
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
if
(
stringRedisTemplate
==
null
)
{
log
.
error
(
"redis template is null "
);
return
;
}
// initialize bits allocator
int
timeBits
=
64
-
1
-
dataCenterIdBits
-
workerBits
-
seqBits
;
allocator
=
new
BitsAllocator
(
timeBits
,
dataCenterIdBits
,
workerBits
,
seqBits
);
// initialize worker id
workerId
=
stringRedisTemplate
.
opsForValue
().
increment
(
REDIS_WORK_ID_KEY
+
dataCenterId
,
1
)
%
allocator
.
getMaxWorkerId
();
Assert
.
isTrue
(
workerId
<=
allocator
.
getMaxWorkerId
(),
"WORKER_ID is too big"
);
Assert
.
isTrue
(
dataCenterId
<=
allocator
.
getMaxDataCenterId
(),
"DATA_CENTER_ID is too big"
);
epochSeconds
=
TimeUnit
.
MILLISECONDS
.
toSeconds
(
DateUtils
.
parseDate
(
epochStr
,
new
String
[]{
DAY_PATTERN
}).
getTime
());
log
.
info
(
"Initialized bits dataCenterBits:{}, workerBits:{}, seqBits:{}"
,
dataCenterIdBits
,
workerBits
,
seqBits
);
log
.
info
(
"Initialized nodes, WORKER_ID:{}, DATA_CENTER_ID:{}"
,
workerId
,
dataCenterId
);
idGenerator
=
new
IDGenerator
(
dataCenterId
,
epochSeconds
,
workerId
,
allocator
);
}
}
idgenerator-spring-boot-starter/src/main/resources/META-INF/spring.factories
0 → 100644
View file @
e8f5fbb8
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.quantgroup.tech.generator.configuration.GeneratorAutoConfiguration
\ No newline at end of file
pom.xml
View file @
e8f5fbb8
...
...
@@ -19,6 +19,7 @@
<module>
commons-spring
</module>
<module>
shutdown-spring-boot-starter
</module>
<module>
brave-spring-boot-starter
</module>
<module>
idgenerator-spring-boot-starter
</module>
</modules>
<packaging>
pom
</packaging>
...
...
@@ -83,6 +84,11 @@
<artifactId>
brave-spring-boot-starter
</artifactId>
<version>
${common.parent.version}
</version>
</dependency>
<dependency>
<groupId>
cn.quantgroup
</groupId>
<artifactId>
idgenerator-spring-boot-starter
</artifactId>
<version>
${common.parent.version}
</version>
</dependency>
</dependencies>
</dependencyManagement>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment