0%

spring配置双数据源

前段时间有个需求,需要将数据存到两个数据库中,一个库中存放主信息,一个库中存放特殊信息,看来是要使用双数据源了,搞起来吧

既然是双数据源,先不管怎么切换,配置得先搞起来

数据源配置

阅读全文 »

springCloudConfig获取远程配置

client端获取配置

springCloudConfig核心其实在于实现了一个PropertySourceLocator接口来进行获取远程配置的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
@Order(0)
public class ConfigServicePropertySourceLocator implements PropertySourceLocator {

@Override
@Retryable(interceptor = "configServerRetryInterceptor")
public org.springframework.core.env.PropertySource<?> locate(
org.springframework.core.env.Environment environment) {
ConfigClientProperties properties = this.defaultProperties.override(environment);
CompositePropertySource composite = new OriginTrackedCompositePropertySource(
"configService");
RestTemplate restTemplate = this.restTemplate == null
? getSecureRestTemplate(properties) : this.restTemplate;
Exception error = null;
String errorBody = null;
try {
String[] labels = new String[] { "" };
if (StringUtils.hasText(properties.getLabel())) {
labels = StringUtils
.commaDelimitedListToStringArray(properties.getLabel());
}
String state = ConfigClientStateHolder.getState();
// Try all the labels until one works
for (String label : labels) {
// 获取远程配置,这里就是使用restTemplate访问spring.cloud.config.uri对应的配置中心server地址/{name}/{profile}/{label}
Environment result = getRemoteEnvironment(restTemplate, properties,
label.trim(), state);
if (result != null) {
log(result);

// result.getPropertySources() can be null if using xml
if (result.getPropertySources() != null) {
for (PropertySource source : result.getPropertySources()) {
@SuppressWarnings("unchecked")
Map<String, Object> map = translateOrigins(source.getName(),
(Map<String, Object>) source.getSource());
composite.addPropertySource(
new OriginTrackedMapPropertySource(source.getName(),
map));
}
}

if (StringUtils.hasText(result.getState())
|| StringUtils.hasText(result.getVersion())) {
HashMap<String, Object> map = new HashMap<>();
putValue(map, "config.client.state", result.getState());
putValue(map, "config.client.version", result.getVersion());
composite.addFirstPropertySource(
new MapPropertySource("configClient", map));
}
return composite;
}
}
errorBody = String.format("None of labels %s found", Arrays.toString(labels));
}
catch (HttpServerErrorException e) {
error = e;
if (MediaType.APPLICATION_JSON
.includes(e.getResponseHeaders().getContentType())) {
errorBody = e.getResponseBodyAsString();
}
}
catch (Exception e) {
error = e;
}
if (properties.isFailFast()) {
throw new IllegalStateException(
"Could not locate PropertySource and the fail fast property is set, failing"
+ (errorBody == null ? "" : ": " + errorBody),
error);
}

return null;

}

}

那么PropertySourceLocator接口是何时被调用的呢?

阅读全文 »

ShardingSphere-JDBC水平分库分表

ShardingSphere-JDBC水平分库分表非常简单,只需要添加ShardingSphere-JDBC依赖并进行配置即可

1
2
3
4
5
6
<!-- sharding-jdbc 分库分表 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
阅读全文 »

Hystrix隔离策略

Hystrix通过隔离限制依赖的并发量和阻塞扩散,Hystrix的隔离策略有两种:

  • 线程隔离(THREAD) 使用该策略,HystrixCommand将会在单独的线程上执行,并发请求受线程池中的线程数的限制,默认使用该策略,因为该策略有一个除网络超时外的额外保护层

    执行依赖调用的线程与请求线程(tomcat、jetty等服务器线程)分离,通过线程池的大小可以控制并发量,当线程池饱和时可以提前拒绝服务,防止依赖问题扩散

  • 信号量隔离(SEMAPHORE) 使用该策略,HystrixCommand将会在请求线程上执行,开销相对较小,并发请求收到信号量个数的限制,其一般仅适用于非网络调用的隔离,只有当调用负载非常高时(每秒调用几百上千次),才会使用信号量隔离,因为负载过高的情况下使用THREAD开销会比较大

线程隔离

线程隔离主要是指线程池隔离,把请求分类交给不同的线程池处理。当一种业务请求处理发生问题时,不会将故障扩散到其他线程池,从而保证其他服务可用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 服务分组  配置全局唯一标识服务分组的名称,在进行监控时,相同分组的服务会聚合在一起
protected final HystrixCommandGroupKey groupKey;
// 服务标识,配置全局唯一标识服务的名称,默认是类名
protected HystrixCommandKey commandKey;
// 线程池名称,相同线程池名称的线程池是同一个,如果不配置,默认是分组名,此时一个group共用一个线程池
protected HystrixThreadPoolKey threadPoolKey;
// 命令属性配置
protected HystrixCommandProperties.Setter commandPropertiesDefaults;
// 线程池配置
protected HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults;


public TestCommand(){
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("testGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("command"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("testGroupPool"))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(10).withMaxQueueSize(10)));
}

信号量隔离

信号量隔离限制总的并发数,服务使用主线程进行同步调用,没有线程池,如果只是想限制某个服务的总并发调用量可以使用信号量来实现

1
2
3
HystrixCommandProperties.Setter().withExecutionIsolationStrategy(
HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE
).withExecutionIsolationSemaphoreMaxConcurrentRequests(200); // 限制200并发

maven环境配置

在正常项目中一般都会有多个环境,而不同的环境一些配置和流程是不一样的,可以使用maven来进行环境的区分,取不同的配置,不过spring也是支持环境区分的,我一般还是习惯于用spring boot的环境配置

maven支持在settings.xml中配置,也支持在pom.xml中配置

pom.xml中配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!--MAVEN打包选择运行环境-->
<!-- local(默认) 本地 dev:开发环境 test:测试环境 pro:生产环境-->
<profiles>
<profile>
<id>local</id>
<properties>
<profileActive>local</profileActive>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>dev</id>
<properties>
<profileActive>dev</profileActive>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
<profile>
<id>test</id>
<properties>
<profileActive>test</profileActive>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<profileActive>prod</profileActive>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
</profiles>
阅读全文 »