分享几个 SpringBoot 实用的小技巧
前言
最近分享的一些源码、框架设计的东西。我发现大家热情不是特别高,想想大多数应该还是正儿八经写代码的居多;这次就分享一点接地气的: 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 + "----------------");
}
之后只需要使用密文就行。
由于我这里是对数据库用户名和密码加密,所以还得有一个解密的过程。
利用 Spring Bean
的一个增强接口即可实现:
@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
欢迎关注公众号一起交流:
分享几个 SpringBoot 实用的小技巧的更多相关文章
- Facebook内部分享:25个高效工作的小技巧
Facebook内部分享:25个高效工作的小技巧 Facebook 内部分享:不论你如何富有,你都赚不到更多的时间,你也回不到过去.没有那么多的假如,只有指针滴答的时光飞逝和你应该好好把握的现在,以下 ...
- scanf和printf格式化输入输出中非常实用的小技巧
输入输出几乎是每个C程序必须具备的功能,因为有了它们,程序才有了交互性.C提供的输入输出函数除了具有必须的输入输出功能外,还有一些其他实用的小技巧,了解这些小技巧将会为程序带来更友好的用户体验. 一. ...
- 【技术分享】BurpSuite 代理设置的小技巧
作者:三思之旅 预估稿费:300RMB 投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿 在Web渗透测试过程中,BurpSuite是不可或缺的神器之一.BurpSuite的核心是 ...
- 哪些window你不知道的却实用的小技巧----window小技巧
前言 一直想要整理一篇有关于window比较全的使用小技巧,却又不知道从哪里开始写起.而让我准备动手写这边随笔的动力,还是在加入虫部落<一个绿色环保,充满朝气的好地方>,从大家的分享中,我 ...
- Photoshop中比较实用的小技巧
Photoshop是目前最流行的图片处理软件软件之一.能够说,只要接触图片处理,就要和它打交道.Photoshop的强大功能和众多的优点不用多说.用photoshop做一些漂亮的图片,或对照片进行简单 ...
- 盘点 php 里面那些冷门又实用的小技巧
1.实用某个字段索引二维数组 取出一个数组的一个字段的值的数组,我们可以使用 array_column, 这个方法还有另外一个用法,如 array_column($array, null, 'key' ...
- Xcode不太常见又实用的小技巧
备份, 原文: http://rocry.com/2012/12/17/xcode-tips/ 让代码中的TODO和FIXME变成Warning 选中某个Target > Build Phase ...
- 记录一些实用的小技巧-CSS篇
1.单行文本截断 .text{ width: 200px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } 2.多行 ...
- springboot中的小技巧
1.Thymeleaf 在时使用Thymeleaf的时候不用设置html标签:在默认的Thymeleaf的页面中,对于.html的要求比较严格,少写或者多写标签,都会被报错,而在springboot ...
随机推荐
- python分支——if
单分支判断 age = 16 if age >= 18: 判断语句,判断age是否大于等于18,注意if后面要加空格,条件写完后要加: print("你已经成年") prin ...
- C语言--第五次作业--指针
1.本章学习总结 1.1 思维导图 1.2本章学习体会及代码量学习体会 1.2.1学习体会 没想到都已经学习完C语言的灵魂-指针的内容了(当然也是C里面最难学习的内容了).虽然在之前就有听学习进度比较 ...
- scala_2
一.scala类 . 在java中程序的入口是main方法->定义在class中 在scala中程序的入口是main方法->定义在object对象中 案例一: class People { ...
- Oracle 与 Mysql NULL值,空字符串''的区别
Oracle(null等同于空字符'') 1.oracle插入空字符串默认替换成null 2.oracle查询(null和被替换的空字符)时使用 is null/is not null 3.使用聚合函 ...
- Linux--Linux下安装JDk
好不容易免费使用了服务器,还不会安装JDK,记录一下怎么弄. 方法一:远程服务器可以联网下载(高级货) 命令: wget -c -P /root/jdk --no-check-certificate ...
- NOIP-火柴棒等式
题目描述 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0-9的拼法如图所示: 注意: 1. 加号与等 ...
- NOIP-接水问题
题目描述 学校里有一个水房,水房里一共装有m个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为1. 现在有n名同学准备接水,他们的初始接水顺序已经确定.将这些同学按接水顺序从1到n编号,i号同学 ...
- React(九)create-react-app创建项目 + 按需加载Ant Design
(1)create-react-app如何创建项目我前面第一章介绍过了,这里就不过多写了, (2)我们主要来说说按需加载的问题 1. 引入antd npm install antd --save 2. ...
- 非vue-cli的花括号闪现问题
<div id="app" v-cloak></div>[v-cloak] { display: none;}这种方式可以解决网速较慢,vue.js文件还没 ...
- 异步使用委托delegate --- BeginInvoke和EndInvoke方法
当我们定义一个委托的时候,一般语言运行时会自动帮委托定义BeginInvoke 和 EndInvoke两个方法,这两个方法的作用是可以异步调用委托. 方法BeginInvoke有两个参数: Async ...