-
Notifications
You must be signed in to change notification settings - Fork 26
Quick_Start
睿驰 edited this page Mar 16, 2021
·
12 revisions
首先,添加juice-spring-boot-starter依赖:
<dependency>
<groupId>io.infinityclub</groupId>
<artifactId>juice-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
示例代码仓库: juice-samples
application.yml增加redis配置:
# redis
spring:
redis:
database: 0
host: localhost
password: admin
port: 6379
ssl: false
lettuce:
pool:
max-wait: 5000ms
maxActive: 20
maxIdle: 8
minIdle: 1
timeout: 3000ms
代码示例:
@Resource
private DistributedLockClient distributedLockClient;
public ResponseDTO generateBill(BillGenerationMgtParamDTO paramDTO) {
Date now = new Date();
Long loginUserId = paramDTO.getUserId();
//全局加锁
String lockKey = ConsumerBillConstant.getGenerateBillLockKey(loginUserId);
DistributedLock lock = distributedLockClient.getLock(lockKey);
boolean lockSuccess = lock.tryLock(-1, 5, TimeUnit.MINUTES);
if (!lockSuccess) {
LOG.info("订单管理-生成账单, loginUserId:{} 加锁失败:{}", loginUserId, lockKey);
return ResponseDTO.invalidParam("加锁失败");
}
try {
//业务逻辑代码
} finally {
lock.unlock();
}
return ResponseDTO.systemError();
}
/**
* @author Ricky Fung
*/
public class AppTest {
private RateLimiter semaphoreBasedRateLimiter;
private AtomicRateLimiter atomicRateLimiter;
private RedisRateLimiter redisRateLimiter;
@Before
public void setUp() {
RateLimiterConfig rateLimiterConfig = RateLimiterConfig.custom()
.limitForPeriod(20)
.limitRefreshPeriod(Duration.ofMillis(1000))
.timeoutDuration(Duration.ofSeconds(3))
.build();
semaphoreBasedRateLimiter = new SemaphoreBasedRateLimiter("semaphoreBased",
rateLimiterConfig);
atomicRateLimiter = new AtomicRateLimiter("atomicBased", rateLimiterConfig);
redisRateLimiter = new RedisRateLimiter("", rateLimiterConfig);
}
}
在业务代码调用之前:
public ResultDTO secKill() {
boolean success = redisRateLimiter.tryAcquire();
if (!success) {
return ResultDTO.invalidParam("业务繁忙");
}
//正常业务处理
......
return ResultDTO.ok();
}
application.yml增加如下配置:
# tracing
juice.tracing.enable = true
juice.tracing.pathPatterns = /api/*
应用启动后,juice-spring-boot-starter会自动注入juice.tracing.filter.TracingFilter,接口响应头会出现 X-TraceId。
如果希望RestTemplate发送请求时自动携带traceId和spanId,可以在RestTemplate上加上@DistributedTracing,如下:
import juice.tracing.annotation.DistributedTracing;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@DistributedTracing
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(30000);//单位为ms
factory.setConnectTimeout(20000);//单位为ms
return new RestTemplate(factory);
}
}
application.yml增加如下配置:
# DB
# 主库配置.eweishop
spring.datasource.eweishop.master.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.eweishop.master.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.eweishop.master.name = eweishop_master
spring.datasource.eweishop.master.url = jdbc:mysql://localhost:3306/eweishop_ms?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull
spring.datasource.eweishop.master.username = root
spring.datasource.eweishop.master.password = root@2021
spring.datasource.eweishop.master.filters = mergeStat
spring.datasource.eweishop.master.initial-size = 5
spring.datasource.eweishop.master.max-active = 100
spring.datasource.eweishop.master.min-idle = 1
spring.datasource.eweishop.master.max-wait = 20000
spring.datasource.eweishop.master.test-on-borrow = false
spring.datasource.eweishop.master.test-on-return = false
spring.datasource.eweishop.master.test-while-idle = true
spring.datasource.eweishop.master.validation-query = SELECT 'x'
spring.datasource.eweishop.master.time-between-eviction-runs-millis = 60000
spring.datasource.eweishop.master.min-evictable-idle-time-millis = 300000
# 从库配置.eweishop
spring.datasource.eweishop.slave.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.eweishop.slave.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.eweishop.slave.name = eweishop_slave
spring.datasource.eweishop.slave.url = jdbc:mysql://localhost:3306/eweishop_slave?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull
spring.datasource.eweishop.slave.username = root
spring.datasource.eweishop.slave.password = root@2021
spring.datasource.eweishop.slave.filters = mergeStat
spring.datasource.eweishop.slave.initial-size = 5
spring.datasource.eweishop.slave.max-active = 100
spring.datasource.eweishop.slave.min-idle = 1
spring.datasource.eweishop.slave.max-wait = 20000
spring.datasource.eweishop.slave.test-on-borrow = false
spring.datasource.eweishop.slave.test-on-return = false
spring.datasource.eweishop.slave.test-while-idle = true
spring.datasource.eweishop.slave.validation-query = SELECT 'x'
spring.datasource.eweishop.slave.time-between-eviction-runs-millis = 60000
spring.datasource.eweishop.slave.min-evictable-idle-time-millis = 300000
# 主库配置 bypass
spring.datasource.bypass.master.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.bypass.master.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.bypass.master.name = bypass_master
spring.datasource.bypass.master.url = jdbc:mysql://localhost/bypass_ms?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull
spring.datasource.bypass.master.username = root
spring.datasource.bypass.master.password = root@2021
spring.datasource.bypass.master.filters = mergeStat
spring.datasource.bypass.master.initial-size = 5
spring.datasource.bypass.master.max-active = 100
spring.datasource.bypass.master.min-idle = 1
spring.datasource.bypass.master.max-wait = 20000
spring.datasource.bypass.master.test-on-borrow = false
spring.datasource.bypass.master.test-on-return = false
spring.datasource.bypass.master.test-while-idle = true
spring.datasource.bypass.master.validation-query = SELECT 'x'
spring.datasource.bypass.master.time-between-eviction-runs-millis = 60000
spring.datasource.bypass.master.min-evictable-idle-time-millis = 300000
# 从库配置 bypass
spring.datasource.bypass.slave.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.bypass.slave.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.bypass.slave.name = bypass_slave
spring.datasource.bypass.slave.url = jdbc:mysql://localhost:3306/bypass_slave?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull
spring.datasource.bypass.slave.username = root
spring.datasource.bypass.slave.password = root@2021
spring.datasource.bypass.slave.filters = mergeStat
spring.datasource.bypass.slave.initial-size = 5
spring.datasource.bypass.slave.max-active = 100
spring.datasource.bypass.slave.min-idle = 1
spring.datasource.bypass.slave.max-wait = 20000
spring.datasource.bypass.slave.test-on-borrow = false
spring.datasource.bypass.slave.test-on-return = false
spring.datasource.bypass.slave.test-while-idle = true
spring.datasource.bypass.slave.validation-query = SELECT 'x'
spring.datasource.bypass.slave.time-between-eviction-runs-millis = 60000
spring.datasource.bypass.slave.min-evictable-idle-time-millis = 300000
# mybatis的相关配置
mybatis.mapper-locations = classpath*:mapper/**/*Mapper.xml
mybatis.type-aliases-package = com.renzhenmall.oms.storage.entity
mybatis.configLocation = classpath:mybatis/mybatis-config.xml
数据源配置类:
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.renzhenmall.oms.datasource.DataSourceKey;
import juice.datasource.DynamicDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* @author Ricky Fung
*/
@Configuration
@MapperScan(value = "com.renzhenmall.oms.storage.**.mapper", sqlSessionFactoryRef = "sqlSessionFactory")
public class DruidDataSourceConfig {
@Value("${mybatis.mapper-locations:}")
private String mapperLocations;
@Value("${mybatis.type-aliases-package:}")
private String typeAliasesPackage;
@Value("${mybatis.configLocation:}")
private String configLocation;
@Bean
public DataSourceTransactionManager transactionManager(DataSource dynamicDataSource) {
return new DataSourceTransactionManager(dynamicDataSource);
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dynamicDataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
bean.setTypeAliasesPackage(typeAliasesPackage);
bean.setConfigLocation(new PathMatchingResourcePatternResolver().getResource(configLocation));
return bean.getObject();
}
//===========
@Bean
public DynamicDataSource dynamicDataSource() {
Map<String,String> pkgDefaultDsKeyMap = new HashMap<>(4);
pkgDefaultDsKeyMap.put("com.renzhenmall.oms.storage.mapper.eweishop", DataSourceKey.MASTER_EWEISHOP);
pkgDefaultDsKeyMap.put("com.renzhenmall.oms.storage.mapper.bypass", DataSourceKey.MASTER_BYPASS);
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> tarDsMap = new HashMap<>(8);
tarDsMap.put(DataSourceKey.MASTER_EWEISHOP, eweishopMasterDS());
tarDsMap.put(DataSourceKey.SLAVE_EWEISHOP, eweishopSlaveDS());
tarDsMap.put(DataSourceKey.MASTER_BYPASS, bypassMasterDS());
tarDsMap.put(DataSourceKey.SLAVE_BYPASS, bypassSlaveDS());
dynamicDataSource.setTargetDataSources(tarDsMap);
dynamicDataSource.setDefaultTargetDataSource(tarDsMap.get(DataSourceKey.MASTER_EWEISHOP));
dynamicDataSource.setPkgDefaultDsKeyMap(pkgDefaultDsKeyMap);
return dynamicDataSource;
}
//==========
@Bean
@ConfigurationProperties("spring.datasource.eweishop.master")
public DataSource eweishopMasterDS(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.eweishop.slave")
public DataSource eweishopSlaveDS(){
return DruidDataSourceBuilder.create().build();
}
//==========
@Bean
@ConfigurationProperties("spring.datasource.bypass.master")
public DataSource bypassMasterDS(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.bypass.slave")
public DataSource bypassSlaveDS(){
return DruidDataSourceBuilder.create().build();
}
}
在代码中动态切换数据源:
@Component
public class CustomerBillManager {
@DSRouting(value = DataSourceKey.MASTER_BYPASS)
@Transactional
public int deleteBill(Long billId) {
int rows = customerOrderBillMapper.updateDelete(billId);
int detailRows = customerOrderBillDetailMapper.updateDelete(billId);
//删除标记
int goodsRows = customerOrderBillGoodsMapper.deleteByBillId(billId);
LOG.error("甲方账单-删除账单, billId:{} 删除账单数量:{}, 账单详情数量:{}, 订单商品数量:{}", billId, rows, detailRows, goodsRows);
return rows;
}
}
CustomerOrderBillMapper如下:
@DSRouting(value = DataSourceKey.SLAVE_BYPASS)
public interface CustomerOrderBillMapper {
int deleteByPrimaryKey(Long id);
int insert(CustomerOrderBill record);
int insertSelective(CustomerOrderBill record);
CustomerOrderBill selectByPrimaryKey(Long id);
List<CustomerOrderBill> selectByCondition(CustomerOrderBillCondition condition);
int updateByPrimaryKeySelective(CustomerOrderBill record);
int updateByPrimaryKey(CustomerOrderBill record);
List<CustomerOrderBill> queryBillList(CustomerBillQueryParam query);
int updateRemark(@Param("id") Long id, @Param("remark") String remark);
int updateSettlementState(CustomerOrderBillUpdateCondition condition);
int updateDelete(@Param("billId") Long billId);
int updateSendMail(CustomerOrderBillUpdateCondition condition);
int updateConfirm(CustomerOrderBillUpdateCondition condition);
}
@Copyright Ricky Fung 2012-2021 [但行好事,莫问前程]