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
344cb26a
Commit
344cb26a
authored
May 17, 2018
by
xiaoguang.xu
Browse files
Options
Browse Files
Download
Plain Diff
merge
parents
547ff863
3801dc72
Changes
34
Hide whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
1406 additions
and
254 deletions
+1406
-254
README.md
README.md
+22
-0
pom.xml
brave-spring-boot-starter/pom.xml
+110
-0
BraveAutoConfiguration.java
...roup/tech/brave/configuration/BraveAutoConfiguration.java
+284
-0
BraveProperties.java
.../cn/quantgroup/tech/brave/properties/BraveProperties.java
+30
-0
ServiceProperties.java
...n/quantgroup/tech/brave/properties/ServiceProperties.java
+19
-0
ITechRabbitBuilder.java
.../cn/quantgroup/tech/brave/service/ITechRabbitBuilder.java
+26
-0
TechRabbitBuilderNoTrace.java
...antgroup/tech/brave/service/TechRabbitBuilderNoTrace.java
+26
-0
TechRabbitBuilderTrace.java
...quantgroup/tech/brave/service/TechRabbitBuilderTrace.java
+33
-0
MDCCurrentTraceContext.java
...n/quantgroup/tech/brave/slf4j/MDCCurrentTraceContext.java
+126
-0
spring.factories
...boot-starter/src/main/resources/META-INF/spring.factories
+2
-0
pom.xml
commons-core/pom.xml
+1
-1
pom.xml
commons-spring/pom.xml
+8
-65
TechCommonAutoConfiguration.java
...group/tech/autoconfigure/TechCommonAutoConfiguration.java
+0
-20
HealthCheckMvcEndpoint.java
...a/cn/quantgroup/tech/endpoint/HealthCheckMvcEndpoint.java
+1
-0
IDGenerator.java
...ng/src/main/java/cn/quantgroup/tech/util/IDGenerator.java
+0
-152
pom.xml
idgenerator-spring-boot-starter/pom.xml
+31
-0
BitsAllocator.java
...main/java/cn/quantgroup/tech/generator/BitsAllocator.java
+129
-0
IDGenerateException.java
...ava/cn/quantgroup/tech/generator/IDGenerateException.java
+44
-0
IDGenerator.java
...c/main/java/cn/quantgroup/tech/generator/IDGenerator.java
+180
-0
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
+45
-6
pom.xml
shutdown-spring-boot-starter/pom.xml
+48
-0
BaseDestroyHandler.java
.../java/cn/quantgroup/tech/shutdown/BaseDestroyHandler.java
+58
-0
DefaultSignalHandler.java
...ava/cn/quantgroup/tech/shutdown/DefaultSignalHandler.java
+11
-5
GracefulShutdownAutoConfiguration.java
...down/configuration/GracefulShutdownAutoConfiguration.java
+28
-5
GracefulShutdownProperties.java
.../tech/shutdown/properties/GracefulShutdownProperties.java
+0
-0
JettyShutdown.java
...va/cn/quantgroup/tech/shutdown/service/JettyShutdown.java
+0
-0
Shutdown.java
...in/java/cn/quantgroup/tech/shutdown/service/Shutdown.java
+0
-0
TomcatShutdown.java
...a/cn/quantgroup/tech/shutdown/service/TomcatShutdown.java
+0
-0
UndertowShutdown.java
...cn/quantgroup/tech/shutdown/service/UndertowShutdown.java
+0
-0
UndertowShutdownHandlerWrapper.java
...tech/shutdown/wrapper/UndertowShutdownHandlerWrapper.java
+0
-0
spring.factories
...boot-starter/src/main/resources/META-INF/spring.factories
+2
-0
No files found.
README.md
0 → 100644
View file @
344cb26a
commons 简介
=====================
该项目主要利用 Spring Boot 的自动化配置特性.
集成了.
平滑退出/调用链追踪/唯一ID生成器/读写分离/健康检查/
Apollo 配置中心等功能
#基础依赖介绍
spring-boot-starter-parent 1.5.8
lombok 1.6.20
guava 23.0
#如何使用
[
使用说明见Confluence
](
http://confluence.quantgroup.cn/pages/viewpage.action?pageId=5458608
)
#贡献者
[
@张恒
](
heng.zhang@quantgroup.cn
)
[
@刘志国
](
zhiguo.liu@quantgroup.cn
)
[
@朱劲松
](
jinsong.liu@quantgroup.cn
)
brave-spring-boot-starter/pom.xml
0 → 100644
View file @
344cb26a
<?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.3
</version>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<artifactId>
brave-spring-boot-starter
</artifactId>
<properties>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
<brave.version>
4.19.1
</brave.version>
<zipkin-reporter2.version>
2.5.0
</zipkin-reporter2.version>
<zipkin.version>
2.6.1
</zipkin.version>
<okhttp.version>
3.10.0
</okhttp.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>
io.zipkin.reporter2
</groupId>
<artifactId>
zipkin-reporter
</artifactId>
<version>
${zipkin-reporter2.version}
</version>
</dependency>
<dependency>
<groupId>
io.zipkin.zipkin2
</groupId>
<artifactId>
zipkin
</artifactId>
<version>
${zipkin.version}
</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.apache.httpcomponents
</groupId>
<artifactId>
httpclient
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
com.squareup.okhttp3
</groupId>
<artifactId>
okhttp
</artifactId>
<version>
${okhttp.version}
</version>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.springframework.amqp
</groupId>
<artifactId>
spring-rabbit
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
io.zipkin.brave
</groupId>
<artifactId>
brave
</artifactId>
<version>
${brave.version}
</version>
</dependency>
<dependency>
<groupId>
io.zipkin.brave
</groupId>
<artifactId>
brave-spring-beans
</artifactId>
<version>
${brave.version}
</version>
</dependency>
<dependency>
<groupId>
io.zipkin.reporter2
</groupId>
<artifactId>
zipkin-sender-kafka11
</artifactId>
<version>
${zipkin-reporter2.version}
</version>
</dependency>
<dependency>
<groupId>
io.zipkin.brave
</groupId>
<artifactId>
brave-instrumentation-spring-web
</artifactId>
<version>
${brave.version}
</version>
</dependency>
<dependency>
<groupId>
io.zipkin.brave
</groupId>
<artifactId>
brave-instrumentation-spring-webmvc
</artifactId>
<version>
${brave.version}
</version>
</dependency>
<dependency>
<groupId>
io.zipkin.brave
</groupId>
<artifactId>
brave-instrumentation-httpclient
</artifactId>
<version>
${brave.version}
</version>
</dependency>
<dependency>
<groupId>
io.zipkin.brave
</groupId>
<artifactId>
brave-instrumentation-mysql
</artifactId>
<version>
${brave.version}
</version>
</dependency>
<dependency>
<groupId>
io.zipkin.brave
</groupId>
<artifactId>
brave-instrumentation-okhttp3
</artifactId>
<version>
${brave.version}
</version>
</dependency>
<dependency>
<groupId>
io.zipkin.brave
</groupId>
<artifactId>
brave-instrumentation-spring-rabbit
</artifactId>
<version>
${brave.version}
</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
brave-spring-boot-starter/src/main/java/cn/quantgroup/tech/brave/configuration/BraveAutoConfiguration.java
0 → 100644
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
brave
.
configuration
;
import
brave.Tracing
;
import
brave.http.HttpTracing
;
import
brave.httpclient.TracingHttpClientBuilder
;
import
brave.okhttp3.TracingInterceptor
;
import
brave.propagation.B3Propagation
;
import
brave.propagation.ExtraFieldPropagation
;
import
brave.spring.web.TracingClientHttpRequestInterceptor
;
import
brave.spring.webmvc.DelegatingTracingFilter
;
import
brave.spring.webmvc.SpanCustomizingAsyncHandlerInterceptor
;
import
cn.quantgroup.tech.brave.properties.BraveProperties
;
import
cn.quantgroup.tech.brave.properties.ServiceProperties
;
import
cn.quantgroup.tech.brave.service.ITechRabbitBuilder
;
import
cn.quantgroup.tech.brave.service.TechRabbitBuilderNoTrace
;
import
cn.quantgroup.tech.brave.service.TechRabbitBuilderTrace
;
import
cn.quantgroup.tech.brave.slf4j.MDCCurrentTraceContext
;
import
lombok.extern.slf4j.Slf4j
;
import
okhttp3.Dispatcher
;
import
okhttp3.OkHttpClient
;
import
org.apache.http.client.HttpClient
;
import
org.apache.http.impl.client.HttpClientBuilder
;
import
org.springframework.amqp.rabbit.core.RabbitTemplate
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnClass
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication
;
import
org.springframework.boot.context.properties.EnableConfigurationProperties
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Import
;
import
org.springframework.http.client.ClientHttpRequestInterceptor
;
import
org.springframework.web.client.RestTemplate
;
import
org.springframework.web.servlet.config.annotation.InterceptorRegistry
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
;
import
zipkin2.Span
;
import
zipkin2.codec.Encoding
;
import
zipkin2.reporter.AsyncReporter
;
import
zipkin2.reporter.Sender
;
import
zipkin2.reporter.kafka11.KafkaSender
;
import
javax.servlet.Filter
;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* 注册brave
*
* @author zhangheng
* create on 2018.04.25
*/
@Slf4j
@Configuration
public
class
BraveAutoConfiguration
{
@Configuration
public
static
class
BraveUntEnabled
{
@Configuration
@ConditionalOnClass
(
RabbitTemplate
.
class
)
@ConditionalOnProperty
(
prefix
=
"tech.brave"
,
name
=
"enabled"
,
havingValue
=
"false"
,
matchIfMissing
=
true
)
public
static
class
RabbitTemplateEnable
{
/**
* 提供RabbitTemplateBuilder,业务系统需要使用该Builder生成RabbitTemplate
*
* @return
*/
@Bean
(
name
=
"techRabbitBuilder"
)
public
ITechRabbitBuilder
techRabbitBuilder
()
{
return
new
TechRabbitBuilderNoTrace
();
}
}
@Configuration
@ConditionalOnClass
(
HttpClient
.
class
)
@ConditionalOnProperty
(
prefix
=
"tech.brave"
,
name
=
"enabled"
,
havingValue
=
"false"
,
matchIfMissing
=
true
)
public
static
class
HttpClientEnable
{
/**
* 提供HttpClientBuilderBean
*
* @return
*/
@Bean
(
name
=
"techHttpClientBuilder"
)
public
HttpClientBuilder
httpClientBuilder
()
{
log
.
info
(
"注册HttpClientBuilder"
);
return
HttpClientBuilder
.
create
();
}
}
@Configuration
@ConditionalOnClass
(
OkHttpClient
.
class
)
@ConditionalOnProperty
(
prefix
=
"tech.brave"
,
name
=
"enabled"
,
havingValue
=
"false"
,
matchIfMissing
=
true
)
public
static
class
OkHttpClientEnable
{
/**
* 提供OkHttpClientBean
*
* @return
*/
@Bean
(
name
=
"techOkHttpClientBuilder"
)
public
OkHttpClient
.
Builder
okHttpClientBuilder
()
{
log
.
info
(
"注册OkHttpClient.Builder"
);
return
new
OkHttpClient
.
Builder
();
}
}
@Configuration
@ConditionalOnClass
(
RestTemplate
.
class
)
@ConditionalOnProperty
(
prefix
=
"tech.brave"
,
name
=
"enabled"
,
havingValue
=
"false"
,
matchIfMissing
=
true
)
public
static
class
RestTemplateEnable
{
/**
* 提供RestTemplate
*
* @return
*/
@Bean
(
name
=
"techRestTemplate"
)
public
RestTemplate
restTemplate
()
{
log
.
info
(
"添加restTemplate拦截器"
);
return
new
RestTemplate
();
}
}
}
@Configuration
@EnableConfigurationProperties
({
BraveProperties
.
class
,
ServiceProperties
.
class
})
@ConditionalOnProperty
(
prefix
=
"tech.brave"
,
name
=
"enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
true
)
public
static
class
BraveEnabled
{
@Autowired
private
BraveProperties
braveProperties
;
@Autowired
private
ServiceProperties
serviceProperties
;
@Bean
@ConditionalOnMissingBean
Sender
sender
()
{
return
KafkaSender
.
newBuilder
().
bootstrapServers
(
braveProperties
.
getKafkaBootstrapServers
()).
topic
(
braveProperties
.
getKafkaTopic
()).
encoding
(
Encoding
.
JSON
).
build
();
}
@Bean
@ConditionalOnMissingBean
AsyncReporter
<
Span
>
spanReporter
()
{
return
AsyncReporter
.
create
(
sender
());
}
@Bean
@ConditionalOnMissingBean
Tracing
tracing
()
{
return
Tracing
.
newBuilder
()
.
sampler
(
brave
.
sampler
.
Sampler
.
create
(
braveProperties
.
getSample
()))
.
localServiceName
(
serviceProperties
.
getName
())
.
propagationFactory
(
ExtraFieldPropagation
.
newFactory
(
B3Propagation
.
FACTORY
,
"user-name"
))
.
currentTraceContext
(
MDCCurrentTraceContext
.
create
())
.
spanReporter
(
spanReporter
()).
build
();
}
@Bean
@ConditionalOnMissingBean
public
HttpTracing
httpTracing
(
Tracing
tracing
)
{
return
HttpTracing
.
create
(
tracing
);
}
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass
({
Filter
.
class
})
@ConditionalOnProperty
(
prefix
=
"tech.brave"
,
name
=
"enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
true
)
public
static
class
ServletEnable
{
/**
* 创建一个bean
*
* @return
*/
@Bean
(
name
=
"techDelegatingTracingFilter"
)
public
Filter
delegatingTracingFilter
()
{
log
.
info
(
"注册DelegatingTracingFilter"
);
return
new
DelegatingTracingFilter
();
}
}
@Configuration
@ConditionalOnClass
({
WebMvcConfigurerAdapter
.
class
})
@Import
(
SpanCustomizingAsyncHandlerInterceptor
.
class
)
@ConditionalOnProperty
(
prefix
=
"tech.brave"
,
name
=
"enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
true
)
public
static
class
WebMvcEnable
extends
WebMvcConfigurerAdapter
{
@Autowired
private
SpanCustomizingAsyncHandlerInterceptor
spanCustomizingAsyncHandlerInterceptor
;
@Override
public
void
addInterceptors
(
InterceptorRegistry
registry
)
{
log
.
info
(
"添加braveWebmvc拦截器"
);
registry
.
addInterceptor
(
spanCustomizingAsyncHandlerInterceptor
);
}
}
@Configuration
@ConditionalOnClass
(
RabbitTemplate
.
class
)
@ConditionalOnProperty
(
prefix
=
"tech.brave"
,
name
=
"enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
true
)
public
static
class
RabbitTemplateEnable
{
/**
* 提供RabbitTemplateBuilder,业务系统需要使用该Builder生成RabbitTemplate
*
* @param tracing
* @return
*/
@Bean
(
name
=
"techRabbitBuilder"
)
public
ITechRabbitBuilder
rabbitTemplateBuilder
(
Tracing
tracing
)
{
return
new
TechRabbitBuilderTrace
(
tracing
);
}
}
@Configuration
@ConditionalOnClass
(
HttpClient
.
class
)
@ConditionalOnProperty
(
prefix
=
"tech.brave"
,
name
=
"enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
true
)
public
static
class
HttpClientEnable
{
/**
* 提供HttpClientBuilderBean
*
* @param tracing
* @return
*/
@Bean
(
name
=
"techHttpClientBuilder"
)
public
HttpClientBuilder
httpClientBuilder
(
Tracing
tracing
)
{
log
.
info
(
"注册braveHttpClientBuilder"
);
return
TracingHttpClientBuilder
.
create
(
tracing
);
}
}
@Configuration
@ConditionalOnClass
(
OkHttpClient
.
class
)
@ConditionalOnProperty
(
prefix
=
"tech.brave"
,
name
=
"enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
true
)
public
static
class
OkHttpClientEnable
{
/**
* 提供OkHttpClientBean
*
* @param httpTracing
* @return
*/
@Bean
(
name
=
"techOkHttpClientBuilder"
)
public
OkHttpClient
.
Builder
okHttpClientBuilder
(
HttpTracing
httpTracing
)
{
log
.
info
(
"注册braveOkHttpClient.Builder"
);
return
new
OkHttpClient
.
Builder
()
.
dispatcher
(
new
Dispatcher
(
httpTracing
.
tracing
().
currentTraceContext
().
executorService
(
new
Dispatcher
().
executorService
())))
.
addNetworkInterceptor
(
TracingInterceptor
.
create
(
httpTracing
));
}
}
@Configuration
@ConditionalOnClass
(
RestTemplate
.
class
)
@ConditionalOnProperty
(
prefix
=
"tech.brave"
,
name
=
"enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
true
)
@Import
(
TracingClientHttpRequestInterceptor
.
class
)
public
static
class
RestTemplateEnable
{
@Autowired
private
TracingClientHttpRequestInterceptor
clientInterceptor
;
/**
* 提供RestTemplate
*
* @return
*/
@Bean
(
name
=
"techRestTemplate"
)
public
RestTemplate
restTemplate
()
{
log
.
info
(
"添加braveRestTemplate拦截器"
);
RestTemplate
restTemplate
=
new
RestTemplate
();
List
<
ClientHttpRequestInterceptor
>
interceptors
=
new
ArrayList
<>(
restTemplate
.
getInterceptors
());
interceptors
.
add
(
clientInterceptor
);
restTemplate
.
setInterceptors
(
interceptors
);
return
restTemplate
;
}
}
}
}
brave-spring-boot-starter/src/main/java/cn/quantgroup/tech/brave/properties/BraveProperties.java
0 → 100644
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
brave
.
properties
;
import
lombok.Data
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
/**
* brave配置信息
*
* @author zhangheng
* create on 2018.04.25
*/
@Data
@ConfigurationProperties
(
prefix
=
"tech.brave"
)
public
class
BraveProperties
{
/**
* kafka地址
*/
private
String
kafkaBootstrapServers
;
/**
* kafka的topic
*/
private
String
kafkaTopic
;
/**
* 采集率
*/
private
Float
sample
=
1.0f
;
}
brave-spring-boot-starter/src/main/java/cn/quantgroup/tech/brave/properties/ServiceProperties.java
0 → 100644
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
brave
.
properties
;
import
lombok.Data
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
/**
* brave配置信息
*
* @author zhangheng
* create on 2018.04.25
*/
@Data
@ConfigurationProperties
(
"spring.application"
)
public
class
ServiceProperties
{
/**
*
*/
String
name
;
}
brave-spring-boot-starter/src/main/java/cn/quantgroup/tech/brave/service/ITechRabbitBuilder.java
0 → 100644
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
brave
.
service
;
import
org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory
;
import
org.springframework.amqp.rabbit.connection.ConnectionFactory
;
import
org.springframework.amqp.rabbit.core.RabbitTemplate
;
/**
* @author zhangheng
* create on 2018.04.27
*/
public
interface
ITechRabbitBuilder
{
/**
* 构建RabbitTemplate
* @param connectionFactory
* @returne
*/
RabbitTemplate
createRabbitTemplate
(
ConnectionFactory
connectionFactory
);
/**
* 构建SimpleRabbitListenerContainerFactory
* @param connectionFactory
* @return
*/
SimpleRabbitListenerContainerFactory
createSimpleRabbitListenerContainerFactory
(
ConnectionFactory
connectionFactory
);
}
brave-spring-boot-starter/src/main/java/cn/quantgroup/tech/brave/service/TechRabbitBuilderNoTrace.java
0 → 100644
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
brave
.
service
;
import
org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory
;
import
org.springframework.amqp.rabbit.connection.ConnectionFactory
;
import
org.springframework.amqp.rabbit.core.RabbitTemplate
;
/**
* @author zhangheng
* create on 2018.04.27
*/
public
class
TechRabbitBuilderNoTrace
implements
ITechRabbitBuilder
{
public
TechRabbitBuilderNoTrace
()
{
}
@Override
public
RabbitTemplate
createRabbitTemplate
(
ConnectionFactory
connectionFactory
)
{
return
new
RabbitTemplate
(
connectionFactory
);
}
@Override
public
SimpleRabbitListenerContainerFactory
createSimpleRabbitListenerContainerFactory
(
ConnectionFactory
connectionFactory
)
{
SimpleRabbitListenerContainerFactory
factory
=
new
SimpleRabbitListenerContainerFactory
();
factory
.
setConnectionFactory
(
connectionFactory
);
return
factory
;
}
}
brave-spring-boot-starter/src/main/java/cn/quantgroup/tech/brave/service/TechRabbitBuilderTrace.java
0 → 100644
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
brave
.
service
;
import
brave.Tracing
;
import
brave.spring.rabbit.SpringRabbitTracing
;
import
org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory
;
import
org.springframework.amqp.rabbit.connection.ConnectionFactory
;
import
org.springframework.amqp.rabbit.core.RabbitTemplate
;
/**
* @author zhangheng
* create on 2018.04.27
*/
public
class
TechRabbitBuilderTrace
implements
ITechRabbitBuilder
{
private
SpringRabbitTracing
.
Builder
springRabbitTracingBuilder
;
public
TechRabbitBuilderTrace
(
Tracing
tracing
)
{
springRabbitTracingBuilder
=
SpringRabbitTracing
.
newBuilder
(
tracing
);
}
@Override
public
RabbitTemplate
createRabbitTemplate
(
ConnectionFactory
connectionFactory
)
{
String
virtualHost
=
connectionFactory
.
getVirtualHost
();
SpringRabbitTracing
.
Builder
builder
=
springRabbitTracingBuilder
.
remoteServiceName
(
"MQ-"
+
virtualHost
);
return
builder
.
build
().
newRabbitTemplate
(
connectionFactory
);
}
@Override
public
SimpleRabbitListenerContainerFactory
createSimpleRabbitListenerContainerFactory
(
ConnectionFactory
connectionFactory
)
{
String
virtualHost
=
connectionFactory
.
getVirtualHost
();
SpringRabbitTracing
.
Builder
builder
=
springRabbitTracingBuilder
.
remoteServiceName
(
"MQ-"
+
virtualHost
);
return
builder
.
build
().
newSimpleRabbitListenerContainerFactory
(
connectionFactory
);
}
}
brave-spring-boot-starter/src/main/java/cn/quantgroup/tech/brave/slf4j/MDCCurrentTraceContext.java
0 → 100644
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
brave
.
slf4j
;
import
brave.internal.HexCodec
;
import
brave.internal.Nullable
;
import
brave.propagation.CurrentTraceContext
;
import
brave.propagation.TraceContext
;
import
org.slf4j.MDC
;
import
static
brave
.
internal
.
HexCodec
.
lowerHexEqualsTraceId
;
import
static
brave
.
internal
.
HexCodec
.
lowerHexEqualsUnsignedLong
;
/**
* Adds {@linkplain MDC} properties TRACE_ID, PARENT_ID and SPAN_ID when a {@link
* brave.Tracer#currentSpan() span is current}. These can be used in log correlation.
*/
public
final
class
MDCCurrentTraceContext
extends
CurrentTraceContext
{
private
static
final
String
TRACE_ID
=
"X-B3-TraceId"
;
private
static
final
String
SPAN_ID
=
"X-B3-SpanId"
;
private
static
final
String
PARENT_ID
=
"X-B3-ParentId"
;
private
static
final
String
EXPORTABLE
=
"X-Span-Export"
;
public
static
MDCCurrentTraceContext
create
()
{
return
create
(
CurrentTraceContext
.
Default
.
inheritable
());
}
public
static
MDCCurrentTraceContext
create
(
CurrentTraceContext
delegate
)
{
return
new
MDCCurrentTraceContext
(
delegate
);
}
final
CurrentTraceContext
delegate
;
MDCCurrentTraceContext
(
CurrentTraceContext
delegate
)
{
if
(
delegate
==
null
)
throw
new
NullPointerException
(
"delegate == null"
);
this
.
delegate
=
delegate
;
}
@Override
public
TraceContext
get
()
{
return
delegate
.
get
();
}
@Override
public
Scope
newScope
(
@Nullable
TraceContext
currentSpan
)
{
return
newScope
(
currentSpan
,
MDC
.
get
(
TRACE_ID
),
MDC
.
get
(
SPAN_ID
),
MDC
.
get
(
EXPORTABLE
));
}
@Override
public
Scope
maybeScope
(
@Nullable
TraceContext
currentSpan
)
{
String
previousTraceId
=
MDC
.
get
(
TRACE_ID
);
String
previousSpanId
=
MDC
.
get
(
SPAN_ID
);
String
sampled
=
MDC
.
get
(
EXPORTABLE
);
if
(
currentSpan
==
null
)
{
if
(
previousTraceId
==
null
)
{
return
Scope
.
NOOP
;
}
return
newScope
(
null
,
previousTraceId
,
previousSpanId
,
sampled
);
}
if
(
lowerHexEqualsTraceId
(
previousTraceId
,
currentSpan
)
&&
lowerHexEqualsUnsignedLong
(
previousSpanId
,
currentSpan
.
spanId
()))
{
return
Scope
.
NOOP
;
}
return
newScope
(
currentSpan
,
previousTraceId
,
previousSpanId
,
sampled
);
}
// all input parameters are nullable
Scope
newScope
(
TraceContext
currentSpan
,
String
previousTraceId
,
String
previousSpanId
,
String
sampled
)
{
String
previousParentId
=
MDC
.
get
(
PARENT_ID
);
if
(
currentSpan
!=
null
)
{
maybeReplaceTraceContext
(
currentSpan
,
previousTraceId
,
previousParentId
,
previousSpanId
,
sampled
);
}
else
{
MDC
.
remove
(
TRACE_ID
);
MDC
.
remove
(
PARENT_ID
);
MDC
.
remove
(
SPAN_ID
);
MDC
.
remove
(
EXPORTABLE
);
}
Scope
scope
=
delegate
.
newScope
(
currentSpan
);
class
MDCCurrentTraceContextScope
implements
Scope
{
@Override
public
void
close
()
{
scope
.
close
();
replace
(
TRACE_ID
,
previousTraceId
);
replace
(
PARENT_ID
,
previousParentId
);
replace
(
SPAN_ID
,
previousSpanId
);
//true = 采样了. false = 未采样. null = 决定不了...等会再说
replace
(
EXPORTABLE
,
sampled
);
}
}
return
new
MDCCurrentTraceContextScope
();
}
void
maybeReplaceTraceContext
(
TraceContext
currentSpan
,
String
previousTraceId
,
@Nullable
String
previousParentId
,
String
previousSpanId
,
@Nullable
String
sampled
)
{
MDC
.
put
(
EXPORTABLE
,
String
.
valueOf
(
currentSpan
.
sampled
()));
boolean
sameTraceId
=
lowerHexEqualsTraceId
(
previousTraceId
,
currentSpan
);
if
(!
sameTraceId
)
{
MDC
.
put
(
TRACE_ID
,
currentSpan
.
traceIdString
());
}
long
parentId
=
currentSpan
.
parentIdAsLong
();
if
(
parentId
==
0L
)
{
MDC
.
remove
(
PARENT_ID
);
}
else
{
boolean
sameParentId
=
lowerHexEqualsUnsignedLong
(
previousParentId
,
parentId
);
if
(!
sameParentId
)
MDC
.
put
(
PARENT_ID
,
HexCodec
.
toLowerHex
(
parentId
));
}
boolean
sameSpanId
=
lowerHexEqualsUnsignedLong
(
previousSpanId
,
currentSpan
.
spanId
());
if
(!
sameSpanId
)
MDC
.
put
(
SPAN_ID
,
HexCodec
.
toLowerHex
(
currentSpan
.
spanId
()));
}
static
void
replace
(
String
key
,
@Nullable
String
value
)
{
if
(
value
!=
null
)
{
MDC
.
put
(
key
,
value
);
}
else
{
MDC
.
remove
(
key
);
}
}
}
brave-spring-boot-starter/src/main/resources/META-INF/spring.factories
0 → 100644
View file @
344cb26a
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.quantgroup.tech.brave.configuration.BraveAutoConfiguration
\ No newline at end of file
commons-core/pom.xml
View file @
344cb26a
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
<parent>
<parent>
<artifactId>
commons-parent
</artifactId>
<artifactId>
commons-parent
</artifactId>
<groupId>
cn.quantgroup
</groupId>
<groupId>
cn.quantgroup
</groupId>
<version>
0.
1.4
</version>
<version>
0.
2.3
</version>
</parent>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<modelVersion>
4.0.0
</modelVersion>
...
...
commons-spring/pom.xml
View file @
344cb26a
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
<parent>
<parent>
<artifactId>
commons-parent
</artifactId>
<artifactId>
commons-parent
</artifactId>
<groupId>
cn.quantgroup
</groupId>
<groupId>
cn.quantgroup
</groupId>
<version>
0.
1.4
</version>
<version>
0.
2.3
</version>
</parent>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<modelVersion>
4.0.0
</modelVersion>
...
@@ -31,45 +31,17 @@
...
@@ -31,45 +31,17 @@
</dependencyManagement>
</dependencyManagement>
<dependencies>
<dependencies>
<!--健康检查需要-->
<dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
<artifactId>
spring-boot-starter-actuator
</artifactId>
<scope>
compile
</scope>
<exclusions>
<exclusion>
<artifactId>
spring-boot-starter-tomcat
</artifactId>
<groupId>
*
</groupId>
</exclusion>
<exclusion>
<artifactId>
jboss-servlet-api_3.1_spec
</artifactId>
<groupId>
org.jboss.spec.javax.servlet
</groupId>
</exclusion>
<exclusion>
<artifactId>
commons-logging
</artifactId>
<groupId>
commons-logging
</groupId>
</exclusion>
<exclusion>
<artifactId>
annotations
</artifactId>
<groupId>
com.google.code.findbugs
</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-tomcat
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-undertow
</artifactId>
<optional>
true
</optional>
</dependency>
</dependency>
<dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-
jetty
</artifactId>
<artifactId>
spring-boot-starter-
web
</artifactId>
<optional>
true
</optional>
<optional>
true
</optional>
</dependency>
</dependency>
<dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-security
</artifactId>
<artifactId>
spring-boot-starter-security
</artifactId>
...
@@ -80,11 +52,6 @@
...
@@ -80,11 +52,6 @@
<artifactId>
spring-boot-starter-data-redis
</artifactId>
<artifactId>
spring-boot-starter-data-redis
</artifactId>
<optional>
true
</optional>
<optional>
true
</optional>
</dependency>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-actuator
</artifactId>
<scope>
compile
</scope>
</dependency>
<dependency>
<dependency>
<groupId>
com.alibaba
</groupId>
<groupId>
com.alibaba
</groupId>
<artifactId>
fastjson
</artifactId>
<artifactId>
fastjson
</artifactId>
...
@@ -111,23 +78,6 @@
...
@@ -111,23 +78,6 @@
<scope>
compile
</scope>
<scope>
compile
</scope>
</dependency>
</dependency>
<dependency>
<groupId>
com.google.guava
</groupId>
<artifactId>
guava
</artifactId>
<version>
${guava.version}
</version>
</dependency>
<dependency>
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
<version>
1.16.16
</version>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-amqp
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-test
</artifactId>
<artifactId>
spring-boot-starter-test
</artifactId>
...
@@ -135,18 +85,11 @@
...
@@ -135,18 +85,11 @@
</dependency>
</dependency>
<dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-sleuth-stream
</artifactId>
<artifactId>
spring-cloud-starter
</artifactId>
<scope>
compile
</scope>
</dependency>
</dependency>
<dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-cloud-starter-sleuth
</artifactId>
<artifactId>
spring-boot-starter-aop
</artifactId>
<scope>
compile
</scope>
</dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-starter-stream-kafka
</artifactId>
<scope>
compile
</scope>
</dependency>
</dependency>
<dependency>
<dependency>
<groupId>
org.springframework
</groupId>
<groupId>
org.springframework
</groupId>
...
...
commons-spring/src/main/java/cn/quantgroup/tech/autoconfigure/TechCommonAutoConfiguration.java
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
autoconfigure
;
package
cn
.
quantgroup
.
tech
.
autoconfigure
;
import
cn.quantgroup.tech.endpoint.HealthCheckMvcEndpoint
;
import
cn.quantgroup.tech.endpoint.HealthCheckMvcEndpoint
;
import
cn.quantgroup.tech.shutdown.DefaultSignalHandler
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.actuate.endpoint.EndpointProperties
;
import
org.springframework.boot.actuate.endpoint.EndpointProperties
;
import
org.springframework.boot.autoconfigure.AutoConfigureAfter
;
import
org.springframework.boot.autoconfigure.AutoConfigureAfter
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration
;
import
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration
;
import
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration
;
import
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration
;
import
org.springframework.boot.context.properties.EnableConfigurationProperties
;
import
org.springframework.boot.context.properties.EnableConfigurationProperties
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.ConfigurableApplicationContext
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
sun.misc.Signal
;
/**
/**
* @author jinsong.zhu
* @author jinsong.zhu
* @date 2017/12/18
* @date 2017/12/18
*/
*/
@Slf4j
@Configuration
@Configuration
@AutoConfigureAfter
({
FlywayAutoConfiguration
.
class
,
LiquibaseAutoConfiguration
.
class
})
@AutoConfigureAfter
({
FlywayAutoConfiguration
.
class
,
LiquibaseAutoConfiguration
.
class
})
@EnableConfigurationProperties
(
EndpointProperties
.
class
)
@EnableConfigurationProperties
(
EndpointProperties
.
class
)
public
class
TechCommonAutoConfiguration
{
public
class
TechCommonAutoConfiguration
{
ConfigurableApplicationContext
applicationContext
;
@Autowired
public
void
setApplicationContext
(
ApplicationContext
applicationContext
)
{
this
.
applicationContext
=
(
ConfigurableApplicationContext
)
applicationContext
;
initSignalHandler
(
this
.
applicationContext
);
}
private
void
initSignalHandler
(
ConfigurableApplicationContext
applicationContext
)
{
log
.
info
(
"starting init graceful shutdown by listening on int signal ."
);
Signal
.
handle
(
new
Signal
(
"INT"
),
new
DefaultSignalHandler
(
applicationContext
));
}
@Bean
@Bean
@ConditionalOnMissingBean
@ConditionalOnMissingBean
public
HealthCheckMvcEndpoint
healthCheckMvcEndpoint
()
{
public
HealthCheckMvcEndpoint
healthCheckMvcEndpoint
()
{
...
...
commons-spring/src/main/java/cn/quantgroup/tech/endpoint/HealthCheckMvcEndpoint.java
View file @
344cb26a
...
@@ -21,6 +21,7 @@ public class HealthCheckMvcEndpoint implements MvcEndpoint {
...
@@ -21,6 +21,7 @@ public class HealthCheckMvcEndpoint implements MvcEndpoint {
@RequestMapping
(
value
=
"check"
,
method
=
{
RequestMethod
.
GET
,
RequestMethod
.
POST
})
@RequestMapping
(
value
=
"check"
,
method
=
{
RequestMethod
.
GET
,
RequestMethod
.
POST
})
@ResponseBody
@ResponseBody
public
Result
check
()
{
public
Result
check
()
{
return
Result
.
ok
();
return
Result
.
ok
();
}
}
...
...
commons-spring/src/main/java/cn/quantgroup/tech/util/IDGenerator.java
deleted
100644 → 0
View file @
547ff863
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
IDGenerator
{
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
);
}
}
idgenerator-spring-boot-starter/pom.xml
0 → 100644
View file @
344cb26a
<?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.3
</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
idgenerator-spring-boot-starter/src/main/java/cn/quantgroup/tech/generator/BitsAllocator.java
0 → 100644
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
generator
;
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
idgenerator-spring-boot-starter/src/main/java/cn/quantgroup/tech/generator/IDGenerateException.java
0 → 100644
View file @
344cb26a
/*
* 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
.
generator
;
/**
* 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/src/main/java/cn/quantgroup/tech/generator/IDGenerator.java
0 → 100644
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
generator
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.time.DateFormatUtils
;
import
java.math.BigInteger
;
import
java.util.Date
;
import
java.util.concurrent.TimeUnit
;
/**
* Represents an implementation of {@link IDGenerator}
* 基于百度开源项目 uid-generator 的增强版,Snowflake Java 实现版本。项目 Github:https://github.com/baidu/uid-generator
* <p>
* uid-generator 通过对 64 位数字分区来生成唯一 ID,由以下组成:
* <p>
* -----------------------------------------------------------------------------------
* | sign | delta seconds | worker id | SEQUENCE
* -----------------------------------------------------------------------------------
* 1bits 28bits 22bits 13bits
* -----------------------------------------------------------------------------------
* 其中 delta seconds 为 当前时间 - 指定起始时间。
* 该版本有三个问题
* 1. delta seconds 位数有限,28bits 也只能允许运行 8.7 年左右。
* 2. worker id 生成号码为用后即弃,可容纳重启次数有限。
* 3. 微服务分布式的情况下,无法使用统一数据源,则不同服务生成 worker id 时会重复
* <p>
* 于是做出以下改进
* 1. worker id 拆分成 data center id,每个服务通过约定指定自己的 data center id 。
* 2. worker id 通过 redis 自增指定,设计为首尾相连的环形,自增数字达到设定的最大值时,会从0开始。
* 2. 不限制使用 delta seconds 的位数,则实现了无限时间的使用。当位数增长到 64 为后,改用 BigInteger 的位运算实现。
* <p>
* 经测试,BigInteger 实现时,性能降低 60% 左右,每秒发号约为 100w~150w。
* 现在 uid 由以下组成
* ---------------------------------------------------------------------------------------------------------
* | sign(length < 64) | delta seconds (unlimited) | data center id | worker id | SEQUENCE
* ---------------------------------------------------------------------------------------------------------
* 1bits 28bits 22bits 22bits 13bits
* ---------------------------------------------------------------------------------------------------------
* 其中 data center id + worker id + SEQUENCE 设定的位数不大于 63。
* <p>
* 使用注意:
* 1. 号码的位数不固定,会随着时间增长。data center id + worker id + SEQUENCE 总数设定越大,号码位数越长
* 2. 各个分区的位数、起始时间一旦设定完成投入使用,则后续不能更改。否则会导致发号重复。
*
* @author zhiguo.liu
*/
@Slf4j
public
class
IDGenerator
{
private
static
final
String
DATETIME_PATTERN
=
"yyyy-MM-dd HH:mm:ss"
;
private
long
dataCenterId
;
/**
* Customer epoch, unit as second. For example 2018-03-01 (ms: 1463673600000)
*/
private
long
epochSeconds
;
/**
* Stable fields after spring bean initializing
*/
private
BitsAllocator
allocator
;
private
long
workerId
;
/**
* Volatile fields caused by nextId()
*/
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
)
{
log
.
error
(
"Generate unique id exception. "
,
e
);
throw
new
IDGenerateException
(
e
);
}
}
public
String
parseID
(
String
idStr
)
{
BigInteger
bigInteger
=
new
BigInteger
(
idStr
);
int
totalBits
=
bigInteger
.
bitLength
();
long
dataCenterIdBits
=
allocator
.
getDataCenterIdBits
();
long
workerIdBits
=
allocator
.
getWorkerIdBits
();
long
sequenceBits
=
allocator
.
getSequenceBits
();
if
(
totalBits
<
64
)
{
totalBits
=
64
;
long
id
=
bigInteger
.
longValue
();
long
sequence
=
(
id
<<
(
totalBits
-
sequenceBits
))
>>>
(
totalBits
-
sequenceBits
);
long
workerId
=
(
id
<<
(
totalBits
-
workerIdBits
-
sequenceBits
))
>>>
(
totalBits
-
workerIdBits
);
long
dataCenterId
=
(
id
<<
(
totalBits
-
dataCenterIdBits
-
workerIdBits
-
sequenceBits
))
>>>
(
totalBits
-
dataCenterIdBits
);
if
(
dataCenterIdBits
==
0
)
{
dataCenterId
=
0
;
}
long
deltaSeconds
=
id
>>>
(
dataCenterIdBits
+
workerIdBits
+
sequenceBits
);
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
);
}
else
{
long
sequence
=
getBigIntegerFromLength
(
sequenceBits
).
and
(
bigInteger
).
longValue
();
long
workerId
=
getBigIntegerFromLength
(
workerIdBits
).
and
(
bigInteger
.
shiftRight
((
int
)
sequenceBits
)).
longValue
();
long
dataCenterId
=
getBigIntegerFromLength
(
dataCenterIdBits
).
and
(
bigInteger
.
shiftRight
((
int
)
sequenceBits
+
(
int
)
workerIdBits
)).
longValue
();
if
(
dataCenterIdBits
==
0
)
{
dataCenterId
=
0
;
}
long
deltaSeconds
=
bigInteger
.
shiftRight
((
int
)
dataCenterIdBits
+
(
int
)
workerIdBits
+
(
int
)
sequenceBits
).
longValue
();
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
);
}
}
private
BigInteger
getBigIntegerFromLength
(
long
n
)
{
return
BigInteger
.
valueOf
(-
1
).
shiftLeft
((
int
)
n
).
not
();
}
/**
* Get ID
*
* @return ID
* @throws IDGenerateException in the case: Clock moved backwards; Exceeds the max timestamp
*/
protected
synchronized
String
nextId
(
String
preFix
)
{
long
currentSecond
=
getCurrentSecond
();
// Clock moved backwards, wait for newest time
if
(
currentSecond
<
lastSecond
)
{
getNextSecond
(
lastSecond
);
}
// At the same second, increase SEQUENCE
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
(
lastSecond
);
}
// At the different second, SEQUENCE restart from zero
}
else
{
sequence
=
0L
;
}
lastSecond
=
currentSecond
;
// 当前时间小于设定的最大时间,即总位数在 64 位以下,用 long 生成数字
if
(
currentSecond
-
epochSeconds
<=
allocator
.
getMaxDeltaSeconds
())
{
return
preFix
+
allocator
.
allocate
(
currentSecond
-
epochSeconds
,
dataCenterId
,
workerId
,
sequence
);
}
return
preFix
+
allocator
.
allocateBigInteger
(
currentSecond
-
epochSeconds
,
dataCenterId
,
workerId
,
sequence
);
}
/**
* Get next millisecond
*/
private
long
getNextSecond
(
long
lastTimestamp
)
{
long
timestamp
=
getCurrentSecond
();
while
(
timestamp
<=
lastTimestamp
)
{
timestamp
=
getCurrentSecond
();
}
return
timestamp
;
}
/**
* Get current second
*/
private
long
getCurrentSecond
()
{
return
TimeUnit
.
MILLISECONDS
.
toSeconds
(
System
.
currentTimeMillis
());
}
}
idgenerator-spring-boot-starter/src/main/java/cn/quantgroup/tech/generator/configuration/GeneratorAutoConfiguration.java
0 → 100644
View file @
344cb26a
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 @
344cb26a
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 @
344cb26a
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.quantgroup.tech.generator.configuration.GeneratorAutoConfiguration
\ No newline at end of file
pom.xml
View file @
344cb26a
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
<modelVersion>
4.0.0
</modelVersion>
<modelVersion>
4.0.0
</modelVersion>
<groupId>
cn.quantgroup
</groupId>
<groupId>
cn.quantgroup
</groupId>
<artifactId>
commons-parent
</artifactId>
<artifactId>
commons-parent
</artifactId>
<version>
0.
1.4
</version>
<version>
0.
2.3
</version>
<parent>
<parent>
<groupId>
org.springframework.boot
</groupId>
<groupId>
org.springframework.boot
</groupId>
...
@@ -17,25 +17,49 @@
...
@@ -17,25 +17,49 @@
<modules>
<modules>
<module>
commons-core
</module>
<module>
commons-core
</module>
<module>
commons-spring
</module>
<module>
commons-spring
</module>
<module>
shutdown-spring-boot-starter
</module>
<module>
brave-spring-boot-starter
</module>
<module>
idgenerator-spring-boot-starter
</module>
</modules>
</modules>
<packaging>
pom
</packaging>
<packaging>
pom
</packaging>
<properties>
<properties>
<java.version>
1.8
</java.version>
<guava.version>
23.0
</guava.version>
<apollo.client.version>
0.10.2
</apollo.client.version>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
<project.reporting.outputEncoding>
UTF-8
</project.reporting.outputEncoding>
<project.reporting.outputEncoding>
UTF-8
</project.reporting.outputEncoding>
<maven.test.skip>
true
</maven.test.skip>
<maven.test.skip>
true
</maven.test.skip>
<java.version>
1.8
</java.version>
<lombok.version>
1.16.20
</lombok.version>
<guava.version>
23.0
</guava.version>
<apollo.client.version>
0.10.2
</apollo.client.version>
<common.parent.version>
0.2.3
</common.parent.version>
</properties>
</properties>
<dependencies>
<dependencies>
<!--所有工程基础依赖. apollo 配置中心-->
<dependency>
<dependency>
<groupId>
com.ctrip.framework.apollo
</groupId>
<groupId>
com.ctrip.framework.apollo
</groupId>
<artifactId>
apollo-client
</artifactId>
<artifactId>
apollo-client
</artifactId>
<version>
${apollo.client.version}
</version>
<version>
${apollo.client.version}
</version>
</dependency>
</dependency>
<!--所有工程基础依赖. lombok -->
<dependency>
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
<version>
${lombok.version}
</version>
</dependency>
<!--commons 项目需要自动配置-->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter
</artifactId>
</dependency>
<!--所有项目都有guava-->
<dependency>
<groupId>
com.google.guava
</groupId>
<artifactId>
guava
</artifactId>
<version>
${guava.version}
</version>
</dependency>
</dependencies>
</dependencies>
<dependencyManagement>
<dependencyManagement>
...
@@ -43,12 +67,27 @@
...
@@ -43,12 +67,27 @@
<dependency>
<dependency>
<groupId>
cn.quantgroup
</groupId>
<groupId>
cn.quantgroup
</groupId>
<artifactId>
commons-spring
</artifactId>
<artifactId>
commons-spring
</artifactId>
<version>
0.1.4
</version>
<version>
${common.parent.version}
</version>
</dependency>
</dependency>
<dependency>
<dependency>
<groupId>
cn.quantgroup
</groupId>
<groupId>
cn.quantgroup
</groupId>
<artifactId>
commons-core
</artifactId>
<artifactId>
commons-core
</artifactId>
<version>
0.1.4
</version>
<version>
${common.parent.version}
</version>
</dependency>
<dependency>
<groupId>
cn.quantgroup
</groupId>
<artifactId>
shutdown-spring-boot-starter
</artifactId>
<version>
${common.parent.version}
</version>
</dependency>
<dependency>
<groupId>
cn.quantgroup
</groupId>
<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>
</dependency>
</dependencies>
</dependencies>
</dependencyManagement>
</dependencyManagement>
...
...
shutdown-spring-boot-starter/pom.xml
0 → 100644
View file @
344cb26a
<?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.3
</version>
</parent>
<modelVersion>
4.0.0
</modelVersion>
<artifactId>
shutdown-spring-boot-starter
</artifactId>
<dependencies>
<!--以下为可选的-->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-tomcat
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-undertow
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-jetty
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-amqp
</artifactId>
<optional>
true
</optional>
</dependency>
<dependency>
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
commons-spring
/src/main/java/cn/quantgroup/tech/shutdown/BaseDestroyHandler.java
→
shutdown-spring-boot-starter
/src/main/java/cn/quantgroup/tech/shutdown/BaseDestroyHandler.java
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
shutdown
;
package
cn
.
quantgroup
.
tech
.
shutdown
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils
;
import
org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.Lifecycle
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
javax.annotation.PostConstruct
;
import
javax.annotation.PreDestroy
;
import
javax.annotation.PreDestroy
;
/**
/**
...
@@ -19,6 +23,19 @@ public class BaseDestroyHandler {
...
@@ -19,6 +23,19 @@ public class BaseDestroyHandler {
@Autowired
@Autowired
private
ApplicationContext
applicationContext
;
private
ApplicationContext
applicationContext
;
private
RabbitListenerEndpointRegistry
rabbitListenerEndpointRegistry
;
@PostConstruct
public
void
initMQConf
()
{
try
{
rabbitListenerEndpointRegistry
=
applicationContext
.
getBean
(
RabbitListenerConfigUtils
.
RABBIT_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME
,
RabbitListenerEndpointRegistry
.
class
);
}
catch
(
Exception
e
)
{
log
.
warn
(
"注入MQ endpoint registry 失败, 如果你有MQ队列接收, 可能你要关注一下了"
);
}
}
@PreDestroy
@PreDestroy
private
void
stopRedisSub
()
{
private
void
stopRedisSub
()
{
log
.
info
(
"我什么都没做, redis stopped"
);
log
.
info
(
"我什么都没做, redis stopped"
);
...
@@ -26,6 +43,16 @@ public class BaseDestroyHandler {
...
@@ -26,6 +43,16 @@ public class BaseDestroyHandler {
@PreDestroy
@PreDestroy
private
void
stopRabbitMQ
()
{
private
void
stopRabbitMQ
()
{
try
{
if
(
rabbitListenerEndpointRegistry
==
null
)
{
log
.
warn
(
"我什么都没做, MQ listener stopped"
);
return
;
}
rabbitListenerEndpointRegistry
.
getListenerContainers
().
forEach
(
Lifecycle:
:
stop
);
}
catch
(
Exception
e
)
{
//貌似这段日志不会打印...
log
.
error
(
"貌似停止 MQ 遇到了问题... 你有MQ么?"
,
e
);
}
log
.
info
(
"MQ listener stopped"
);
log
.
info
(
"MQ listener stopped"
);
}
}
}
}
commons-spring
/src/main/java/cn/quantgroup/tech/shutdown/DefaultSignalHandler.java
→
shutdown-spring-boot-starter
/src/main/java/cn/quantgroup/tech/shutdown/DefaultSignalHandler.java
View file @
344cb26a
...
@@ -27,12 +27,19 @@ public class DefaultSignalHandler implements SignalHandler {
...
@@ -27,12 +27,19 @@ public class DefaultSignalHandler implements SignalHandler {
String
applicationName
=
context
.
getApplicationName
();
String
applicationName
=
context
.
getApplicationName
();
log
.
info
(
"开始执行停止{}服务"
,
applicationName
);
log
.
info
(
"开始执行停止{}服务"
,
applicationName
);
GracefulShutdownProperties
bean
=
context
.
getBean
(
GracefulShutdownProperties
.
class
);
GracefulShutdownProperties
bean
=
context
.
getBean
(
GracefulShutdownProperties
.
class
);
String
shutdownBeanName
=
null
;
try
{
try
{
context
.
getBean
(
Shutdown
.
class
).
shutdown
(
bean
.
getTimeout
());
String
[]
shutdownBeanNames
=
context
.
getBeanNamesForType
(
Shutdown
.
class
);
log
.
info
(
"servlet container 停止接收请求"
);
shutdownBeanName
=
shutdownBeanNames
[
0
];
}
catch
(
InterruptedException
e
)
{
//如果不是web应用. 这里会找不到shutdown bean
context
.
getBean
(
shutdownBeanName
,
Shutdown
.
class
).
shutdown
(
bean
.
getTimeout
());
log
.
info
(
"{} 停止接收请求"
,
shutdownBeanName
);
}
catch
(
Exception
e
)
{
log
.
info
(
"{} shutdown 失败"
,
shutdownBeanName
);
}
}
log
.
info
(
"{} 即将执行 @PreDestroy 方法"
,
applicationName
);
System
.
exit
(
0
);
//处理无法exit(0)的动作
Thread
.
getAllStackTraces
().
forEach
((
thread
,
stackTraceElements
)
->
{
Thread
.
getAllStackTraces
().
forEach
((
thread
,
stackTraceElements
)
->
{
if
(!
thread
.
isDaemon
())
{
if
(!
thread
.
isDaemon
())
{
//如果中断 daemon 线程, 会导致 PreDestroy 方法不执行,
//如果中断 daemon 线程, 会导致 PreDestroy 方法不执行,
...
@@ -41,7 +48,6 @@ public class DefaultSignalHandler implements SignalHandler {
...
@@ -41,7 +48,6 @@ public class DefaultSignalHandler implements SignalHandler {
thread
.
interrupt
();
thread
.
interrupt
();
}
}
});
});
log
.
info
(
"{} 即将执行 @PreDestroy 方法"
,
applicationName
);
System
.
exit
(
0
);
System
.
exit
(
0
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
// 此处可能导致异常的里面包含了logback中类未能找到, 所以增加输出到控制台.
// 此处可能导致异常的里面包含了logback中类未能找到, 所以增加输出到控制台.
...
...
commons-spring
/src/main/java/cn/quantgroup/tech/shutdown/configuration/GracefulShutdownAutoConfiguration.java
→
shutdown-spring-boot-starter
/src/main/java/cn/quantgroup/tech/shutdown/configuration/GracefulShutdownAutoConfiguration.java
View file @
344cb26a
package
cn
.
quantgroup
.
tech
.
shutdown
.
configuration
;
package
cn
.
quantgroup
.
tech
.
shutdown
.
configuration
;
import
cn.quantgroup.tech.shutdown.DefaultSignalHandler
;
import
cn.quantgroup.tech.shutdown.properties.GracefulShutdownProperties
;
import
cn.quantgroup.tech.shutdown.properties.GracefulShutdownProperties
;
import
cn.quantgroup.tech.shutdown.service.JettyShutdown
;
import
cn.quantgroup.tech.shutdown.service.JettyShutdown
;
import
cn.quantgroup.tech.shutdown.service.TomcatShutdown
;
import
cn.quantgroup.tech.shutdown.service.TomcatShutdown
;
import
cn.quantgroup.tech.shutdown.service.UndertowShutdown
;
import
cn.quantgroup.tech.shutdown.service.UndertowShutdown
;
import
cn.quantgroup.tech.shutdown.wrapper.UndertowShutdownHandlerWrapper
;
import
cn.quantgroup.tech.shutdown.wrapper.UndertowShutdownHandlerWrapper
;
import
io.undertow.Undertow
;
import
io.undertow.Undertow
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.catalina.startup.Tomcat
;
import
org.apache.catalina.startup.Tomcat
;
import
org.eclipse.jetty.server.Server
;
import
org.eclipse.jetty.server.Server
;
import
org.eclipse.jetty.util.Loader
;
import
org.eclipse.jetty.util.Loader
;
import
org.eclipse.jetty.webapp.WebAppContext
;
import
org.eclipse.jetty.webapp.WebAppContext
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnClass
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.AutoConfigureOrder
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
;
import
org.springframework.boot.autoconfigure.condition.*
;
import
org.springframework.boot.autoconfigure.condition.SearchStrategy
;
import
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration
;
import
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration
;
import
org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer
;
import
org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer
;
import
org.springframework.boot.context.embedded.EmbeddedServletContainerFactory
;
import
org.springframework.boot.context.embedded.EmbeddedServletContainerFactory
;
...
@@ -22,9 +23,14 @@ import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletCon
...
@@ -22,9 +23,14 @@ import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletCon
import
org.springframework.boot.context.embedded.undertow.UndertowDeploymentInfoCustomizer
;
import
org.springframework.boot.context.embedded.undertow.UndertowDeploymentInfoCustomizer
;
import
org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory
;
import
org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory
;
import
org.springframework.boot.context.properties.EnableConfigurationProperties
;
import
org.springframework.boot.context.properties.EnableConfigurationProperties
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.ConfigurableApplicationContext
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Import
;
import
org.springframework.context.annotation.Import
;
import
org.springframework.core.Ordered
;
import
org.xnio.SslClientAuthMode
;
import
sun.misc.Signal
;
import
javax.servlet.Servlet
;
import
javax.servlet.Servlet
;
...
@@ -33,12 +39,26 @@ import javax.servlet.Servlet;
...
@@ -33,12 +39,26 @@ import javax.servlet.Servlet;
* This configuration class will be picked up by Spring Boot's auto configuration capabilities as soon as it's
* This configuration class will be picked up by Spring Boot's auto configuration capabilities as soon as it's
* on the classpath.
* on the classpath.
*/
*/
@Slf4j
@Configuration
@Configuration
@ConditionalOnWebApplication
@ConditionalOnProperty
(
prefix
=
"shutdown.graceful"
,
name
=
"enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
true
)
@ConditionalOnProperty
(
prefix
=
"shutdown.graceful"
,
name
=
"enabled"
,
havingValue
=
"true"
,
matchIfMissing
=
true
)
@AutoConfigureOrder
(
Ordered
.
HIGHEST_PRECEDENCE
)
@EnableConfigurationProperties
(
GracefulShutdownProperties
.
class
)
@EnableConfigurationProperties
(
GracefulShutdownProperties
.
class
)
@Import
(
EmbeddedServletContainerAutoConfiguration
.
BeanPostProcessorsRegistrar
.
class
)
@Import
(
EmbeddedServletContainerAutoConfiguration
.
BeanPostProcessorsRegistrar
.
class
)
public
class
GracefulShutdownAutoConfiguration
{
public
class
GracefulShutdownAutoConfiguration
{
ConfigurableApplicationContext
applicationContext
;
@Autowired
public
void
setApplicationContext
(
ApplicationContext
applicationContext
)
{
this
.
applicationContext
=
(
ConfigurableApplicationContext
)
applicationContext
;
log
.
info
(
"注册对 Signal INT 信号的接收."
);
Signal
.
handle
(
new
Signal
(
"INT"
),
new
DefaultSignalHandler
(
this
.
applicationContext
));
}
/**
/**
* Configuration for Tomcat.
* Configuration for Tomcat.
*/
*/
...
@@ -49,6 +69,7 @@ public class GracefulShutdownAutoConfiguration {
...
@@ -49,6 +69,7 @@ public class GracefulShutdownAutoConfiguration {
@Bean
@Bean
public
TomcatShutdown
tomcatShutdown
()
{
public
TomcatShutdown
tomcatShutdown
()
{
log
.
info
(
"容器是 tomcat,成功构造 shutdown hook."
);
return
new
TomcatShutdown
();
return
new
TomcatShutdown
();
}
}
...
@@ -76,6 +97,7 @@ public class GracefulShutdownAutoConfiguration {
...
@@ -76,6 +97,7 @@ public class GracefulShutdownAutoConfiguration {
@Bean
@Bean
public
JettyShutdown
jettyShutdown
()
{
public
JettyShutdown
jettyShutdown
()
{
log
.
info
(
"容器是 jetty,成功构造 shutdown hook."
);
return
new
JettyShutdown
();
return
new
JettyShutdown
();
}
}
...
@@ -100,12 +122,13 @@ public class GracefulShutdownAutoConfiguration {
...
@@ -100,12 +122,13 @@ public class GracefulShutdownAutoConfiguration {
* Configuration for Undertow.
* Configuration for Undertow.
*/
*/
@Configuration
@Configuration
@ConditionalOnClass
({
Servlet
.
class
,
Undertow
.
class
})
@ConditionalOnClass
({
Servlet
.
class
,
Undertow
.
class
,
SslClientAuthMode
.
class
})
@ConditionalOnMissingBean
(
value
=
EmbeddedServletContainerFactory
.
class
,
search
=
SearchStrategy
.
CURRENT
)
@ConditionalOnMissingBean
(
value
=
EmbeddedServletContainerFactory
.
class
,
search
=
SearchStrategy
.
CURRENT
)
public
static
class
EmbeddedUndertow
{
public
static
class
EmbeddedUndertow
{
@Bean
@Bean
public
UndertowShutdown
undertowShutdown
()
{
public
UndertowShutdown
undertowShutdown
()
{
log
.
info
(
"容器是 undertow,成功构造 shutdown hook."
);
return
new
UndertowShutdown
();
return
new
UndertowShutdown
();
}
}
...
...
commons-spring
/src/main/java/cn/quantgroup/tech/shutdown/properties/GracefulShutdownProperties.java
→
shutdown-spring-boot-starter
/src/main/java/cn/quantgroup/tech/shutdown/properties/GracefulShutdownProperties.java
View file @
344cb26a
File moved
commons-spring
/src/main/java/cn/quantgroup/tech/shutdown/service/JettyShutdown.java
→
shutdown-spring-boot-starter
/src/main/java/cn/quantgroup/tech/shutdown/service/JettyShutdown.java
View file @
344cb26a
File moved
commons-spring
/src/main/java/cn/quantgroup/tech/shutdown/service/Shutdown.java
→
shutdown-spring-boot-starter
/src/main/java/cn/quantgroup/tech/shutdown/service/Shutdown.java
View file @
344cb26a
File moved
commons-spring
/src/main/java/cn/quantgroup/tech/shutdown/service/TomcatShutdown.java
→
shutdown-spring-boot-starter
/src/main/java/cn/quantgroup/tech/shutdown/service/TomcatShutdown.java
View file @
344cb26a
File moved
commons-spring
/src/main/java/cn/quantgroup/tech/shutdown/service/UndertowShutdown.java
→
shutdown-spring-boot-starter
/src/main/java/cn/quantgroup/tech/shutdown/service/UndertowShutdown.java
View file @
344cb26a
File moved
commons-spring
/src/main/java/cn/quantgroup/tech/shutdown/wrapper/UndertowShutdownHandlerWrapper.java
→
shutdown-spring-boot-starter
/src/main/java/cn/quantgroup/tech/shutdown/wrapper/UndertowShutdownHandlerWrapper.java
View file @
344cb26a
File moved
shutdown-spring-boot-starter/src/main/resources/META-INF/spring.factories
0 → 100644
View file @
344cb26a
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.quantgroup.tech.shutdown.configuration.GracefulShutdownAutoConfiguration
\ No newline at end of file
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