惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
V
V2EX
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
Martin Fowler
Martin Fowler
小众软件
小众软件
Blog — PlanetScale
Blog — PlanetScale
月光博客
月光博客
The Cloudflare Blog
T
Tailwind CSS Blog
H
Help Net Security
腾讯CDC
爱范儿
爱范儿
人人都是产品经理
人人都是产品经理
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The GitHub Blog
The GitHub Blog
Microsoft Security Blog
Microsoft Security Blog
Stack Overflow Blog
Stack Overflow Blog
D
DataBreaches.Net
C
Check Point Blog
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
美团技术团队
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

犀利豆的博客

《SRE google 运维解密》读书笔记 (六) 《SRE google 运维解密》读书笔记 (五) 《SRE google 运维解密》读书笔记 (四) 《SRE google 运维解密》读书笔记 (三) 《SRE google 运维解密》读书笔记 (二) 《SRE google 运维解密》读书笔记 (一) 2021 总结 终于有一个 Java 可以用的微信机器人了 Vertx入门到实战—实现钉钉机器人内网穿透代理 钉钉机器人回调内网穿透代理--使用篇 周末补习(一)trie 树 那些有趣的代码(三)--勤俭持家的 ArrayList 那些有趣的代码(二)--偏不听父母话的 Tomcat 类加载器 那些有趣的代码(一)--有点萌的 Tomcat 的线程池 从需求第三定律说起--为什么知乎的回答质量下降了 如何利用 Spring Hibernate 高级特性设计实现一个权限系统 居然有人能忘记吃饭?写个微信机器人提醒他 我的2018年总结 从 LongAdder 中窥见并发组件的设计思路 徒手撸框架--实现 RPC 远程调用 我的写作工具链 Java 渲染 docx 文件,并生成 pdf 加水印 撸码的福音--变量名生成器的实现 Raft 协议学习笔记 dubbo 源码学习(一)开篇 Redis 命令的执行过程 Redis 中的事件驱动模型 Redis 数据库、键过期的实现 Redis 的基础数据结构(三)对象 Redis 的基础数据结构(二) 整数集合、跳跃表、压缩列表
最近遇到的几个问题集合
Zhengxin Diao · 2017-11-29 · via 犀利豆的博客

最近在写项目的时候遇到了几个小问题,记录下来。希望对大家也有所帮助。

如何获取 T 的 class

在写BaseDao 之类的代码的时候,经常会遇到获取泛型T的class的情况?我们发现并没有T.class这种写法,那怎么办呢?想起之前写的Hibernate 里面有相关的代码。通过反射获取T的class

1
2
3
4
5
6
7
8
9
10
11
12
public class AbstractDao<T>{

private Class<T> clz;

public AbstractDao(){
this.clz = (Class<T>)
((ParameterizedType)getClass()
.getGenericSuperclass())
.getActualTypeArguments()[0];
}
...
}

Spring中的 @Value 加载时间

首先 @Value 注解可以方便的获取配置文件*.properties的参数。

在写代码的时候遇到这样一个问题。为了减少重复代码,我们通常需要写一个抽象类把共有的方法抽象到Abstract 类中。AbstractDao<T> 如果遇到需要向这个class的构造方法注入参数。且这个参数是通过抽象方法获取的。且这个数据是使用 Spring的 @Value 注解获取的。这个描述比较绕,我们直接看代码:

1
2
3
4
5
6
7
8
9
public class AbstractDao<T>{
private int tableId;

public AbstractDao(){
this.tableId = setTableId();
}

protected abstract int setTableId();
}
1
2
3
4
5
6
7
8
9
public class UserDao extends AbstractDao<User>{

@Value("${tableid.user}")
private int userTableId;

protected int setTableId() {
return buserTableId;
}
}

代码运行起来以后,我们发现 userTableId,并不能取到相应的值,这个时候@Value失效了。实际上这个问题的根源是因为@Value的加载是发生在对象实例化之后。也就是首先调用对象的构造函数,然后再获取配置文件中的数据。

解决的方案是使用注解 @PostConstruct,意思是构造函数执行完以后再执行注解标记的方法。我们可以吧抽象函数做如下修改:

1
2
3
4
5
6
7
8
9
10
public class AbstractDao<T>{
private int tableId;

@PostConstruct
public init(){
this.tableId = setTableId();
}

protected abstract int setTableId();
}

使用 Java 8 的 lambda 和 stream 来 merge List

在使用微服务架构以后。我们经常会遇到 Merge两个List的场景。比如我们从索引里面获取了一个 List<Long> 包含的是对象的ID的 list。由于前端对象展示的元素需要。用这个ID 的list分别从两个服务批量的查询得到 List<A>List<B>,然后将两个List合二为一成为一个List<C>,返回给前端作为列表页展示。

看代码:
首先我们有一个对象 A:

1
2
3
4
public class A{
private long id;
private String aStr;
}

有另一个对象 B:

1
2
3
4
public class B{
private long id;
private String bStr;
}

页面需要的对象C:

1
2
3
4
5
public class C{
private long id;
private String aStr;
private String bStr;
}

如何有效的把 List<A>List<B> merge 为一个 List呢?

总体思路,因为两个list从不同服务里面获取。有可能两个服务出于健壮性的考虑会抛弃某些查询不到的对象,所以两个list的长度有可能不一致。所以使用一个Map<Long,B> 作为索引。
如果直接写代码会相当繁琐。如果使用 Java 8 的新特性Lamabdastream api 就能快速写出代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

private C getCForAAndB(A a,B b){
C c = new C();
c.setId(a.getId());
c.setAstr(a.getAStr())
c.setBstr(b.getBStr())
return c;
}

private List<C> mergeList(List<A> aList,List<B> bList){

Map<Long,B> bMap = bList.parallelStream()
.collect(Collectors.toMap(B::getId,b -> b));

return aList.parallelStream()
.map(a -> getCForAAndB(a,bMap.get(a.getId)))
.collect(Collectors.toList());
}

这样merge的代码简洁明了。

如果不明白的同学可以参考我之前的 Java 8 教程。