业务背景
1.代码里所有的rpc调用都散落在各个项目中,重复代码太多,实现成本和可重用性差
2.由于某个工具出现漏洞需要把所有项目中用到这个工具的地方全部修改
3.中间键多实例问题,没法做到实例间的业务隔离
针对以上问题,设计封装了三个以下可通用型框架
项目中只需要引入对应的maven依赖,在apollo配置中心配置相应环境的地址,即可正常引入到项目中,各个项目仅需注入需要的Bean,调用对应方法即可使用。以下是框架内容
基础组件
uupaotui-sdk
一个基于springboot的sdkClient接口调用封装工具
下面我们来看下一下如何实现的
框架组成部分
- uupaotui-common主要涉及公共部分常量, 异常定义,响应形式,工具等部分
- uupaotui-service 主要负责实现调用各个服务中心的业务逻辑实现
public class SDKAccountClient extends DefaultUUClient {
private String userPlusUrl;
public SDKAccountClient(String userPlusUrl) {
this.userPlusUrl = userPlusUrl;
}
/**
* 第三方授权登录
* @param request 请求参数
* @return 相应信息
*/
public SDKResponse<LoginResponse> externalAuthorizeRegisterAndLogin(AuthorizeRegisterAndLoginRequest request) {
CheckUtils.checkArgument(request != null, ErrorMessage.PARAM_ERROR);
String url = userPlusUrl + "/***/***/***/****";
return postEntity(url, request, new TypeReference<SDKResponse<LoginResponse>>() {
});
}
......
}
uupaotui-service-spring-boot-starter 主要服务框架的配置,将对应服务的实现逻辑以Bean的方式注入到spring容器,并随着项目的自动化装配加载到项目中
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties({ThirdAuthProperties.class})
@ConditionalOnProperty(prefix = "uupaotui.***.***.***.***", value = "enabled")
public class ThirdAuthConfiguration {
@Bean
@ConditionalOnMissingBean
public SDKOTokenClient sdkoTokenClient(ThirdAuthProperties thirdAuthProperties) {
return new SDKOTokenClient(thirdAuthProperties.getUrl());
}
}
结合spring.factories 实现自动装配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.uupaotui.service.springboot.****.SmsAutoConfiguration,\
com.uupaotui.service.springboot.****.CityAutoConfiguration,\
com.uupaotui.service.springboot.****.UserAutoConfiguration,\
uupt-redis-helper
一个基于springboot的redis使用工具封装
框架分为以下部分
- redis-config 主要负责redis实例的配置
@Configuration
@ConditionalOnBean({GenericObjectPoolConfig.class})
@EnableConfigurationProperties({UURedisCollectionProperties.class})
public class UUCollectionRedisAutoConfiguration {
/**
* 集合redis配置
* @return
*/
@Bean
public RedisStandaloneConfiguration redisConfigCollection(UURedisCollectionProperties uuRedisCollectionProperties) {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setDatabase(uuRedisCollectionProperties.getDatabase());
redisStandaloneConfiguration.setHostName(uuRedisCollectionProperties.getHostName());
redisStandaloneConfiguration.setPassword(uuRedisCollectionProperties.getPassword());
redisStandaloneConfiguration.setPort(uuRedisCollectionProperties.getPort());
return redisStandaloneConfiguration;
}
@Bean
public LettuceConnectionFactory factoryCollection(GenericObjectPoolConfig redisPool, RedisStandaloneConfiguration redisConfigCollection) {
LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder()
.poolConfig(redisPool).commandTimeout(Duration.ofMillis(redisPool.getMaxWaitMillis())).build();
return new LettuceConnectionFactory(redisConfigCollection, clientConfiguration);
}
@Bean
public RedisTemplate<String, Object> redisTemplateCollection(@Autowired @Qualifier("factoryCollection")LettuceConnectionFactory factoryCollection) {
return getRedisTemplate(factoryCollection);
}
private RedisTemplate<String, Object> getRedisTemplate(LettuceConnectionFactory factoryCollection) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factoryCollection);
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
......
}
reids-helper 负责redis主要方法的实现逻辑
主要根据redis 的数据类型分为RedisGoingOrderHelper, RedisDmallHelper,RedisDriverHelper,RedisUserHelper,RedisMarketingHelper
public class RedisStringHelper extends AbstractRedisHelper {
private final static int LOCK_DEFAULT_TIME = 10;
private RedisTemplate stringRedisTemplate;
public RedisStringHelper(RedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
/**
* 缓存对象和字符串
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @return 缓存的对象
*/
public void setCache(String key, Object value, Integer timeout) {
setCache(key, value, timeout, TimeUnit.SECONDS);
}
/**
* 缓存对象和字符串
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
* @return 缓存的对象
*/
public void setCache(String key, Object value, Integer timeout, TimeUnit timeUnit) {
stringRedisTemplate.opsForValue().set(key, toJSONString(value), timeout, timeUnit);
}
/**
* 自增步长为1
*
* @param key 缓存的键值
* @param timeout 时间
* @return
*/
public Long increment(String key, Integer timeout) {
return increment(key, 1, timeout, TimeUnit.SECONDS);
}
/**
* 自增
*
* @param key 缓存的键值
* @param delta 自增量
* @param timeout 时间
* @param timeUnit 时间颗粒度
* @return
*/
public Long increment(String key, long delta, Integer timeout, TimeUnit timeUnit) {
ValueOperations operation = stringRedisTemplate.opsForValue();
Long increment = operation.increment(key, delta);
expire(key, timeout, timeUnit);
return increment;
}
......
}
Rabbitmq-helper
一个基于springboot的rabbitmq使用工具
框架分为以下部分
rabbitmq-config 主要负责mq实例的配置
主要以业务模块进行划分
@Configuration
@ConditionalOnProperty(prefix = "uupt.rabbitmq.****", name = "host")
@EnableConfigurationProperties({UURabbitmqUserProperties.class})
public class RabbitMqUserAutoConfiguration {
@Bean(name = "userConnectionFactory")
public ConnectionFactory userConnectionFactory(UURabbitmqUserProperties uuRabbitmqUserProperties) {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(uuRabbitmqUserProperties.getHost());
connectionFactory.setPort(uuRabbitmqUserProperties.getPort());
connectionFactory.setUsername(uuRabbitmqUserProperties.getUsername());
connectionFactory.setPassword(uuRabbitmqUserProperties.getPassword());
return connectionFactory;
}
......
}
总结
1.本次分享的主要是三个基础组件的实现方式,主要是根据现有业务对工具进行进一步封装,结合springboot的自动化装配进行加载
2.我们的配置中心主要用的apollo,上面工具可以结合apollo的公共配置实现不同环境同样配置,减少因配置错误导致问题
3.上述框架主要是根据业务进行拆分,可以根据使用的工具知道本块业务使用的哪个实例,或者是哪些业务。不仅可以减少重复代码编写量,还能增加代码可读性