分享几个 SpringBoot 实用的小技巧
作者:crossoverJie
来源:crossoverJie
前言
最近分享的一些源码、框架设计的东西。我发现大家热情不是特别高,想想大多数应该还是正儿八经写代码的居多;这次就分享一点接地气的: SpringBoot 使用中的一些小技巧。
算不上多高大上的东西,但都还挺有用。
屏蔽外部依赖
第一个是 屏蔽外部依赖,什么意思呢?
比如大家日常开发时候有没有这样的烦恼:
项目是基于 SpringCloud 或者是 dubbo 这样的分布式服务,你需要依赖许多基础服务。
比如说某个订单号的生成、获取用户信息等。
由于服务拆分,这些功能都是在其他应用中以接口的形式提供,单测还好我还可以利用 Mock 把它屏蔽掉。但如果自己想把应用启动起来同时把自己相关的代码跑一遍呢?
通常有几种做法:
本地把所有的服务都启动起来。
把注册中心换为开发环境,依赖开发环境的服务。
直接把代码推送到开发环境自测。
看起来三种都可以,以前我也是这么干的。但还是有几个小问题:
本地启动有可能服务很多,全部起来电脑能不能撑住还两说,万一服务有问题就进行不下去了。
依赖开发环境的前提是网络打通,还有一个问题就是开发环境代码很不稳定很大可能会影响你的测试。
推送到开发环境应该是比较靠谱的方案,但如果想调试只有日志大法,没有本地 debug 的效率高效。
那如何解决问题呢?既可以在本地调试也不用启动其他服务。其实也可以利用单测的做法,把其他外部依赖 Mock 掉就行了。
大致的流程分为以下几步:
SpringBoot 启动之后在 Spring 中找出你需要屏蔽的那个 API 的 bean(通常情况下这个接口都是交给 Spring 管理的)。
手动从 bean 容器中删除该 bean。
重新创建一个该 API 的对象,只不过是通过 Mock 出来的。
再手动注册进 bean 容器中。
以下面这段代码为例:
@Override
public BaseResponse<OrderNoResVO> getUserByHystrix(@RequestBody UserReqVO userReqVO) {
OrderNoReqVO vo = new OrderNoReqVO();
vo.setAppId(123L);
vo.setReqNo(userReqVO.getReqNo());
BaseResponse<OrderNoResVO> orderNo = orderServiceClient.getOrderNo(vo);
return orderNo;
}
这是一个 SpringCloud 应用。
它依赖于 orderServiceClient 获取一个订单号。
其中的 orderServiceClient 就是一个外部 API,也是被 Spring 所管理。
替换原有的 Bean,下一步就是替换原有的 Bean。
@Component
public class OrderMockServiceConfig implements CommandLineRunner {
private final static Logger logger = LoggerFactory.getLogger(OrderMockServiceConfig.class);
@Autowired
private ApplicationContext applicationContext;
@Value("${excute.env}")
private String env;
@Override
public void run(String... strings) throws Exception {
// 非本地环境不做处理
if ("dev".equals(env) || "test".equals(env) || "pro".equals(env)) {
return;
}
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
OrderServiceClient orderServiceClient = defaultListableBeanFactory.getBean(OrderServiceClient.class);
logger.info("======orderServiceClient {}=====", orderServiceClient.getClass());
defaultListableBeanFactory.removeBeanDefinition(OrderServiceClient.class.getCanonicalName());
OrderServiceClient mockOrderApi = PowerMockito.mock(OrderServiceClient.class,
invocationOnMock -> BaseResponse.createSuccess(DateUtil.getLongTime() + "", "mock orderNo success"));
defaultListableBeanFactory.registerSingleton(OrderServiceClient.class.getCanonicalName(), mockOrderApi);
logger.info("======mockOrderApi {}=====", mockOrderApi.getClass());
}
}
其中实现了 CommandLineRunner 接口,可以在 Spring 容器初始化完成之后调用 run() 方法。
代码非常简单,简单来说首先判断下是什么环境,毕竟除开本地环境其余的都是需要真正调用远程服务的。之后就是获取 bean 然后手动删除掉。
关键的一步:
OrderServiceClient mockOrderApi = PowerMockito.mock(OrderServiceClient.class,
invocationOnMock -> BaseResponse.createSuccess(DateUtil.getLongTime() + "", "mock orderNo success"));
defaultListableBeanFactory.registerSingleton(OrderServiceClient.class.getCanonicalName(), mockOrderApi);
创建了一个新的 OrderServiceClient 对象并手动注册进了 Spring 容器中。
第一段代码使用的是 PowerMockito.mock 的 API,他可以创建一个代理对象,让所有调用 OrderServiceClient 的方法都会做默认的返回。
BaseResponse.createSuccess(DateUtil.getLongTime() + "", "mock orderNo success"))
测试一下,当我们没有替换时调用刚才那个接口并且本地也没有启动 OrderService:
因为没有配置 fallback 所以会报错,表示找不到这个服务。
替换掉 bean 时:
再次请求没有报错,并且获得了我们默认的返回。
通过日志也会发现 OrderServiceClient 最后已经被 Mock 代理了,并不会去调用真正的方法。
配置加密
下一个则是配置加密,这应该算是一个基本功能。
比如我们配置文件中的一些账号和密码,都应该是密文保存的。
因此这次使用了一个开源组件来实现加密与解密,并且对 SpringBoot 非常友好只需要几段代码即可完成。
首先根据加密密码将需要加密的配置加密为密文。
替换原本明文保存的配置。
再使用时进行解密。
使用该包也只需要引入一个依赖即可:
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>1.14</version>
</dependency>
同时写一个单测根据密码生成密文,密码也可保存在配置文件中:
jasypt.encryptor.password=123456
接着在单测中生成密文。
@Autowired
private StringEncryptor encryptor;
@Test
public void getPass() {
String name = encryptor.encrypt("userName");
String password = encryptor.encrypt("password");
System.out.println(name + "----------------");
System.out.println(password + "----------------");
}
之后只需要使用密文就行。
由于我这里是对数据库用户名和密码加密,所以还得有一个解密的过程。
利用 SpringBean 的一个增强接口即可实现:
@Component
public class DataSourceProcess implements BeanPostProcessor {
@Autowired
private StringEncryptor encryptor;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof DataSourceProperties){
DataSourceProperties dataSourceProperties = (DataSourceProperties) bean;
dataSourceProperties.setUsername(encryptor.decrypt(dataSourceProperties.getUsername())) ;
dataSourceProperties.setPassword(encryptor.decrypt(dataSourceProperties.getPassword()));
return dataSourceProperties ;
}
return bean;
}
}
这样就可以在真正使用时还原为明文。
同时也可以在启动命令中配置刚才的密码:
java -Djasypt.encryptor.password=password -jar target/jasypt-spring-boot-demo-0.0.1-SNAPSHOT.jar
总结
这样两个小技巧就讲完了,大家有 SpringBoot 的更多使用技巧欢迎留言讨论。
上文的一些实例代码可以在这里找到:
https://github.com/crossoverJie/springboot-cloud
-END-
近期热文:
Swagger中配置了@ApiModelProperty的allowableValues属性但不显示的问题
为什么Kafka中的分区数只能增加不能减少?
一文带你吃透线程池
设计一个百万级的消息推送系统
Hmily:高性能异步分布式事务TCC框架
并行化:你的高并发大杀器
Spring Boot整合 Sentry 监控项目日志
重磅:Elasticsearch上市!市值近50亿美元
利用SPRING管理热加载的GROOVY对象!
Spring Boot中如何扩展XML请求和响应的支持
Java 11正式发布,新特性解读
关注我
点击“阅读原文”,看本号其他精彩内容
分享几个 SpringBoot 实用的小技巧相关推荐
- 25个实用编程小技巧
点击上方"朱小厮的博客",选择"设为星标" 回复"1024"获取独家整理的学习资料 如果每个程序开发人员都只是周而复始地写代码,想必编程的工 ...
- 计算机给文件重命名快捷键,实用电脑小技巧:批量重命名文件常用的小工具也可以设快捷键...
沪江小编:对于很多人来说,电脑应该算是使用频率最高的工具了,可是你真的会用电脑么?实用电脑小技巧,用最简单明了的方式给你无比有趣的电脑使用新体验. [视觉遗像]注视图形中央的四个黑点30秒,然后闭眼仰 ...
- Revit软件的【项目管理类】实用的小技巧,提高效率
Revit是我国建筑业BIM体系中应用最广泛的软件之一.在项目建模过程中常会遇到一些小问题,导致工作效率降低. 今天给大家分享一些实用的小技巧,希望能帮大家提高效率. 项目管理类 1.房间识别设置 机 ...
- 企业微博营销都有哪些实用的小技巧呢?
现代微博客喜欢使用社交平台,企业常用的推广平台.企业界想利用微博进行推广,让大多数微博用户浏览推广的内容并转发,随意写一些内容当然不行,但很多人也不知道如何去利用微博.事实上,微博推广有方法,掌握了相 ...
- 云服务器回收站图片修复,回收站删除的照片怎么恢复?简单实用的小技巧
回收站删除的照片怎么恢复?简单实用的小技巧 2020年06月29日 14:20作者:黄页编辑:黄页 分享 回收站删除的照片怎么恢复?在平时生活工作和学习中,相信很多人也都会定期对电脑桌面和磁盘进行清理 ...
- Python五种实用的小技巧
本文经"机器之心"授权,禁止二次转载. 作者:Peter Nistru 机器之心编译 参与:思 最开始学 Python 时,如果我能掌握这些方法,那么代码看起来会更加优美. 在本文 ...
- html制作nba网页,NBA篮球_实用电脑小技巧:通俗解答html 自己动手建一个非常简单的网页_沪江英语...
沪江小编:对于很多人来说,电脑应该算是使用频率最高的工具了,可是你真的会用电脑么?实用电脑小技巧,用最简单明了的方式给你无比有趣的电脑使用新体验. html是什么,什么是html通俗解答: 通俗的讲h ...
- 教师节html源码,教师节_实用电脑小技巧:通俗解答html 自己动手建一个非常简单的网页_沪江英语...
沪江小编:对于很多人来说,电脑应该算是使用频率最高的工具了,可是你真的会用电脑么?实用电脑小技巧,用最简单明了的方式给你无比有趣的电脑使用新体验. html是什么,什么是html通俗解答: 通俗的讲h ...
- 工作中这些实用的小技巧,90%的程序员不知道
工作中这些实用的小技巧,90%的程序员不知道 Linux 有些Linux命令我们是经常用的,但是这些命令有的特别长(如进入层级特别深的项目部署目录),这时就可以为这些命令定义一个别名 系统级别定义的别 ...
最新文章
- android实现分类搜索功能,android应用中的搜索功能怎么实现的
- 实战SSM_O2O商铺_46【Redis缓存】头条信息+商铺目录Service层加入缓存
- elemet UI 中表格数据的排序操作
- [C++11]继承构造函数
- Makefile函数使用
- 无心剑中译叶芝诗17首
- MTK驱动(77)---Android getevent用法
- bug9-TypeError: ‘generator‘ object is not subscriptable
- Python实现空间直角坐标转高斯克吕格平面坐标
- 上大计算机专业在哪校区,好消息!成都理工大学在川扩招751人,宜宾校区新增计算机443人...
- 什么是开环控制?什么是闭环控制?它们有什么区别?
- 若依(RuoYi)配置教程
- 基于AOP的优惠券发送异常哨兵监控
- 将CSDN中文章同步到微信公众号
- paypal支付 paypal网站付款标准版问题解决
- Git学习笔记:中国版GItHub,码云
- 射频开关主要性能指标
- Windows 安装Docker 打包镜像
- ApproximateVoxelGrid和VoxelGrid详解
- Model Inspector — 软件模型静态规范检查工具
热门文章
- centos7 yum 错误 This system is not registered with an entitlement server
- linux 使用dd命令 写入镜像文件到u盘
- postgresql(pg)数据库简介
- searchsploit工具(exploit-db.com)使用实例 (linux 内核漏洞提权) exploitdb
- UUID介绍与生成方法
- 渗透神器sqlmap的使用笔记
- UNIX文件mode_t详解
- php 头部utf8,PHP去掉utf8格式文件中的bom头部_PHP教程
- mysql查询不到邮件_mysql – sql查询通过电子邮件获取用户列表
- android 安装 apk 7.0,android 7.0及以上版本安装apk