工作任务项杂记_201904
文章目录
最近的工作比较杂,因此一直没有整理一篇博文。刚好五一假期了,想着不能再拖下去了,即使写出的东西太琐碎,也稍微记录下,作个备忘也挺好的。
spring boot应用中使用redis缓存
如子标题,有需求要在spring boot应用中使用redis缓存,这个还是比较简单的,如下:
添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
添加配置
spring:
redis:
# Redis服务器连接密码(默认为空)
password:
# Redis数据库索引(默认为0)
database: 0
# Redis服务器连接端口
port: 6379
pool:
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 0
# 连接池最大连接数(使用负值表示没有限制)
max-active: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1
# Redis服务器地址
host: localhost
# 连接超时时间(毫秒)
timeout: 0
然后就可以使用了StringRedisTemplate
等Bean了
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void test() throws Exception {
// 保存字符串
stringRedisTemplate.opsForValue().set("aaa", "111");
Assert.assertEquals("111", stringRedisTemplate.opsForValue().get("aaa"));
}
上面的代码通过自动配置的StringRedisTemplate
对象进行Redis的读写操作,该对象从命名中就可注意到支持的是String类型。StringRedisTemplate
就相当于RedisTemplate<String, String>
的实现。除了String类型,实战中我们还经常会在Redis中存储对象,这时可以自己实现RedisSerializer<T>
接口来对传入对象进行序列化和反序列化,进而将该对象写入Redis缓存。
public class User implements Serializable {
private static final long serialVersionUID = -1L;
private String username;
...
}
public class RedisObjectSerializer implements RedisSerializer<Object> {
private Converter<Object, byte[]> serializer = new SerializingConverter();
private Converter<byte[], Object> deserializer = new DeserializingConverter();
static final byte[] EMPTY_ARRAY = new byte[0];
public Object deserialize(byte[] bytes) {
if (isEmpty(bytes)) {
return null;
}
try {
return deserializer.convert(bytes);
} catch (Exception ex) {
throw new SerializationException("Cannot deserialize", ex);
}
}
public byte[] serialize(Object object) {
if (object == null) {
return EMPTY_ARRAY;
}
try {
return serializer.convert(object);
} catch (Exception ex) {
return EMPTY_ARRAY;
}
}
private boolean isEmpty(byte[] data) {
return (data == null || data.length == 0);
}
}
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, User> userRedisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, User> template = new RedisTemplate<String, User>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new RedisObjectSerializer());
return template;
}
}
@Autowired
private RedisTemplate<String, User> redisTemplate;
@Test
public void test() throws Exception {
// 保存对象
User user = new User("超人", 20);
redisTemplate.opsForValue().set(user.getUsername(), user);
user = new User("蝙蝠侠", 30);
redisTemplate.opsForValue().set(user.getUsername(), user);
user = new User("蜘蛛侠", 40);
redisTemplate.opsForValue().set(user.getUsername(), user);
Assert.assertEquals(20, redisTemplate.opsForValue().get("超人").getAge().longValue());
Assert.assertEquals(30, redisTemplate.opsForValue().get("蝙蝠侠").getAge().longValue());
Assert.assertEquals(40, redisTemplate.opsForValue().get("蜘蛛侠").getAge().longValue());
}
RedisTemplate
接口的方法很多,基本上涵盖了Redis了绝大部分操作,使用时参考其API文档就可以了。
spring boot应用中使用rabbitmq
如子标题,有需求要在spring boot应用中使用redis缓存,这个还是比较简单的,如下:
添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
添加配置项
spring:
rabbitmq:
password: 123456
port: 5672
host: localhost
username: spring
配置队列、交换器、路由等高级信息,一般会用到org.springframework.amqp.core.Queue
、org.springframework.amqp.core.QueueBuilder
等类、org.springframework.amqp.core.Exchange
的实现类,使用时参考其API文档。
@Configuration
public class RabbitConfig {
@Bean
public Queue helloQueue() {
return new Queue("hello");
}
}
使用AmqpTemplate
发送MQ消息,基本使用AmqpTemplate
就可以进行MQ消息的绝大部分操作,使用时参考其API文档就可以了。
@Autowired
private AmqpTemplate rabbitTemplate;
public void send() {
String context = "hello " + new Date();
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("hello", context);
}
使用RabbitListener
配合RabbitHandler
接收MQ消息,一般会用到org.springframework.amqp.rabbit.annotation.RabbitListener
、org.springframework.amqp.rabbit.annotation.RabbitHandler
、org.springframework.amqp.rabbit.annotation.Queue
、org.springframework.amqp.rabbit.annotation.Exchange
等类,使用时参考其API文档。
@Component
@RabbitListener(queues = "hello")
public class Receiver {
@RabbitHandler
public void process(String hello) {
System.out.println("Receiver : " + hello);
}
}
spring boot应用打包成docker镜像
spring boot应用的构建工具已经很完善了,要完成子标题所述的任务已经有很成熟的maven plugin - docker-maven-plugin。
简单使用方法
<build>
<plugins>
...
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>VERSION GOES HERE</version>
<configuration>
<imageName>example</imageName>
<baseImage>java</baseImage>
<entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
<!-- copy the service's jar file from target into the root directory of the image -->
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
...
</plugins>
</build>
如果要使用自定义的Dockerfile,则如下配置,在dockerDirectory
指定的目录下放入Dockerfile文件就可以了:
<build>
<plugins>
...
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>VERSION GOES HERE</version>
<configuration>
<imageName>example</imageName>
<dockerDirectory>docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
...
</plugins>
</build>
其它还可以在package时自动打docker镜像,在deploy时自动将docker镜像推入registry,这些高级功能参考官方文档。
centos7下手动设置DNS服务器
centos7下网络默认是由NetworkManager管理的,如果直接修改/etc/resolv.conf
设置的DNS服务器很容易被冲掉,因此找到了一个办法解决这个问题。
- 修改 /etc/NetworkManager/NetworkManager.conf 文件,在main部分添加 “dns=none” 选项:
[main]
plugins=ifcfg-rh
dns=none
- NetworkManager重新装载上面修改的配置
# systemctl restart NetworkManager.service
- 手工修改 /etc/resolv.conf
nameserver 114.114.114.114
nameserver 8.8.8.8
专业的bash脚本
最近看了istio-sidecar相关的bash脚本,发现一个专业的bash脚本最好还是不要像写流水帐一样书写脚本逻辑,是很有必要加入必要的注释、输入参数解析、脚本使用说明、定义主函数及各分支函数。
在脚本开关需要用英文书写必要的注释详细说明脚本的用途,这一点参考一些专业的脚本都可以看到。
建议使用Linux风格的输入参数风格解析,可以使用bash的内置命令
getopts
和外部命令getopt
,这两种方法的使用方法可参考shell脚本之shift和getopts、shell中的getopt与getopts。脚本使用说明可使用
usage
函数完成,如下:usage() { echo "bla bla bla ..." } # 解析参数时,当发现-h或--help参数,立即执行usage,输出脚本使用说明 -h|--help) usage ;;
为了避免bash脚本成为流水帐,建议整个脚本按以下函数组织
# 解析参数 parse_args() { ... } # 校验参数 validate_args() { ... } # 脚本所做工作第一步 do_work_step1() { ... } # 脚本所做工作第二步 do_work_step2() { ... } # 脚本所做工作第三步 do_work_step3() { ... } main() { parse_args validate_args do_work_step1 do_work_step2 do_work_step3 ... } # 脚本入口函数 main
swagger文档的妙用
很多后端的项目都以swagger文档的方式向外暴露API文档,最近在工作确实体会到这种方式的好处。
前端拿到swagger API文档后,可使用swagger-editor轻松生成nodejs-server版的server stub,在此基础上即可开发简易的mock server了,这样前端的开发即可不再依赖后端了。
后端可使用swagger-editor生成对应语言的server stub,生成的代码很有参考价值,可直接在此基础上改造或将部分代码拷贝到已有后端项目中。
如果是微服务架构的应用,可使用swagger-editor生成相应语言的客户端代码,这样服务间的调用直接用客户端代码组合形成的SDK即可,不再需要手动发送HTTP请求及解析HTTP响应了。
微服务架构的应用,每个微服务都以swagger方式暴露API,这时可以将这些API文档聚合起来,请团队中的成员在统一的文档中心查看各微服务的文档,如下:
docker run -d --name swagger-docs -p 8888:8080 -e 'URLS=[{ url: "http://petstore.swagger.io/v2/swagger.json", name: "Petstore" }, { url: "http://generator.swagger.io/api/swagger.json", name: "Generator" }]' swaggerapi/swagger-ui:latest
这里使用了swagger-ui的一个urls选项,这个选项在2017年初就已经存在了,不知道为什么网上讲swagger API文档聚合的方案基本都是让改造swagger-ui的代码,汗!
参考
- http://blog.didispace.com/springbootredis/
- http://blog.didispace.com/spring-boot-rabbitmq/
- https://github.com/spotify/docker-maven-plugin
- http://www.pubyun.com/blog/announce/centos-7-%E4%B8%8B%EF%BC%8C%E5%A6%82%E4%BD%95%E8%AE%BE%E7%BD%AEdns%E6%9C%8D%E5%8A%A1%E5%99%A8/
- http://www.361way.com/shell-shift-getopts/4973.html
- http://www.361way.com/shell-getopt/4981.html
- https://github.com/swagger-api/swagger-ui/pull/3261
文章作者 Jeremy Xu
上次更新 2019-05-04
许可协议 © Copyright 2020 Jeremy Xu